Ignore external resources in CssLinkResourceTransormer

Prior to this commit, the CssLinkResourceTransformer would transform
"external resources", i.e. resources not served by the web application.

This commit only allows transformation for resources which path don't
contain scheme such as "file://" or "http://". Only relative and
absolute paths for resources served by the webapp are valid.

Issue: SPR-11860
This commit is contained in:
Brian Clozel 2014-06-12 10:54:41 +02:00
parent e18e44980d
commit 72baa9bf27
5 changed files with 82 additions and 5 deletions

View File

@ -101,7 +101,10 @@ public class CssLinkResourceTransformer implements ResourceTransformer {
for (CssLinkInfo info : sortedInfos) {
writer.write(content.substring(index, info.getStart()));
String link = content.substring(info.getStart(), info.getEnd());
String newLink = transformerChain.getResolverChain().resolveUrlPath(link, Arrays.asList(resource));
String newLink = null;
if(!hasScheme(link)) {
newLink = transformerChain.getResolverChain().resolveUrlPath(link, Arrays.asList(resource));
}
if (logger.isTraceEnabled()) {
if (newLink != null && !link.equals(newLink)) {
logger.trace("Link modified: " + newLink + " (original: " + link + ")");
@ -118,6 +121,11 @@ public class CssLinkResourceTransformer implements ResourceTransformer {
return new TransformedResource(resource, writer.toString().getBytes(DEFAULT_CHARSET));
}
private boolean hasScheme(String link) {
int schemeIndex = link.indexOf(":");
return schemeIndex > 0 && !link.substring(0, schemeIndex).contains("/");
}
protected static interface CssLinkParser {

View File

@ -17,10 +17,12 @@
package org.springframework.web.servlet.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@ -77,8 +79,7 @@ public class CssLinkResourceTransformerTests {
"@import url(bar-11e16cf79faee7ac698c805cf28248d2.css);\n\n" +
"@import \"foo-e36d2e05253c6c7085a91522ce43a0b4.css\";\n" +
"@import 'foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
"body { background: url(\"images/image-f448cd1d5dba82b774f3202c878230b3.png\") }\n\n" +
"li { list-style: url(http://www.example.com/redball.png) disc }\n";
"body { background: url(\"images/image-f448cd1d5dba82b774f3202c878230b3.png\") }\n";
String result = new String(transformedResource.getByteArray(), "UTF-8");
result = StringUtils.deleteAny(result, "\r");
@ -92,4 +93,26 @@ public class CssLinkResourceTransformerTests {
assertSame(expected, actual);
}
@Test
public void transformExtLinksNotAllowed() throws Exception {
ResourceResolverChain resolverChain = Mockito.mock(DefaultResourceResolverChain.class);
ResourceTransformerChain transformerChain = new DefaultResourceTransformerChain(resolverChain,
Arrays.asList(new CssLinkResourceTransformer()));
Resource externalCss = new ClassPathResource("test/external.css", getClass());
Resource resource = transformerChain.transform(this.request, externalCss);
TransformedResource transformedResource = (TransformedResource) resource;
String expected = "@import url(\"http://example.org/fonts/css\");\n" +
"body { background: url(\"file:///home/spring/image.png\") }";
String result = new String(transformedResource.getByteArray(), "UTF-8");
result = StringUtils.deleteAny(result, "\r");
assertEquals(expected, result);
Mockito.verify(resolverChain, Mockito.never())
.resolveUrlPath("http://example.org/fonts/css", Arrays.asList(externalCss));
Mockito.verify(resolverChain, Mockito.never())
.resolveUrlPath("file:///home/spring/image.png", Arrays.asList(externalCss));
}
}

View File

@ -0,0 +1,46 @@
package org.springframework.web.servlet.resource;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* Unit tests for
* {@link org.springframework.web.servlet.resource.PathResourceResolver}.
*
* @author Brian Clozel
*/
public class PathResourceResolverTests {
private ResourceResolverChain chain;
private List<Resource> locations;
@Before
public void setup() {
List<ResourceResolver> resolvers = new ArrayList<>();
resolvers.add(new PathResourceResolver());
this.chain = new DefaultResourceResolverChain(resolvers);
this.locations = new ArrayList<>();
this.locations.add(new ClassPathResource("test/", getClass()));
}
@Test
public void resolveResourceInternal() {
String file = "bar.css";
Resource expected = new ClassPathResource("test/" + file, getClass());
Resource actual = this.chain.resolveResource(null, file, this.locations);
assertEquals(expected, actual);
}
}

View File

@ -0,0 +1,2 @@
@import url("http://example.org/fonts/css");
body { background: url("file:///home/spring/image.png") }

View File

@ -7,5 +7,3 @@
@import 'foo.css';
body { background: url("images/image.png") }
li { list-style: url(http://www.example.com/redball.png) disc }