mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-26 17:09:05 +00:00
Skip invalid links in CssLinkResourceTransformer
Prior to this commit, both `CssLinkResourceTransformer` implementations could fail at runtime in case of invalid CSS links (for example, with out of bounds exceptions). This commit skips invalid links and writes them out to the resulting CSS without any transformation. Fixes gh-37336
This commit is contained in:
+10
-1
@@ -176,9 +176,12 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
||||
return;
|
||||
}
|
||||
position += getKeyword().length();
|
||||
while (Character.isWhitespace(content.charAt(position))) {
|
||||
while (position < content.length() && Character.isWhitespace(content.charAt(position))) {
|
||||
position++;
|
||||
}
|
||||
if (position == content.length()) {
|
||||
return;
|
||||
}
|
||||
if (content.charAt(position) == '\'') {
|
||||
position = extractLink(position, '\'', content, result);
|
||||
}
|
||||
@@ -194,6 +197,12 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
||||
protected int extractLink(int index, char endChar, String content, Set<ContentChunkInfo> result) {
|
||||
int start = index + 1;
|
||||
int end = content.indexOf(endChar, start);
|
||||
if (end == -1) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Unterminated link at index " + start + ", no closing '" + endChar + "'");
|
||||
}
|
||||
return content.length();
|
||||
}
|
||||
result.add(new ContentChunkInfo(start, end, true));
|
||||
return end + 1;
|
||||
}
|
||||
|
||||
+19
@@ -183,6 +183,25 @@ class CssLinkResourceTransformerTests {
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void transformUnclosedUrlFunction() {
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/unclosed_url_function.css"));
|
||||
Resource css = getResource("unclosed_url_function.css");
|
||||
String expected = """
|
||||
body { background: url("/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix") }
|
||||
div { background: url(images/image.png
|
||||
""";
|
||||
|
||||
StepVerifier.create(this.transformerChain.transform(exchange, css)
|
||||
.cast(TransformedResource.class))
|
||||
.consumeNextWith(transformedResource -> {
|
||||
String result = new String(transformedResource.getByteArray(), UTF_8);
|
||||
assertThat(result).isEqualToNormalizingNewlines(expected);
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
private Resource getResource(String filePath) {
|
||||
return new ClassPathResource("test/" + filePath, getClass());
|
||||
}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
body { background: url("images/image.png?#iefix") }
|
||||
div { background: url(images/image.png
|
||||
+10
-1
@@ -140,9 +140,12 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
||||
return;
|
||||
}
|
||||
position += getKeyword().length();
|
||||
while (Character.isWhitespace(content.charAt(position))) {
|
||||
while (position < content.length() && Character.isWhitespace(content.charAt(position))) {
|
||||
position++;
|
||||
}
|
||||
if (position == content.length()) {
|
||||
return;
|
||||
}
|
||||
if (content.charAt(position) == '\'') {
|
||||
position = extractLink(position, "'", content, result);
|
||||
}
|
||||
@@ -158,6 +161,12 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
||||
protected int extractLink(int index, String endKey, String content, SortedSet<ContentChunkInfo> linksToAdd) {
|
||||
int start = index + 1;
|
||||
int end = content.indexOf(endKey, start);
|
||||
if (end == -1) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Unterminated link at index " + start + ", no closing \"" + endKey + "\"");
|
||||
}
|
||||
return content.length();
|
||||
}
|
||||
linksToAdd.add(new ContentChunkInfo(start, end));
|
||||
return end + endKey.length();
|
||||
}
|
||||
|
||||
+14
@@ -167,6 +167,20 @@ class CssLinkResourceTransformerTests {
|
||||
assertThat(result).isEqualToNormalizingNewlines(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void transformUnclosedUrlFunction() throws Exception {
|
||||
this.request = new MockHttpServletRequest("GET", "/static/unclosed_url_function.css");
|
||||
Resource css = getResource("unclosed_url_function.css");
|
||||
String expected = """
|
||||
body { background: url("/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix") }
|
||||
div { background: url(images/image.png
|
||||
""";
|
||||
|
||||
TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css);
|
||||
String result = new String(actual.getByteArray(), UTF_8);
|
||||
assertThat(result).isEqualToNormalizingNewlines(expected);
|
||||
}
|
||||
|
||||
private Resource getResource(String filePath) {
|
||||
return new ClassPathResource("test/" + filePath, getClass());
|
||||
}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
body { background: url("images/image.png?#iefix") }
|
||||
div { background: url(images/image.png
|
||||
Reference in New Issue
Block a user