From 200ac6db3042e62939d71946a619b203b8351e2d Mon Sep 17 00:00:00 2001 From: Rob Tompkins Date: Fri, 29 Jun 2018 09:21:13 -0400 Subject: [PATCH] Add configuration for Tomcat's cachingAllowed property See gh-13614 --- .../autoconfigure/web/ServerProperties.java | 30 +++++++++++++++++++ .../TomcatWebServerFactoryCustomizer.java | 20 +++++++++++++ ...TomcatWebServerFactoryCustomizerTests.java | 19 ++++++++++++ .../appendix-application-properties.adoc | 1 + 4 files changed, 70 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 1ec029bcd6..d3490ec879 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 @@ -52,6 +52,7 @@ import org.springframework.util.StringUtils; * @author Aurélien Leboulanger * @author Brian Clozel * @author Olivier Lamy + * @author Rob Tompkins */ @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { @@ -265,6 +266,11 @@ public class ServerProperties { */ private final Accesslog accesslog = new Accesslog(); + /** + * Web resource configuration. + */ + private final WebResource webResource = new WebResource(); + /** * Regular expression matching trusted IP addresses. */ @@ -399,6 +405,10 @@ public class ServerProperties { return this.accesslog; } + public WebResource getWebResource() { + return this.webResource; + } + public Duration getBackgroundProcessorDelay() { return this.backgroundProcessorDelay; } @@ -515,6 +525,26 @@ public class ServerProperties { return this.resource; } + /** + * Tomcat web resource properties. + */ + public static class WebResource { + + /** + * Whether tomcat WebResource caching is permitted for this web application. + */ + private Boolean useCaching = Boolean.TRUE; + + public Boolean getUseCaching() { + return this.useCaching; + } + + public void setUseCaching(Boolean useCaching) { + this.useCaching = useCaching; + } + + } + /** * 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 b1e2c0272b..12369ef899 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 @@ -19,9 +19,11 @@ package org.springframework.boot.autoconfigure.web.embedded; import java.time.Duration; import org.apache.catalina.Lifecycle; +import org.apache.catalina.WebResourceRoot; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.ErrorReportValve; import org.apache.catalina.valves.RemoteIpValve; +import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.http11.AbstractHttp11Protocol; @@ -46,6 +48,7 @@ import org.springframework.util.StringUtils; * @author Yulin Qin * @author Stephane Nicoll * @author Phillip Webb + * @author Rob Tompkins * @since 2.0.0 */ public class TomcatWebServerFactoryCustomizer implements @@ -70,6 +73,8 @@ public class TomcatWebServerFactoryCustomizer implements public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; ServerProperties.Tomcat tomcatProperties = properties.getTomcat(); + ServerProperties.Tomcat.WebResource tomcatWebResourceProperties = tomcatProperties + .getWebResource(); PropertyMapper propertyMapper = PropertyMapper.get(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull() .to(factory::setBaseDirectory); @@ -101,6 +106,9 @@ public class TomcatWebServerFactoryCustomizer implements .to((maxConnections) -> customizeMaxConnections(factory, maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount) -> customizeAcceptCount(factory, acceptCount)); + propertyMapper.from(tomcatWebResourceProperties::getUseCaching).whenFalse() + .to((isWebResourceCachingAllowed) -> customizeWebResourceCaching(factory, + isWebResourceCachingAllowed)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(), factory); } @@ -126,6 +134,18 @@ public class TomcatWebServerFactoryCustomizer implements }); } + private void customizeWebResourceCaching(ConfigurableTomcatWebServerFactory factory, + Boolean useWebResourceCaching) { + factory.addContextCustomizers((context) -> { + WebResourceRoot webResourceRoot = context.getResources(); + if (webResourceRoot == null) { + webResourceRoot = new StandardRoot(context); + } + webResourceRoot.setCachingAllowed(useWebResourceCaching); + context.setResources(webResourceRoot); + }); + } + private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) { factory.addConnectorCustomizers((connector) -> { 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 3cf616e88a..c426ae9030 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 @@ -16,14 +16,17 @@ package org.springframework.boot.autoconfigure.web.embedded; +import java.util.Map; import java.util.function.Consumer; import org.apache.catalina.Context; import org.apache.catalina.Valve; +import org.apache.catalina.mapper.Mapper; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.ErrorReportValve; import org.apache.catalina.valves.RemoteIpValve; +import org.apache.catalina.webresources.StandardRoot; import org.apache.coyote.AbstractProtocol; import org.junit.Before; import org.junit.Test; @@ -36,6 +39,7 @@ import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactor import org.springframework.boot.web.embedded.tomcat.TomcatWebServer; import org.springframework.mock.env.MockEnvironment; import org.springframework.test.context.support.TestPropertySourceUtils; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -44,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Brian Clozel * @author Phillip Webb + * @author Rob Tompkins */ public class TomcatWebServerFactoryCustomizerTests { @@ -94,6 +99,20 @@ public class TomcatWebServerFactoryCustomizerTests { .isEqualTo(5)); } + @Test + public void turnOffWebResourceCaching() { + bind("server.tomcat.webresource.use-caching=false"); + customizeAndRunServer((server) -> { + Mapper mapper = server.getTomcat().getService().getMapper(); + Object contextObjectToContextVersionMap = ReflectionTestUtils.getField(mapper, + "contextObjectToContextVersionMap"); + Object tomcatEmbeddedContext = ((Map) contextObjectToContextVersionMap) + .values().toArray()[0]; + assertThat(((StandardRoot) ReflectionTestUtils.getField(tomcatEmbeddedContext, + "resources")).isCachingAllowed()).isFalse(); + }); + } + @Test public void customMaxHttpPostSize() { bind("server.tomcat.max-http-post-size=10000"); diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index da8528ec56..98bddec845 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -262,6 +262,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache. server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI. server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. + server.tomcat.webresource.use-caching= # Whether tomcat WebResource caching is permitted for this web application. server.undertow.accesslog.dir= # Undertow access log directory. server.undertow.accesslog.enabled=false # Whether to enable the access log. server.undertow.accesslog.pattern=common # Format pattern for access logs.