Resolve absolute resource links in ResourceTransformers

Prior to this commit, `ResourceTransformer` implementations would
resolve internal links to other resources: both relative and absolute
request paths.
For relative request paths, those transformers would call
`ResourceTransformerSupport.resolveUrlPath` with the resource path,
as provided in the original file. This can cause problems when a
`CachingResourceResolver` is configured in the resolver chain, because
this resolver is caching resources, deriving the cache key from the
given resource path — this can cause collisions for cases like this:

    resources/
    |--foo/
    |  |--foo.css (imports style.css)
    |  |--style.css
    |--bar/
    |  |--bar.css (imports style.css)
    |  |--style.css

The first "style.css" resolved resource is then cached and will be given
to any request asking for "style.css".

To avoid those issues, this commit improves the `ResourceTransformer`
implementations to calculate the absolute request path before asking the
chain to resolve the resource URL, thus avoiding duplications.
The resource chain will be then asked to resolve "/foo/style/css" or
"/bar/style.css".

Issue: SPR-14597
This commit is contained in:
Brian Clozel
2016-10-07 22:25:56 +02:00
parent 9bf8489afd
commit 679b661e19
5 changed files with 76 additions and 37 deletions

View File

@@ -146,7 +146,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport {
Resource appCacheResource = transformerChain.getResolverChain()
.resolveResource(null, info.getLine(), Collections.singletonList(resource));
String path = resolveUrlPath(info.getLine(), request, resource, transformerChain);
String path = resolveUrlPath(toAbsolutePath(info.getLine(), request), request, resource, transformerChain);
if (logger.isTraceEnabled()) {
logger.trace("Link modified: " + path + " (original: " + info.getLine() + ")");
}

View File

@@ -102,7 +102,7 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
String link = content.substring(linkSegment.getStart(), linkSegment.getEnd());
String newLink = null;
if (!hasScheme(link)) {
newLink = resolveUrlPath(link, request, resource, transformerChain);
newLink = resolveUrlPath(toAbsolutePath(link, request), request, resource, transformerChain);
}
if (logger.isTraceEnabled()) {
if (newLink != null && !link.equals(newLink)) {

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
/**
* A base class for a {@code ResourceTransformer} with an optional helper method
@@ -86,6 +87,20 @@ public abstract class ResourceTransformerSupport implements ResourceTransformer
}
}
/**
* Transform the given relative request path to an absolute path,
* taking the path of the given request as a point of reference.
* The resulting path is also cleaned from sequences like "path/..".
* @param path the relative path to transform
* @param request the referer request
* @return the absolute request path for the given resource path
*/
protected String toAbsolutePath(String path, HttpServletRequest request) {
String requestPath = this.getResourceUrlProvider().getUrlPathHelper().getRequestUri(request);
String absolutePath = StringUtils.applyRelativePath(requestPath, path);
return StringUtils.cleanPath(absolutePath);
}
private ResourceUrlProvider findResourceUrlProvider(HttpServletRequest request) {
if (this.resourceUrlProvider != null) {
return this.resourceUrlProvider;