protected List<ResourceResolver> getResourceResolvers() { if (!this.hasPathResolver) { List<ResourceResolver> result = new ArrayList<>(this.resolvers); if (isWebJarsAssetLocatorPresent && !this.hasWebjarsResolver) { result.add(new WebJarsResourceResolver()); } result.add(new PathResourceResolver()); return result; } return this.resolvers; }
Resource resource = location.createRelative(resourcePath); if (resource.isReadable()) { if (checkResource(resource, location)) { return Mono.just(resource); Resource[] allowedLocations = getAllowedLocations(); logger.warn("Resource path \"" + resourcePath + "\" was successfully resolved " + "but resource \"" + resource.getURL() + "\" is neither under the " +
/** * Look for a {@code PathResourceResolver} among the configured resource * resolvers and set its {@code allowedLocations} property (if empty) to * match the {@link #setLocations locations} configured on this class. */ protected void initAllowedLocations() { if (CollectionUtils.isEmpty(this.locations)) { 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."); } return; } for (int i = getResourceResolvers().size() - 1; i >= 0; i--) { if (getResourceResolvers().get(i) instanceof PathResourceResolver) { PathResourceResolver resolver = (PathResourceResolver) getResourceResolvers().get(i); if (ObjectUtils.isEmpty(resolver.getAllowedLocations())) { resolver.setAllowedLocations(getLocations().toArray(new Resource[0])); } break; } } }
/** * Perform additional checks on a resolved resource beyond checking whether the * resources exists and is readable. The default implementation also verifies * the resource is either under the location relative to which it was found or * is under one of the {@link #setAllowedLocations allowed locations}. * @param resource the resource to check * @param location the location relative to which the resource was found * @return "true" if resource is in a valid location, "false" otherwise. */ protected boolean checkResource(Resource resource, Resource location) throws IOException { if (isResourceUnderLocation(resource, location)) { return true; } if (getAllowedLocations() != null) { for (Resource current : getAllowedLocations()) { if (isResourceUnderLocation(resource, current)) { return true; } } } return false; }
@Test public void initAllowedLocationsWithExplicitConfiguration() throws Exception { ClassPathResource location1 = new ClassPathResource("test/", getClass()); ClassPathResource location2 = new ClassPathResource("testalternatepath/", getClass()); PathResourceResolver pathResolver = new PathResourceResolver(); pathResolver.setAllowedLocations(location1); ResourceWebHandler handler = new ResourceWebHandler(); handler.setResourceResolvers(Collections.singletonList(pathResolver)); handler.setLocations(Arrays.asList(location1, location2)); handler.afterPropertiesSet(); Resource[] locations = pathResolver.getAllowedLocations(); assertEquals(1, locations.length); assertEquals("test/", ((ClassPathResource) locations[0]).getPath()); }
@Before public void setup() { VersionResourceResolver versionResolver = new VersionResourceResolver(); versionResolver.setStrategyMap(Collections.singletonMap("/**", new ContentVersionStrategy())); PathResourceResolver pathResolver = new PathResourceResolver(); pathResolver.setAllowedLocations(new ClassPathResource("test/", getClass())); List<ResourceResolver> resolvers = new ArrayList<>(); resolvers.add(versionResolver); resolvers.add(pathResolver); ResourceResolverChain resolverChain = new DefaultResourceResolverChain(resolvers); this.chain = new DefaultResourceTransformerChain(resolverChain, Collections.emptyList()); this.transformer = new TestResourceTransformerSupport(); this.transformer.setResourceUrlProvider(createUrlProvider(resolvers)); }
@Test public void checkResourceWithAllowedLocations() { this.resolver.setAllowedLocations( new ClassPathResource("test/", PathResourceResolver.class), new ClassPathResource("testalternatepath/", PathResourceResolver.class) ); Resource location = getResource("main.css"); String actual = this.resolver.resolveUrlPath("../testalternatepath/bar.css", singletonList(location), null).block(TIMEOUT); assertEquals("../testalternatepath/bar.css", actual); }
@Override protected Mono<Resource> resolveResourceInternal(@Nullable ServerWebExchange exchange, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) { return getResource(requestPath, locations); }
@Test // SPR-12747 public void checkFileLocation() throws Exception { Resource resource = getResource("main.css"); assertTrue(this.resolver.checkResource(resource, resource)); }
@Test public void initAllowedLocations() { PathResourceResolver resolver = (PathResourceResolver) this.handler.getResourceResolvers().get(0); Resource[] locations = resolver.getAllowedLocations(); assertEquals(3, locations.length); assertEquals("test/", ((ClassPathResource) locations[0]).getPath()); assertEquals("testalternatepath/", ((ClassPathResource) locations[1]).getPath()); assertEquals("META-INF/resources/webjars/", ((ClassPathResource) locations[2]).getPath()); }
@Test public void resolveFromClasspathRoot() { Resource location = new ClassPathResource("/"); String path = "org/springframework/web/reactive/resource/test/bar.css"; List<Resource> locations = singletonList(location); Resource actual = this.resolver.resolveResource(null, path, locations, null).block(TIMEOUT); assertNotNull(actual); }
private boolean isResourceUnderLocation(Resource resource, Resource location) throws IOException { if (resource.getClass() != location.getClass()) { return false; } String resourcePath; String locationPath; if (resource instanceof UrlResource) { resourcePath = resource.getURL().toExternalForm(); locationPath = StringUtils.cleanPath(location.getURL().toString()); } else if (resource instanceof ClassPathResource) { resourcePath = ((ClassPathResource) resource).getPath(); locationPath = StringUtils.cleanPath(((ClassPathResource) location).getPath()); } else { resourcePath = resource.getURL().getPath(); locationPath = StringUtils.cleanPath(location.getURL().getPath()); } if (locationPath.equals(resourcePath)) { return true; } locationPath = (locationPath.endsWith("/") || locationPath.isEmpty() ? locationPath : locationPath + "/"); return (resourcePath.startsWith(locationPath) && !isInvalidEncodedPath(resourcePath)); }
/** * Perform additional checks on a resolved resource beyond checking whether the * resources exists and is readable. The default implementation also verifies * the resource is either under the location relative to which it was found or * is under one of the {@link #setAllowedLocations allowed locations}. * @param resource the resource to check * @param location the location relative to which the resource was found * @return "true" if resource is in a valid location, "false" otherwise. */ protected boolean checkResource(Resource resource, Resource location) throws IOException { if (isResourceUnderLocation(resource, location)) { return true; } if (getAllowedLocations() != null) { for (Resource current : getAllowedLocations()) { if (isResourceUnderLocation(resource, current)) { return true; } } } return false; }
@Override protected Mono<String> resolveUrlPathInternal(String path, List<? extends Resource> locations, ResourceResolverChain chain) { if (StringUtils.hasText(path)) { return getResource(path, locations).map(resource -> path); } else { return Mono.empty(); } }
private void testCheckResource(Resource location, String requestPath) throws IOException { List<Resource> locations = singletonList(location); Resource actual = this.resolver.resolveResource(null, requestPath, locations, null).block(TIMEOUT); if (!location.createRelative(requestPath).exists() && !requestPath.contains(":")) { fail(requestPath + " doesn't actually exist as a relative path"); } assertNull(actual); }
@Override public void afterPropertiesSet() throws Exception { resolveResourceLocations(); if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) { logger.warn("Locations list is empty. No resources will be served unless a " + "custom ResourceResolver is configured as an alternative to PathResourceResolver."); } if (this.resourceResolvers.isEmpty()) { this.resourceResolvers.add(new PathResourceResolver()); } initAllowedLocations(); if (getResourceHttpMessageWriter() == null) { this.resourceHttpMessageWriter = new ResourceHttpMessageWriter(); } // Initialize immutable resolver and transformer chains this.resolverChain = new DefaultResourceResolverChain(this.resourceResolvers); this.transformerChain = new DefaultResourceTransformerChain(this.resolverChain, this.resourceTransformers); }
/** * Look for a {@code PathResourceResolver} among the configured resource * resolvers and set its {@code allowedLocations} property (if empty) to * match the {@link #setLocations locations} configured on this class. */ protected void initAllowedLocations() { if (CollectionUtils.isEmpty(this.locations)) { return; } for (int i = getResourceResolvers().size() - 1; i >= 0; i--) { if (getResourceResolvers().get(i) instanceof PathResourceResolver) { PathResourceResolver resolver = (PathResourceResolver) getResourceResolvers().get(i); if (ObjectUtils.isEmpty(resolver.getAllowedLocations())) { resolver.setAllowedLocations(getLocations().toArray(new Resource[getLocations().size()])); } break; } } }
Resource resource = location.createRelative(resourcePath); if (resource.exists() && resource.isReadable()) { if (checkResource(resource, location)) { if (logger.isTraceEnabled()) { logger.trace("Found match: " + resource); "but resource=\"" + resource.getURL() + "\" is neither under the " + "current location=\"" + location.getURL() + "\" nor under any of the " + "allowed locations=" + Arrays.asList(getAllowedLocations()));
private Mono<Resource> getResource(String resourcePath, List<? extends Resource> locations) { return Flux.fromIterable(locations) .concatMap(location -> getResource(resourcePath, location)) .next(); }
@Test public void resolveFromClasspath() throws IOException { Resource location = new ClassPathResource("test/", PathResourceResolver.class); String path = "bar.css"; List<Resource> locations = singletonList(location); Resource actual = this.resolver.resolveResource(null, path, locations, null).block(TIMEOUT); assertEquals(location.createRelative(path), actual); }