Skip to content

Commit 173ff87

Browse files
committed
Merge pull request #17538 from adavid9
* gh-17538: Polish "Hide loader classes from Tomcat's ServletContext resource paths" Hide loader classes from Tomcat's ServletContext resource paths Closes gh-17538
2 parents b725c60 + 591250f commit 173ff87

File tree

4 files changed

+117
-18
lines changed

4 files changed

+117
-18
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Locale;
3333
import java.util.Set;
34+
import java.util.stream.Collectors;
3435

3536
import javax.servlet.ServletContainerInitializer;
3637

@@ -88,6 +89,7 @@
8889
* @author Andy Wilkinson
8990
* @author Eddú Meléndez
9091
* @author Christoffer Sawicki
92+
* @author Dawid Antecki
9193
* @since 2.0.0
9294
* @see #setPort(int)
9395
* @see #setContextLifecycleListeners(Collection)
@@ -751,7 +753,9 @@ public String[] list(String path) {
751753

752754
@Override
753755
public Set<String> listWebAppPaths(String path) {
754-
return this.delegate.listWebAppPaths(path);
756+
return this.delegate.listWebAppPaths(path).stream()
757+
.filter((webAppPath) -> !webAppPath.startsWith("/org/springframework/boot"))
758+
.collect(Collectors.toSet());
755759
}
756760

757761
@Override

spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/com/example/ResourceHandlingApplication.java

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import java.net.URL;
21+
import java.util.LinkedHashSet;
22+
import java.util.Set;
2123

2224
import javax.servlet.ServletException;
2325
import javax.servlet.http.HttpServlet;
@@ -38,31 +40,62 @@
3840
@SpringBootApplication
3941
public class ResourceHandlingApplication {
4042

43+
@Bean
44+
public ServletRegistrationBean<?> resourceServletRegistration() {
45+
ServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(new GetResourceServlet());
46+
registration.addUrlMappings("/servletContext");
47+
return registration;
48+
}
49+
50+
@Bean
51+
public ServletRegistrationBean<?> resourcePathsServletRegistration() {
52+
ServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(
53+
new GetResourcePathsServlet());
54+
registration.addUrlMappings("/resourcePaths");
55+
return registration;
56+
}
57+
4158
public static void main(String[] args) {
4259
new SpringApplicationBuilder(ResourceHandlingApplication.class).properties("server.port:0")
4360
.listeners(new WebServerPortFileWriter("target/server.port")).run(args);
4461
}
4562

46-
@Bean
47-
public ServletRegistrationBean<?> resourceServletRegistration() {
48-
ServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(new HttpServlet() {
49-
50-
@Override
51-
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
52-
throws ServletException, IOException {
53-
URL resource = getServletContext().getResource(req.getQueryString());
54-
if (resource == null) {
55-
resp.sendError(404);
56-
}
57-
else {
58-
resp.getWriter().println(resource);
59-
resp.getWriter().flush();
63+
private static final class GetResourcePathsServlet extends HttpServlet {
64+
65+
@Override
66+
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
67+
collectResourcePaths("/").forEach(resp.getWriter()::println);
68+
resp.getWriter().flush();
69+
}
70+
71+
private Set<String> collectResourcePaths(String path) {
72+
Set<String> allResourcePaths = new LinkedHashSet<>();
73+
Set<String> pathsForPath = getServletContext().getResourcePaths(path);
74+
if (pathsForPath != null) {
75+
for (String resourcePath : pathsForPath) {
76+
allResourcePaths.add(resourcePath);
77+
allResourcePaths.addAll(collectResourcePaths(resourcePath));
6078
}
6179
}
80+
return allResourcePaths;
81+
}
82+
83+
}
84+
85+
private static final class GetResourceServlet extends HttpServlet {
86+
87+
@Override
88+
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
89+
URL resource = getServletContext().getResource(req.getQueryString());
90+
if (resource == null) {
91+
resp.sendError(404);
92+
}
93+
else {
94+
resp.getWriter().println(resource);
95+
resp.getWriter().flush();
96+
}
97+
}
6298

63-
});
64-
registration.addUrlMappings("/servletContext");
65-
return registration;
6699
}
67100

68101
}

spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616

1717
package org.springframework.boot.context.embedded;
1818

19+
import java.io.BufferedReader;
20+
import java.io.IOException;
21+
import java.io.StringReader;
22+
import java.util.ArrayList;
1923
import java.util.Arrays;
24+
import java.util.Collections;
25+
import java.util.List;
2026

2127
import org.junit.Test;
2228
import org.junit.runner.RunWith;
@@ -67,4 +73,29 @@ public void webappResourcesAreAvailableViaHttp() {
6773
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
6874
}
6975

76+
@Test
77+
public void loaderClassesAreNotAvailableViaResourcePaths() {
78+
ResponseEntity<String> entity = this.rest.getForEntity("/resourcePaths", String.class);
79+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
80+
assertThat(readLines(entity.getBody()))
81+
.noneMatch((resourcePath) -> resourcePath.startsWith("/org/springframework/boot/loader"));
82+
}
83+
84+
private List<String> readLines(String input) {
85+
if (input == null) {
86+
return Collections.emptyList();
87+
}
88+
List<String> lines = new ArrayList<>();
89+
try (BufferedReader reader = new BufferedReader(new StringReader(input))) {
90+
String line;
91+
while ((line = reader.readLine()) != null) {
92+
lines.add(line);
93+
}
94+
return lines;
95+
}
96+
catch (IOException ex) {
97+
throw new RuntimeException("Failed to read lines from input '" + input + "'");
98+
}
99+
}
100+
70101
}

spring-boot-tests/spring-boot-integration-tests/spring-boot-server-tests/src/test/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616

1717
package org.springframework.boot.context.embedded;
1818

19+
import java.io.BufferedReader;
20+
import java.io.IOException;
21+
import java.io.StringReader;
22+
import java.util.ArrayList;
1923
import java.util.Arrays;
24+
import java.util.Collections;
25+
import java.util.List;
2026

2127
import org.junit.Test;
2228
import org.junit.runner.RunWith;
@@ -90,4 +96,29 @@ public void loaderClassesAreNotAvailableViaHttp() {
9096
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
9197
}
9298

99+
@Test
100+
public void loaderClassesAreNotAvailableViaResourcePaths() {
101+
ResponseEntity<String> entity = this.rest.getForEntity("/resourcePaths", String.class);
102+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
103+
assertThat(readLines(entity.getBody()))
104+
.noneMatch((resourcePath) -> resourcePath.startsWith("/org/springframework/boot/loader"));
105+
}
106+
107+
private List<String> readLines(String input) {
108+
if (input == null) {
109+
return Collections.emptyList();
110+
}
111+
List<String> lines = new ArrayList<>();
112+
try (BufferedReader reader = new BufferedReader(new StringReader(input))) {
113+
String line;
114+
while ((line = reader.readLine()) != null) {
115+
lines.add(line);
116+
}
117+
return lines;
118+
}
119+
catch (IOException ex) {
120+
throw new RuntimeException("Failed to read lines from input '" + input + "'");
121+
}
122+
}
123+
93124
}

0 commit comments

Comments
 (0)