From 0adf03741072117b5603785d4ba0c04b6898650f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 28 Oct 2015 17:22:39 +0000 Subject: [PATCH] Consider custom server.context-path when configuring dev tools endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the auto-configuration of DevTools’ debug, restart, and health handlers assumed that the server was running on its default context path and, if server.context-path was set to a non-default value, the handlers would not work as expected. This commit updates the auto-configuration of the three handlers to consider the server’s context path when configuring their URIs. Now, when a custom server context path is used, no further configuration is required other than the inclusion of that context path when providing the remote URL as an argument to RemoteSpringApplication. Closes gh-4301 --- .../RemoteDevToolsAutoConfiguration.java | 23 ++++++++++--- .../RemoteDevToolsAutoConfigurationTests.java | 34 +++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfiguration.java index c19dcb24fdd..51aaed9dc4b 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfiguration.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfiguration.java @@ -31,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.devtools.remote.server.AccessManager; import org.springframework.boot.devtools.remote.server.Dispatcher; @@ -76,6 +77,9 @@ public class RemoteDevToolsAutoConfiguration { @Autowired private DevToolsProperties properties; + @Autowired + private ServerProperties serverProperties; + @Bean @ConditionalOnMissingBean public AccessManager remoteDevToolsAccessManager() { @@ -87,8 +91,9 @@ public class RemoteDevToolsAutoConfiguration { @Bean public HandlerMapper remoteDevToolsHealthCheckHandlerMapper() { Handler handler = new HttpStatusHandler(); - return new UrlHandlerMapper(this.properties.getRemote().getContextPath(), - handler); + return new UrlHandlerMapper((this.serverProperties.getContextPath() == null ? "" + : this.serverProperties.getContextPath()) + + this.properties.getRemote().getContextPath(), handler); } @Bean @@ -108,6 +113,9 @@ public class RemoteDevToolsAutoConfiguration { @Autowired private DevToolsProperties properties; + @Autowired + private ServerProperties serverProperties; + @Bean @ConditionalOnMissingBean public SourceFolderUrlFilter remoteRestartSourceFolderUrlFilter() { @@ -124,7 +132,9 @@ public class RemoteDevToolsAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "remoteRestartHanderMapper") public UrlHandlerMapper remoteRestartHanderMapper(HttpRestartServer server) { - String url = this.properties.getRemote().getContextPath() + "/restart"; + String url = (this.serverProperties.getContextPath() == null ? "" + : this.serverProperties.getContextPath()) + + this.properties.getRemote().getContextPath() + "/restart"; logger.warn("Listening for remote restart updates on " + url); Handler handler = new HttpRestartServerHandler(server); return new UrlHandlerMapper(url, handler); @@ -141,11 +151,16 @@ public class RemoteDevToolsAutoConfiguration { @Autowired private DevToolsProperties properties; + @Autowired + private ServerProperties serverProperties; + @Bean @ConditionalOnMissingBean(name = "remoteDebugHanderMapper") public UrlHandlerMapper remoteDebugHanderMapper( @Qualifier("remoteDebugHttpTunnelServer") HttpTunnelServer server) { - String url = this.properties.getRemote().getContextPath() + "/debug"; + String url = (this.serverProperties.getContextPath() == null ? "" + : this.serverProperties.getContextPath()) + + this.properties.getRemote().getContextPath() + "/debug"; logger.warn("Listening for remote debug traffic on " + url); Handler handler = new HttpTunnelServerHandler(server); return new UrlHandlerMapper(url, handler); diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java index 682f5980164..acb2ad1c4e2 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java @@ -137,6 +137,17 @@ public class RemoteDevToolsAutoConfigurationTests { assertRestartInvoked(true); } + @Test + public void invokeRestartWithCustomServerContextPath() throws Exception { + loadContext("spring.devtools.remote.secret:supersecret", + "server.context-path:/test"); + DispatcherFilter filter = this.context.getBean(DispatcherFilter.class); + this.request.setRequestURI("/test" + DEFAULT_CONTEXT_PATH + "/restart"); + this.request.addHeader(DEFAULT_SECRET_HEADER_NAME, "supersecret"); + filter.doFilter(this.request, this.response, this.chain); + assertRestartInvoked(true); + } + @Test public void disableRestart() throws Exception { loadContext("spring.devtools.remote.secret:supersecret", @@ -155,6 +166,17 @@ public class RemoteDevToolsAutoConfigurationTests { assertTunnelInvoked(true); } + @Test + public void invokeTunnelWithCustomServerContextPath() throws Exception { + loadContext("spring.devtools.remote.secret:supersecret", + "server.context-path:/test"); + DispatcherFilter filter = this.context.getBean(DispatcherFilter.class); + this.request.setRequestURI("/test" + DEFAULT_CONTEXT_PATH + "/debug"); + this.request.addHeader(DEFAULT_SECRET_HEADER_NAME, "supersecret"); + filter.doFilter(this.request, this.response, this.chain); + assertTunnelInvoked(true); + } + @Test public void invokeTunnelWithCustomHeaderName() throws Exception { loadContext("spring.devtools.remote.secret:supersecret", @@ -185,6 +207,18 @@ public class RemoteDevToolsAutoConfigurationTests { assertThat(this.response.getStatus(), equalTo(200)); } + @Test + public void devToolsHealthWithCustomServerContextPathReturns200() throws Exception { + loadContext("spring.devtools.remote.secret:supersecret", + "server.context-path:/test"); + DispatcherFilter filter = this.context.getBean(DispatcherFilter.class); + this.request.setRequestURI("/test" + DEFAULT_CONTEXT_PATH); + this.request.addHeader(DEFAULT_SECRET_HEADER_NAME, "supersecret"); + this.response.setStatus(500); + filter.doFilter(this.request, this.response, this.chain); + assertThat(this.response.getStatus(), equalTo(200)); + } + private void assertTunnelInvoked(boolean value) { assertThat(this.context.getBean(MockHttpTunnelServer.class).invoked, equalTo(value));