diff --git a/vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java b/vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java index a28f3699976..1e16780c8cc 100644 --- a/vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java +++ b/vertx-core/src/main/generated/io/vertx/core/http/HttpServerOptionsConverter.java @@ -87,6 +87,11 @@ static void fromJson(Iterable> json, HttpSer obj.setMaxFormBufferedBytes(((Number)member.getValue()).intValue()); } break; + case "maxQueryParams": + if (member.getValue() instanceof Number) { + obj.setMaxQueryParams(((Number)member.getValue()).intValue()); + } + break; case "initialSettings": if (member.getValue() instanceof JsonObject) { obj.setInitialSettings(new io.vertx.core.http.Http2Settings((io.vertx.core.json.JsonObject)member.getValue())); @@ -219,6 +224,7 @@ static void toJson(HttpServerOptions obj, java.util.Map json) { json.put("maxFormAttributeSize", obj.getMaxFormAttributeSize()); json.put("maxFormFields", obj.getMaxFormFields()); json.put("maxFormBufferedBytes", obj.getMaxFormBufferedBytes()); + json.put("maxQueryParams", obj.getMaxQueryParams()); if (obj.getInitialSettings() != null) { json.put("initialSettings", obj.getInitialSettings().toJson()); } diff --git a/vertx-core/src/main/java/io/vertx/core/http/HttpServerConfig.java b/vertx-core/src/main/java/io/vertx/core/http/HttpServerConfig.java index 70250ae48e6..2190747ece3 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/HttpServerConfig.java +++ b/vertx-core/src/main/java/io/vertx/core/http/HttpServerConfig.java @@ -64,6 +64,7 @@ private static TcpServerConfig defaultTcpServerConfig() { private int maxFormAttributeSize; private int maxFormFields; private int maxFormBufferedBytes; + private int maxQueryParams; private boolean handle100ContinueAutomatically; private boolean strictThreadMode; private ObservabilityConfig observabilityConfig; @@ -123,6 +124,7 @@ public HttpServerConfig(HttpServerOptions options) { this.maxFormAttributeSize = options.getMaxFormAttributeSize(); this.maxFormFields = options.getMaxFormFields(); this.maxFormBufferedBytes = options.getMaxFormBufferedBytes(); + this.maxQueryParams = options.getMaxQueryParams(); this.handle100ContinueAutomatically = options.isHandle100ContinueAutomatically(); this.strictThreadMode = options.getStrictThreadMode(); this.observabilityConfig = observabilityConfig; @@ -142,6 +144,7 @@ public HttpServerConfig() { this.maxFormAttributeSize = HttpServerOptions.DEFAULT_MAX_FORM_ATTRIBUTE_SIZE; this.maxFormFields = HttpServerOptions.DEFAULT_MAX_FORM_FIELDS; this.maxFormBufferedBytes = HttpServerOptions.DEFAULT_MAX_FORM_BUFFERED_SIZE; + this.maxQueryParams = HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS; this.handle100ContinueAutomatically = HttpServerOptions.DEFAULT_HANDLE_100_CONTINE_AUTOMATICALLY; this.strictThreadMode = HttpServerOptions.DEFAULT_STRICT_THREAD_MODE_STRICT; this.observabilityConfig = null; @@ -164,6 +167,7 @@ public HttpServerConfig(HttpServerConfig other) { this.maxFormAttributeSize = other.maxFormAttributeSize; this.maxFormFields = other.maxFormFields; this.maxFormBufferedBytes = other.maxFormBufferedBytes; + this.maxQueryParams = other.maxQueryParams; this.handle100ContinueAutomatically = other.handle100ContinueAutomatically; this.strictThreadMode = other.strictThreadMode; this.observabilityConfig = other.observabilityConfig != null ? new ObservabilityConfig(other.observabilityConfig) : null; @@ -405,6 +409,24 @@ public int getMaxFormFields() { return maxFormFields; } + /** + * @return Returns the maximum number of query params + */ + public int getMaxQueryParams() { + return maxQueryParams; + } + + /** + * Set the maximum number of query params + * + * @param maxQueryParams the new maximum + * @return a reference to this, so the API can be used fluently + */ + public HttpServerConfig setMaxQueryParams(int maxQueryParams) { + this.maxQueryParams = maxQueryParams; + return this; + } + /** * Set the maximum number of fields of a form. Set to {@code -1} to allow unlimited number of attributes * diff --git a/vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java b/vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java index 6d1b19af18a..fcea04f0a61 100755 --- a/vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java +++ b/vertx-core/src/main/java/io/vertx/core/http/HttpServerOptions.java @@ -101,6 +101,11 @@ public class HttpServerOptions extends NetServerOptions { */ public static final int DEFAULT_MAX_FORM_BUFFERED_SIZE = 1024; + /** + * Default max number of query params = 1024 + */ + public static final int DEFAULT_MAX_QUERY_PARAMS = 1024; + /** * Default value of whether 100-Continue should be handled automatically = {@code false} */ @@ -214,6 +219,7 @@ public class HttpServerOptions extends NetServerOptions { private int maxFormAttributeSize; private int maxFormFields; private int maxFormBufferedBytes; + private int maxQueryParams; private Http1ServerConfig http1Config; private Http2ServerConfig http2Config; private WebSocketServerConfig webSocketConfig; @@ -246,6 +252,7 @@ public HttpServerOptions(HttpServerOptions other) { this.maxFormAttributeSize = other.getMaxFormAttributeSize(); this.maxFormFields = other.getMaxFormFields(); this.maxFormBufferedBytes = other.getMaxFormBufferedBytes(); + this.maxQueryParams = other.getMaxQueryParams(); this.compressionLevel = other.getCompressionLevel(); this.compression = other.compression != null ? new CompressionConfig(other.compression) : new CompressionConfig(); this.handle100ContinueAutomatically = other.handle100ContinueAutomatically; @@ -287,6 +294,7 @@ private void init() { maxFormAttributeSize = DEFAULT_MAX_FORM_ATTRIBUTE_SIZE; maxFormFields = DEFAULT_MAX_FORM_FIELDS; maxFormBufferedBytes = DEFAULT_MAX_FORM_BUFFERED_SIZE; + maxQueryParams = DEFAULT_MAX_QUERY_PARAMS; strictThreadMode = DEFAULT_STRICT_THREAD_MODE_STRICT; compression = new CompressionConfig(); handle100ContinueAutomatically = DEFAULT_HANDLE_100_CONTINE_AUTOMATICALLY; @@ -861,6 +869,24 @@ public HttpServerOptions setMaxFormBufferedBytes(int maxFormBufferedBytes) { return this; } + /** + * @return Returns the maximum number of query params + */ + public int getMaxQueryParams() { + return maxQueryParams; + } + + /** + * Set the maximum number of query params + * + * @param maxQueryParams the new maximum + * @return a reference to this, so the API can be used fluently + */ + public HttpServerOptions setMaxQueryParams(int maxQueryParams) { + this.maxQueryParams = maxQueryParams; + return this; + } + /** * @return the initial HTTP/2 connection settings */ diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java index 604b52998b0..a480a69f892 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpServerRequestImpl.java @@ -52,6 +52,7 @@ public class HttpServerRequestImpl extends HttpServerRequestInternal { private final int maxFormAttributeSize; private final int maxFormFields; private final int maxFormBufferedBytes; + private final int maxQueryParams; private final Handler handler; // Accessed on context thread @@ -79,6 +80,7 @@ public HttpServerRequestImpl(Handler handler, int maxFormAttributeSize, int maxFormFields, int maxFormBufferedBytes, + int maxQueryParams, String serverOrigin) { this.handler = handler; this.context = context; @@ -89,6 +91,7 @@ public HttpServerRequestImpl(Handler handler, this.handle100ContinueAutomatically = handle100ContinueAutomatically; this.maxFormAttributeSize = maxFormAttributeSize; this.maxFormFields = maxFormFields; + this.maxQueryParams = maxQueryParams; this.maxFormBufferedBytes = maxFormBufferedBytes; } @@ -397,7 +400,7 @@ public String getParamsCharset() { public MultiMap params(boolean semicolonIsNormalChar) { synchronized (connection) { if (params == null || semicolonIsNormalChar != semicolonIsNormalCharInParams) { - params = HttpUtils.params(uri(), paramsCharset, semicolonIsNormalChar); + params = HttpUtils.params(uri(), paramsCharset, maxQueryParams, semicolonIsNormalChar); semicolonIsNormalCharInParams = semicolonIsNormalChar; } return params; diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java index 2f43224c86c..cbfcf86c187 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java @@ -344,7 +344,11 @@ public static String absoluteURI(String serverOrigin, HttpServerRequest req) { } public static MultiMap params(String uri, Charset charset, boolean semicolonIsNormalChar) { - QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, charset, true, 1024, semicolonIsNormalChar); + return params(uri, charset, 1024, semicolonIsNormalChar); + } + + public static MultiMap params(String uri, Charset charset, int maxParams, boolean semicolonIsNormalChar) { + QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, charset, true, maxParams, semicolonIsNormalChar); Map> prms = queryStringDecoder.parameters(); MultiMap params = MultiMap.caseInsensitiveMultiMap(); if (!prms.isEmpty()) { diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java b/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java index 7b93d6a1b4a..96020477414 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerConnection.java @@ -78,6 +78,7 @@ public class Http1ServerConnection extends Http1Connection implements HttpServer private final boolean eagerCreateRequestQueue; private final int maxFormAttributeSize; private final int maxFormFields; + private final int maxQueryParams; private final int maxFormBufferedBytes; private final Http1ServerConfig serverConfig; private final boolean registerWebSocketWriteHandlers; @@ -104,6 +105,7 @@ public Http1ServerConnection(ThreadingModel threadingModel, SslContextManager sslContextManager, int maxFormAttributeSize, int maxFormFields, + int maxQueryParams, int maxFormBufferedBytes, Http1ServerConfig serverConfig, boolean registerWebSocketWriteHandlers, @@ -119,6 +121,7 @@ public Http1ServerConnection(ThreadingModel threadingModel, this.streamContextSupplier = streamContextSupplier; this.maxFormAttributeSize = maxFormAttributeSize; this.maxFormFields = maxFormFields; + this.maxQueryParams = maxQueryParams; this.maxFormBufferedBytes = maxFormBufferedBytes; this.serverConfig = serverConfig; this.registerWebSocketWriteHandlers = registerWebSocketWriteHandlers; @@ -142,6 +145,10 @@ int maxFormFields() { return maxFormFields; } + int maxQueryParams() { + return maxQueryParams; + } + int maxFormBufferedBytes() { return maxFormBufferedBytes; } diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java b/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java index c815278e2c3..a6484f60ed0 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerRequest.java @@ -337,7 +337,7 @@ public String getParamsCharset() { @Override public MultiMap params(boolean semicolonIsNormalChar) { if (params == null || semicolonIsNormalChar != semicolonIsNormalCharInParams) { - params = HttpUtils.params(uri(), paramsCharset, semicolonIsNormalChar); + params = HttpUtils.params(uri(), paramsCharset, this.conn.maxQueryParams(), semicolonIsNormalChar); semicolonIsNormalCharInParams = semicolonIsNormalChar; } return params; diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java b/vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java index 4a2afed258c..65ec966aa8f 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/quic/QuicHttpServer.java @@ -143,6 +143,7 @@ private static class ConnectionHandler implements Handler { private final boolean handle100ContinueAutomatically; private final int maxFormAttributeSize; private final int maxFormFields; + private final int maxQueryParams; private final int maxFormBufferedSize; private final Http3Settings localSettings; private final boolean logEnabled; @@ -154,6 +155,7 @@ public ConnectionHandler(QuicServer transport, boolean handle100ContinueAutomatically, int maxFormAttributeSize, int maxFormFields, + int maxQueryParams, int maxFormBufferedSize, Http3Settings localSettings, boolean logEnabled) { @@ -164,6 +166,7 @@ public ConnectionHandler(QuicServer transport, this.handle100ContinueAutomatically = handle100ContinueAutomatically; this.maxFormAttributeSize = maxFormAttributeSize; this.maxFormFields = maxFormFields; + this.maxQueryParams = maxQueryParams; this.maxFormBufferedSize = maxFormBufferedSize; this.localSettings = localSettings; this.logEnabled = logEnabled; @@ -186,7 +189,7 @@ public void handle(QuicConnection connection) { http3Connection.streamHandler(stream -> { HttpServerRequestImpl request = new HttpServerRequestImpl(requestHandler, stream, stream.context(), handle100ContinueAutomatically, maxFormAttributeSize, - maxFormFields, maxFormBufferedSize, serverOrigin); + maxFormFields, maxFormBufferedSize, maxQueryParams, serverOrigin); request.init(); }); @@ -239,7 +242,9 @@ public Future listen(ContextInternal current, SocketAddress address) quicConfig.setLogConfig(null); quicServer.handler(new ConnectionHandler(quicServer, httpMetrics, requestHandler, connectionHandler, - config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), config.getMaxFormFields(), config.getMaxFormBufferedBytes(), + config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), + config.getMaxFormFields(), config.getMaxQueryParams(), + config.getMaxFormBufferedBytes(), http3Config.getInitialSettings() != null ? http3Config.getInitialSettings().copy() : new Http3Settings(), logEnabled)); return quicServer .bind(current, address) diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionHandler.java b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionHandler.java index 13b5401f433..ceb338220e9 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionHandler.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionHandler.java @@ -101,7 +101,7 @@ public void handle(HttpServerConnection conn) { HttpServerConfig config = server.config; HttpServerRequestImpl request = new HttpServerRequestImpl(requestHandler, stream, stream.context(), config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), config.getMaxFormFields(), - config.getMaxFormBufferedBytes(), serverOrigin); + config.getMaxFormBufferedBytes(), config.getMaxQueryParams(), serverOrigin); request.init(); }); } diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionInitializer.java b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionInitializer.java index adadd2ecc34..11a52984f8f 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionInitializer.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/HttpServerConnectionInitializer.java @@ -66,6 +66,7 @@ public class HttpServerConnectionInitializer { private final boolean handle100ContinueAutomatically; private final int maxFormAttributeSize; private final int maxFormFields; + private final int maxQueryParams; private final int maxFormBufferedBytes; private final Http1ServerConfig http1Config; private final Http2ServerConfig http2Config; @@ -91,6 +92,7 @@ public HttpServerConnectionInitializer(ContextInternal context, boolean handle100ContinueAutomatically, int maxFormAttributeSize, int maxFormFields, + int maxQueryParams, int maxFormBufferedBytes, Http1ServerConfig http1Config, Http2ServerConfig http2Config, @@ -157,6 +159,7 @@ public HttpServerConnectionInitializer(ContextInternal context, this.handle100ContinueAutomatically = handle100ContinueAutomatically; this.maxFormAttributeSize = maxFormAttributeSize; this.maxFormFields = maxFormFields; + this.maxQueryParams = maxQueryParams; this.maxFormBufferedBytes = maxFormBufferedBytes; this.http1Config = http1Config; this.http2Config = http2Config; @@ -305,6 +308,7 @@ public void configureHttp1Handler(ChannelPipeline pipeline, SslContextManager ss sslContextManager, maxFormAttributeSize, maxFormFields, + maxQueryParams, maxFormBufferedBytes, http1Config, registerWebSocketWriteHandlers, diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/TcpHttpServer.java b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/TcpHttpServer.java index 8215e01c637..0aff4921e1a 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/TcpHttpServer.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/tcp/TcpHttpServer.java @@ -253,6 +253,7 @@ public synchronized Future listen(ContextInternal context, SocketAdd config.isHandle100ContinueAutomatically(), config.getMaxFormAttributeSize(), config.getMaxFormFields(), + config.getMaxQueryParams(), config.getMaxFormBufferedBytes(), http1Config, http2Config, diff --git a/vertx-core/src/test/java/io/vertx/benchmarks/HttpServerHandlerBenchmark.java b/vertx-core/src/test/java/io/vertx/benchmarks/HttpServerHandlerBenchmark.java index d30b1c94442..2f701e8cdf2 100644 --- a/vertx-core/src/test/java/io/vertx/benchmarks/HttpServerHandlerBenchmark.java +++ b/vertx-core/src/test/java/io/vertx/benchmarks/HttpServerHandlerBenchmark.java @@ -236,6 +236,7 @@ public void setup() { null, HttpServerOptions.DEFAULT_MAX_FORM_ATTRIBUTE_SIZE, HttpServerOptions.DEFAULT_MAX_FORM_FIELDS, + HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, HttpServerOptions.DEFAULT_MAX_FORM_BUFFERED_SIZE, new Http1ServerConfig(), false, diff --git a/vertx-core/src/test/java/io/vertx/test/http/HttpConfig.java b/vertx-core/src/test/java/io/vertx/test/http/HttpConfig.java index 9f04729179a..ee3ea92c9c0 100644 --- a/vertx-core/src/test/java/io/vertx/test/http/HttpConfig.java +++ b/vertx-core/src/test/java/io/vertx/test/http/HttpConfig.java @@ -120,6 +120,11 @@ public HttpServerConfig setMaxFormFields(int maxFormFields) { return this; } @Override + public HttpServerConfig setMaxQueryParams(int maxQueryParams) { + options.setMaxQueryParams(maxQueryParams); + return this; + } + @Override public HttpServerConfig setLogActivity(boolean logActivity) { options.setLogActivity(logActivity); return this; diff --git a/vertx-core/src/test/java/io/vertx/test/http/HttpServerConfig.java b/vertx-core/src/test/java/io/vertx/test/http/HttpServerConfig.java index 251cd48dcee..655e0bea80a 100644 --- a/vertx-core/src/test/java/io/vertx/test/http/HttpServerConfig.java +++ b/vertx-core/src/test/java/io/vertx/test/http/HttpServerConfig.java @@ -13,6 +13,7 @@ public interface HttpServerConfig { HttpServerConfig setMaxFormBufferedBytes(int maxFormBufferedBytes); HttpServerConfig setMaxFormAttributeSize(int maxSize); HttpServerConfig setMaxFormFields(int maxFormFields); + HttpServerConfig setMaxQueryParams(int maxQueryParams); HttpServerConfig setIdleTimeout(Duration timeout); HttpServerConfig setLogActivity(boolean logActivity); HttpServerConfig setHandle100ContinueAutomatically(boolean b); diff --git a/vertx-core/src/test/java/io/vertx/tests/benchmark/Http1xServerConnectionTest.java b/vertx-core/src/test/java/io/vertx/tests/benchmark/Http1xServerConnectionTest.java index 30b2958f1ba..20347609c6a 100644 --- a/vertx-core/src/test/java/io/vertx/tests/benchmark/Http1xServerConnectionTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/benchmark/Http1xServerConnectionTest.java @@ -67,6 +67,7 @@ public void testSimple() { null, HttpServerOptions.DEFAULT_MAX_FORM_ATTRIBUTE_SIZE, HttpServerOptions.DEFAULT_MAX_FORM_FIELDS, + HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, HttpServerOptions.DEFAULT_MAX_FORM_BUFFERED_SIZE, new Http1ServerConfig(), false, diff --git a/vertx-core/src/test/java/io/vertx/tests/http/Http1xTest.java b/vertx-core/src/test/java/io/vertx/tests/http/Http1xTest.java index 5f5270dcbd0..77e51eaeac5 100644 --- a/vertx-core/src/test/java/io/vertx/tests/http/Http1xTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/http/Http1xTest.java @@ -423,6 +423,9 @@ public void testServerOptions() { assertEquals(256, options.getDecoderInitialBufferSize()); assertIllegalArgumentException(() -> options.setDecoderInitialBufferSize(-1)); + assertEquals(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, options.getMaxQueryParams()); + assertEquals(options, options.setMaxQueryParams(1025)); + assertEquals(1025, options.getMaxQueryParams()); } @Test @@ -787,6 +790,7 @@ public void testCopyServerOptions() { boolean decompressionSupported = rand.nextBoolean(); boolean acceptUnmaskedFrames = rand.nextBoolean(); int decoderInitialBufferSize = TestUtils.randomPositiveInt(); + int maxQueryParams = TestUtils.randomPositiveInt(); options.setSendBufferSize(sendBufferSize); options.setReceiveBufferSize(receiverBufferSize); @@ -818,6 +822,7 @@ public void testCopyServerOptions() { options.setDecompressionSupported(decompressionSupported); options.setAcceptUnmaskedFrames(acceptUnmaskedFrames); options.setDecoderInitialBufferSize(decoderInitialBufferSize); + options.setMaxQueryParams(maxQueryParams); HttpServerOptions copy = new HttpServerOptions(options); checkCopyHttpServerOptions(options, copy); @@ -922,6 +927,7 @@ public void testServerOptionsJson() { boolean decompressionSupported = TestUtils.randomBoolean(); boolean acceptUnmaskedFrames = TestUtils.randomBoolean(); int decoderInitialBufferSize = TestUtils.randomPositiveInt(); + int maxQueryParams = TestUtils.randomPositiveInt(); JsonObject json = new JsonObject(); json.put("sendBufferSize", sendBufferSize) @@ -963,7 +969,8 @@ public void testServerOptionsJson() { .put("openSslSessionCacheEnabled", openSslSessionCacheEnabled) .put("decompressionSupported", decompressionSupported) .put("acceptUnmaskedFrames", acceptUnmaskedFrames) - .put("decoderInitialBufferSize", decoderInitialBufferSize); + .put("decoderInitialBufferSize", decoderInitialBufferSize) + .put("maxQueryParams", maxQueryParams); HttpServerOptions options = new HttpServerOptions(json); assertEquals(sendBufferSize, options.getSendBufferSize()); @@ -1014,6 +1021,7 @@ public void testServerOptionsJson() { assertEquals(decompressionSupported, options.isDecompressionSupported()); assertEquals(acceptUnmaskedFrames, options.isAcceptUnmaskedFrames()); assertEquals(decoderInitialBufferSize, options.getDecoderInitialBufferSize()); + assertEquals(maxQueryParams, options.getMaxQueryParams()); // Test other keystore/truststore types json.remove("keyStoreOptions"); diff --git a/vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java b/vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java index 62c592fed23..afc6e32672c 100644 --- a/vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/http/HttpTest.java @@ -2344,6 +2344,48 @@ public void test1xxRemovesTransferEncodingHeader() throws Exception { assertNull(respHeaders.get("transfer-encoding")); } + @Test + public void testMaxQueryParams() { + testMaxQueryParams(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS); + } + + @Test + public void testMaxQueryParamsOption() { + testMaxQueryParams(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS * 2); + } + + private void testMaxQueryParams(Integer maxQueryParams) { + MultiMap params = TestUtils.randomMultiMap(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS + 10); + String query = generateQueryString(params, ';'); + + vertx.createHttpServer(new HttpServerOptions().setMaxQueryParams(maxQueryParams).setMaxInitialLineLength(Integer.MAX_VALUE)) + .requestHandler(req -> { + assertEquals(query, req.query()); + if (maxQueryParams > HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS) { + assertEquals(params.size(), req.params().size()); + } else { + assertEquals(HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS, req.params().size()); + req.response().setStatusCode(414); + } + req.response().end(); + }).listen(testAddress).onComplete(onSuccess(res -> { + client.close(); + client = vertx.createHttpClient(new HttpClientOptions()); + client + .request(new RequestOptions(requestOptions).setURI("some-uri/?" + query)) + .compose(req -> req.send().compose(resp -> { + if (maxQueryParams > HttpServerOptions.DEFAULT_MAX_QUERY_PARAMS) { + assertEquals(200, resp.statusCode()); + } else { + assertEquals(414, resp.statusCode()); + } + return resp.end(); + })) + .onComplete(onSuccess(v -> testComplete())); + })); + await(); + } + protected MultiMap checkEmptyHttpResponse(HttpMethod method, int sc, MultiMap reqHeaders) throws Exception { server.requestHandler(req -> { HttpServerResponse resp = req.response(); diff --git a/vertx-core/src/test/java/io/vertx/tests/http/http3/Http3Config.java b/vertx-core/src/test/java/io/vertx/tests/http/http3/Http3Config.java index 0a839bcb647..f1de81cf401 100644 --- a/vertx-core/src/test/java/io/vertx/tests/http/http3/Http3Config.java +++ b/vertx-core/src/test/java/io/vertx/tests/http/http3/Http3Config.java @@ -85,6 +85,11 @@ public HttpServerConfig setMaxFormFields(int maxFormFields) { return this; } @Override + public HttpServerConfig setMaxQueryParams(int maxQueryParams) { + config.setMaxQueryParams(maxQueryParams); + return this; + } + @Override public HttpServerConfig setLogActivity(boolean logActivity) { throw new UnsupportedOperationException(); }