Skip to content

Commit 60a03df

Browse files
committed
Add option for setting max query params
Relates to: quarkusio/quarkus#47431
1 parent caa3962 commit 60a03df

File tree

8 files changed

+94
-5
lines changed

8 files changed

+94
-5
lines changed

vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, HttpSer
8787
obj.setMaxFormBufferedBytes(((Number)member.getValue()).intValue());
8888
}
8989
break;
90+
case "maxQueryParams":
91+
if (member.getValue() instanceof Number) {
92+
obj.setMaxQueryParams(((Number)member.getValue()).intValue());
93+
}
94+
break;
9095
case "initialSettings":
9196
if (member.getValue() instanceof JsonObject) {
9297
obj.setInitialSettings(new io.vertx.core.http.Http2Settings((io.vertx.core.json.JsonObject)member.getValue()));
@@ -214,6 +219,7 @@ static void toJson(HttpServerOptions obj, java.util.Map<String, Object> json) {
214219
json.put("maxFormAttributeSize", obj.getMaxFormAttributeSize());
215220
json.put("maxFormFields", obj.getMaxFormFields());
216221
json.put("maxFormBufferedBytes", obj.getMaxFormBufferedBytes());
222+
json.put("maxQueryParams", obj.getMaxQueryParams());
217223
if (obj.getInitialSettings() != null) {
218224
json.put("initialSettings", obj.getInitialSettings().toJson());
219225
}

vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ public class HttpServerOptions extends NetServerOptions {
101101
*/
102102
public static final int DEFAULT_MAX_FORM_BUFFERED_SIZE = 1024;
103103

104+
/**
105+
* Default max number of query params = 1024
106+
*/
107+
public static final int DEFAULT_MAX_QUERY_PARAMS = 1024;
108+
104109
/**
105110
* Default value of whether 100-Continue should be handled automatically = {@code false}
106111
*/
@@ -209,6 +214,7 @@ public class HttpServerOptions extends NetServerOptions {
209214
private int maxFormAttributeSize;
210215
private int maxFormFields;
211216
private int maxFormBufferedBytes;
217+
private int maxQueryParams;
212218
private Http1ServerConfig http1Config;
213219
private Http2ServerConfig http2Config;
214220
private WebSocketServerConfig webSocketConfig;
@@ -239,6 +245,7 @@ public HttpServerOptions(HttpServerOptions other) {
239245
this.maxFormAttributeSize = other.getMaxFormAttributeSize();
240246
this.maxFormFields = other.getMaxFormFields();
241247
this.maxFormBufferedBytes = other.getMaxFormBufferedBytes();
248+
this.maxQueryParams = other.getMaxQueryParams();
242249
this.compressionLevel = other.getCompressionLevel();
243250
this.compression = other.compression != null ? new HttpCompressionConfig(other.compression) : new HttpCompressionConfig();
244251
this.handle100ContinueAutomatically = other.handle100ContinueAutomatically;
@@ -278,6 +285,7 @@ private void init() {
278285
maxFormAttributeSize = DEFAULT_MAX_FORM_ATTRIBUTE_SIZE;
279286
maxFormFields = DEFAULT_MAX_FORM_FIELDS;
280287
maxFormBufferedBytes = DEFAULT_MAX_FORM_BUFFERED_SIZE;
288+
maxQueryParams = DEFAULT_MAX_QUERY_PARAMS;
281289
strictThreadMode = DEFAULT_STRICT_THREAD_MODE_STRICT;
282290
compression = new HttpCompressionConfig();
283291
handle100ContinueAutomatically = DEFAULT_HANDLE_100_CONTINE_AUTOMATICALLY;
@@ -845,6 +853,24 @@ public HttpServerOptions setMaxFormBufferedBytes(int maxFormBufferedBytes) {
845853
return this;
846854
}
847855

856+
/**
857+
* @return Returns the maximum number of query params
858+
*/
859+
public int getMaxQueryParams() {
860+
return maxQueryParams;
861+
}
862+
863+
/**
864+
* Set the maximum number of query params
865+
*
866+
* @param maxQueryParams the new maximum
867+
* @return a reference to this, so the API can be used fluently
868+
*/
869+
public HttpServerOptions setMaxQueryParams(int maxQueryParams) {
870+
this.maxQueryParams = maxQueryParams;
871+
return this;
872+
}
873+
848874
/**
849875
* @return the initial HTTP/2 connection settings
850876
*/

vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class HttpServerRequestImpl extends HttpServerRequestInternal {
5252
private final int maxFormAttributeSize;
5353
private final int maxFormFields;
5454
private final int maxFormBufferedBytes;
55+
private final int maxQueryParams;
5556
private final Handler<HttpServerRequest> handler;
5657

5758
// Accessed on context thread
@@ -79,6 +80,7 @@ public HttpServerRequestImpl(Handler<HttpServerRequest> handler,
7980
int maxFormAttributeSize,
8081
int maxFormFields,
8182
int maxFormBufferedBytes,
83+
int maxQueryParams,
8284
String serverOrigin) {
8385
this.handler = handler;
8486
this.context = context;
@@ -89,6 +91,7 @@ public HttpServerRequestImpl(Handler<HttpServerRequest> handler,
8991
this.handle100ContinueAutomatically = handle100ContinueAutomatically;
9092
this.maxFormAttributeSize = maxFormAttributeSize;
9193
this.maxFormFields = maxFormFields;
94+
this.maxQueryParams = maxQueryParams;
9295
this.maxFormBufferedBytes = maxFormBufferedBytes;
9396
}
9497

@@ -397,7 +400,7 @@ public String getParamsCharset() {
397400
public MultiMap params(boolean semicolonIsNormalChar) {
398401
synchronized (connection) {
399402
if (params == null || semicolonIsNormalChar != semicolonIsNormalCharInParams) {
400-
params = HttpUtils.params(uri(), paramsCharset, semicolonIsNormalChar);
403+
params = HttpUtils.params(uri(), paramsCharset, maxQueryParams, semicolonIsNormalChar);
401404
semicolonIsNormalCharInParams = semicolonIsNormalChar;
402405
}
403406
return params;

vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,11 @@ public static String absoluteURI(String serverOrigin, HttpServerRequest req) {
344344
}
345345

346346
public static MultiMap params(String uri, Charset charset, boolean semicolonIsNormalChar) {
347-
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, charset, true, 1024, semicolonIsNormalChar);
347+
return params(uri, charset, 1024, semicolonIsNormalChar);
348+
}
349+
350+
public static MultiMap params(String uri, Charset charset, int maxParams, boolean semicolonIsNormalChar) {
351+
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, charset, true, maxParams, semicolonIsNormalChar);
348352
Map<String, List<String>> prms = queryStringDecoder.parameters();
349353
MultiMap params = MultiMap.caseInsensitiveMultiMap();
350354
if (!prms.isEmpty()) {

vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ public String getParamsCharset() {
337337
@Override
338338
public MultiMap params(boolean semicolonIsNormalChar) {
339339
if (params == null || semicolonIsNormalChar != semicolonIsNormalCharInParams) {
340-
params = HttpUtils.params(uri(), paramsCharset, semicolonIsNormalChar);
340+
params = HttpUtils.params(uri(), paramsCharset, this.conn.options.getMaxQueryParams(), semicolonIsNormalChar);
341341
semicolonIsNormalCharInParams = semicolonIsNormalChar;
342342
}
343343
return params;

vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public void handle(HttpServerConnection conn) {
101101
HttpServerConfig config = server.config;
102102
HttpServerRequestImpl request = new HttpServerRequestImpl(requestHandler, stream, stream.context(),
103103
config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), config.getMaxFormFields(),
104-
config.getMaxFormBufferedBytes(), serverOrigin);
104+
config.getMaxFormBufferedBytes(), config.getMaxQueryParams(), serverOrigin);
105105
request.init();
106106
});
107107
}

vertx-core/src/test/java/io/vertx/tests/http/Http1xTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ public void testServerOptions() {
411411
assertEquals(256, options.getDecoderInitialBufferSize());
412412
assertIllegalArgumentException(() -> options.setDecoderInitialBufferSize(-1));
413413

414+
assertEquals(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, options.getMaxQueryParams());
415+
assertEquals(options, options.setMaxQueryParams(1025));
416+
assertEquals(1025, options.getMaxQueryParams());
414417
}
415418

416419
@Test
@@ -772,6 +775,7 @@ public void testCopyServerOptions() {
772775
boolean decompressionSupported = rand.nextBoolean();
773776
boolean acceptUnmaskedFrames = rand.nextBoolean();
774777
int decoderInitialBufferSize = TestUtils.randomPositiveInt();
778+
int maxQueryParams = TestUtils.randomPositiveInt();
775779

776780
options.setSendBufferSize(sendBufferSize);
777781
options.setReceiveBufferSize(receiverBufferSize);
@@ -803,6 +807,7 @@ public void testCopyServerOptions() {
803807
options.setDecompressionSupported(decompressionSupported);
804808
options.setAcceptUnmaskedFrames(acceptUnmaskedFrames);
805809
options.setDecoderInitialBufferSize(decoderInitialBufferSize);
810+
options.setMaxQueryParams(maxQueryParams);
806811

807812
HttpServerOptions copy = new HttpServerOptions(options);
808813
checkCopyHttpServerOptions(options, copy);
@@ -906,6 +911,7 @@ public void testServerOptionsJson() {
906911
boolean decompressionSupported = TestUtils.randomBoolean();
907912
boolean acceptUnmaskedFrames = TestUtils.randomBoolean();
908913
int decoderInitialBufferSize = TestUtils.randomPositiveInt();
914+
int maxQueryParams = TestUtils.randomPositiveInt();
909915

910916
JsonObject json = new JsonObject();
911917
json.put("sendBufferSize", sendBufferSize)
@@ -946,7 +952,8 @@ public void testServerOptionsJson() {
946952
.put("openSslSessionCacheEnabled", openSslSessionCacheEnabled)
947953
.put("decompressionSupported", decompressionSupported)
948954
.put("acceptUnmaskedFrames", acceptUnmaskedFrames)
949-
.put("decoderInitialBufferSize", decoderInitialBufferSize);
955+
.put("decoderInitialBufferSize", decoderInitialBufferSize)
956+
.put("maxQueryParams", maxQueryParams);
950957

951958
HttpServerOptions options = new HttpServerOptions(json);
952959
assertEquals(sendBufferSize, options.getSendBufferSize());
@@ -996,6 +1003,7 @@ public void testServerOptionsJson() {
9961003
assertEquals(decompressionSupported, options.isDecompressionSupported());
9971004
assertEquals(acceptUnmaskedFrames, options.isAcceptUnmaskedFrames());
9981005
assertEquals(decoderInitialBufferSize, options.getDecoderInitialBufferSize());
1006+
assertEquals(maxQueryParams, options.getMaxQueryParams());
9991007

10001008
// Test other keystore/truststore types
10011009
json.remove("keyStoreOptions");

vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,6 +2344,48 @@ public void test1xxRemovesTransferEncodingHeader() throws Exception {
23442344
assertNull(respHeaders.get("transfer-encoding"));
23452345
}
23462346

2347+
@Test
2348+
public void testMaxQueryParams() {
2349+
testMaxQueryParams(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS);
2350+
}
2351+
2352+
@Test
2353+
public void testMaxQueryParamsOption() {
2354+
testMaxQueryParams(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS * 2);
2355+
}
2356+
2357+
private void testMaxQueryParams(Integer maxQueryParams) {
2358+
MultiMap params = TestUtils.randomMultiMap(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS + 10);
2359+
String query = generateQueryString(params, ';');
2360+
2361+
vertx.createHttpServer(new HttpServerOptions().setMaxQueryParams(maxQueryParams).setMaxInitialLineLength(Integer.MAX_VALUE))
2362+
.requestHandler(req -> {
2363+
assertEquals(query, req.query());
2364+
if (maxQueryParams > HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS) {
2365+
assertEquals(params.size(), req.params().size());
2366+
} else {
2367+
assertEquals(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, req.params().size());
2368+
req.response().setStatusCode(414);
2369+
}
2370+
req.response().end();
2371+
}).listen(testAddress).onComplete(onSuccess(res -> {
2372+
client.close();
2373+
client = vertx.createHttpClient(new HttpClientOptions());
2374+
client
2375+
.request(new RequestOptions(requestOptions).setURI("some-uri/?" + query))
2376+
.compose(req -> req.send().compose(resp -> {
2377+
if (maxQueryParams > HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS) {
2378+
assertEquals(200, resp.statusCode());
2379+
} else {
2380+
assertEquals(414, resp.statusCode());
2381+
}
2382+
return resp.end();
2383+
}))
2384+
.onComplete(onSuccess(v -> testComplete()));
2385+
}));
2386+
await();
2387+
}
2388+
23472389
protected MultiMap checkEmptyHttpResponse(HttpMethod method, int sc, MultiMap reqHeaders) throws Exception {
23482390
server.requestHandler(req -> {
23492391
HttpServerResponse resp = req.response();

0 commit comments

Comments
 (0)