From dc2fefe447e766fdd581dbd9688af925283b4c5a Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 00:39:16 +0200 Subject: [PATCH 01/10] LibWeb: Implement TrustedTypes spec for set_attribute on Element This part of the spec is still under a PR in GitHub, but it should be safe to implement like it is. --- Libraries/LibWeb/DOM/Element.cpp | 40 +++++++---- Libraries/LibWeb/DOM/Element.h | 7 +- Libraries/LibWeb/DOM/Element.idl | 3 +- .../LibWeb/TrustedTypes/TrustedTypePolicy.cpp | 67 +++++++++++++++++++ .../LibWeb/TrustedTypes/TrustedTypePolicy.h | 4 ++ .../LibWeb/TrustedTypes/TrustedTypePolicy.idl | 3 + .../TrustedTypes/TrustedTypePolicyFactory.cpp | 13 +--- 7 files changed, 108 insertions(+), 29 deletions(-) diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index b0b8a00471e7..081c707d7e19 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -205,38 +206,49 @@ GC::Ptr Element::get_attribute_node_ns(Optional const& namespac return m_attributes->get_attribute_ns(namespace_, name); } -// https://dom.spec.whatwg.org/#dom-element-setattribute -WebIDL::ExceptionOr Element::set_attribute(FlyString const& 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-setattribute +WebIDL::ExceptionOr Element::set_attribute(FlyString qualified_name, Variant, GC::Root, GC::Root, Utf16String> const& value) { // 1. If qualifiedName is not a valid attribute local name, then throw an "InvalidCharacterError" DOMException. - if (!is_valid_attribute_local_name(name)) + if (!is_valid_attribute_local_name(qualified_name)) return WebIDL::InvalidCharacterError::create(realm(), "Attribute name must not be empty or contain invalid characters"_utf16); - // 2. If this is in the HTML namespace and its node document is an HTML document, then set qualifiedName to qualifiedName in ASCII lowercase. - bool insert_as_lowercase = namespace_uri() == Namespace::HTML && document().document_type() == Document::Type::HTML; + // 2. If this is in the HTML namespace and its node document is an HTML document, then set qualifiedName to + // qualifiedName in ASCII lowercase. + if (namespace_uri() == Namespace::HTML && document().document_type() == Document::Type::HTML) + qualified_name = qualified_name.to_ascii_lowercase(); - // 3. Let attribute be the first attribute in this’s attribute list whose qualified name is qualifiedName, and null otherwise. - auto* attribute = attributes()->get_attribute(name); + // 3. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value + // with qualifiedName, null, this, and value. + auto const verified_value = TRY(TrustedTypes::get_trusted_types_compliant_attribute_value(qualified_name, {}, *this, value)); - // 4. If attribute is null, create an attribute whose local name is qualifiedName, value is value, and node document + // 4. Let attribute be the first attribute in this’s attribute list whose qualified name is qualifiedName, and null otherwise. + auto* attribute = attributes()->get_attribute(qualified_name); + + // 5. If attribute is null, create an attribute whose local name is qualifiedName, value is verifiedValue, and node document // is this’s node document, then append this attribute to this, and then return. if (!attribute) { - auto new_attribute = Attr::create(document(), insert_as_lowercase ? name.to_ascii_lowercase() : name, value); + auto new_attribute = Attr::create(document(), qualified_name, verified_value.to_utf8_but_should_be_ported_to_utf16()); m_attributes->append_attribute(new_attribute); return {}; } - // 5. Change attribute to value. - attribute->change_attribute(value); + // 6. Change attribute to verifiedValue. + attribute->change_attribute(verified_value.to_utf8_but_should_be_ported_to_utf16()); return {}; } -// https://dom.spec.whatwg.org/#dom-element-setattribute -WebIDL::ExceptionOr Element::set_attribute(FlyString const& name, Utf16String 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-setattribute +WebIDL::ExceptionOr Element::set_attribute(FlyString qualified_name, Variant, GC::Root, GC::Root, String> const& value) { - return set_attribute(name, value.to_utf8_but_should_be_ported_to_utf16()); + return set_attribute(move(qualified_name), + 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); })); } // https://dom.spec.whatwg.org/#valid-namespace-prefix diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 1f81eb7b0496..c0ae09c1bf7b 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include #include @@ -147,8 +150,8 @@ class WEB_API Element Optional lang() const; - WebIDL::ExceptionOr set_attribute(FlyString const& name, String const& value); - WebIDL::ExceptionOr set_attribute(FlyString const& name, Utf16String const& value); + 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); void set_attribute_value(FlyString const& local_name, String const& value, Optional const& prefix = {}, Optional const& namespace_ = {}); diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index a72de6af8cfc..7874cb54c769 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -14,6 +14,7 @@ #import #import #import +#import enum ScrollLogicalPosition { "start", "center", "end", "nearest" }; // https://drafts.csswg.org/cssom-view-1/#dictdef-scrollintoviewoptions @@ -52,7 +53,7 @@ interface Element : Node { sequence getAttributeNames(); DOMString? getAttribute(DOMString qualifiedName); DOMString? getAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName); - [CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value); + [CEReactions] undefined setAttribute(DOMString qualifiedName, (TrustedType or Utf16DOMString) value); [CEReactions] undefined setAttributeNS([FlyString] DOMString? namespace , [FlyString] DOMString qualifiedName , DOMString value); [CEReactions] undefined removeAttribute([FlyString] DOMString qualifiedName); [CEReactions] undefined removeAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName); diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.cpp b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.cpp index 945ae31614a1..a2a4a6b2b97b 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.cpp +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.cpp @@ -10,7 +10,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -340,4 +343,68 @@ WebIDL::ExceptionOr get_trusted_type_compliant_string(TrustedTypeNa }); } +// https://w3c.github.io/trusted-types/dist/spec/#validate-attribute-mutation +WebIDL::ExceptionOr get_trusted_types_compliant_attribute_value(FlyString const& attribute_name, Optional attribute_ns, const DOM::Element& element, Variant, GC::Root, GC::Root, Utf16String> const& new_value) +{ + // 1. If attributeNs is the empty string, set attributeNs to null. + if (attribute_ns.has_value() && attribute_ns.value().is_empty()) + attribute_ns.clear(); + + // 2. Set attributeData to the result of Get Trusted Type data for attribute algorithm, with the following arguments: + // element + // attributeName + // attributeNs + auto const attribute_data = get_trusted_type_data_for_attribute( + element_interface_name(Utf16String::from_utf8(element.local_name()), attribute_ns.has_value() ? attribute_ns.value() : Utf16String::from_utf8(Namespace::HTML)), + Utf16String::from_utf8(attribute_name), + attribute_ns); + + // 3. If attributeData is null, then: + if (!attribute_data.has_value()) { + // 1. If newValue is a string, return newValue. + if (new_value.has()) + return new_value.get(); + + // 2. Assert: newValue is TrustedHTML or TrustedScript or TrustedScriptURL. + VERIFY(new_value.has>() || new_value.has>() || new_value.has>()); + + // 3. Return value’s associated data. + // FIXME: This is badly worded in the spec it should say "Return stringified newvalues's" + return new_value.downcast().visit([](auto& value) { return value->to_string(); }); + } + + // 4. Let expectedType be the value of the fourth member of attributeData. + auto const expected_type = attribute_data->trusted_type; + + // 5. Let sink be the value of the fifth member of attributeData. + auto const sink = attribute_data->sink; + + // 6. Return the result of executing Get Trusted Type compliant string with the following arguments: + // expectedType + // newValue as input + // element’s node document’s relevant global object as global + // sink + // 'script' as sinkGroup + return get_trusted_type_compliant_string( + expected_type, + HTML::relevant_global_object(element.document()), + new_value, + sink, + Script.to_string()); +} + +Utf16String element_interface_name(Utf16String const& local_name, Utf16String const& element_ns) +{ + // FIXME: We don't have a method in ElementFactory that can give us the interface name but these are all the cases + // we care about in the table in get_trusted_type_data_for_attribute function + if (local_name == HTML::TagNames::iframe && element_ns == Namespace::HTML) + return "HTMLIFrameElement"_utf16; + if (local_name == HTML::TagNames::script && element_ns == Namespace::HTML) + return "HTMLScriptElement"_utf16; + if (local_name == SVG::TagNames::script && element_ns == Namespace::SVG) + return "SVGScriptElement"_utf16; + + return "Element"_utf16; +} + } diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h index 172339e5560d..00bbbaac606d 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.h @@ -69,4 +69,8 @@ WebIDL::ExceptionOr> process_value_with_a_default_policy(T WebIDL::ExceptionOr get_trusted_type_compliant_string(TrustedTypeName, JS::Object&, Variant, GC::Root, GC::Root, Utf16String> input, InjectionSink sink, String sink_group); +WebIDL::ExceptionOr get_trusted_types_compliant_attribute_value(FlyString const& attribute_name, Optional attribute_ns, const DOM::Element& element, Variant, GC::Root, GC::Root, Utf16String> const& new_value); + +Utf16String element_interface_name(Utf16String const& local_name, Utf16String const& element_ns); + } diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl index d869bb8253be..bb9ca883c50c 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicy.idl @@ -2,6 +2,9 @@ #import #import +// https://www.w3.org/TR/trusted-types/#typedefdef-trustedtype +typedef (TrustedHTML or TrustedScript or TrustedScriptURL) TrustedType; + // https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy [Exposed=(Window,Worker)] interface TrustedTypePolicy { diff --git a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp index 38b29a12fab7..50fdcc71421c 100644 --- a/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp +++ b/Libraries/LibWeb/TrustedTypes/TrustedTypePolicyFactory.cpp @@ -48,19 +48,8 @@ Optional TrustedTypePolicyFactory::get_attribute_type(Utf16String c if (attr_ns.has_value() && attr_ns.value().is_empty()) attr_ns.clear(); - // FIXME: We don't have a method in ElementFactory that can give us the interface name but these are all the cases - // we care about in the table in get_trusted_type_data_for_attribute function // 5. Let interface be the element interface for localName and elementNs. - Utf16String interface; - if (local_name == HTML::TagNames::iframe && element_ns == Namespace::HTML) { - interface = "HTMLIFrameElement"_utf16; - } else if (local_name == HTML::TagNames::script && element_ns == Namespace::HTML) { - interface = "HTMLScriptElement"_utf16; - } else if (local_name == SVG::TagNames::script && element_ns == Namespace::SVG) { - interface = "SVGScriptElement"_utf16; - } else { - interface = "Element"_utf16; - } + Utf16String const interface = element_interface_name(local_name, element_ns.value()); // 6. Let expectedType be null. Optional expected_type {}; From 613705b74ef91036a824913decfd791563182ad8 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 00:53:55 +0200 Subject: [PATCH 02/10] LibWeb: Implement TrustedTypes spec for the concept of set_attribute --- Libraries/LibWeb/DOM/NamedNodeMap.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Libraries/LibWeb/DOM/NamedNodeMap.cpp b/Libraries/LibWeb/DOM/NamedNodeMap.cpp index f45e8a860375..a570ffc382b9 100644 --- a/Libraries/LibWeb/DOM/NamedNodeMap.cpp +++ b/Libraries/LibWeb/DOM/NamedNodeMap.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace Web::DOM { @@ -194,31 +195,43 @@ Attr const* NamedNodeMap::get_attribute_ns(Optional const& namespace_ return nullptr; } -// https://dom.spec.whatwg.org/#concept-element-attributes-set +// FIXME: Trusted Types integration with DOM is still under review https://github.com/whatwg/dom/pull/1268 +// https://whatpr.org/dom/1268.html#concept-element-attributes-set WebIDL::ExceptionOr> NamedNodeMap::set_attribute(Attr& attribute) { - // 1. If attr’s element is neither null nor element, throw an "InUseAttributeError" DOMException. + // 1. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value + // with attr’s local name, attr’s namespace, element, and attr’s value + auto const verifiedValue = TRY(TrustedTypes::get_trusted_types_compliant_attribute_value( + attribute.local_name(), + attribute.namespace_uri().has_value() ? Utf16String::from_utf8(attribute.namespace_uri().value()) : Optional(), + associated_element(), + Utf16String::from_utf8(attribute.value()))); + + // 2. If attr’s element is neither null nor element, throw an "InUseAttributeError" DOMException. if ((attribute.owner_element() != nullptr) && (attribute.owner_element() != &associated_element())) return WebIDL::InUseAttributeError::create(realm(), "Attribute must not already be in use"_utf16); - // 2. Let oldAttr be the result of getting an attribute given attr’s namespace, attr’s local name, and element. + // 3. Let oldAttr be the result of getting an attribute given attr’s namespace, attr’s local name, and element. size_t old_attribute_index = 0; auto* old_attribute = get_attribute_ns(attribute.namespace_uri(), attribute.local_name(), &old_attribute_index); - // 3. If oldAttr is attr, return attr. + // 4. If oldAttr is attr, return attr. if (old_attribute == &attribute) return &attribute; - // 4. If oldAttr is non-null, then replace oldAttr with attr. + // 5. Set attr’s value to verifiedValue. + attribute.set_value(verifiedValue.to_utf8_but_should_be_ported_to_utf16()); + + // 6. If oldAttr is non-null, then replace oldAttr with attr. if (old_attribute) { replace_attribute(*old_attribute, attribute, old_attribute_index); } - // 5. Otherwise, append attr to element. + // 7. Otherwise, append attr to element. else { append_attribute(attribute); } - // 6. Return oldAttr. + // 8. Return oldAttr. return old_attribute; } From 65bd3bba6708d6be167bcaedb3ff5c3a16a28500 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 02:05:30 +0200 Subject: [PATCH 03/10] 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 081c707d7e19..f5a5f3479dd0 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -361,14 +361,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 c0ae09c1bf7b..213d805ececf 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -153,7 +153,7 @@ class WEB_API Element 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 7874cb54c769..60cad7a00ffa 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 ae9b7da843bf..b1c10738f6f8 100644 --- a/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp +++ b/Libraries/LibWeb/XML/XMLDocumentBuilder.cpp @@ -162,16 +162,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; From 487cb487fab6ed682b5feedfbc8ac738e4b9df50 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 02:12:15 +0200 Subject: [PATCH 04/10] LibWeb: Implement TrustedTypes spec for set_value on Attribute --- Libraries/LibWeb/DOM/Attr.cpp | 36 ++++++++++++++++++++++++--- Libraries/LibWeb/DOM/Attr.h | 2 +- Libraries/LibWeb/DOM/NamedNodeMap.cpp | 2 +- Libraries/LibWeb/DOM/Node.cpp | 8 +++--- Libraries/LibWeb/DOM/Node.h | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Libraries/LibWeb/DOM/Attr.cpp b/Libraries/LibWeb/DOM/Attr.cpp index 985bd2c8f7fb..b732a91b10e3 100644 --- a/Libraries/LibWeb/DOM/Attr.cpp +++ b/Libraries/LibWeb/DOM/Attr.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2021, Tim Flynn * Copyright (c) 2023, Luke Wilde + * Copyright (c) 2025, Miguel Sacristán Izcue * * SPDX-License-Identifier: BSD-2-Clause */ @@ -13,6 +14,7 @@ #include #include #include +#include namespace Web::DOM { @@ -69,17 +71,43 @@ void Attr::set_owner_element(Element* owner_element) m_owner_element = owner_element; } -// https://dom.spec.whatwg.org/#set-an-existing-attribute-value -void Attr::set_value(String value) +// FIXME: Trusted Types integration with DOM is still under review https://github.com/whatwg/dom/pull/1268 +// https://whatpr.org/dom/1268.html#set-an-existing-attribute-value +WebIDL::ExceptionOr Attr::set_value(String value) { // 1. If attribute’s element is null, then set attribute’s value to value. if (!owner_element()) { m_value = move(value); } - // 2. Otherwise, change attribute to value. + // 2. Otherwise: else { - change_attribute(move(value)); + // 1. Let element be attribute’s element. + auto const* element = owner_element(); + + // 2. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value with + // attribute’s local name, attribute’s namespace, element, and value. + auto const verified_value = TRY(TrustedTypes::get_trusted_types_compliant_attribute_value( + local_name(), + namespace_uri().has_value() ? Utf16String::from_utf8(namespace_uri().value()) : Optional(), + *element, + Utf16String::from_utf8(value))); + + // 3. If attribute’s element is null, then set attribute’s value to verifiedValue, and return. + if (!owner_element()) { + m_value = verified_value.to_utf8_but_should_be_ported_to_utf16(); + return {}; + } + + // 4. If attribute’s element is not element, then return. + if (owner_element() != element) { + return {}; + } + + // 5. Change attribute to verifiedValue. + change_attribute(verified_value.to_utf8_but_should_be_ported_to_utf16()); } + + return {}; } // https://dom.spec.whatwg.org/#concept-element-attributes-change diff --git a/Libraries/LibWeb/DOM/Attr.h b/Libraries/LibWeb/DOM/Attr.h index b537e3e4aaf3..93415cf3e812 100644 --- a/Libraries/LibWeb/DOM/Attr.h +++ b/Libraries/LibWeb/DOM/Attr.h @@ -34,7 +34,7 @@ class WEB_API Attr final : public Node { FlyString const& lowercase_name() const { return m_lowercase_name; } String const& value() const { return m_value; } - void set_value(String value); + WebIDL::ExceptionOr set_value(String value); void change_attribute(String value); Element* owner_element(); diff --git a/Libraries/LibWeb/DOM/NamedNodeMap.cpp b/Libraries/LibWeb/DOM/NamedNodeMap.cpp index a570ffc382b9..bef2f9cf0a75 100644 --- a/Libraries/LibWeb/DOM/NamedNodeMap.cpp +++ b/Libraries/LibWeb/DOM/NamedNodeMap.cpp @@ -220,7 +220,7 @@ WebIDL::ExceptionOr> NamedNodeMap::set_attribute(Attr& attribute) return &attribute; // 5. Set attr’s value to verifiedValue. - attribute.set_value(verifiedValue.to_utf8_but_should_be_ported_to_utf16()); + TRY(attribute.set_value(verifiedValue.to_utf8_but_should_be_ported_to_utf16())); // 6. If oldAttr is non-null, then replace oldAttr with attr. if (old_attribute) { diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 2f64f353e720..65dd0cf5b9d7 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -221,7 +221,8 @@ void Node::set_text_content(Optional const& maybe_content) // If Attr, set an existing attribute value with this and the given value. else if (auto* attribute = as_if(*this)) { - attribute->set_value(content.to_utf8_but_should_be_ported_to_utf16()); + // FIXME: This should propagate + MUST(attribute->set_value(content.to_utf8_but_should_be_ported_to_utf16())); } // Otherwise, do nothing. @@ -368,7 +369,7 @@ Optional Node::node_value() const } // https://dom.spec.whatwg.org/#ref-for-dom-node-nodevalue%E2%91%A0 -void Node::set_node_value(Optional const& maybe_value) +WebIDL::ExceptionOr Node::set_node_value(Optional const& maybe_value) { // The nodeValue setter steps are to, if the given value is null, act as if it was the empty string instead, // and then do as described below, switching on the interface this implements: @@ -376,13 +377,14 @@ void Node::set_node_value(Optional const& maybe_value) // If Attr, set an existing attribute value with this and the given value. if (auto* attr = as_if(this)) { - attr->set_value(move(value)); + TRY(attr->set_value(move(value))); } else if (auto* character_data = as_if(this)) { // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value. character_data->set_data(Utf16String::from_utf8(value)); } // Otherwise, do nothing. + return {}; } // https://html.spec.whatwg.org/multipage/document-sequences.html#node-navigable diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index bce7a9d412a4..7c883f393682 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -285,7 +285,7 @@ class WEB_API Node : public EventTarget WebIDL::ExceptionOr normalize(); Optional node_value() const; - void set_node_value(Optional const&); + WebIDL::ExceptionOr set_node_value(Optional const&); GC::Ptr navigable() const; From 8541ad38148906d5f727b43569e2c6a264379f08 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 02:25:57 +0200 Subject: [PATCH 05/10] LibWeb: Properly propagate errors for Node set_text_content This function was supposed to throw errors even before the TrustedTypes spec thanks to the CharacterData replaceData call but had a MUST. This changes this to ensure this function can throw an error --- Libraries/LibWeb/DOM/DocumentLoading.cpp | 4 ++-- Libraries/LibWeb/DOM/Node.cpp | 10 +++++----- Libraries/LibWeb/DOM/Node.h | 2 +- Libraries/LibWeb/HTML/HTMLDetailsElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLInputElement.cpp | 10 +++++----- Libraries/LibWeb/HTML/HTMLSelectElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp | 6 +++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Libraries/LibWeb/DOM/DocumentLoading.cpp b/Libraries/LibWeb/DOM/DocumentLoading.cpp index c548b321130e..d92a6db0aafb 100644 --- a/Libraries/LibWeb/DOM/DocumentLoading.cpp +++ b/Libraries/LibWeb/DOM/DocumentLoading.cpp @@ -296,7 +296,7 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav }; auto style_element = TRY(DOM::create_element(document, HTML::TagNames::style, Namespace::HTML)); - style_element->set_text_content(R"~~~( + MUST(style_element->set_text_content(R"~~~( :root { background-color: #222; } @@ -310,7 +310,7 @@ static WebIDL::ExceptionOr> load_media_document(HTML::Nav img { background-color: #fff; } - )~~~"_utf16); + )~~~"_utf16)); TRY(document->head()->append_child(style_element)); auto url_string = document->url_string(); diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 65dd0cf5b9d7..eecf840c615a 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -199,7 +199,7 @@ Optional Node::text_content() const } // https://dom.spec.whatwg.org/#ref-for-dom-node-textcontent%E2%91%A0 -void Node::set_text_content(Optional const& maybe_content) +WebIDL::ExceptionOr Node::set_text_content(Optional const& maybe_content) { // The textContent setter steps are to, if the given value is null, act as if it was the empty string instead, // and then do as described below, switching on the interface this implements: @@ -209,20 +209,19 @@ void Node::set_text_content(Optional const& maybe_content) if (is(this) || is(this)) { // OPTIMIZATION: Replacing nothing with nothing is a no-op. Avoid all invalidation in this case. if (!first_child() && content.is_empty()) { - return; + return {}; } string_replace_all(content); } // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value. else if (auto* character_data = as_if(*this)) { - MUST(character_data->replace_data(0, character_data->length_in_utf16_code_units(), content)); + TRY(character_data->replace_data(0, character_data->length_in_utf16_code_units(), content)); } // If Attr, set an existing attribute value with this and the given value. else if (auto* attribute = as_if(*this)) { - // FIXME: This should propagate - MUST(attribute->set_value(content.to_utf8_but_should_be_ported_to_utf16())); + TRY(attribute->set_value(content.to_utf8_but_should_be_ported_to_utf16())); } // Otherwise, do nothing. @@ -233,6 +232,7 @@ void Node::set_text_content(Optional const& maybe_content) } document().bump_dom_tree_version(); + return {}; } // https://dom.spec.whatwg.org/#dom-node-normalize diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 7c883f393682..1d3b402dc151 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -280,7 +280,7 @@ class WEB_API Node : public EventTarget Utf16String descendant_text_content() const; Optional text_content() const; - void set_text_content(Optional const&); + WebIDL::ExceptionOr set_text_content(Optional const&); WebIDL::ExceptionOr normalize(); diff --git a/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp b/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp index a8a88b347efd..655d4ba8903f 100644 --- a/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp @@ -243,7 +243,7 @@ WebIDL::ExceptionOr HTMLDetailsElement::create_shadow_tree_if_needed() // The third child element is either a link or style element with the following styles for the default summary: auto style = TRY(DOM::create_element(document(), HTML::TagNames::style, Namespace::HTML)); - style->set_text_content(R"~~~( + MUST(style->set_text_content(R"~~~( :host summary { display: list-item; counter-increment: list-item 0; @@ -252,7 +252,7 @@ WebIDL::ExceptionOr HTMLDetailsElement::create_shadow_tree_if_needed() :host([open]) summary { list-style-type: disclosure-open; } - )~~~"_utf16); + )~~~"_utf16)); MUST(shadow_root->append_child(style)); m_summary_slot = static_cast(*summary_slot); diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 990aab8c8786..35a7e9bd4fbb 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -1083,7 +1083,7 @@ void HTMLInputElement::create_text_input_shadow_tree() m_text_node = realm().create(document(), Utf16String {}); if (type_state() == TypeAttributeState::Password) m_text_node->set_is_password_input({}, true); - m_text_node->set_text_content(m_value); + MUST(m_text_node->set_text_content(m_value)); handle_maxlength_attribute(); MUST(m_inner_text_element->append_child(*m_text_node)); @@ -1226,15 +1226,15 @@ void HTMLInputElement::update_file_input_shadow_tree() return; auto files_label = has_attribute(HTML::AttributeNames::multiple) ? "files"sv : "file"sv; - m_file_button->set_text_content(Utf16String::formatted("Select {}...", files_label)); + MUST(m_file_button->set_text_content(Utf16String::formatted("Select {}...", files_label))); if (m_selected_files && m_selected_files->length() > 0) { if (m_selected_files->length() == 1) - m_file_label->set_text_content(Utf16String::from_utf8(m_selected_files->item(0)->name())); + MUST(m_file_label->set_text_content(Utf16String::from_utf8(m_selected_files->item(0)->name()))); else - m_file_label->set_text_content(Utf16String::formatted("{} files selected.", m_selected_files->length())); + MUST(m_file_label->set_text_content(Utf16String::formatted("{} files selected.", m_selected_files->length()))); } else { - m_file_label->set_text_content(Utf16String::formatted("No {} selected.", files_label)); + MUST(m_file_label->set_text_content(Utf16String::formatted("No {} selected.", files_label))); } } diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index 8f3768b4a6ea..5de6a60fc42a 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -633,7 +633,7 @@ void HTMLSelectElement::update_inner_text_element() // Update inner text element to the label of the selected option for (auto const& option_element : m_cached_list_of_options) { if (option_element->selected()) { - m_inner_text_element->set_text_content(Infra::strip_and_collapse_whitespace(Utf16String::from_utf8(option_element->label()))); + MUST(m_inner_text_element->set_text_content(Infra::strip_and_collapse_whitespace(Utf16String::from_utf8(option_element->label())))); return; } } diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index dda2ba70a1b1..7100542c3c2f 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -117,7 +117,7 @@ void HTMLTextAreaElement::reset_algorithm() set_raw_value(child_text_content()); if (m_text_node) { - m_text_node->set_text_content(m_raw_value); + MUST(m_text_node->set_text_content(m_raw_value)); update_placeholder_visibility(); } } @@ -350,7 +350,7 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed() m_text_node = realm().create(document(), Utf16String {}); // NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content. // Otherwise, it will get filled in whenever that does get called. - m_text_node->set_text_content(m_raw_value); + MUST(m_text_node->set_text_content(m_raw_value)); handle_maxlength_attribute(); MUST(m_inner_text_element->append_child(*m_text_node)); @@ -403,7 +403,7 @@ void HTMLTextAreaElement::children_changed(ChildrenChangedMetadata const* metada if (!m_dirty_value) { set_raw_value(child_text_content()); if (m_text_node) - m_text_node->set_text_content(m_raw_value); + MUST(m_text_node->set_text_content(m_raw_value)); update_placeholder_visibility(); } } From 4f4294b5af77a36c3fbe15de6796e211e5e9e384 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Fri, 8 Aug 2025 17:34:23 +0200 Subject: [PATCH 06/10] LibWeb: Amend Document interface to make it compatible with TrustedTypes --- Libraries/LibWeb/DOM/Document.cpp | 56 ++++++++++++++----- Libraries/LibWeb/DOM/Document.h | 8 +-- Libraries/LibWeb/DOM/Document.idl | 10 ++-- Libraries/LibWeb/TrustedTypes/InjectionSink.h | 1 + 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index c4008e765b61..b2d74dbb4e86 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -165,6 +165,8 @@ #include #include #include +#include +#include #include #include #include @@ -644,41 +646,56 @@ GC::Ptr Document::get_selection() const } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-write -WebIDL::ExceptionOr Document::write(Vector const& text) +WebIDL::ExceptionOr Document::write(Vector const& text) { // The document.write(...text) method steps are to run the document write steps with this, text, false, and "Document write". return run_the_document_write_steps(text, AddLineFeed::No, TrustedTypes::InjectionSink::Documentwrite); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-document-writeln -WebIDL::ExceptionOr Document::writeln(Vector const& text) +WebIDL::ExceptionOr Document::writeln(Vector const& text) { // The document.writeln(...text) method steps are to run the document write steps with this, text, true, and "Document writeln". return run_the_document_write_steps(text, AddLineFeed::Yes, TrustedTypes::InjectionSink::Documentwriteln); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#document-write-steps -WebIDL::ExceptionOr Document::run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink) +WebIDL::ExceptionOr Document::run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink) { // 1. Let string be the empty string. StringBuilder string; // 2. Let isTrusted be false if text contains a string; otherwise true. - // FIXME: We currently only accept strings. Revisit this once we support the TrustedHTML type. auto is_trusted = true; + for (auto const& value : text) { + if (value.has()) { + is_trusted = false; + break; + } + } // 3. For each value of text: for (auto const& value : text) { - // FIXME: 1. If value is a TrustedHTML object, then append value's associated data to string. - - // 2. Otherwise, append value to string. - string.append(value); + string.append(value.visit( + // 1. If value is a TrustedHTML object, then append value's associated data to string. + [](GC::Root const& value) { return value->to_string(); }, + // 2. Otherwise, append value to string. + [](Utf16String const& value) { return value; }) + .to_utf8_but_should_be_ported_to_utf16()); } - // FIXME: 4. If isTrusted is false, set string to the result of invoking the Get Trusted Type compliant string algorithm + // 4. If isTrusted is false, set string to the result of invoking the Get Trusted Type compliant string algorithm // with TrustedHTML, this's relevant global object, string, sink, and "script". - (void)is_trusted; - (void)sink; + if (!is_trusted) { + auto const new_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + relevant_global_object(*this), + Utf16String::from_utf8(MUST(string.to_string())), + sink, + TrustedTypes::Script.to_string())); + string.clear(); + string.append(new_string.to_utf8_but_should_be_ported_to_utf16()); + } // 5. If lineFeed is true, append U+000A LINE FEED to string. if (line_feed == AddLineFeed::Yes) @@ -6345,10 +6362,19 @@ void Document::parse_html_from_a_string(StringView html) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsehtmlunsafe -GC::Ref Document::parse_html_unsafe(JS::VM& vm, StringView html) +WebIDL::ExceptionOr> Document::parse_html_unsafe(JS::VM& vm, TrustedTypes::TrustedHTMLOrString const& html) { auto& realm = *vm.current_realm(); - // FIXME: 1. Let compliantHTML to the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, html, "Document parseHTMLUnsafe", and "script". + + // FIXME: update description once https://github.com/whatwg/html/issues/11778 gets solved + // 1. Let compliantHTML to the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, html, "Document parseHTMLUnsafe", and "script". + auto const compliant_html = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::current_principal_global_object(), + html, + TrustedTypes::InjectionSink::DocumentparseHTMLUnsafe, + TrustedTypes::Script.to_string())); // 2. Let document be a new Document, whose content type is "text/html". auto document = Document::create_for_fragment_parsing(realm); @@ -6357,8 +6383,8 @@ GC::Ref Document::parse_html_unsafe(JS::VM& vm, StringView html) // 3. Set document's allow declarative shadow roots to true. document->set_allow_declarative_shadow_roots(true); - // 4. Parse HTML from a string given document and compliantHTML. // FIXME: Use compliantHTML. - document->parse_html_from_a_string(html); + // 4. Parse HTML from a string given document and compliantHTML. + document->parse_html_from_a_string(compliant_html.to_utf8_but_should_be_ported_to_utf16()); // AD-HOC: Setting the origin to match that of the associated document matches the behavior of existing browsers. auto& associated_document = as(realm.global_object()).associated_document(); diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index b97efe03de0c..154b1976d0e3 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -472,8 +472,8 @@ class WEB_API Document void set_window(HTML::Window&); - WebIDL::ExceptionOr write(Vector const& strings); - WebIDL::ExceptionOr writeln(Vector const& strings); + WebIDL::ExceptionOr write(Vector const& text); + WebIDL::ExceptionOr writeln(Vector const& text); WebIDL::ExceptionOr open(Optional const& = {}, Optional const& = {}); WebIDL::ExceptionOr> open(StringView url, StringView name, StringView features); @@ -828,7 +828,7 @@ class WEB_API Document Vector> find_matching_text(String const&, CaseSensitivity); void parse_html_from_a_string(StringView); - static GC::Ref parse_html_unsafe(JS::VM&, StringView); + static WebIDL::ExceptionOr> parse_html_unsafe(JS::VM&, TrustedTypes::TrustedHTMLOrString const&); void set_console_client(GC::Ptr console_client) { m_console_client = console_client; } GC::Ptr console_client() const { return m_console_client; } @@ -972,7 +972,7 @@ class WEB_API Document Yes, No, }; - WebIDL::ExceptionOr run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink); + WebIDL::ExceptionOr run_the_document_write_steps(Vector const& text, AddLineFeed line_feed, TrustedTypes::InjectionSink sink); void queue_intersection_observer_task(); void queue_an_intersection_observer_entry(IntersectionObserver::IntersectionObserver&, HighResolutionTime::DOMHighResTimeStamp time, GC::Ref root_bounds, GC::Ref bounding_client_rect, GC::Ref intersection_rect, bool is_intersecting, double intersection_ratio, GC::Ref target); diff --git a/Libraries/LibWeb/DOM/Document.idl b/Libraries/LibWeb/DOM/Document.idl index 986faddec970..347f19e14cc1 100644 --- a/Libraries/LibWeb/DOM/Document.idl +++ b/Libraries/LibWeb/DOM/Document.idl @@ -26,6 +26,7 @@ #import #import #import +#import #import #import #import @@ -56,13 +57,10 @@ interface Document : Node { [CEReactions] Document open(optional DOMString unused1, optional DOMString unused2); WindowProxy? open(USVString url, DOMString name, DOMString features); [CEReactions] undefined close(); - // FIXME: [CEReactions] undefined write((TrustedHTML or DOMString)... text); - [CEReactions] undefined write(DOMString... text); - // FIXME: [CEReactions] undefined writeln((TrustedHTML or DOMString)... text); - [CEReactions] undefined writeln(DOMString... text); + [CEReactions] undefined write((TrustedHTML or Utf16DOMString)... text); + [CEReactions] undefined writeln((TrustedHTML or Utf16DOMString)... text); - // FIXME: static Document parseHTMLUnsafe((TrustedHTML or DOMString) html); - static Document parseHTMLUnsafe(DOMString html); + static Document parseHTMLUnsafe((TrustedHTML or Utf16DOMString) html); attribute DOMString cookie; diff --git a/Libraries/LibWeb/TrustedTypes/InjectionSink.h b/Libraries/LibWeb/TrustedTypes/InjectionSink.h index 75441b115cb2..5c6ad5c9dc21 100644 --- a/Libraries/LibWeb/TrustedTypes/InjectionSink.h +++ b/Libraries/LibWeb/TrustedTypes/InjectionSink.h @@ -17,6 +17,7 @@ namespace Web::TrustedTypes { // https://w3c.github.io/trusted-types/dist/spec/#injection-sink #define ENUMERATE_INJECTION_SINKS \ + __ENUMERATE_INJECTION_SINKS(DocumentparseHTMLUnsafe, "Document parseHTMLUnsafe") \ __ENUMERATE_INJECTION_SINKS(Documentwrite, "Document write") \ __ENUMERATE_INJECTION_SINKS(Documentwriteln, "Document writeln") \ __ENUMERATE_INJECTION_SINKS(DocumentexecCommand, "Document execCommand") \ From 726e09387715b2232debf9522f42a135c79ed839 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Sun, 10 Aug 2025 23:49:19 +0200 Subject: [PATCH 07/10] LibWeb: Amend Element interface to make it compatible with TrustedTypes --- Libraries/LibWeb/DOM/Element.cpp | 81 +++++++++++++------ Libraries/LibWeb/DOM/Element.h | 12 +-- Libraries/LibWeb/DOM/Element.idl | 13 ++- Libraries/LibWeb/DOM/Node.cpp | 8 +- Libraries/LibWeb/DOM/Node.h | 2 +- Libraries/LibWeb/DOM/ShadowRoot.cpp | 2 +- Libraries/LibWeb/HTML/HTMLInputElement.cpp | 4 +- Libraries/LibWeb/HTML/HTMLSelectElement.cpp | 2 +- Libraries/LibWeb/TrustedTypes/InjectionSink.h | 4 + Libraries/LibWeb/XHR/XMLHttpRequest.cpp | 2 +- Services/WebContent/ConnectionFromClient.cpp | 18 ++--- Services/WebContent/WebDriverConnection.cpp | 8 +- 12 files changed, 94 insertions(+), 62 deletions(-) diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index f5a5f3479dd0..8d38fe16eb79 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -369,7 +370,7 @@ WebIDL::ExceptionOr Element::set_attribute_ns(Optional const& n auto extracted_qualified_name = TRY(validate_and_extract(realm(), namespace_, qualified_name, ValidationContext::Element)); // 2. Let verifiedValue be the result of calling get Trusted Types-compliant attribute value - // with localName, namespace, element, and value. + // with localName, namespace, this, 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(), @@ -1056,15 +1057,22 @@ WebIDL::ExceptionOr Element::closest(StringView selectors) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-innerhtml -WebIDL::ExceptionOr Element::set_inner_html(StringView value) +WebIDL::ExceptionOr Element::set_inner_html(TrustedTypes::TrustedHTMLOrString const& value) { - // FIXME: 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, the given value, "Element innerHTML", and "script". + // 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, the given value, "Element innerHTML", and "script". + auto const compliant_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + value, + TrustedTypes::InjectionSink::ElementinnerHTML, + TrustedTypes::Script.to_string())); // 2. Let context be this. DOM::Node* context = this; - // 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. FIXME: Use compliantString. - auto fragment = TRY(as(*context).parse_fragment(value)); + // 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. + auto fragment = TRY(as(*context).parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16())); // 4. If context is a template element, then set context to the template element's template contents (a DocumentFragment). auto* template_element = as_if(*context); @@ -1088,9 +1096,9 @@ WebIDL::ExceptionOr Element::set_inner_html(StringView value) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-innerhtml -WebIDL::ExceptionOr Element::inner_html() const +WebIDL::ExceptionOr Element::inner_html() const { - return serialize_fragment(HTML::RequireWellFormed::Yes); + return TRY(serialize_fragment(HTML::RequireWellFormed::Yes)); } bool Element::is_focused() const @@ -2096,15 +2104,22 @@ WebIDL::ExceptionOr> Element::parse_fragment(Stri } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-outerhtml -WebIDL::ExceptionOr Element::outer_html() const +WebIDL::ExceptionOr Element::outer_html() const { - return serialize_fragment(HTML::RequireWellFormed::Yes, FragmentSerializationMode::Outer); + return TRY(serialize_fragment(HTML::RequireWellFormed::Yes, FragmentSerializationMode::Outer)); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-outerhtml -WebIDL::ExceptionOr Element::set_outer_html(String const& value) +WebIDL::ExceptionOr Element::set_outer_html(TrustedTypes::TrustedHTMLOrString const& value) { - // 1. FIXME: Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, the given value, "Element outerHTML", and "script". + // 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, the given value, "Element outerHTML", and "script". + auto const compliant_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + value, + TrustedTypes::InjectionSink::ElementouterHTML, + TrustedTypes::Script.to_string())); // 2. Let parent be this's parent. auto* parent = this->parent(); @@ -2121,8 +2136,8 @@ WebIDL::ExceptionOr Element::set_outer_html(String const& value) if (parent->is_document_fragment()) parent = TRY(create_element(document(), HTML::TagNames::body, Namespace::HTML)); - // 6. Let fragment be the result of invoking the fragment parsing algorithm steps given parent and compliantString. FIXME: Use compliantString. - auto fragment = TRY(as(*parent).parse_fragment(value)); + // 6. Let fragment be the result of invoking the fragment parsing algorithm steps given parent and compliantString. + auto fragment = TRY(as(*parent).parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16())); // 6. Replace this with fragment within this's parent. TRY(parent->replace_child(fragment, *this)); @@ -2131,12 +2146,21 @@ WebIDL::ExceptionOr Element::set_outer_html(String const& value) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#the-insertadjacenthtml()-method -WebIDL::ExceptionOr Element::insert_adjacent_html(String const& position, String const& string) -{ - // 1. Let context be null. +WebIDL::ExceptionOr Element::insert_adjacent_html(String const& position, TrustedTypes::TrustedHTMLOrString const& string) +{ + // 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, string, "Element insertAdjacentHTML", and "script". + auto const compliant_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + string, + TrustedTypes::InjectionSink::ElementinsertAdjacentHTML, + TrustedTypes::Script.to_string())); + + // 2. Let context be null. GC::Ptr context; - // 2. Use the first matching item from this list: + // 3. Use the first matching item from this list: // - If position is an ASCII case-insensitive match for the string "beforebegin" // - If position is an ASCII case-insensitive match for the string "afterend" if (position.equals_ignoring_ascii_case("beforebegin"sv) @@ -2161,7 +2185,7 @@ WebIDL::ExceptionOr Element::insert_adjacent_html(String const& position, return WebIDL::SyntaxError::create(realm(), "insertAdjacentHTML: invalid position argument"_utf16); } - // 3. If context is not an Element or the following are all true: + // 4. If context is not an Element or the following are all true: // - context's node document is an HTML document, // - context's local name is "html", and // - context's namespace is the HTML namespace; @@ -2173,10 +2197,10 @@ WebIDL::ExceptionOr Element::insert_adjacent_html(String const& position, context = TRY(create_element(document(), HTML::TagNames::body, Namespace::HTML)); } - // 4. Let fragment be the result of invoking the fragment parsing algorithm steps with context and string. - auto fragment = TRY(as(*context).parse_fragment(string)); + // 5. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. + auto fragment = TRY(as(*context).parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16())); - // 5. Use the first matching item from this list: + // 6. Use the first matching item from this list: // - If position is an ASCII case-insensitive match for the string "beforebegin" if (position.equals_ignoring_ascii_case("beforebegin"sv)) { @@ -3934,17 +3958,24 @@ WebIDL::ExceptionOr Element::get_html(GetHTMLOptions const& options) con } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-element-sethtmlunsafe -WebIDL::ExceptionOr Element::set_html_unsafe(StringView html) +WebIDL::ExceptionOr Element::set_html_unsafe(TrustedTypes::TrustedHTMLOrString const& html) { - // FIXME: 1. Let compliantHTML be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, html, "Element setHTMLUnsafe", and "script". + // 1. Let compliantHTML be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, html, "Element setHTMLUnsafe", and "script". + auto const compliant_html = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + html, + TrustedTypes::InjectionSink::ElementsetHTMLUnsafe, + TrustedTypes::Script.to_string())); // 2. Let target be this's template contents if this is a template element; otherwise this. DOM::Node* target = this; if (is(*this)) target = as(*this).content().ptr(); - // 3. Unsafe set HTML given target, this, and compliantHTML. FIXME: Use compliantHTML. - TRY(target->unsafely_set_html(*this, html)); + // 3. Unsafe set HTML given target, this, and compliantHTML. + TRY(target->unsafely_set_html(*this, compliant_html.to_utf8_but_should_be_ported_to_utf16())); return {}; } diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 213d805ececf..24e977aadefa 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -240,17 +240,17 @@ class WEB_API Element [[nodiscard]] GC::Ptr element_to_inherit_style_from(Optional) const; - WebIDL::ExceptionOr inner_html() const; - WebIDL::ExceptionOr set_inner_html(StringView); + WebIDL::ExceptionOr inner_html() const; + WebIDL::ExceptionOr set_inner_html(TrustedTypes::TrustedHTMLOrString const&); - WebIDL::ExceptionOr set_html_unsafe(StringView); + WebIDL::ExceptionOr set_html_unsafe(TrustedTypes::TrustedHTMLOrString const&); WebIDL::ExceptionOr get_html(GetHTMLOptions const&) const; - WebIDL::ExceptionOr insert_adjacent_html(String const& position, String const&); + WebIDL::ExceptionOr insert_adjacent_html(String const& position, TrustedTypes::TrustedHTMLOrString const&); - WebIDL::ExceptionOr outer_html() const; - WebIDL::ExceptionOr set_outer_html(String const&); + WebIDL::ExceptionOr outer_html() const; + WebIDL::ExceptionOr set_outer_html(TrustedTypes::TrustedHTMLOrString const&); bool is_focused() const; bool is_active() const; diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index 60cad7a00ffa..f2f9c2e4f621 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -14,6 +14,7 @@ #import #import #import +#import #import enum ScrollLogicalPosition { "start", "center", "end", "nearest" }; @@ -109,18 +110,14 @@ interface Element : Node { readonly attribute double currentCSSZoom; // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization - // FIXME: [CEReactions] undefined setHTMLUnsafe((TrustedHTML or DOMString) html); - [CEReactions] undefined setHTMLUnsafe(DOMString html); + [CEReactions] undefined setHTMLUnsafe((TrustedHTML or Utf16DOMString) html); DOMString getHTML(optional GetHTMLOptions options = {}); - // FIXME: [CEReactions] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) innerHTML; - [CEReactions, LegacyNullToEmptyString] attribute DOMString innerHTML; + [CEReactions, LegacyNullToEmptyString] attribute (TrustedHTML or Utf16DOMString) innerHTML; - // FIXME: [CEReactions] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) outerHTML; - [CEReactions, LegacyNullToEmptyString] attribute DOMString outerHTML; + [CEReactions, LegacyNullToEmptyString] attribute (TrustedHTML or Utf16DOMString) outerHTML; - // FIXME: [CEReactions] undefined insertAdjacentHTML(DOMString position, (TrustedHTML or DOMString) string); - [CEReactions] undefined insertAdjacentHTML(DOMString position, DOMString text); + [CEReactions] undefined insertAdjacentHTML(DOMString position, (TrustedHTML or Utf16DOMString) text); // https://w3c.github.io/pointerevents/#extensions-to-the-element-interface undefined setPointerCapture(long pointerId); diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index eecf840c615a..32634c8a7821 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -2091,14 +2091,14 @@ void Node::string_replace_all(Utf16String string) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#fragment-serializing-algorithm-steps -WebIDL::ExceptionOr Node::serialize_fragment(HTML::RequireWellFormed require_well_formed, FragmentSerializationMode fragment_serialization_mode) const +WebIDL::ExceptionOr Node::serialize_fragment(HTML::RequireWellFormed require_well_formed, FragmentSerializationMode fragment_serialization_mode) const { // 1. Let context document be the value of node's node document. auto const& context_document = document(); // 2. If context document is an HTML document, return the result of HTML fragment serialization algorithm with node, false, and « ». if (context_document.is_html_document()) - return HTML::HTMLParser::serialize_html_fragment(*this, HTML::HTMLParser::SerializableShadowRoots::No, {}, fragment_serialization_mode); + return Utf16String::from_utf8(HTML::HTMLParser::serialize_html_fragment(*this, HTML::HTMLParser::SerializableShadowRoots::No, {}, fragment_serialization_mode)); // 3. Return the XML serialization of node given require well-formed. // AD-HOC: XML serialization algorithm returns the "outer" XML serialization of the node. @@ -2109,9 +2109,9 @@ WebIDL::ExceptionOr Node::serialize_fragment(HTML::RequireWellFormed req auto child_markup = TRY(HTML::serialize_node_to_xml_string(*child, require_well_formed)); markup.append(child_markup.bytes_as_string_view()); } - return MUST(markup.to_string()); + return Utf16String::from_utf8(MUST(markup.to_string())); } - return HTML::serialize_node_to_xml_string(*this, require_well_formed); + return Utf16String::from_utf8(TRY(HTML::serialize_node_to_xml_string(*this, require_well_formed))); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#unsafely-set-html diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 1d3b402dc151..37bfc3c1d1cc 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -403,7 +403,7 @@ class WEB_API Node : public EventTarget [[nodiscard]] UniqueNodeID unique_id() const { return m_unique_id; } static Node* from_unique_id(UniqueNodeID); - WebIDL::ExceptionOr serialize_fragment(HTML::RequireWellFormed, FragmentSerializationMode = FragmentSerializationMode::Inner) const; + WebIDL::ExceptionOr serialize_fragment(HTML::RequireWellFormed, FragmentSerializationMode = FragmentSerializationMode::Inner) const; WebIDL::ExceptionOr unsafely_set_html(Element&, StringView); diff --git a/Libraries/LibWeb/DOM/ShadowRoot.cpp b/Libraries/LibWeb/DOM/ShadowRoot.cpp index 28789381309a..aad25ba9400e 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.cpp +++ b/Libraries/LibWeb/DOM/ShadowRoot.cpp @@ -65,7 +65,7 @@ EventTarget* ShadowRoot::get_parent(Event const& event) // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml WebIDL::ExceptionOr ShadowRoot::inner_html() const { - return serialize_fragment(HTML::RequireWellFormed::Yes); + return TRY(serialize_fragment(HTML::RequireWellFormed::Yes)).to_utf8_but_should_be_ported_to_utf16(); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 35a7e9bd4fbb..8c1532e26e34 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -1104,7 +1104,7 @@ void HTMLInputElement::create_text_input_shadow_tree() padding: 0; cursor: default; )~~~"_string)); - MUST(up_button->set_inner_html(""sv)); + MUST(up_button->set_inner_html(""_utf16)); MUST(element->append_child(up_button)); auto mouseup_callback_function = JS::NativeFunction::create( @@ -1136,7 +1136,7 @@ void HTMLInputElement::create_text_input_shadow_tree() padding: 0; cursor: default; )~~~"_string)); - MUST(down_button->set_inner_html(""sv)); + MUST(down_button->set_inner_html(""_utf16)); MUST(element->append_child(down_button)); auto down_callback_function = JS::NativeFunction::create( diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index 5de6a60fc42a..d50d3264ab07 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -612,7 +612,7 @@ void HTMLSelectElement::create_shadow_tree_if_needed() height: 16px; margin-left: 4px; )~~~"_string)); - MUST(m_chevron_icon_element->set_inner_html(chevron_svg)); + MUST(m_chevron_icon_element->set_inner_html(Utf16String::from_utf8(chevron_svg))); MUST(border->append_child(*m_chevron_icon_element)); update_inner_text_element(); diff --git a/Libraries/LibWeb/TrustedTypes/InjectionSink.h b/Libraries/LibWeb/TrustedTypes/InjectionSink.h index 5c6ad5c9dc21..7847dc64e918 100644 --- a/Libraries/LibWeb/TrustedTypes/InjectionSink.h +++ b/Libraries/LibWeb/TrustedTypes/InjectionSink.h @@ -21,6 +21,10 @@ namespace Web::TrustedTypes { __ENUMERATE_INJECTION_SINKS(Documentwrite, "Document write") \ __ENUMERATE_INJECTION_SINKS(Documentwriteln, "Document writeln") \ __ENUMERATE_INJECTION_SINKS(DocumentexecCommand, "Document execCommand") \ + __ENUMERATE_INJECTION_SINKS(ElementinnerHTML, "Element innerHTML") \ + __ENUMERATE_INJECTION_SINKS(ElementinsertAdjacentHTML, "Element insertAdjacentHTML") \ + __ENUMERATE_INJECTION_SINKS(ElementouterHTML, "Element outerHTML") \ + __ENUMERATE_INJECTION_SINKS(ElementsetHTMLUnsafe, "Element setHTMLUnsafe") \ __ENUMERATE_INJECTION_SINKS(Function, "Function") \ __ENUMERATE_INJECTION_SINKS(HTMLIFrameElementsrcdoc, "HTMLIFrameElement srcdoc") \ __ENUMERATE_INJECTION_SINKS(HTMLScriptElementinnerText, "HTMLScriptElement innerText") \ diff --git a/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index 227047215637..1b407dab0fc5 100644 --- a/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -573,7 +573,7 @@ WebIDL::ExceptionOr XMLHttpRequest::send(Optionalhas>()) { auto string_serialized_document = TRY(body->get>().cell()->serialize_fragment(HTML::RequireWellFormed::No)); - m_request_body = Fetch::Infrastructure::byte_sequence_as_body(realm, string_serialized_document.bytes()); + m_request_body = Fetch::Infrastructure::byte_sequence_as_body(realm, string_serialized_document.to_utf8().bytes()); } // 3. Otherwise: else { diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index 617fd9910450..50887cf49a7c 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -661,19 +661,19 @@ void ConnectionFromClient::get_dom_node_inner_html(u64 page_id, Web::UniqueNodeI if (!dom_node) return; - String html; + Utf16String html; if (dom_node->is_element()) { auto const& element = static_cast(*dom_node); - html = element.inner_html().release_value_but_fixme_should_propagate_errors(); + html = element.inner_html().release_value_but_fixme_should_propagate_errors().get(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto const& character_data = static_cast(*dom_node); - html = character_data.data().to_utf8_but_should_be_ported_to_utf16(); + html = character_data.data(); } else { return; } - async_did_get_dom_node_html(page_id, html); + async_did_get_dom_node_html(page_id, html.to_utf8_but_should_be_ported_to_utf16()); } void ConnectionFromClient::get_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id) @@ -682,19 +682,19 @@ void ConnectionFromClient::get_dom_node_outer_html(u64 page_id, Web::UniqueNodeI if (!dom_node) return; - String html; + Utf16String html; if (dom_node->is_element()) { auto const& element = static_cast(*dom_node); - html = element.outer_html().release_value_but_fixme_should_propagate_errors(); + html = element.outer_html().release_value_but_fixme_should_propagate_errors().get(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto const& character_data = static_cast(*dom_node); - html = character_data.data().to_utf8_but_should_be_ported_to_utf16(); + html = character_data.data(); } else { return; } - async_did_get_dom_node_html(page_id, html); + async_did_get_dom_node_html(page_id, html.to_utf8_but_should_be_ported_to_utf16()); } void ConnectionFromClient::set_dom_node_outer_html(u64 page_id, Web::UniqueNodeID node_id, String html) @@ -707,7 +707,7 @@ void ConnectionFromClient::set_dom_node_outer_html(u64 page_id, Web::UniqueNodeI if (dom_node->is_element()) { auto& element = static_cast(*dom_node); - element.set_outer_html(html).release_value_but_fixme_should_propagate_errors(); + element.set_outer_html(Utf16String::from_utf8(html)).release_value_but_fixme_should_propagate_errors(); } else if (dom_node->is_text() || dom_node->is_comment()) { auto& character_data = static_cast(*dom_node); character_data.set_data(Utf16String::from_utf8(html)); diff --git a/Services/WebContent/WebDriverConnection.cpp b/Services/WebContent/WebDriverConnection.cpp index 7171316379ec..5f7db813d001 100644 --- a/Services/WebContent/WebDriverConnection.cpp +++ b/Services/WebContent/WebDriverConnection.cpp @@ -1749,14 +1749,14 @@ Web::WebDriver::Response WebDriverConnection::element_clear_impl(StringView elem // https://w3c.github.io/webdriver/#dfn-clear-a-content-editable-element auto clear_content_editable_element = [&](Web::DOM::Element& element) { // 1. If element's innerHTML IDL attribute is an empty string do nothing and return. - if (auto result = element.inner_html(); result.is_error() || result.value().is_empty()) + if (auto result = element.inner_html(); result.is_error() || result.value().get().is_empty()) return; // 2. Run the focusing steps for element. Web::HTML::run_focusing_steps(&element); // 3. Set element's innerHTML IDL attribute to an empty string. - (void)element.set_inner_html({}); + (void)element.set_inner_html(""_utf16); // 4. Run the unfocusing steps for the element. Web::HTML::run_unfocusing_steps(&element); @@ -2028,7 +2028,7 @@ Messages::WebDriverClient::GetSourceResponse WebDriverConnection::get_source() // 2. Try to handle any user prompts with session. handle_any_user_prompts([this]() { auto* document = current_browsing_context().active_document(); - Optional source; + Optional source; // 3. Let source be the result of invoking the fragment serializing algorithm on a fictional node whose only // child is the document element providing true for the require well-formed flag. If this causes an exception @@ -2042,7 +2042,7 @@ Messages::WebDriverClient::GetSourceResponse WebDriverConnection::get_source() source = MUST(document->serialize_fragment(Web::HTML::RequireWellFormed::No)); // 5. Return success with data source. - async_driver_execution_complete({ source.release_value() }); + async_driver_execution_complete({ source.release_value().to_utf8_but_should_be_ported_to_utf16() }); }); return JsonValue {}; From dd458a2295a0566d26a35384faea8d0782b6ad73 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Mon, 11 Aug 2025 00:01:41 +0200 Subject: [PATCH 08/10] LibWeb: Amend ShadowRoot to make it compatible with TrustedTypes --- Libraries/LibWeb/DOM/ShadowRoot.cpp | 40 +++++++++++++------ Libraries/LibWeb/DOM/ShadowRoot.h | 6 +-- Libraries/LibWeb/DOM/ShadowRoot.idl | 7 ++-- Libraries/LibWeb/TrustedTypes/InjectionSink.h | 2 + 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Libraries/LibWeb/DOM/ShadowRoot.cpp b/Libraries/LibWeb/DOM/ShadowRoot.cpp index aad25ba9400e..c7530276a01c 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.cpp +++ b/Libraries/LibWeb/DOM/ShadowRoot.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include namespace Web::DOM { @@ -63,22 +65,29 @@ EventTarget* ShadowRoot::get_parent(Event const& event) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml -WebIDL::ExceptionOr ShadowRoot::inner_html() const +WebIDL::ExceptionOr ShadowRoot::inner_html() const { - return TRY(serialize_fragment(HTML::RequireWellFormed::Yes)).to_utf8_but_should_be_ported_to_utf16(); + return TRY(serialize_fragment(HTML::RequireWellFormed::Yes)); } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-innerhtml -WebIDL::ExceptionOr ShadowRoot::set_inner_html(StringView value) +WebIDL::ExceptionOr ShadowRoot::set_inner_html(TrustedTypes::TrustedHTMLOrString const& value) { - // FIXME: 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, the given value, "ShadowRoot innerHTML", and "script". + // 1. Let compliantString be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, the given value, "ShadowRoot innerHTML", and "script". + auto const compliant_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + value, + TrustedTypes::InjectionSink::ShadowRootinnerHTML, + TrustedTypes::Script.to_string())); // 2. Let context be this's host. auto context = this->host(); VERIFY(context); - // 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. FIXME: Use compliantString instead of markup. - auto fragment = TRY(context->parse_fragment(value)); + // 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. + auto fragment = TRY(context->parse_fragment(compliant_string.to_utf8_but_should_be_ported_to_utf16())); // 4. Replace all with fragment within this. this->replace_all(fragment); @@ -110,12 +119,19 @@ WebIDL::ExceptionOr ShadowRoot::get_html(GetHTMLOptions const& options) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-shadowroot-sethtmlunsafe -WebIDL::ExceptionOr ShadowRoot::set_html_unsafe(StringView html) -{ - // FIXME: 1. Let compliantHTML be the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, html, "ShadowRoot setHTMLUnsafe", and "script". - - // 3. Unsafe set HTML given this, this's shadow host, and compliantHTML. FIXME: Use compliantHTML. - TRY(unsafely_set_html(*this->host(), html)); +WebIDL::ExceptionOr ShadowRoot::set_html_unsafe(TrustedTypes::TrustedHTMLOrString const& html) +{ + // 1. Let compliantHTML be the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, html, "ShadowRoot setHTMLUnsafe", and "script". + auto const compliant_html = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + HTML::relevant_global_object(*this), + html, + TrustedTypes::InjectionSink::ShadowRootsetHTMLUnsafe, + TrustedTypes::Script.to_string())); + + // 2. Unsafely set HTML given this, this's shadow host, and compliantHTML. + TRY(unsafely_set_html(*this->host(), compliant_html.to_utf8_but_should_be_ported_to_utf16())); return {}; } diff --git a/Libraries/LibWeb/DOM/ShadowRoot.h b/Libraries/LibWeb/DOM/ShadowRoot.h index ac854acc0a96..db5874459fb0 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.h +++ b/Libraries/LibWeb/DOM/ShadowRoot.h @@ -45,10 +45,10 @@ class WEB_API ShadowRoot final : public DocumentFragment { // ^EventTarget virtual EventTarget* get_parent(Event const&) override; - WebIDL::ExceptionOr inner_html() const; - WebIDL::ExceptionOr set_inner_html(StringView); + WebIDL::ExceptionOr inner_html() const; + WebIDL::ExceptionOr set_inner_html(TrustedTypes::TrustedHTMLOrString const&); - WebIDL::ExceptionOr set_html_unsafe(StringView); + WebIDL::ExceptionOr set_html_unsafe(TrustedTypes::TrustedHTMLOrString const&); WebIDL::ExceptionOr get_html(GetHTMLOptions const&) const; diff --git a/Libraries/LibWeb/DOM/ShadowRoot.idl b/Libraries/LibWeb/DOM/ShadowRoot.idl index 186f410434b1..3327357cbf77 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.idl +++ b/Libraries/LibWeb/DOM/ShadowRoot.idl @@ -1,6 +1,7 @@ #import #import #import +#import // https://dom.spec.whatwg.org/#shadowroot [Exposed=Window] @@ -15,12 +16,10 @@ interface ShadowRoot : DocumentFragment { // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization - // FIXME: [CEReactions] undefined setHTMLUnsafe((TrustedHTML or DOMString) html); - [CEReactions] undefined setHTMLUnsafe(DOMString html); + [CEReactions] undefined setHTMLUnsafe((TrustedHTML or Utf16DOMString) html); DOMString getHTML(optional GetHTMLOptions options = {}); - // FIXME: [CEReactions] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) innerHTML; - [CEReactions, LegacyNullToEmptyString] attribute DOMString innerHTML; + [CEReactions, LegacyNullToEmptyString] attribute (TrustedHTML or Utf16DOMString) innerHTML; }; ShadowRoot includes DocumentOrShadowRoot; diff --git a/Libraries/LibWeb/TrustedTypes/InjectionSink.h b/Libraries/LibWeb/TrustedTypes/InjectionSink.h index 7847dc64e918..edafe5c573e4 100644 --- a/Libraries/LibWeb/TrustedTypes/InjectionSink.h +++ b/Libraries/LibWeb/TrustedTypes/InjectionSink.h @@ -34,6 +34,8 @@ namespace Web::TrustedTypes { __ENUMERATE_INJECTION_SINKS(Locationhref, "Location href") \ __ENUMERATE_INJECTION_SINKS(RangecreateContextualFragment, "Range createContextualFragment") \ __ENUMERATE_INJECTION_SINKS(ServiceWorkerContainerregister, "ServiceWorkerContainer register") \ + __ENUMERATE_INJECTION_SINKS(ShadowRootinnerHTML, "ShadowRoot innerHTML") \ + __ENUMERATE_INJECTION_SINKS(ShadowRootsetHTMLUnsafe, "ShadowRoot setHTMLUnsafe") \ __ENUMERATE_INJECTION_SINKS(SharedWorkerconstructor, "SharedWorker constructor") \ __ENUMERATE_INJECTION_SINKS(SVGScriptElementhref, "SVGScriptElement href") \ __ENUMERATE_INJECTION_SINKS(Workerconstructor, "Worker constructor") \ From fc0615c041a04bc0a91360e0a37ba27aacc17188 Mon Sep 17 00:00:00 2001 From: Tete17 Date: Mon, 11 Aug 2025 00:31:46 +0200 Subject: [PATCH 09/10] LibWeb: Amend DomParser to make it compatible with TrustedTypes --- Libraries/LibWeb/HTML/DOMParser.cpp | 24 +++++++++++++------ Libraries/LibWeb/HTML/DOMParser.h | 2 +- Libraries/LibWeb/HTML/DOMParser.idl | 2 +- Libraries/LibWeb/TrustedTypes/InjectionSink.h | 1 + 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Libraries/LibWeb/HTML/DOMParser.cpp b/Libraries/LibWeb/HTML/DOMParser.cpp index 7b70b863e487..4e4b099cea55 100644 --- a/Libraries/LibWeb/HTML/DOMParser.cpp +++ b/Libraries/LibWeb/HTML/DOMParser.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include namespace Web::HTML { @@ -37,9 +39,16 @@ void DOMParser::initialize(JS::Realm& realm) } // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring -GC::Ref DOMParser::parse_from_string(StringView string, Bindings::DOMParserSupportedType type) +WebIDL::ExceptionOr> DOMParser::parse_from_string(Utf16String string, Bindings::DOMParserSupportedType type) { - // FIXME: 1. Let compliantString to the result of invoking the Get Trusted Type compliant string algorithm with TrustedHTML, this's relevant global object, string, "DOMParser parseFromString", and "script". + // 1. Let compliantString to the result of invoking the Get Trusted Type compliant string algorithm with + // TrustedHTML, this's relevant global object, string, "DOMParser parseFromString", and "script". + auto const compliant_string = TRY(TrustedTypes::get_trusted_type_compliant_string( + TrustedTypes::TrustedTypeName::TrustedHTML, + relevant_global_object(*this), + move(string), + TrustedTypes::InjectionSink::DOMParserparseFromString, + TrustedTypes::Script.to_string())); // 2. Let document be a new Document, whose content type is type and url is this's relevant global object's associated Document's URL. GC::Ptr document; @@ -52,8 +61,8 @@ GC::Ref DOMParser::parse_from_string(StringView string, Bindings: document->set_content_type(Bindings::idl_enum_to_string(type)); document->set_document_type(DOM::Document::Type::HTML); - // 1. Parse HTML from a string given document and compliantString. FIXME: Use compliantString. - document->parse_html_from_a_string(string); + // 1. Parse HTML from a string given document and compliantString. + document->parse_html_from_a_string(compliant_string.to_utf8_but_should_be_ported_to_utf16()); } else { // -> Otherwise document = DOM::Document::create(realm(), associated_document.url()); @@ -61,9 +70,10 @@ GC::Ref DOMParser::parse_from_string(StringView string, Bindings: document->set_document_type(DOM::Document::Type::XML); // 1. Create an XML parser parse, associated with document, and with XML scripting support disabled. - XML::Parser parser(string, { .resolve_external_resource = resolve_xml_resource }); + auto const utf8_complaint_string = compliant_string.to_utf8_but_should_be_ported_to_utf16(); + XML::Parser parser(utf8_complaint_string, { .resolve_external_resource = resolve_xml_resource }); XMLDocumentBuilder builder { *document, XMLScriptingSupport::Disabled }; - // 2. Parse compliantString using parser. FIXME: Use compliantString. + // 2. Parse compliantString using parser. auto result = parser.parse_with_listener(builder); // 3. If the previous step resulted in an XML well-formedness or XML namespace well-formedness error, then: if (result.is_error() || builder.has_error()) { @@ -84,7 +94,7 @@ GC::Ref DOMParser::parse_from_string(StringView string, Bindings: document->set_origin(associated_document.origin()); // 3. Return document. - return *document; + return document; } } diff --git a/Libraries/LibWeb/HTML/DOMParser.h b/Libraries/LibWeb/HTML/DOMParser.h index 7ef8ce9eab68..1b908cf7da14 100644 --- a/Libraries/LibWeb/HTML/DOMParser.h +++ b/Libraries/LibWeb/HTML/DOMParser.h @@ -24,7 +24,7 @@ class DOMParser final : public Bindings::PlatformObject { virtual ~DOMParser() override; - GC::Ref parse_from_string(StringView, Bindings::DOMParserSupportedType type); + WebIDL::ExceptionOr> parse_from_string(Utf16String, Bindings::DOMParserSupportedType type); private: explicit DOMParser(JS::Realm&); diff --git a/Libraries/LibWeb/HTML/DOMParser.idl b/Libraries/LibWeb/HTML/DOMParser.idl index bfe112d109b0..cee3f08ba1be 100644 --- a/Libraries/LibWeb/HTML/DOMParser.idl +++ b/Libraries/LibWeb/HTML/DOMParser.idl @@ -13,5 +13,5 @@ enum DOMParserSupportedType { interface DOMParser { constructor(); - Document parseFromString(DOMString string, DOMParserSupportedType type); + Document parseFromString(Utf16DOMString string, DOMParserSupportedType type); }; diff --git a/Libraries/LibWeb/TrustedTypes/InjectionSink.h b/Libraries/LibWeb/TrustedTypes/InjectionSink.h index edafe5c573e4..0f525448b4b2 100644 --- a/Libraries/LibWeb/TrustedTypes/InjectionSink.h +++ b/Libraries/LibWeb/TrustedTypes/InjectionSink.h @@ -21,6 +21,7 @@ namespace Web::TrustedTypes { __ENUMERATE_INJECTION_SINKS(Documentwrite, "Document write") \ __ENUMERATE_INJECTION_SINKS(Documentwriteln, "Document writeln") \ __ENUMERATE_INJECTION_SINKS(DocumentexecCommand, "Document execCommand") \ + __ENUMERATE_INJECTION_SINKS(DOMParserparseFromString, "DOMParser parseFromString") \ __ENUMERATE_INJECTION_SINKS(ElementinnerHTML, "Element innerHTML") \ __ENUMERATE_INJECTION_SINKS(ElementinsertAdjacentHTML, "Element insertAdjacentHTML") \ __ENUMERATE_INJECTION_SINKS(ElementouterHTML, "Element outerHTML") \ From 78de0e2afbce0578e511aae6fc813530d1ec62ce Mon Sep 17 00:00:00 2001 From: Tete17 Date: Mon, 13 Oct 2025 11:56:41 +0200 Subject: [PATCH 10/10] LibWeb: Add a bunch of new passing WPT tests --- .../Document-write-appending-line-feed.txt | 11 + ...ssignment-to-DOMParser-parseFromString.txt | 11 + ...assignment-to-Document-parseHTMLUnsafe.txt | 10 + ...ck-string-assignment-to-Document-write.txt | 26 +++ ...signment-to-Element-insertAdjacentHTML.txt | 12 + ...string-assignment-to-Element-outerHTML.txt | 13 ++ ...ing-assignment-to-Element-setAttribute.txt | 19 ++ ...ng-assignment-to-Element-setHTMLUnsafe.txt | 10 + ...ing-assignment-to-ShadowRoot-innerHTML.txt | 11 + ...assignment-to-ShadowRoot-setHTMLUnsafe.txt | 10 + .../Document-write-appending-line-feed.html | 76 +++++++ ...signment-to-DOMParser-parseFromString.html | 54 +++++ ...ssignment-to-Document-parseHTMLUnsafe.html | 55 +++++ ...k-string-assignment-to-Document-write.html | 192 ++++++++++++++++ ...ignment-to-Element-insertAdjacentHTML.html | 207 ++++++++++++++++++ ...tring-assignment-to-Element-outerHTML.html | 96 ++++++++ ...ng-assignment-to-Element-setAttribute.html | 129 +++++++++++ ...g-assignment-to-Element-setHTMLUnsafe.html | 84 +++++++ ...ng-assignment-to-ShadowRoot-innerHTML.html | 84 +++++++ ...ssignment-to-ShadowRoot-setHTMLUnsafe.html | 84 +++++++ 20 files changed, 1194 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/Document-write-appending-line-feed.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-write.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/Document-write-appending-line-feed.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-write.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/Document-write-appending-line-feed.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/Document-write-appending-line-feed.txt new file mode 100644 index 000000000000..8b08a218745f --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/Document-write-appending-line-feed.txt @@ -0,0 +1,11 @@ +Harness status: OK + +Found 6 tests + +6 Pass +Pass document.write() with TrustedHTML arguments only. +Pass document.write() with String arguments only. +Pass document.write() with TrustedHTML for all but one argument. +Pass document.writeln() with TrustedHTML arguments only. +Pass document.writeln() with String arguments only. +Pass document.writeln() with TrustedHTML for all but one argument. \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.txt new file mode 100644 index 000000000000..b7c7971b5363 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.txt @@ -0,0 +1,11 @@ +Harness status: OK + +Found 5 tests + +4 Pass +1 Fail +Fail document.innerText assigned via policy (successful HTML transformation). +Pass `document.innerText = string` throws. +Pass 'document.innerText = null' throws +Pass 'document.innerText = string' assigned via default policy (successful HTML transformation). +Pass 'document.innerText = null' assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.txt new file mode 100644 index 000000000000..2a719fca435c --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.txt @@ -0,0 +1,10 @@ +Harness status: OK + +Found 5 tests + +5 Pass +Pass Document.parseHTMLUnsafe assigned via policy (successful HTML transformation). +Pass `Document.parseHTMLUnsafe(string)` throws. +Pass 'Document.parseHTMLUnsafe(null)' throws +Pass 'Document.parseHTMLUnsafe(string)' assigned via default policy (successful HTML transformation). +Pass 'Document.parseHTMLUnsafe(null)' assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-write.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-write.txt new file mode 100644 index 000000000000..949ffd8492f4 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Document-write.txt @@ -0,0 +1,26 @@ +Harness status: OK + +Found 20 tests + +15 Pass +5 Fail +Pass document.write with html assigned via policy (successful URL transformation). +Pass document.write with multiple trusted arguments. +Fail document.writeln with html assigned via policy (successful URL transformation). +Fail document.writeln with multiple trusted arguments. +Pass `document.write(string)` throws +Pass `document.write(string, string)` throws +Pass `document.write(string, TrustedHTML)` throws +Pass `document.writeln(string)` throws +Pass `document.writeln(string, string)` throws +Pass `document.writeln(string, TrustedHTML)` throws +Pass `document.write(null)` throws +Pass `document.writeln(null)` throws +Pass `document.write(string)` observes default policy +Pass `document.write(string, string)` observes default policy +Pass `document.write(string, TrustedHTML)` observes default policy +Pass `document.write` passes the correct sink string to the default policy +Fail `document.writeln(string)` observes default policy +Fail `document.writeln(string, string)` observes default policy +Fail `document.writeln(string, TrustedHTML)` observes default policy +Pass `document.writeln` passes the correct sink string to the default policy \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.txt new file mode 100644 index 000000000000..6c646aa4bfca --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.txt @@ -0,0 +1,12 @@ +Harness status: OK + +Found 7 tests + +7 Pass +Pass insertAdjacentHTML with html assigned via policy (successful HTML transformation). +Pass insertAdjacentHTML(TrustedHTML) throws SyntaxError DOMException when position invalid. +Pass `insertAdjacentHTML(string)` throws. +Pass `insertAdjacentHTML(string)` still throws TypeError when position invalid. +Pass `insertAdjacentHTML(null)` throws. +Pass `insertAdjacentHTML(string)` assigned via default policy (successful HTML transformation). +Pass `insertAdjacentHTML(null)` assigned via default policy does not throw. \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.txt new file mode 100644 index 000000000000..edb4ca9c0fa6 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.txt @@ -0,0 +1,13 @@ +Harness status: OK + +Found 7 tests + +6 Pass +1 Fail +Pass outerHTML with html assigned via policy (successful HTML transformation). +Pass `outerHTML = TrustedHTML` throws NoModificationAllowedError when parent is a document. +Pass `outerHTML = string` throws. +Pass `outerHTML = string` throws TypeError even when parent is a document. +Pass `outerHTML = null` throws. +Pass `outerHTML = string` assigned via default policy (successful HTML transformation). +Fail `outerHTML = null` assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.txt new file mode 100644 index 000000000000..5fe954a92d84 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.txt @@ -0,0 +1,19 @@ +Harness status: OK + +Found 14 tests + +14 Pass +Pass script.src accepts only TrustedScriptURL +Pass iframe.srcdoc accepts only TrustedHTML +Pass div.onclick accepts only TrustedScript +Pass `Script.prototype.setAttribute.SrC = string` throws. +Pass script.src accepts string and null after default policy was created. +Pass script.src's mutationobservers receive the default policy's value. +Pass iframe.srcdoc's mutationobservers receive the default policy's value. +Pass div.onclick's mutationobservers receive the default policy's value. +Pass iframe.srcdoc accepts string and null after default policy was created. +Pass div.onclick accepts string and null after default policy was created. +Pass a.rel accepts a Trusted Type +Pass a.rel accepts strings +Pass a.rel accepts null +Pass `script.src = setAttributeNode(embed.src)` with string works. \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.txt new file mode 100644 index 000000000000..d0cd976faa12 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.txt @@ -0,0 +1,10 @@ +Harness status: OK + +Found 5 tests + +5 Pass +Pass element.setHTMLUnsafe(html) assigned via policy (successful HTML transformation). +Pass `element.setHTMLUnsafe(string)` throws. +Pass `element.setHTMLUnsafe(null)` throws. +Pass `element.setHTMLUnsafe(string)` assigned via default policy (successful HTML transformation). +Pass `element.setHTMLUnsafe(string)` assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.txt new file mode 100644 index 000000000000..4a7378711e1c --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.txt @@ -0,0 +1,11 @@ +Harness status: OK + +Found 5 tests + +4 Pass +1 Fail +Pass shadowRoot.innerHTML = html assigned via policy (successful HTML transformation). +Pass `shadowRoot.innerHTML = string` throws. +Pass `shadowRoot.innerHTML = null` throws. +Pass `shadowRoot.innerHTML = string` assigned via default policy (successful HTML transformation). +Fail `shadowRoot.innerHTML = string` assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.txt b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.txt new file mode 100644 index 000000000000..bd5e2ee4efc5 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.txt @@ -0,0 +1,10 @@ +Harness status: OK + +Found 5 tests + +5 Pass +Pass shadowRoot.setHTMLUnsafe(html) assigned via policy (successful HTML transformation). +Pass `shadowRoot.setHTMLUnsafe(string)` throws. +Pass `shadowRoot.setHTMLUnsafe(null)` throws. +Pass `shadowRoot.setHTMLUnsafe(string)` assigned via default policy (successful HTML transformation). +Pass `shadowRoot.setHTMLUnsafe(string)` assigned via default policy does not throw \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/Document-write-appending-line-feed.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/Document-write-appending-line-feed.html new file mode 100644 index 000000000000..41e58d55907b --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/Document-write-appending-line-feed.html @@ -0,0 +1,76 @@ + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.html new file mode 100644 index 000000000000..421af21ec009 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-DOMParser-parseFromString.html @@ -0,0 +1,54 @@ + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.html new file mode 100644 index 000000000000..5eac895b46fc --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-parseHTMLUnsafe.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-write.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-write.html new file mode 100644 index 000000000000..35914b79ae77 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Document-write.html @@ -0,0 +1,192 @@ + + + + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html new file mode 100644 index 000000000000..b202d8b571ab --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.html @@ -0,0 +1,207 @@ + + + + + + + + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.html new file mode 100644 index 000000000000..dc7977bba56f --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-outerHTML.html @@ -0,0 +1,96 @@ + + + + + + + + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.html new file mode 100644 index 000000000000..0a831f6b1b25 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setAttribute.html @@ -0,0 +1,129 @@ + + + + + + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html new file mode 100644 index 000000000000..76a6b7f7effc --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-Element-setHTMLUnsafe.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.html new file mode 100644 index 000000000000..0335f81b113e --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-innerHTML.html @@ -0,0 +1,84 @@ + + + + + + + + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html new file mode 100644 index 000000000000..725acfa03bcf --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/trusted-types/block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html @@ -0,0 +1,84 @@ + + + + + + + + + + + +
+ + +