diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java index f599f210660..270a7a63aeb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java @@ -754,7 +754,8 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto @Override public Set listWebAppPaths(String path) { return this.delegate.listWebAppPaths(path).stream() - .filter((p) -> !p.startsWith("org/springframework/boot/loader")).collect(Collectors.toSet()); + .filter((webAppPath) -> !webAppPath.startsWith("/org/springframework/boot")) + .collect(Collectors.toSet()); } @Override diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/com/example/ResourceHandlingApplication.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/com/example/ResourceHandlingApplication.java index 288b680d407..ff7c25f2b42 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/com/example/ResourceHandlingApplication.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/com/example/ResourceHandlingApplication.java @@ -18,6 +18,8 @@ package com.example; import java.io.IOException; import java.net.URL; +import java.util.LinkedHashSet; +import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -38,31 +40,62 @@ import org.springframework.context.annotation.Bean; @SpringBootApplication public class ResourceHandlingApplication { + @Bean + public ServletRegistrationBean resourceServletRegistration() { + ServletRegistrationBean registration = new ServletRegistrationBean(new GetResourceServlet()); + registration.addUrlMappings("/servletContext"); + return registration; + } + + @Bean + public ServletRegistrationBean resourcePathsServletRegistration() { + ServletRegistrationBean registration = new ServletRegistrationBean( + new GetResourcePathsServlet()); + registration.addUrlMappings("/resourcePaths"); + return registration; + } + public static void main(String[] args) { new SpringApplicationBuilder(ResourceHandlingApplication.class).properties("server.port:0") .listeners(new WebServerPortFileWriter("target/server.port")).run(args); } - @Bean - public ServletRegistrationBean resourceServletRegistration() { - ServletRegistrationBean registration = new ServletRegistrationBean(new HttpServlet() { + private static final class GetResourcePathsServlet extends HttpServlet { - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - URL resource = getServletContext().getResource(req.getQueryString()); - if (resource == null) { - resp.sendError(404); - } - else { - resp.getWriter().println(resource); - resp.getWriter().flush(); + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + collectResourcePaths("/").forEach(resp.getWriter()::println); + resp.getWriter().flush(); + } + + private Set collectResourcePaths(String path) { + Set allResourcePaths = new LinkedHashSet<>(); + Set pathsForPath = getServletContext().getResourcePaths(path); + if (pathsForPath != null) { + for (String resourcePath : pathsForPath) { + allResourcePaths.add(resourcePath); + allResourcePaths.addAll(collectResourcePaths(resourcePath)); } } + return allResourcePaths; + } + + } + + private static final class GetResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + URL resource = getServletContext().getResource(req.getQueryString()); + if (resource == null) { + resp.sendError(404); + } + else { + resp.getWriter().println(resource); + resp.getWriter().flush(); + } + } - }); - registration.addUrlMappings("/servletContext"); - return registration; } } diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java index c0731c56381..7a71f201b7a 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java @@ -16,7 +16,13 @@ package org.springframework.boot.context.embedded; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,4 +73,29 @@ public class EmbeddedServletContainerWarDevelopmentIntegrationTests assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); } + @Test + public void loaderClassesAreNotAvailableViaResourcePaths() { + ResponseEntity entity = this.rest.getForEntity("/resourcePaths", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(readLines(entity.getBody())) + .noneMatch((resourcePath) -> resourcePath.startsWith("/org/springframework/boot/loader")); + } + + private List readLines(String input) { + if (input == null) { + return Collections.emptyList(); + } + List lines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new StringReader(input))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + return lines; + } + catch (IOException ex) { + throw new RuntimeException("Failed to read lines from input '" + input + "'"); + } + } + } diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java index cd938996511..b1fff70aa07 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java @@ -16,7 +16,13 @@ package org.springframework.boot.context.embedded; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -90,4 +96,29 @@ public class EmbeddedServletContainerWarPackagingIntegrationTests assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } + @Test + public void loaderClassesAreNotAvailableViaResourcePaths() { + ResponseEntity entity = this.rest.getForEntity("/resourcePaths", String.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(readLines(entity.getBody())) + .noneMatch((resourcePath) -> resourcePath.startsWith("/org/springframework/boot/loader")); + } + + private List readLines(String input) { + if (input == null) { + return Collections.emptyList(); + } + List lines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new StringReader(input))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + return lines; + } + catch (IOException ex) { + throw new RuntimeException("Failed to read lines from input '" + input + "'"); + } + } + }