Skip to content

Commit c2887b3

Browse files
authored
Merge pull request graphql-java#3062 from AntaresS/add-trackData-to-ParserOptions
Allow users to disable MultiSourceReader trackData through ParserOptions
2 parents 640d282 + 836ed59 commit c2887b3

3 files changed

Lines changed: 34 additions & 6 deletions

File tree

src/main/java/graphql/parser/Parser.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,19 @@ private Type<?> parseTypeImpl(String input) throws InvalidSyntaxException {
254254
}
255255

256256
private Node<?> parseImpl(ParserEnvironment environment, BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction) throws InvalidSyntaxException {
257+
// default in the parser options if they are not set
258+
ParserOptions parserOptions = environment.getParserOptions();
259+
parserOptions = Optional.ofNullable(parserOptions).orElse(ParserOptions.getDefaultParserOptions());
260+
257261
MultiSourceReader multiSourceReader;
258262
Reader reader = environment.getDocument();
259263
if (reader instanceof MultiSourceReader) {
260264
multiSourceReader = (MultiSourceReader) reader;
261265
} else {
262266
multiSourceReader = MultiSourceReader.newMultiSourceReader()
263-
.reader(reader, null).build();
267+
.reader(reader, null)
268+
.trackData(parserOptions.isReaderTrackData())
269+
.build();
264270
}
265271
CodePointCharStream charStream;
266272
try {
@@ -290,10 +296,6 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
290296
}
291297
});
292298

293-
// default in the parser options if they are not set
294-
ParserOptions parserOptions = environment.getParserOptions();
295-
parserOptions = Optional.ofNullable(parserOptions).orElse(ParserOptions.getDefaultParserOptions());
296-
297299
// this lexer wrapper allows us to stop lexing when too many tokens are in place. This prevents DOS attacks.
298300
int maxTokens = parserOptions.getMaxTokens();
299301
int maxWhitespaceTokens = parserOptions.getMaxWhitespaceTokens();

