diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index e4a3eef931d..0e087c0d9a9 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1135,10 +1135,10 @@ Vector const* Document::background_layers() const void Document::update_base_element(Badge) { - GC::Ptr base_element_with_href = nullptr; - GC::Ptr base_element_with_target = nullptr; + GC::Ptr base_element_with_href = nullptr; + GC::Ptr base_element_with_target = nullptr; - for_each_in_subtree_of_type([&base_element_with_href, &base_element_with_target](HTML::HTMLBaseElement const& base_element_in_tree) { + for_each_in_subtree_of_type([&base_element_with_href, &base_element_with_target](HTML::HTMLBaseElement& base_element_in_tree) { if (!base_element_with_href && base_element_in_tree.has_attribute(HTML::AttributeNames::href)) { base_element_with_href = &base_element_in_tree; if (base_element_with_target) @@ -1157,12 +1157,12 @@ void Document::update_base_element(Badge) m_first_base_element_with_target_in_tree_order = base_element_with_target; } -GC::Ptr Document::first_base_element_with_href_in_tree_order() const +GC::Ptr Document::first_base_element_with_href_in_tree_order() const { return m_first_base_element_with_href_in_tree_order; } -GC::Ptr Document::first_base_element_with_target_in_tree_order() const +GC::Ptr Document::first_base_element_with_target_in_tree_order() const { return m_first_base_element_with_target_in_tree_order; } diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index cc68e4d97af..22edbdb4610 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -223,8 +223,8 @@ public: URL::URL base_url() const; void update_base_element(Badge); - GC::Ptr first_base_element_with_href_in_tree_order() const; - GC::Ptr first_base_element_with_target_in_tree_order() const; + GC::Ptr first_base_element_with_href_in_tree_order() const; + GC::Ptr first_base_element_with_target_in_tree_order() const; String url_string() const { return m_url.to_string(); } String document_uri() const { return url_string(); } @@ -1135,8 +1135,8 @@ private: GC::Ptr m_selection; // NOTE: This is a cache to make finding the first or element O(1). - GC::Ptr m_first_base_element_with_href_in_tree_order; - GC::Ptr m_first_base_element_with_target_in_tree_order; + GC::Ptr m_first_base_element_with_href_in_tree_order; + GC::Ptr m_first_base_element_with_target_in_tree_order; // https://html.spec.whatwg.org/multipage/images.html#list-of-available-images GC::Ptr m_list_of_available_images; diff --git a/Libraries/LibWeb/HTML/HTMLBaseElement.cpp b/Libraries/LibWeb/HTML/HTMLBaseElement.cpp index 4cba0578e1e..bacda241da2 100644 --- a/Libraries/LibWeb/HTML/HTMLBaseElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLBaseElement.cpp @@ -43,7 +43,14 @@ void HTMLBaseElement::inserted() void HTMLBaseElement::removed_from(Node* old_parent, Node& old_root) { HTMLElement::removed_from(old_parent, old_root); + auto old_first_base_element_with_href_in_tree_order = document().first_base_element_with_href_in_tree_order(); document().update_base_element({}); + + // The frozen base URL must be immediately set for an element whenever any of the following situations occur: + // - The base element becomes the first base element in tree order with an href content attribute in its Document. + auto first_base_element_with_href_in_document = document().first_base_element_with_href_in_tree_order(); + if (first_base_element_with_href_in_document != old_first_base_element_with_href_in_tree_order) + first_base_element_with_href_in_document->set_the_frozen_base_url(); } void HTMLBaseElement::attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) @@ -72,13 +79,17 @@ void HTMLBaseElement::set_the_frozen_base_url() auto href = get_attribute_value(AttributeNames::href); auto url_record = document.fallback_base_url().complete_url(href); - // 3. Set element's frozen base URL to document's fallback base URL, if urlRecord is failure or running Is base allowed for Document? on the resulting URL record and document returns "Blocked", and to urlRecord otherwise. - // FIXME: Apply "Is base allowed for Document?" CSP - if (!url_record.has_value()) { + // 3. If any of the following are true: + // - urlRecord is failure; + // - urlRecord's scheme is "data" or "javascript"; or + // FIXME: - running Is base allowed for Document? on urlRecord and document returns "Blocked", + // then set element's frozen base URL to document's fallback base URL and return. + if (!url_record.has_value() || url_record->scheme() == "data" || url_record->scheme() == "javascript") { m_frozen_base_url = document.fallback_base_url(); return; } + // 4. Set element's frozen base URL to urlRecord. m_frozen_base_url = url_record.release_value(); } diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-data.txt b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-data.txt new file mode 100644 index 00000000000..fdd6341c3a3 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-data.txt @@ -0,0 +1,8 @@ +Harness status: OK + +Found 3 tests + +3 Pass +Pass First has a data: URL so fallback is used +Pass First is removed so second is used +Pass Dynamically inserted first has a data: URL so fallback is used \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.txt b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.txt new file mode 100644 index 00000000000..a32e8f7bf7b --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.txt @@ -0,0 +1,8 @@ +Harness status: OK + +Found 3 tests + +3 Pass +Pass First has a javascript: URL so fallback is used +Pass First is removed so second is used +Pass Dynamically inserted first has a javascript: URL so fallback is used \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-data.html b/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-data.html new file mode 100644 index 00000000000..9109d4b6787 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-data.html @@ -0,0 +1,32 @@ + + + +<base> and data: URLs + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.html b/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.html new file mode 100644 index 00000000000..0cc72165705 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/semantics/document-metadata/the-base-element/base-javascript.html @@ -0,0 +1,32 @@ + + + +<base> and javascript: URLs + + + + +
+