Transform absolute links in ResourceTransformers
Prior to this change, ResourceTransformers that transformed resources by updating the links to other resources, worked only if links were relative to the resource being transformed. For example, when the CssLinkResourceTransformer rewrote links within a "main.css" resource, only links such as "../css/other.css" were rewritten. Using relative links is a recommended approach, because it's totally independent from the application servlet path, context path, mappings... This change allows absolute links to be rewritten by those Transformers, provided those links are accurate and point to existing resources. Issue: SPR-12137
This commit is contained in:
@@ -58,7 +58,7 @@ import org.springframework.util.StringUtils;
|
||||
* applications spec</a>
|
||||
* @since 4.1
|
||||
*/
|
||||
public class AppCacheManifestTransformer implements ResourceTransformer {
|
||||
public class AppCacheManifestTransformer extends ResourceTransformerSupport {
|
||||
|
||||
private static final String MANIFEST_HEADER = "CACHE MANIFEST";
|
||||
|
||||
@@ -129,7 +129,7 @@ public class AppCacheManifestTransformer implements ResourceTransformer {
|
||||
hashBuilder.appendString(line);
|
||||
}
|
||||
else {
|
||||
contentWriter.write(currentTransformer.transform(line, hashBuilder, resource, transformerChain) + "\n");
|
||||
contentWriter.write(currentTransformer.transform(line, hashBuilder, resource, transformerChain, request) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,14 +151,14 @@ public class AppCacheManifestTransformer implements ResourceTransformer {
|
||||
* for the current manifest section (CACHE, NETWORK, FALLBACK, etc).
|
||||
*/
|
||||
String transform(String line, HashBuilder builder, Resource resource,
|
||||
ResourceTransformerChain transformerChain) throws IOException;
|
||||
ResourceTransformerChain transformerChain, HttpServletRequest request) throws IOException;
|
||||
}
|
||||
|
||||
|
||||
private static class NoOpSection implements SectionTransformer {
|
||||
|
||||
public String transform(String line, HashBuilder builder, Resource resource, ResourceTransformerChain transformerChain)
|
||||
throws IOException {
|
||||
public String transform(String line, HashBuilder builder, Resource resource,
|
||||
ResourceTransformerChain transformerChain, HttpServletRequest request) throws IOException {
|
||||
|
||||
builder.appendString(line);
|
||||
return line;
|
||||
@@ -166,17 +166,18 @@ public class AppCacheManifestTransformer implements ResourceTransformer {
|
||||
}
|
||||
|
||||
|
||||
private static class CacheSection implements SectionTransformer {
|
||||
private class CacheSection implements SectionTransformer {
|
||||
|
||||
private final String COMMENT_DIRECTIVE = "#";
|
||||
|
||||
@Override
|
||||
public String transform(String line, HashBuilder builder,
|
||||
Resource resource, ResourceTransformerChain transformerChain) throws IOException {
|
||||
public String transform(String line, HashBuilder builder, Resource resource,
|
||||
ResourceTransformerChain transformerChain, HttpServletRequest request) throws IOException {
|
||||
|
||||
if (isLink(line) && !hasScheme(line)) {
|
||||
Resource appCacheResource = transformerChain.getResolverChain().resolveResource(null, line, Arrays.asList(resource));
|
||||
String path = transformerChain.getResolverChain().resolveUrlPath(line, Arrays.asList(resource));
|
||||
ResourceResolverChain resolverChain = transformerChain.getResolverChain();
|
||||
Resource appCacheResource = resolverChain.resolveResource(null, line, Arrays.asList(resource));
|
||||
String path = resolveUrlPath(line, request, resource, transformerChain);
|
||||
builder.appendResource(appCacheResource);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Link modified: " + path + " (original: " + line + ")");
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -47,7 +46,7 @@ import java.util.Set;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public class CssLinkResourceTransformer implements ResourceTransformer {
|
||||
public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CssLinkResourceTransformer.class);
|
||||
|
||||
@@ -103,7 +102,7 @@ public class CssLinkResourceTransformer implements ResourceTransformer {
|
||||
String link = content.substring(info.getStart(), info.getEnd());
|
||||
String newLink = null;
|
||||
if (!hasScheme(link)) {
|
||||
newLink = transformerChain.getResolverChain().resolveUrlPath(link, Arrays.asList(resource));
|
||||
newLink = resolveUrlPath(link, request, resource, transformerChain);
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
if (newLink != null && !link.equals(newLink)) {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.web.servlet.resource;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* A base class for a {@code ResourceTransformer} with an optional helper method
|
||||
* for resolving public links within a transformed resource.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class ResourceTransformerSupport implements ResourceTransformer {
|
||||
|
||||
private ResourceUrlProvider resourceUrlProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Configure a {@link ResourceUrlProvider} to use when resolving the public
|
||||
* URL of links in a transformed resource (e.g. import links in a CSS file).
|
||||
* This is required only for links expressed as full paths, i.e. including
|
||||
* context and servlet path, and not for relative links.
|
||||
*
|
||||
* <p>By default this property is not set. In that case if a
|
||||
* {@code ResourceUrlProvider} is needed an attempt is made to find the
|
||||
* {@code ResourceUrlProvider} exposed through the
|
||||
* {@link org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor
|
||||
* ResourceUrlProviderExposingInterceptor} (configured by default in the MVC
|
||||
* Java config and XML namespace). Therefore explicitly configuring this
|
||||
* property should not be needed in most cases.
|
||||
* @param resourceUrlProvider the URL provider to use
|
||||
*/
|
||||
public void setResourceUrlProvider(ResourceUrlProvider resourceUrlProvider) {
|
||||
this.resourceUrlProvider = resourceUrlProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configured {@code ResourceUrlProvider}.
|
||||
*/
|
||||
public ResourceUrlProvider getResourceUrlProvider() {
|
||||
return this.resourceUrlProvider;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 request the current request
|
||||
* @param resource the resource being transformed
|
||||
* @param transformerChain the transformer chain
|
||||
* @return the resolved URL or null
|
||||
*/
|
||||
protected String resolveUrlPath(String resourcePath, HttpServletRequest request,
|
||||
Resource resource, ResourceTransformerChain transformerChain) {
|
||||
|
||||
if (!resourcePath.startsWith("/")) {
|
||||
// try resolving as relative path
|
||||
return transformerChain.getResolverChain().resolveUrlPath(resourcePath, Arrays.asList(resource));
|
||||
}
|
||||
else {
|
||||
// full resource path
|
||||
ResourceUrlProvider urlProvider = findResourceUrlProvider(request);
|
||||
return (urlProvider != null ? urlProvider.getForRequestUrl(request, resourcePath) : null);
|
||||
}
|
||||
}
|
||||
|
||||
private ResourceUrlProvider findResourceUrlProvider(HttpServletRequest request) {
|
||||
if (this.resourceUrlProvider != null) {
|
||||
return this.resourceUrlProvider;
|
||||
}
|
||||
return (ResourceUrlProvider) request.getAttribute(
|
||||
ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user