From 336ccdb5f1c97cd20000c010abb0b0b523a86731 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 11 Apr 2025 15:37:52 +0100 Subject: [PATCH] LibWeb/XML: Treat declared namespaces as valid for attributes Previously if we encountered any attributes with a namespace other than `xml` or `xmlns`, we treated it as a parse error. Now, allow it as long as it's been declared in the current context. We also handle errors more gracefully - instead of exploding if setting the namespace fails, treat it as an error and carry on. --- Libraries/LibWeb/XML/XMLDocumentBuilder.cpp | 28 +++++++++++-------- .../svg/custom-namespaced-attributes-ref.svg | 8 ++++++ .../svg/custom-namespaced-attributes.svg | 11 ++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 Tests/LibWeb/Ref/expected/svg/custom-namespaced-attributes-ref.svg create mode 100644 Tests/LibWeb/Ref/input/svg/custom-namespaced-attributes.svg diff --git a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp index b6299957ddc..8a0b3e5ae4b 100644 --- a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp +++ b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp @@ -152,21 +152,27 @@ void XMLDocumentBuilder::element_start(const XML::Name& name, HashMapset_attribute_ns(Namespace::XMLNS, MUST(String::from_byte_string(name)), MUST(String::from_byte_string(attribute.value)))); - } else { - m_has_error = true; + // The prefix xmlns is used only to declare namespace bindings and is by definition bound to the namespace name http://www.w3.org/2000/xmlns/. + if (!attribute.key.is_one_of("xmlns:"sv, "xmlns:xmlns"sv)) { + if (!node->set_attribute_ns(Namespace::XMLNS, MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value))).is_error()) + continue; } - } else if (attribute.key.contains(":"sv)) { - if (!attribute.key.starts_with("xml:"sv)) { - m_has_error = true; + m_has_error = true; + } else if (attribute.key.contains(':')) { + if (auto ns = namespace_for_name(attribute.key); ns.has_value()) { + if (!node->set_attribute_ns(ns.value(), MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value))).is_error()) + continue; + } else if (attribute.key.starts_with("xml:"sv)) { + if (auto maybe_error = node->set_attribute_ns(Namespace::XML, MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value))); !maybe_error.is_error()) + continue; } + m_has_error = true; + } else { + if (!node->set_attribute(MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value))).is_error()) + continue; + m_has_error = true; } - MUST(node->set_attribute(MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value)))); } m_current_node = node.ptr(); diff --git a/Tests/LibWeb/Ref/expected/svg/custom-namespaced-attributes-ref.svg b/Tests/LibWeb/Ref/expected/svg/custom-namespaced-attributes-ref.svg new file mode 100644 index 00000000000..9fdc887af39 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/svg/custom-namespaced-attributes-ref.svg @@ -0,0 +1,8 @@ + + + + diff --git a/Tests/LibWeb/Ref/input/svg/custom-namespaced-attributes.svg b/Tests/LibWeb/Ref/input/svg/custom-namespaced-attributes.svg new file mode 100644 index 00000000000..c01c4d8be23 --- /dev/null +++ b/Tests/LibWeb/Ref/input/svg/custom-namespaced-attributes.svg @@ -0,0 +1,11 @@ + + + + +