瀏覽代碼

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 11 月之前
父節點
當前提交
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.
         // If it is not, add the attribute and its corresponding value to that element.
         token.for_each_attribute([&](auto& attribute) {
         token.for_each_attribute([&](auto& attribute) {
             if (!current_node().has_attribute(attribute.local_name))
             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 IterationDecision::Continue;
         });
         });
         return;
         return;
@@ -1743,7 +1743,6 @@ void HTMLParser::handle_in_body(HTMLToken& token)
 
 
     // -> A start tag whose tag name is "body"
     // -> A start tag whose tag name is "body"
     if (token.is_start_tag() && token.tag_name() == HTML::TagNames::body) {
     if (token.is_start_tag() && token.tag_name() == HTML::TagNames::body) {
-
         // Parse error.
         // Parse error.
         log_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);
         auto& body_element = m_stack_of_open_elements.elements().at(1);
         token.for_each_attribute([&](auto& attribute) {
         token.for_each_attribute([&](auto& attribute) {
             if (!body_element->has_attribute(attribute.local_name))
             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 IterationDecision::Continue;
         });
         });
         return;
         return;