diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 2882b7079cbe..84e871f2bcac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -73,6 +73,7 @@ * @author Florian Storz * @author Michael Weidmann * @author Lasse Wulff + * @author Yanming Zhou * @since 1.0.0 */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) @@ -513,13 +514,11 @@ public static class Tomcat { */ private DataSize maxHttpResponseHeaderSize = DataSize.ofKilobytes(8); - public DataSize getMaxHttpFormPostSize() { - return this.maxHttpFormPostSize; - } - - public void setMaxHttpFormPostSize(DataSize maxHttpFormPostSize) { - this.maxHttpFormPostSize = maxHttpFormPostSize; - } + /** + * Maximum number of parameters (GET plus POST) that will be automatically parsed + * by the container. A value of less than 0 means no limit. + */ + private int maxParameterCount = 10000; public Accesslog getAccesslog() { return this.accesslog; @@ -669,6 +668,22 @@ public void setMaxHttpResponseHeaderSize(DataSize maxHttpResponseHeaderSize) { this.maxHttpResponseHeaderSize = maxHttpResponseHeaderSize; } + public DataSize getMaxHttpFormPostSize() { + return this.maxHttpFormPostSize; + } + + public void setMaxHttpFormPostSize(DataSize maxHttpFormPostSize) { + this.maxHttpFormPostSize = maxHttpFormPostSize; + } + + public int getMaxParameterCount() { + return this.maxParameterCount; + } + + public void setMaxParameterCount(int maxParameterCount) { + this.maxParameterCount = maxParameterCount; + } + /** * Tomcat access log properties. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java index 6feadf329bf0..b25ab2d0a221 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java @@ -62,6 +62,7 @@ * @author Parviz Rozikov * @author Florian Storz * @author Michael Weidmann + * @author Yanming Zhou * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer @@ -119,6 +120,8 @@ public void customize(ConfigurableTomcatWebServerFactory factory) { .asInt(DataSize::toBytes) .when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0) .to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize)); + map.from(properties::getMaxParameterCount) + .to((maxParameterCount) -> customizeMaxParameterCount(factory, maxParameterCount)); map.from(properties::getAccesslog) .when(ServerProperties.Tomcat.Accesslog::isEnabled) .to((enabled) -> customizeAccessLog(factory)); @@ -292,6 +295,10 @@ private void customizeMaxHttpFormPostSize(ConfigurableTomcatWebServerFactory fac factory.addConnectorCustomizers((connector) -> connector.setMaxPostSize(maxHttpFormPostSize)); } + private void customizeMaxParameterCount(ConfigurableTomcatWebServerFactory factory, int maxParameterCount) { + factory.addConnectorCustomizers((connector) -> connector.setMaxParameterCount(maxParameterCount)); + } + private void customizeAccessLog(ConfigurableTomcatWebServerFactory factory) { ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat(); AccessLogValve valve = new AccessLogValve(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java index 231df5b4c927..7ede269a03a5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java @@ -69,6 +69,7 @@ * @author Chris Bono * @author Parviz Rozikov * @author Lasse Wulff + * @author Yanming Zhou */ @DirtiesUrlFactories class ServerPropertiesTests { @@ -199,7 +200,7 @@ void testCustomizedMimeMapping() { } @Test - void testCustomizeUriEncoding() { + void testCustomizeTomcatUriEncoding() { bind("server.tomcat.uri-encoding", "US-ASCII"); assertThat(this.properties.getTomcat().getUriEncoding()).isEqualTo(StandardCharsets.US_ASCII); } @@ -235,17 +236,23 @@ void testCustomizeTomcatKeepAliveTimeoutWithInfinite() { } @Test - void customizeMaxKeepAliveRequests() { + void testCustomizeTomcatMaxKeepAliveRequests() { bind("server.tomcat.max-keep-alive-requests", "200"); assertThat(this.properties.getTomcat().getMaxKeepAliveRequests()).isEqualTo(200); } @Test - void customizeMaxKeepAliveRequestsWithInfinite() { + void testCustomizeTomcatMaxKeepAliveRequestsWithInfinite() { bind("server.tomcat.max-keep-alive-requests", "-1"); assertThat(this.properties.getTomcat().getMaxKeepAliveRequests()).isEqualTo(-1); } + @Test + void testCustomizeTomcatMaxParameterCount() { + bind("server.tomcat.max-parameter-count", "100"); + assertThat(this.properties.getTomcat().getMaxParameterCount()).isEqualTo(100); + } + @Test void testCustomizeTomcatMinSpareThreads() { bind("server.tomcat.threads.min-spare", "10"); @@ -379,6 +386,12 @@ void tomcatMaxHttpPostSizeMatchesConnectorDefault() { .isEqualTo(getDefaultConnector().getMaxPostSize()); } + @Test + void tomcatMaxParameterCountMatchesConnectorDefault() { + assertThat(this.properties.getTomcat().getMaxParameterCount()) + .isEqualTo(getDefaultConnector().getMaxParameterCount()); + } + @Test void tomcatBackgroundProcessorDelayMatchesEngineDefault() { assertThat(this.properties.getTomcat().getBackgroundProcessorDelay()) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java index f3c1ed493041..3e85de8e070b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java @@ -31,6 +31,8 @@ import org.apache.coyote.http2.Http2Protocol; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.ServerProperties.ForwardHeadersStrategy; @@ -59,6 +61,7 @@ * @author Victor Mandujano * @author Parviz Rozikov * @author Moritz Halbritter + * @author Yanming Zhou */ class TomcatWebServerFactoryCustomizerTests { @@ -194,6 +197,14 @@ void customMaxHttpRequestHeaderSize() { .isEqualTo(DataSize.ofMegabytes(10).toBytes())); } + @ParameterizedTest + @ValueSource(ints = { -1, 0, 100 }) + void customMaxParameterCount(int maxParameterCount) { + bind("server.tomcat.max-parameter-count=" + maxParameterCount); + customizeAndRunServer((server) -> assertThat(server.getTomcat().getConnector().getMaxParameterCount()) + .isEqualTo(maxParameterCount)); + } + @Test void customMaxRequestHttpHeaderSizeIgnoredIfNegative() { bind("server.max-http-request-header-size=-1");