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:
parent
e18e44980d
commit
72baa9bf27
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
@import url("http://example.org/fonts/css");
|
||||
body { background: url("file:///home/spring/image.png") }
|
||||
|
|
@ -7,5 +7,3 @@
|
|||
@import 'foo.css';
|
||||
|
||||
body { background: url("images/image.png") }
|
||||
|
||||
li { list-style: url(http://www.example.com/redball.png) disc }
|
||||
|
|
|
|||
Loading…
Reference in New Issue