From e2adce84e79d0b9d0b47584fde09d13f784c4315 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 02:05:30 +0200 Subject: [PATCH] LibWeb: Implement TrustedTypes spec for the concept of set_attribute_ns --- Libraries/LibWeb/DOM/Element.cpp | 19 +++++++++++++++---- Libraries/LibWeb/DOM/Element.h | 2 +- Libraries/LibWeb/DOM/Element.idl | 2 +- Libraries/LibWeb/XML/XMLDocumentBuilder.cpp | 6 +++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 4b08fbc9fa7..7c540cb7dd7 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -362,14 +362,25 @@ WebIDL::ExceptionOr validate_and_extract(JS::Realm& realm, Option return QualifiedName { local_name, prefix, namespace_ }; } -// https://dom.spec.whatwg.org/#dom-element-setattributens -WebIDL::ExceptionOr Element::set_attribute_ns(Optional const& namespace_, FlyString const& qualified_name, String const& value) +// FIXME: Trusted Types integration with DOM is still under review https://github.com/whatwg/dom/pull/1268 +// https://whatpr.org/dom/1268.html#dom-element-setattributens +WebIDL::ExceptionOr Element::set_attribute_ns(Optional const& namespace_, FlyString const& qualified_name, Variant, GC::Root, GC::Root, Utf16String> const& value) { // 1. Let (namespace, prefix, localName) be the result of validating and extracting namespace and qualifiedName given "element". auto extracted_qualified_name = TRY(validate_and_extract(realm(), namespace_, qualified_name, ValidationContext::Element)); - // 2. Set an attribute value for this using localName, value, and also prefix and namespace. - set_attribute_value(extracted_qualified_name.local_name(), value, extracted_qualified_name.prefix(), extracted_qualified_name.namespace_()); + // 2. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value + // with localName, namespace, element, and value. + auto const verified_value = TRY(TrustedTypes::get_trusted_types_compliant_attribute_value( + extracted_qualified_name.local_name(), + extracted_qualified_name.namespace_().has_value() ? Utf16String::from_utf8(extracted_qualified_name.namespace_().value()) : Optional(), + *this, + value.visit( + [](auto const& trusted_type) -> Variant, GC::Root, GC::Root, Utf16String> { return trusted_type; }, + [](String const& string) -> Variant, GC::Root, GC::Root, Utf16String> { return Utf16String::from_utf8(string); }))); + + // 3. Set an attribute value for this using localName, verifiedValue, and also prefix and namespace. + set_attribute_value(extracted_qualified_name.local_name(), verified_value.to_utf8_but_should_be_ported_to_utf16(), extracted_qualified_name.prefix(), extracted_qualified_name.namespace_()); return {}; } diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 5b6527f1d47..996cbffd8b1 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -152,7 +152,7 @@ public: WebIDL::ExceptionOr set_attribute(FlyString qualified_name, Variant, GC::Root, GC::Root, String> const& value); WebIDL::ExceptionOr set_attribute(FlyString qualified_name, Variant, GC::Root, GC::Root, Utf16String> const& value); - WebIDL::ExceptionOr set_attribute_ns(Optional const& namespace_, FlyString const& qualified_name, String const& value); + WebIDL::ExceptionOr set_attribute_ns(Optional const& namespace_, FlyString const& qualified_name, Variant, GC::Root, GC::Root, Utf16String> const& value); void set_attribute_value(FlyString const& local_name, String const& value, Optional const& prefix = {}, Optional const& namespace_ = {}); WebIDL::ExceptionOr> set_attribute_node(Attr&); WebIDL::ExceptionOr> set_attribute_node_ns(Attr&); diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index 7874cb54c76..60cad7a00ff 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -54,7 +54,7 @@ interface Element : Node { DOMString? getAttribute(DOMString qualifiedName); DOMString? getAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName); [CEReactions] undefined setAttribute(DOMString qualifiedName, (TrustedType or Utf16DOMString) value); - [CEReactions] undefined setAttributeNS([FlyString] DOMString? namespace , [FlyString] DOMString qualifiedName , DOMString value); + [CEReactions] undefined setAttributeNS([FlyString] DOMString? namespace , [FlyString] DOMString qualifiedName , (TrustedType or Utf16DOMString) value); [CEReactions] undefined removeAttribute([FlyString] DOMString qualifiedName); [CEReactions] undefined removeAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName); [CEReactions] boolean toggleAttribute(DOMString qualifiedName, optional boolean force); diff --git a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp index 801f70d6a6a..fd1357a151d 100644 --- a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp +++ b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp @@ -164,16 +164,16 @@ void XMLDocumentBuilder::element_start(XML::Name const& name, OrderedHashMapset_attribute_ns(Namespace::XMLNS, MUST(String::from_byte_string(attribute.key)), MUST(String::from_byte_string(attribute.value))).is_error()) + if (!node->set_attribute_ns(Namespace::XMLNS, MUST(String::from_byte_string(attribute.key)), Utf16String::from_utf8(attribute.value)).is_error()) continue; } 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()) + if (!node->set_attribute_ns(ns.value(), MUST(String::from_byte_string(attribute.key)), Utf16String::from_utf8(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()) + if (auto maybe_error = node->set_attribute_ns(Namespace::XML, MUST(String::from_byte_string(attribute.key)), Utf16String::from_utf8(attribute.value)); !maybe_error.is_error()) continue; } m_has_error = true;