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 08d66f1ee3c..271bfc5ac12 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 @@ -600,6 +600,12 @@ public class ServerProperties { */ private Boolean redirectContextRoot; + /** + * Whether HTTP 1.1 and later location headers generated by a call to sendRedirect + * will use relative or absolute redirects. + */ + private Boolean useRelativeRedirects; + /** * Character encoding to use to decode the URI. */ @@ -714,6 +720,14 @@ public class ServerProperties { this.redirectContextRoot = redirectContextRoot; } + public Boolean getUseRelativeRedirects() { + return this.useRelativeRedirects; + } + + public void setUseRelativeRedirects(Boolean useRelativeRedirects) { + this.useRelativeRedirects = useRelativeRedirects; + } + public String getRemoteIpHeader() { return this.remoteIpHeader; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizer.java index 97510594583..cda33729be7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizer.java @@ -256,6 +256,10 @@ public class DefaultServletWebServerFactoryCustomizer customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot()); } + if (tomcatProperties.getUseRelativeRedirects() != null) { + customizeUseRelativeRedirects(factory, + tomcatProperties.getUseRelativeRedirects()); + } if (tomcatProperties.getMaxConnections() > 0) { customizeMaxConnections(factory, tomcatProperties.getMaxConnections()); } @@ -392,6 +396,13 @@ public class DefaultServletWebServerFactoryCustomizer .setMapperContextRootRedirectEnabled(redirectContextRoot)); } + private static void customizeUseRelativeRedirects( + TomcatServletWebServerFactory factory, + final boolean useRelativeRedirects) { + factory.addContextCustomizers((context) -> context + .setUseRelativeRedirects(useRelativeRedirects)); + } + private static void customizeStaticResources(Resource resource, TomcatServletWebServerFactory factory) { if (resource.getCacheTtl() == null) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizerTests.java index 5b3328ffba5..bc3e6868c54 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/DefaultServletWebServerFactoryCustomizerTests.java @@ -168,6 +168,22 @@ public class DefaultServletWebServerFactoryCustomizerTests { verify(context).setMapperContextRootRedirectEnabled(false); } + @Test + public void useRelativeRedirectsCanBeConfigured() { + Map map = new HashMap<>(); + map.put("server.tomcat.use-relative-redirects", "true"); + bindProperties(map); + ServerProperties.Tomcat tomcat = this.properties.getTomcat(); + assertThat(tomcat.getUseRelativeRedirects()).isTrue(); + TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); + this.customizer.customize(factory); + Context context = mock(Context.class); + for (TomcatContextCustomizer customizer : factory.getTomcatContextCustomizers()) { + customizer.customize(context); + } + verify(context).setUseRelativeRedirects(true); + } + @Test public void testCustomizeTomcat() throws Exception { ConfigurableServletWebServerFactory factory = mock( 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 a6afafdc394..4ff31707edf 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 @@ -254,6 +254,7 @@ content into your application. Rather, pick only the properties that you need. server.tomcat.remote-ip-header= # Name of the HTTP header from which the remote IP is extracted. For instance, `X-FORWARDED-FOR`. 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.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.