Skip to content

Commit 08c1329

Browse files
Merge pull request #63 from sebastian-nagel/CssExtractLongRunner
Make regular expression to extract URLs from CSS more restrictive
2 parents bb36b6a + 194a1fa commit 08c1329

2 files changed

Lines changed: 45 additions & 51 deletions

File tree

src/main/java/org/archive/resource/html/ExtractingParseObserver.java

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@ public class ExtractingParseObserver implements ParseObserver {
2121
boolean inTitle = false;
2222

2323
protected static String cssUrlPatString =
24-
"url\\s*\\(\\s*([\\\\\"']*.+?[\\\\\"']*)\\s*\\)";
24+
"url\\s*\\(\\s*((?:\\\\?[\"'])?.+?(?:\\\\?[\"'])?)\\s*\\)";
25+
protected static String cssUrlTrimPatString =
26+
"^(?:\\\\?[\"'])+|(?:\\\\?[\"'])+$";
2527
protected static String cssImportNoUrlPatString =
26-
"@import\\s+(('[^']+')|(\"[^\"]+\")|(\\('[^']+'\\))|(\\(\"[^\"]+\"\\))|(\\([^)]+\\))|([a-z0-9_.:/\\\\-]+))\\s*;";
28+
"@import\\s+((?:'[^']+')|(?:\"[^\"]+\")|(?:\\('[^']+'\\))|(?:\\(\"[^\"]+\"\\))|(?:\\([^)]+\\))|(?:[a-z0-9_.:/\\\\-]+))\\s*;";
2729

2830
protected static Pattern cssImportNoUrlPattern = Pattern
2931
.compile(cssImportNoUrlPatString);
3032

3133
protected static Pattern cssUrlPattern = Pattern.compile(cssUrlPatString);
34+
35+
protected static Pattern cssUrlTrimPattern = Pattern.compile(cssUrlTrimPatString);
36+
3237
private final static int MAX_TEXT_LEN = 100;
3338

3439
// private static String GLOBAL_ATTR[] = {"background"};
@@ -372,36 +377,16 @@ private void patternCSSExtract(HTMLMetaData data, Pattern pattern, String conten
372377
Matcher m = pattern.matcher(content);
373378
int idx = 0;
374379
int contentLen = content.length();
375-
while((idx < contentLen) && m.find(idx)) {
380+
if (contentLen > 100000)
381+
// extract URLs only from the first 100 kB
382+
contentLen = 100000;
383+
while((idx < contentLen) && m.find()) {
384+
idx = m.end();
376385
String url = m.group(1);
377-
int origUrlLength = url.length();
378-
int urlStart = m.start(1);
379-
int urlEnd = m.end(1);
380-
idx = urlEnd;
381-
if(url.length() < 2) {
382-
continue;
383-
}
384-
if ((url.charAt(0) == '(')
385-
&& (url.charAt(origUrlLength-1) == ')')) {
386-
url = url.substring(1, origUrlLength - 1);
387-
urlStart += 1;
388-
origUrlLength -= 2;
389-
}
390-
if (url.charAt(0) == '"') {
391-
url = url.substring(1, origUrlLength - 1);
392-
urlStart += 1;
393-
} else if (url.charAt(0) == '\'') {
394-
url = url.substring(1, origUrlLength - 1);
395-
urlStart += 1;
396-
} else if (url.charAt(0) == '\\') {
397-
if(url.length() == 2)
398-
continue;
399-
url = url.substring(2, origUrlLength - 2);
400-
urlStart += 2;
386+
url = cssUrlTrimPattern.matcher(url).replaceAll("");
387+
if (!url.isEmpty()) {
388+
data.addHref("path","STYLE/#text","href", url);
401389
}
402-
int urlLength = url.length();
403-
data.addHref("path","STYLE/#text","href",url);
404-
idx += urlLength;
405390
}
406391
}
407392
}

src/test/java/org/archive/resource/html/ExtractingParseObserverTest.java

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ public void testHandleStyleNodeExceptions() throws Exception {
1919
"url (' ')",
2020
"url('\")",
2121
"url(')",
22-
"url('\"')"
22+
"url('\"')",
23+
"url('\\\"\"')",
24+
"url(''''')"
2325
};
2426
boolean except = false;
2527
HTMLMetaData md = new HTMLMetaData(new MetaData());
@@ -37,6 +39,7 @@ public void testHandleStyleNodeExceptions() throws Exception {
3739
assertFalse(except);
3840
}
3941
}
42+
4043
public void testHandleStyleNode() throws Exception {
4144
String[][] tests = {
4245
{""},
@@ -45,31 +48,36 @@ public void testHandleStyleNode() throws Exception {
4548
{"url(\"foo.gif\")","foo.gif"},
4649
{"url(\\\"foo.gif\\\")","foo.gif"},
4750
{"url(\\'foo.gif\\')","foo.gif"},
48-
49-
};
51+
{"url(''foo.gif'')","foo.gif"},
52+
{"url( foo.gif )","foo.gif"},
53+
{"url('''')"},
54+
{"url('foo.gif'')","foo.gif"},
55+
};
5056
for(String[] testa : tests) {
5157
checkExtract(testa);
5258
}
53-
// boolean except = false;
54-
// HTMLMetaData md = new HTMLMetaData(new MetaData());
55-
// ExtractingParseObserver epo = new ExtractingParseObserver(md);
56-
// for(String css : tests) {
57-
// try {
58-
// TextNode tn = new TextNode(css);
59-
// epo.handleStyleNode(tn);
60-
// } catch(Exception e) {
61-
// System.err.format("And the winner is....(%s)\n", css);
62-
// e.printStackTrace();
63-
// except = true;
64-
// throw e;
65-
// }
66-
// assertFalse(except);
67-
// }
6859
}
60+
61+
/**
62+
* Test whether the pattern matcher does extract nothing and also does not
63+
* not hang-up if an overlong CSS link is truncated.
64+
*/
65+
public void testHandleStyleNodeNoHangupTruncated() throws Exception {
66+
StringBuilder sb = new StringBuilder();
67+
sb.append("url(");
68+
for (int i = 0; i < 500000; i++)
69+
sb.append('\'');
70+
sb.append("foo.gif");
71+
for (int i = 0; i < 499000; i++)
72+
sb.append('\'');
73+
String[] test = new String[1];
74+
test[0] = sb.toString();
75+
checkExtract(test);
76+
}
77+
6978
private void checkExtract(String[] data) throws JSONException {
7079
// System.err.format("CSS(%s) want[0](%s)\n",css,want[0]);
7180
String css = data[0];
72-
boolean except = false;
7381
HTMLMetaData md = new HTMLMetaData(new MetaData());
7482
ExtractingParseObserver epo = new ExtractingParseObserver(md);
7583
try {
@@ -87,10 +95,11 @@ private void checkExtract(String[] data) throws JSONException {
8795

8896
assertTrue(o instanceof JSONObject);
8997
JSONObject jo = (JSONObject) o;
90-
assertEquals(data[i],jo.getString("href"));
98+
assertEquals("CSS link extraction failed for <" + css + ">",
99+
data[i], jo.getString("href"));
91100
}
92101
} else {
93-
assertNull(a);
102+
assertNull("Expected no extracted link for <" + css + ">", a);
94103
}
95104
}
96105

0 commit comments

Comments
 (0)