瀏覽代碼

LibWeb: Allow cloneNode() to clone elements with weird attributes

We can't rely on Element.setAttribute() in cloneNode() since that will
throw on weird attribute names. Instead, just follow the spec and copy
attributes into cloned elements verbatim.

This fixes a crash when loading the "issues" tab on GitHub repos.
They are actually sending us unintentionally broken markup, but we
should still support cloning it. :^)
Andreas Kling 1 年之前
父節點
當前提交
193fc7ef98

+ 2 - 0
Tests/LibWeb/Text/expected/DOM/cloneNode-with-goofy-attribute.txt

@@ -0,0 +1,2 @@
+  a(
+a(

+ 9 - 0
Tests/LibWeb/Text/input/DOM/cloneNode-with-goofy-attribute.html

@@ -0,0 +1,9 @@
+<script src="../include.js"></script>
+<svg><circle id=c a(></svg>
+<script>
+    test(() => {
+        let cloned = c.cloneNode()
+        println(c.attributes[1].localName)
+        println(cloned.attributes[1].localName)
+    });
+</script>

+ 6 - 0
Userland/Libraries/LibWeb/DOM/Element.cpp

@@ -246,6 +246,12 @@ WebIDL::ExceptionOr<void> Element::set_attribute_ns(Optional<FlyString> const& n
     return {};
     return {};
 }
 }
 
 
+// https://dom.spec.whatwg.org/#concept-element-attributes-append
+void Element::append_attribute(FlyString const& name, String const& value)
+{
+    m_attributes->append_attribute(Attr::create(document(), name, value));
+}
+
 // https://dom.spec.whatwg.org/#concept-element-attributes-append
 // https://dom.spec.whatwg.org/#concept-element-attributes-append
 void Element::append_attribute(Attr& attribute)
 void Element::append_attribute(Attr& attribute)
 {
 {

+ 1 - 0
Userland/Libraries/LibWeb/DOM/Element.h

@@ -109,6 +109,7 @@ public:
     WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node(Attr&);
     WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node(Attr&);
     WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node_ns(Attr&);
     WebIDL::ExceptionOr<JS::GCPtr<Attr>> set_attribute_node_ns(Attr&);
 
 
+    void append_attribute(FlyString const& name, String const& value);
     void append_attribute(Attr&);
     void append_attribute(Attr&);
     void remove_attribute(FlyString const& name);
     void remove_attribute(FlyString const& name);
     void remove_attribute_ns(Optional<FlyString> const& namespace_, FlyString const& name);
     void remove_attribute_ns(Optional<FlyString> const& namespace_, FlyString const& name);

+ 1 - 1
Userland/Libraries/LibWeb/DOM/Node.cpp

@@ -826,7 +826,7 @@ JS::NonnullGCPtr<Node> Node::clone_node(Document* document, bool clone_children)
         element.for_each_attribute([&](auto& name, auto& value) {
         element.for_each_attribute([&](auto& name, auto& value) {
             // 1. Let copyAttribute be a clone of attribute.
             // 1. Let copyAttribute be a clone of attribute.
             // 2. Append copyAttribute to copy.
             // 2. Append copyAttribute to copy.
-            MUST(element_copy->set_attribute(name, value));
+            element_copy->append_attribute(name, value);
         });
         });
         copy = move(element_copy);
         copy = move(element_copy);