Browse Source

LibWeb: Use an infallible method to add attributes to nodes

In the HTML parser spec, there are 2 instances of the following text:

    add the attribute and its corresponding value to that element

The "add the attribute" text does not have a corresponding spec link to
actually specify what to do. We currently use `set_attribute`, which can
throw an exception if the attribute name contains an invalid character
(such as '<'). Instead, switch to `append_attribute`, which allows such
attribute names. This behavior matches Firefox.

Note we cannot yet make the unclosed-html-element.html test match the
expectations of the unclosed-body-element.html due to another bug that
would prevent checking if the expected element has the right attribute.
That will be fixed in an upcoming commit.
Timothy Flynn 1 year ago
parent
commit
9fe35ddddf

+ 1 - 0
Tests/LibWeb/Text/expected/unclosed-body-element.txt

@@ -0,0 +1 @@
+   Body element has '<pre' attribute: true

+ 1 - 0
Tests/LibWeb/Text/expected/unclosed-html-element.txt

@@ -0,0 +1 @@
+PASS (didn't crash)

+ 10 - 0
Tests/LibWeb/Text/input/unclosed-body-element.html

@@ -0,0 +1,10 @@
+<div>
+<body
+<pre>
+
+<script src="include.js"></script>
+<script>
+    test(() => {
+        println(`Body element has '<pre' attribute: ${document.body.hasAttribute('<pre')}`);
+    });
+</script>

+ 10 - 0
Tests/LibWeb/Text/input/unclosed-html-element.html

@@ -0,0 +1,10 @@
+<link>
+<html
+<head>
+
+<script src="include.js"></script>
+<script>
+    test(() => {
+        println("PASS (didn't crash)");
+    });
+</script>

+ 2 - 3
Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp

@@ -1721,7 +1721,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
         // If it is not, add the attribute and its corresponding value to that element.
         token.for_each_attribute([&](auto& attribute) {
             if (!current_node().has_attribute(attribute.local_name))
-                MUST(current_node().set_attribute(attribute.local_name, attribute.value));
+                current_node().append_attribute(attribute.local_name, attribute.value);
             return IterationDecision::Continue;
         });
         return;
@@ -1743,7 +1743,6 @@ void HTMLParser::handle_in_body(HTMLToken& token)
 
     // -> A start tag whose tag name is "body"
     if (token.is_start_tag() && token.tag_name() == HTML::TagNames::body) {
-
         // Parse error.
         log_parse_error();
 
@@ -1763,7 +1762,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
         auto& body_element = m_stack_of_open_elements.elements().at(1);
         token.for_each_attribute([&](auto& attribute) {
             if (!body_element->has_attribute(attribute.local_name))
-                MUST(body_element->set_attribute(attribute.local_name, attribute.value));
+                body_element->append_attribute(attribute.local_name, attribute.value);
             return IterationDecision::Continue;
         });
         return;