From 1fee797af79a86043a3d64fd260919e07ef0ea7c Mon Sep 17 00:00:00 2001 From: dirkdeyne Date: Sun, 14 Jul 2019 12:46:48 +0200 Subject: [PATCH] Add support for configuring Tomcat's relaxed path and query chars See gh-17510 --- .../autoconfigure/web/ServerProperties.java | 31 +++++++++++++++++++ .../TomcatWebServerFactoryCustomizer.java | 13 ++++++++ .../web/ServerPropertiesTests.java | 4 +++ 3 files changed, 48 insertions(+) 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 97183844258..b90d9e9c430 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 @@ -61,6 +61,7 @@ import org.springframework.util.unit.DataSize; * @author Artsiom Yudovin * @author Andrew McGhie * @author Rafiullah Hamedy + * @author Dirk Deyne * @since 1.0.0 */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) @@ -405,6 +406,20 @@ public class ServerProperties { */ private final Mbeanregistry mbeanregistry = new Mbeanregistry(); + /** + * Specify additional unencoded characters that Tomcat should allow in a + * querystring. The value may be any combination of the following characters: " < + * > [ \ ] ^ ` { | } . Any other characters present in the value will be ignored. + */ + private String relaxedQueryChars; + + /** + * Specify additional unencoded characters that Tomcat should allow in the path. + * The value may be any combination of the following characters: " < > [ \ ] ^ ` { + * | } . Any other characters present in the value will be ignored. + */ + private String relaxedPathChars; + public int getMaxThreads() { return this.maxThreads; } @@ -561,6 +576,22 @@ public class ServerProperties { return this.mbeanregistry; } + public String getRelaxedPathChars() { + return this.relaxedPathChars; + } + + public void setRelaxedPathChars(String relaxedPathChars) { + this.relaxedPathChars = relaxedPathChars; + } + + public String getRelaxedQueryChars() { + return this.relaxedQueryChars; + } + + public void setRelaxedQueryChars(String relaxedQueryChars) { + this.relaxedQueryChars = relaxedQueryChars; + } + /** * 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 7fca30d3417..c90eeda1130 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 @@ -51,6 +51,7 @@ import org.springframework.util.unit.DataSize; * @author Artsiom Yudovin * @author Chentao Qu * @author Andrew McGhie + * @author Dirk Deyne * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer @@ -102,6 +103,10 @@ public class TomcatWebServerFactoryCustomizer .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); propertyMapper.from(tomcatProperties::getProcessorCache) .to((processorCache) -> customizeProcessorCache(factory, processorCache)); + propertyMapper.from(tomcatProperties::getRelaxedQueryChars) + .to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars)); + propertyMapper.from(tomcatProperties::getRelaxedPathChars) + .to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -149,6 +154,14 @@ public class TomcatWebServerFactoryCustomizer }); } + private void customizeRelaxedQueryChars(ConfigurableTomcatWebServerFactory factory, String relaxedChars) { + factory.addConnectorCustomizers((connector) -> connector.setAttribute("relaxedQueryChars", relaxedChars)); + } + + private void customizeRelaxedPathChars(ConfigurableTomcatWebServerFactory factory, String relaxedChars) { + factory.addConnectorCustomizers((connector) -> connector.setAttribute("relaxedPathChars", relaxedChars)); + } + private void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory) { Tomcat tomcatProperties = this.serverProperties.getTomcat(); String protocolHeader = tomcatProperties.getProtocolHeader(); 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 eee30bf1883..0a43545b9b2 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 @@ -127,6 +127,8 @@ class ServerPropertiesTests { map.put("server.tomcat.remote-ip-header", "Remote-Ip"); map.put("server.tomcat.internal-proxies", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); map.put("server.tomcat.background-processor-delay", "10"); + map.put("server.tomcat.relaxed-path-chars", "|"); + map.put("server.tomcat.relaxed-query-chars", "^^"); bind(map); ServerProperties.Tomcat tomcat = this.properties.getTomcat(); Accesslog accesslog = tomcat.getAccesslog(); @@ -146,6 +148,8 @@ class ServerPropertiesTests { assertThat(tomcat.getProtocolHeader()).isEqualTo("X-Forwarded-Protocol"); assertThat(tomcat.getInternalProxies()).isEqualTo("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); assertThat(tomcat.getBackgroundProcessorDelay()).isEqualTo(Duration.ofSeconds(10)); + assertThat(tomcat.getRelaxedPathChars()).isEqualTo("|"); + assertThat(tomcat.getRelaxedQueryChars()).isEqualTo("^^"); } @Test