src/main/java/graphql/parser/ParserOptions.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class ParserOptions {
3636
.captureIgnoredChars(false)
3737
.captureSourceLocation(true)
3838
.captureLineComments(true)
39+
.readerTrackData(true)
3940
.maxTokens(MAX_QUERY_TOKENS) // to prevent a billion laughs style attacks, we set a default for graphql-java
4041
.maxWhitespaceTokens(MAX_WHITESPACE_TOKENS)
4142
.build();
@@ -44,6 +45,7 @@ public class ParserOptions {
4445
.captureIgnoredChars(false)
4546
.captureSourceLocation(true)
4647
.captureLineComments(false) // #comments are not useful in query parsing
48+
.readerTrackData(true)
4749
.maxTokens(MAX_QUERY_TOKENS) // to prevent a billion laughs style attacks, we set a default for graphql-java
4850
.maxWhitespaceTokens(MAX_WHITESPACE_TOKENS)
4951
.build();
@@ -52,6 +54,7 @@ public class ParserOptions {
5254
.captureIgnoredChars(false)
5355
.captureSourceLocation(true)
5456
.captureLineComments(true) // #comments are useful in SDL parsing
57+
.readerTrackData(true)
5558
.maxTokens(Integer.MAX_VALUE) // we are less worried about a billion laughs with SDL parsing since the call path is not facing attackers
5659
.maxWhitespaceTokens(Integer.MAX_VALUE)
5760
.build();
@@ -154,6 +157,7 @@ public static void setDefaultSdlParserOptions(ParserOptions options) {
154157
private final boolean captureIgnoredChars;
155158
private final boolean captureSourceLocation;
156159
private final boolean captureLineComments;
160+
private final boolean readerTrackData;
157161
private final int maxTokens;
158162
private final int maxWhitespaceTokens;
159163
private final ParsingListener parsingListener;
@@ -162,6 +166,7 @@ private ParserOptions(Builder builder) {
162166
this.captureIgnoredChars = builder.captureIgnoredChars;
163167
this.captureSourceLocation = builder.captureSourceLocation;
164168
this.captureLineComments = builder.captureLineComments;
169+
this.readerTrackData = builder.readerTrackData;
165170
this.maxTokens = builder.maxTokens;
166171
this.maxWhitespaceTokens = builder.maxWhitespaceTokens;
167172
this.parsingListener = builder.parsingListener;
@@ -204,6 +209,15 @@ public boolean isCaptureLineComments() {
204209
return captureLineComments;
205210
}
206211

212+
/**
213+
* Controls whether the underlying {@link MultiSourceReader} should track previously read data or not.
214+
*
215+
* @return true if {@link MultiSourceReader} should track data in memory.
216+
*/
217+
public boolean isReaderTrackData() {
218+
return readerTrackData;
219+
}
220+
207221
/**
208222
* A graphql hacking vector is to send nonsensical queries that burn lots of parsing CPU time and burns
209223
* memory representing a document that won't ever execute. To prevent this you can set a maximum number of parse
@@ -245,6 +259,7 @@ public static class Builder {
245259
private boolean captureIgnoredChars = false;
246260
private boolean captureSourceLocation = true;
247261
private boolean captureLineComments = true;
262+
private boolean readerTrackData = true;
248263
private int maxTokens = MAX_QUERY_TOKENS;
249264
private ParsingListener parsingListener = ParsingListener.NOOP;
250265
private int maxWhitespaceTokens = MAX_WHITESPACE_TOKENS;
@@ -276,6 +291,11 @@ public Builder captureLineComments(boolean captureLineComments) {
276291
return this;
277292
}
278293

294+
public Builder readerTrackData(boolean readerTrackData) {
295+
this.readerTrackData = readerTrackData;
296+
return this;
297+
}
298+
279299
public Builder maxTokens(int maxTokens) {
280300
this.maxTokens = maxTokens;
281301
return this;

src/test/groovy/graphql/parser/ParserOptionsTest.groovy

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,25 @@ class ParserOptionsTest extends Specification {
2626
defaultOptions.isCaptureSourceLocation()
2727
defaultOptions.isCaptureLineComments()
2828
!defaultOptions.isCaptureIgnoredChars()
29+
defaultOptions.isReaderTrackData()
2930

3031
defaultOperationOptions.getMaxTokens() == 15_000
3132
defaultOperationOptions.getMaxWhitespaceTokens() == 200_000
3233
defaultOperationOptions.isCaptureSourceLocation()
3334
!defaultOperationOptions.isCaptureLineComments()
3435
!defaultOperationOptions.isCaptureIgnoredChars()
36+
defaultOptions.isReaderTrackData()
3537

3638
defaultSdlOptions.getMaxTokens() == Integer.MAX_VALUE
3739
defaultSdlOptions.getMaxWhitespaceTokens() == Integer.MAX_VALUE
3840
defaultSdlOptions.isCaptureSourceLocation()
3941
defaultSdlOptions.isCaptureLineComments()
4042
!defaultSdlOptions.isCaptureIgnoredChars()
43+
defaultOptions.isReaderTrackData()
4144
}
4245

4346
def "can set in new option JVM wide"() {
44-
def newDefaultOptions = defaultOptions.transform({ it.captureIgnoredChars(true) })
47+
def newDefaultOptions = defaultOptions.transform({ it.captureIgnoredChars(true).readerTrackData(false) })
4548
def newDefaultOperationOptions = defaultOperationOptions.transform(
4649
{ it.captureIgnoredChars(true).captureLineComments(true).maxWhitespaceTokens(300_000) })
4750
def newDefaultSDlOptions = defaultSdlOptions.transform(
@@ -63,17 +66,20 @@ class ParserOptionsTest extends Specification {
6366
currentDefaultOptions.isCaptureSourceLocation()
6467
currentDefaultOptions.isCaptureLineComments()
6568
currentDefaultOptions.isCaptureIgnoredChars()
69+
!currentDefaultOptions.isReaderTrackData()
6670

6771
currentDefaultOperationOptions.getMaxTokens() == 15_000
6872
currentDefaultOperationOptions.getMaxWhitespaceTokens() == 300_000
6973
currentDefaultOperationOptions.isCaptureSourceLocation()
7074
currentDefaultOperationOptions.isCaptureLineComments()
7175
currentDefaultOperationOptions.isCaptureIgnoredChars()
76+
currentDefaultOperationOptions.isReaderTrackData()
7277

7378
currentDefaultSdlOptions.getMaxTokens() == Integer.MAX_VALUE
7479
currentDefaultSdlOptions.getMaxWhitespaceTokens() == 300_000
7580
currentDefaultSdlOptions.isCaptureSourceLocation()
7681
currentDefaultSdlOptions.isCaptureLineComments()
7782
currentDefaultSdlOptions.isCaptureIgnoredChars()
83+
currentDefaultSdlOptions.isReaderTrackData()
7884
}
7985
}

0 commit comments

Comments
 (0)