Filter non-existing static resource locations
Same as a2c52a97ba, on the WebFlux side.
See gh-27538
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -96,7 +96,9 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
|
||||
private final List<String> locationValues = new ArrayList<>(4);
|
||||
|
||||
private final List<Resource> locations = new ArrayList<>(4);
|
||||
private final List<Resource> locationResources = new ArrayList<>(4);
|
||||
|
||||
private final List<Resource> locationsToUse = new ArrayList<>(4);
|
||||
|
||||
private final List<ResourceResolver> resourceResolvers = new ArrayList<>(4);
|
||||
|
||||
@@ -147,9 +149,9 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
* for serving static resources.
|
||||
*/
|
||||
public void setLocations(@Nullable List<Resource> locations) {
|
||||
this.locations.clear();
|
||||
this.locationResources.clear();
|
||||
if (locations != null) {
|
||||
this.locations.addAll(locations);
|
||||
this.locationResources.addAll(locations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,11 +161,18 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
* <p>Note that if {@link #setLocationValues(List) locationValues} are provided,
|
||||
* instead of loaded Resource-based locations, this method will return
|
||||
* empty until after initialization via {@link #afterPropertiesSet()}.
|
||||
* <p><strong>Note:</strong> As of 5.3.11 the list of locations is filtered
|
||||
* to exclude those that don't actually exist and therefore the list returned
|
||||
* from this method may be a subset of all given locations.
|
||||
* @see #setLocationValues
|
||||
* @see #setLocations
|
||||
*/
|
||||
public List<Resource> getLocations() {
|
||||
return this.locations;
|
||||
if (this.locationsToUse.isEmpty()) {
|
||||
// Possibly not yet initialized, return only what we have so far
|
||||
return this.locationResources;
|
||||
}
|
||||
return this.locationsToUse;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,7 +304,7 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
resolveResourceLocations();
|
||||
|
||||
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
|
||||
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(getLocations())) {
|
||||
logger.warn("Locations list is empty. No resources will be served unless a " +
|
||||
"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
|
||||
}
|
||||
@@ -316,21 +325,22 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
}
|
||||
|
||||
private void resolveResourceLocations() {
|
||||
if (CollectionUtils.isEmpty(this.locationValues)) {
|
||||
return;
|
||||
}
|
||||
else if (!CollectionUtils.isEmpty(this.locations)) {
|
||||
throw new IllegalArgumentException("Please set either Resource-based \"locations\" or " +
|
||||
"String-based \"locationValues\", but not both.");
|
||||
List<Resource> result = new ArrayList<>(this.locationResources);
|
||||
|
||||
if (!this.locationValues.isEmpty()) {
|
||||
Assert.notNull(this.resourceLoader,
|
||||
"ResourceLoader is required when \"locationValues\" are configured.");
|
||||
Assert.isTrue(CollectionUtils.isEmpty(this.locationResources), "Please set " +
|
||||
"either Resource-based \"locations\" or String-based \"locationValues\", but not both.");
|
||||
for (String location : this.locationValues) {
|
||||
result.add(this.resourceLoader.getResource(location));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.notNull(this.resourceLoader,
|
||||
"ResourceLoader is required when \"locationValues\" are configured.");
|
||||
result = result.stream().filter(Resource::exists).collect(Collectors.toList());
|
||||
|
||||
for (String location : this.locationValues) {
|
||||
Resource resource = this.resourceLoader.getResource(location);
|
||||
this.locations.add(resource);
|
||||
}
|
||||
this.locationsToUse.clear();
|
||||
this.locationsToUse.addAll(result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +349,7 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
* match the {@link #setLocations locations} configured on this class.
|
||||
*/
|
||||
protected void initAllowedLocations() {
|
||||
if (CollectionUtils.isEmpty(this.locations)) {
|
||||
if (CollectionUtils.isEmpty(getLocations())) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Locations list is empty. No resources will be served unless a " +
|
||||
"custom ResourceResolver is configured as an alternative to PathResourceResolver.");
|
||||
@@ -618,8 +628,8 @@ public class ResourceWebHandler implements WebHandler, InitializingBean {
|
||||
if (!this.locationValues.isEmpty()) {
|
||||
return this.locationValues.stream().collect(Collectors.joining("\", \"", "[\"", "\"]"));
|
||||
}
|
||||
else if (!this.locations.isEmpty()) {
|
||||
return "[" + this.locations.toString()
|
||||
if (!getLocations().isEmpty()) {
|
||||
return "[" + getLocations().toString()
|
||||
.replaceAll("class path resource", "Classpath")
|
||||
.replaceAll("ServletContext resource", "ServletContext") + "]";
|
||||
}
|
||||
|
||||
@@ -253,6 +253,23 @@ public class ResourceWebHandlerTests {
|
||||
assertResponseBody(exchange, "h1 { color:red; }");
|
||||
}
|
||||
|
||||
@Test // gh-27538
|
||||
public void filterNonExistingLocations() throws Exception {
|
||||
List<Resource> inputLocations = Arrays.asList(
|
||||
new ClassPathResource("test/", getClass()),
|
||||
new ClassPathResource("testalternatepath/", getClass()),
|
||||
new ClassPathResource("nosuchpath/", getClass()));
|
||||
|
||||
ResourceWebHandler handler = new ResourceWebHandler();
|
||||
handler.setLocations(inputLocations);
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
List<Resource> actual = handler.getLocations();
|
||||
assertThat(actual).hasSize(2);
|
||||
assertThat(actual.get(0).getURL().toString()).endsWith("test/");
|
||||
assertThat(actual.get(1).getURL().toString()).endsWith("testalternatepath/");
|
||||
}
|
||||
|
||||
@Test // SPR-14577
|
||||
public void getMediaTypeWithFavorPathExtensionOff() throws Exception {
|
||||
List<Resource> paths = Collections.singletonList(new ClassPathResource("test/", getClass()));
|
||||
|
||||
@@ -189,6 +189,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||
* locations provided via {@link #setLocations(List) setLocations}.
|
||||
* <p>Note that the returned list is fully initialized only after
|
||||
* initialization via {@link #afterPropertiesSet()}.
|
||||
* <p><strong>Note:</strong> As of 5.3.11 the list of locations is filtered
|
||||
* to exclude those that don't actually exist and therefore the list returned
|
||||
* from this method may be a subset of all given locations.
|
||||
* @see #setLocationValues
|
||||
* @see #setLocations
|
||||
*/
|
||||
@@ -467,6 +470,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||
result.addAll(this.locationResources);
|
||||
result = result.stream().filter(Resource::exists).collect(Collectors.toList());
|
||||
|
||||
this.locationsToUse.clear();
|
||||
this.locationsToUse.addAll(result);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user