Assert static resource location

Closes gh-33712
This commit is contained in:
rstoyanchev
2024-10-15 19:15:43 +01:00
parent f204f4962d
commit 789d7effa9
10 changed files with 92 additions and 9 deletions

View File

@@ -44,12 +44,11 @@ class PathResourceLookupFunction implements Function<ServerRequest, Mono<Resourc
public PathResourceLookupFunction(String pattern, Resource location) {
Assert.hasLength(pattern, "'pattern' must not be empty");
Assert.notNull(location, "'location' must not be null");
ResourceHandlerUtils.assertResourceLocation(location);
this.pattern = PathPatternParser.defaultInstance.parse(pattern);
this.location = location;
}
@Override
public Mono<Resource> apply(ServerRequest request) {
PathContainer pathContainer = request.requestPath().pathWithinApplication();

View File

@@ -27,6 +27,8 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriUtils;
@@ -42,6 +44,42 @@ public abstract class ResourceHandlerUtils {
private static final Log logger = LogFactory.getLog(ResourceHandlerUtils.class);
private static final String FOLDER_SEPARATOR = "/";
private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
/**
* Assert the given location is not null, and its path ends on slash.
*/
public static void assertResourceLocation(@Nullable Resource location) {
Assert.notNull(location, "Resource location must not be null");
try {
String path;
if (location instanceof UrlResource) {
path = location.getURL().toExternalForm();
}
else if (location instanceof ClassPathResource classPathResource) {
path = classPathResource.getPath();
}
else {
path = location.getURL().getPath();
}
assertLocationPath(path);
}
catch (IOException ex) {
// ignore
}
}
/**
* Assert the given location path is a directory and ends on slash.
*/
public static void assertLocationPath(@Nullable String path) {
Assert.notNull(path, "Resource location path must not be null");
Assert.isTrue(path.endsWith(FOLDER_SEPARATOR) || path.endsWith(WINDOWS_FOLDER_SEPARATOR),
"Resource location does not end with slash: " + path);
}
/**
* Normalize the given resource path replacing the following:

View File

@@ -160,7 +160,10 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
public void setLocations(@Nullable List<Resource> locations) {
this.locationResources.clear();
if (locations != null) {
this.locationResources.addAll(locations);
for (Resource location : locations) {
ResourceHandlerUtils.assertResourceLocation(location);
this.locationResources.add(location);
}
}
}
@@ -376,6 +379,7 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
Assert.isTrue(CollectionUtils.isEmpty(this.locationResources), "Please set " +
"either Resource-based \"locations\" or String-based \"locationValues\", but not both.");
for (String location : this.locationValues) {
ResourceHandlerUtils.assertLocationPath(location);
result.add(this.resourceLoader.getResource(location));
}
}

View File

@@ -124,7 +124,7 @@ public class DelegatingWebFluxConfigurationTests {
delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer));
willAnswer(invocation -> {
ResourceHandlerRegistry registry = invocation.getArgument(0);
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static");
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
return null;
}).given(webFluxConfigurer).addResourceHandlers(any(ResourceHandlerRegistry.class));

View File

@@ -47,7 +47,7 @@ class PathResourceLookupFunction implements Function<ServerRequest, Optional<Res
public PathResourceLookupFunction(String pattern, Resource location) {
Assert.hasLength(pattern, "'pattern' must not be empty");
Assert.notNull(location, "'location' must not be null");
ResourceHandlerUtils.assertResourceLocation(location);
this.pattern = PathPatternParser.defaultInstance.parse(pattern);
this.location = location;
}

View File

@@ -27,6 +27,8 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.ServletContextResource;
@@ -42,6 +44,42 @@ public abstract class ResourceHandlerUtils {
private static final Log logger = LogFactory.getLog(ResourceHandlerUtils.class);
private static final String FOLDER_SEPARATOR = "/";
private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
/**
* Assert the given location is not null, and its path ends on slash.
*/
public static void assertResourceLocation(@Nullable Resource location) {
Assert.notNull(location, "Resource location must not be null");
try {
String path;
if (location instanceof UrlResource) {
path = location.getURL().toExternalForm();
}
else if (location instanceof ClassPathResource classPathResource) {
path = classPathResource.getPath();
}
else {
path = location.getURL().getPath();
}
assertLocationPath(path);
}
catch (IOException ex) {
// ignore
}
}
/**
* Assert the given location path is a directory and ends on slash.
*/
public static void assertLocationPath(@Nullable String path) {
Assert.notNull(path, "Resource location path must not be null");
Assert.isTrue(path.endsWith(FOLDER_SEPARATOR) || path.endsWith(WINDOWS_FOLDER_SEPARATOR),
"Resource location does not end with slash: " + path);
}
/**
* Normalize the given resource path replacing the following:

View File

@@ -180,7 +180,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
public void setLocations(List<Resource> locations) {
Assert.notNull(locations, "Locations list must not be null");
this.locationResources.clear();
this.locationResources.addAll(locations);
for (Resource location : locations) {
ResourceHandlerUtils.assertResourceLocation(location);
this.locationResources.add(location);
}
}
/**
@@ -493,6 +496,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
charset = Charset.forName(value);
location = location.substring(endIndex + 1);
}
ResourceHandlerUtils.assertLocationPath(location);
Resource resource = applicationContext.getResource(location);
if (location.equals("/") && !(resource instanceof ServletContextResource)) {
throw new IllegalStateException(

View File

@@ -204,7 +204,7 @@ class ResourceHandlerRegistryTests {
@Test
void urlResourceWithCharset() {
this.registration.addResourceLocations("[charset=ISO-8859-1]file:///tmp");
this.registration.addResourceLocations("[charset=ISO-8859-1]file:///tmp/");
this.registration.resourceChain(true);
ResourceHttpRequestHandler handler = getHandler("/resources/**");

View File

@@ -457,7 +457,7 @@ class WebMvcConfigurationSupportExtensionTests {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java");
registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java/");
}
@Override

View File

@@ -23,7 +23,7 @@
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>location=file:///tmp</value>
<value>location=file:///tmp/</value>
</property>
</bean>