@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations) .switchIfEmpty(Mono.defer(() -> { String webJarResourcePath = findWebJarResourcePath(resourceUrlPath); if (webJarResourcePath != null) { return chain.resolveUrlPath(webJarResourcePath, locations); } else { return Mono.empty(); } })); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { String key = RESOLVED_URL_PATH_CACHE_KEY_PREFIX + resourceUrlPath; String cachedUrlPath = this.cache.get(key, String.class); if (cachedUrlPath != null) { logger.trace("Path resolved from cache"); return Mono.just(cachedUrlPath); } return chain.resolveUrlPath(resourceUrlPath, locations) .doOnNext(resolvedPath -> this.cache.put(key, resolvedPath)); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations) .flatMap(baseUrl -> { if (StringUtils.hasText(baseUrl)) { VersionStrategy strategy = getStrategyForPath(resourceUrlPath); if (strategy == null) { return Mono.just(baseUrl); } return chain.resolveResource(null, baseUrl, locations) .flatMap(resource -> strategy.getResourceVersion(resource) .map(version -> strategy.addVersion(baseUrl, version))); } return Mono.empty(); }); }
/** * A transformer can use this method when a resource being transformed * contains links to other resources. Such links need to be replaced with the * public facing link as determined by the resource resolver chain (e.g. the * public URL may have a version inserted). * @param resourcePath the path to a resource that needs to be re-written * @param exchange the current exchange * @param resource the resource being transformed * @param transformerChain the transformer chain * @return the resolved URL or an empty {@link Mono} */ protected Mono<String> resolveUrlPath(String resourcePath, ServerWebExchange exchange, Resource resource, ResourceTransformerChain transformerChain) { if (resourcePath.startsWith("/")) { // full resource path ResourceUrlProvider urlProvider = getResourceUrlProvider(); return (urlProvider != null ? urlProvider.getForUriString(resourcePath, exchange) : Mono.empty()); } else { // try resolving as relative path return transformerChain.getResolverChain() .resolveUrlPath(resourcePath, Collections.singletonList(resource)); } }
private Mono<String> resolveResourceUrl(ServerWebExchange exchange, PathContainer lookupPath) { return this.handlerMap.entrySet().stream() .filter(entry -> entry.getKey().matches(lookupPath)) .min((entry1, entry2) -> PathPattern.SPECIFICITY_COMPARATOR.compare(entry1.getKey(), entry2.getKey())) .map(entry -> { PathContainer path = entry.getKey().extractPathWithinPattern(lookupPath); int endIndex = lookupPath.elements().size() - path.elements().size(); PathContainer mapping = lookupPath.subPath(0, endIndex); ResourceWebHandler handler = entry.getValue(); List<ResourceResolver> resolvers = handler.getResourceResolvers(); ResourceResolverChain chain = new DefaultResourceResolverChain(resolvers); return chain.resolveUrlPath(path.value(), handler.getLocations()) .map(resolvedPath -> mapping.value() + resolvedPath); }) .orElseGet(() ->{ if (logger.isTraceEnabled()) { logger.trace(exchange.getLogPrefix() + "No match for \"" + lookupPath + "\""); } return Mono.empty(); }); }
@Test public void resolverUrlPath() { String expected = "/foo.css"; String actual = this.chain.resolveUrlPath(expected, this.locations).block(TIMEOUT); assertEquals(expected, actual); }
@Test public void resolverUrlPathNoMatch() { assertNull(this.chain.resolveUrlPath("invalid.css", this.locations).block(TIMEOUT)); }
@Test public void resolveUrlExisting() { this.locations = singletonList(new ClassPathResource("/META-INF/resources/webjars/", getClass())); String file = "/foo/2.3/foo.txt"; given(this.chain.resolveUrlPath(file, this.locations)).willReturn(Mono.just(file)); String actual = this.resolver.resolveUrlPath(file, this.locations, this.chain).block(TIMEOUT); assertEquals(file, actual); verify(this.chain, times(1)).resolveUrlPath(file, this.locations); }
@Test public void resolveUrlExistingNotInJarFile() { this.locations = singletonList(new ClassPathResource("/META-INF/resources/webjars/", getClass())); String file = "foo/foo.txt"; given(this.chain.resolveUrlPath(file, this.locations)).willReturn(Mono.empty()); String actual = this.resolver.resolveUrlPath(file, this.locations, this.chain).block(TIMEOUT); assertNull(actual); verify(this.chain, times(1)).resolveUrlPath(file, this.locations); verify(this.chain, never()).resolveUrlPath("foo/2.3/foo.txt", this.locations); }
@Test public void resolveUrlWebJarResource() { String file = "underscorejs/underscore.js"; String expected = "underscorejs/1.8.3/underscore.js"; given(this.chain.resolveUrlPath(file, this.locations)).willReturn(Mono.empty()); given(this.chain.resolveUrlPath(expected, this.locations)).willReturn(Mono.just(expected)); String actual = this.resolver.resolveUrlPath(file, this.locations, this.chain).block(TIMEOUT); assertEquals(expected, actual); verify(this.chain, times(1)).resolveUrlPath(file, this.locations); verify(this.chain, times(1)).resolveUrlPath(expected, this.locations); }
@Test // SPR-15372 public void resolveUrlPathNoVersionStrategy() { given(this.chain.resolveUrlPath("/foo.css", this.locations)).willReturn(Mono.just("/foo.css")); String resolved = this.resolver.resolveUrlPathInternal("/foo.css", this.locations, this.chain) .block(Duration.ofMillis(1000)); assertThat(resolved, is("/foo.css")); }
@Test public void resolverUrlPathFromCache() { String expected = "cached-imaginary.css"; this.cache.put(CachingResourceResolver.RESOLVED_URL_PATH_CACHE_KEY_PREFIX + "imaginary.css", expected); String actual = this.chain.resolveUrlPath("imaginary.css", this.locations).block(TIMEOUT); assertEquals(expected, actual); }
@Test public void resolveUrlWebJarResourceNotFound() { String file = "something/something.js"; given(this.chain.resolveUrlPath(file, this.locations)).willReturn(Mono.empty()); String actual = this.resolver.resolveUrlPath(file, this.locations, this.chain).block(TIMEOUT); assertNull(actual); verify(this.chain, times(1)).resolveUrlPath(file, this.locations); verify(this.chain, never()).resolveUrlPath(null, this.locations); }
@Test public void transformExtLinksNotAllowed() { MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/external.css")); List<ResourceTransformer> transformers = Collections.singletonList(new CssLinkResourceTransformer()); ResourceResolverChain mockChain = Mockito.mock(DefaultResourceResolverChain.class); ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers); Resource resource = getResource("external.css"); String expected = "@import url(\"http://example.org/fonts/css\");\n" + "body { background: url(\"file:///home/spring/image.png\") }\n" + "figure { background: url(\"//example.org/style.css\")}"; StepVerifier.create(chain.transform(exchange, resource) .cast(TransformedResource.class)) .consumeNextWith(transformedResource -> { String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8); result = StringUtils.deleteAny(result, "\r"); assertEquals(expected, result); }) .expectComplete() .verify(); List<Resource> locations = Collections.singletonList(resource); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("http://example.org/fonts/css", locations); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("file:///home/spring/image.png", locations); Mockito.verify(mockChain, Mockito.never()).resolveUrlPath("//example.org/style.css", locations); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { return chain.resolveUrlPath(resourceUrlPath, locations) .otherwiseIfEmpty(Mono.defer(() -> { String webJarResourcePath = findWebJarResourcePath(resourceUrlPath); if (webJarResourcePath != null) { return chain.resolveUrlPath(webJarResourcePath, locations); } else { return Mono.empty(); } })); }
@Override protected Mono<String> resolveUrlPathInternal(String resourceUrlPath, List<? extends Resource> locations, ResourceResolverChain chain) { String key = RESOLVED_URL_PATH_CACHE_KEY_PREFIX + resourceUrlPath; String cachedUrlPath = this.cache.get(key, String.class); if (cachedUrlPath != null) { if (logger.isTraceEnabled()) { logger.trace("Found match: \"" + cachedUrlPath + "\""); } return Mono.just(cachedUrlPath); } return chain.resolveUrlPath(resourceUrlPath, locations) .doOnNext(resolvedPath -> { if (logger.isTraceEnabled()) { logger.trace("Putting resolved resource URL path in cache: \"" + resolvedPath + "\""); } this.cache.put(key, resolvedPath); }); }
/** * A transformer can use this method when a resource being transformed * contains links to other resources. Such links need to be replaced with the * public facing link as determined by the resource resolver chain (e.g. the * public URL may have a version inserted). * @param resourcePath the path to a resource that needs to be re-written * @param exchange the current exchange * @param resource the resource being transformed * @param transformerChain the transformer chain * @return the resolved URL or null */ protected Mono<String> resolveUrlPath(String resourcePath, ServerWebExchange exchange, Resource resource, ResourceTransformerChain transformerChain) { if (resourcePath.startsWith("/")) { // full resource path ResourceUrlProvider urlProvider = getResourceUrlProvider(); return (urlProvider != null ? urlProvider.getForRequestUrl(exchange, resourcePath) : Mono.empty()); } else { // try resolving as relative path return transformerChain.getResolverChain() .resolveUrlPath(resourcePath, Collections.singletonList(resource)); } }