Skip to content

Commit a623db7

Browse files
committed
Check attribute name is not empty after trimming before creating attribute
Fixes jhy#793
1 parent d8eb9bd commit a623db7

5 files changed

Lines changed: 31 additions & 10 deletions

File tree

CHANGES

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
jsoup changelog
22

3+
*** Release 1.10.3 [PENDING]
4+
* Bugfix: if an attribute name started or ended with a control character, the parse would fail with a validation
5+
exception.
6+
<https://github.com/jhy/jsoup/issues/793>
7+
38
*** Release 1.10.2 [2017-Jan-02]
49
* Improved startup time, particularly on Android, by reducing garbage generation and CPU execution time when loading
510
the HTML entity files. About 1.72x faster in this area.

src/main/java/org/jsoup/nodes/Attribute.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ public class Attribute implements Map.Entry<String, String>, Cloneable {
2929
* @see #createFromEncoded
3030
*/
3131
public Attribute(String key, String value) {
32-
Validate.notEmpty(key);
32+
Validate.notNull(key);
3333
Validate.notNull(value);
3434
this.key = key.trim();
35+
Validate.notEmpty(key); // trimming could potentially make empty, so validate here
3536
this.value = value;
3637
}
3738

src/main/java/org/jsoup/parser/Token.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,19 @@ final void newAttribute() {
102102
attributes = new Attributes();
103103

104104
if (pendingAttributeName != null) {
105-
Attribute attribute;
106-
if (hasPendingAttributeValue)
107-
attribute = new Attribute(pendingAttributeName,
108-
pendingAttributeValue.length() > 0 ? pendingAttributeValue.toString() : pendingAttributeValueS);
109-
else if (hasEmptyAttributeValue)
110-
attribute = new Attribute(pendingAttributeName, "");
111-
else
112-
attribute = new BooleanAttribute(pendingAttributeName);
113-
attributes.put(attribute);
105+
// the tokeniser has skipped whitespace control chars, but trimming could collapse to empty for other control codes, so verify here
106+
pendingAttributeName = pendingAttributeName.trim();
107+
if (pendingAttributeName.length() > 0) {
108+
Attribute attribute;
109+
if (hasPendingAttributeValue)
110+
attribute = new Attribute(pendingAttributeName,
111+
pendingAttributeValue.length() > 0 ? pendingAttributeValue.toString() : pendingAttributeValueS);
112+
else if (hasEmptyAttributeValue)
113+
attribute = new Attribute(pendingAttributeName, "");
114+
else
115+
attribute = new BooleanAttribute(pendingAttributeName);
116+
attributes.put(attribute);
117+
}
114118
}
115119
pendingAttributeName = null;
116120
hasEmptyAttributeValue = false;

src/test/java/org/jsoup/parser/HtmlParserTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,4 +941,9 @@ public void testInvalidTableContents() throws IOException {
941941
Document doc = parser.parseInput("<div id=1><SPAN ID=2>", "");
942942
assertEquals("<html> <head></head> <body> <div id=\"1\"> <SPAN ID=\"2\"></SPAN> </div> </body> </html>", StringUtil.normaliseWhitespace(doc.outerHtml()));
943943
}
944+
945+
@Test public void handlesControlCodeInAttributeName() {
946+
Document doc = Jsoup.parse("<p><a \06=foo>One</a><a/\06=bar><a foo\06=bar>Two</a></p>");
947+
assertEquals("<p><a>One</a><a></a><a foo=\"bar\">Two</a></p>", doc.body().html());
948+
}
944949
}

src/test/java/org/jsoup/safety/CleanerTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,4 +277,10 @@ public void bailsIfRemovingProtocolThatsNotSet() {
277277
w.addAttributes("a", "href");
278278
w.removeProtocols("a", "href", "javascript"); // with no protocols enforced, this was a noop. Now validates.
279279
}
280+
281+
@Test public void handlesControlCharactersAfterTagName() {
282+
String html = "<a/\06>";
283+
String clean = Jsoup.clean(html, Whitelist.basic());
284+
assertEquals("<a rel=\"nofollow\"></a>", clean);
285+
}
280286
}

0 commit comments

Comments
 (0)