Bläddra i källkod

LibWeb: Make iframe insertion steps check the shadow including root

The insertion steps for iframes were following an old version of the
spec, where it was checking if the iframe was "in a document tree",
which doesn't cross shadow root boundaries. The spec has since been
updated to check the shadow including root instead.

This is now needed for Cloudflare Turnstile iframe widgets to appear,
as they are now inserted into a shadow root.
Luke Wilde 8 månader sedan
förälder
incheckning
4dd14d812f

+ 20 - 11
Libraries/LibWeb/HTML/HTMLIFrameElement.cpp

@@ -66,17 +66,26 @@ void HTMLIFrameElement::inserted()
 {
     HTMLElement::inserted();
 
-    // When an iframe element element is inserted into a document whose browsing context is non-null, the user agent must run these steps:
-    if (in_a_document_tree() && document().browsing_context() && document().is_fully_active()) {
-        // 1. Create a new child navigable for element.
-        MUST(create_new_child_navigable(JS::create_heap_function(realm().heap(), [this] {
-            // 3. Process the iframe attributes for element, with initialInsertion set to true.
-            process_the_iframe_attributes(true);
-            set_content_navigable_initialized();
-        })));
-
-        // FIXME: 2. If element has a sandbox attribute, then parse the sandboxing directive given the attribute's value and element's iframe sandboxing flag set.
-    }
+    // The iframe HTML element insertion steps, given insertedNode, are:
+    // 1. If insertedNode's shadow-including root's browsing context is null, then return.
+    if (!is<DOM::Document>(shadow_including_root()))
+        return;
+
+    DOM::Document& document = verify_cast<DOM::Document>(shadow_including_root());
+
+    // NOTE: The check for "not fully active" is to prevent a crash on the dom/nodes/node-appendchild-crash.html WPT test.
+    if (!document.browsing_context() || !document.is_fully_active())
+        return;
+
+    // 2. Create a new child navigable for insertedNode.
+    MUST(create_new_child_navigable(JS::create_heap_function(realm().heap(), [this] {
+        // FIXME: 3. If insertedNode has a sandbox attribute, then parse the sandboxing directive given the attribute's
+        //           value and insertedNode's iframe sandboxing flag set.
+
+        // 4. Process the iframe attributes for insertedNode, with initialInsertion set to true.
+        process_the_iframe_attributes(true);
+        set_content_navigable_initialized();
+    })));
 }
 
 // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#process-the-iframe-attributes

+ 2 - 0
Tests/LibWeb/Text/expected/HTML/iframe-successfully-loads-in-shadow-root.txt

@@ -0,0 +1,2 @@
+Received a message: 'Hello from iframe in the shadow root of the just inserted div!'
+Was it from the shadow root iframe? true

+ 25 - 0
Tests/LibWeb/Text/input/HTML/iframe-successfully-loads-in-shadow-root.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../include.js"></script>
+<script>
+    asyncTest((done) => {
+        const div = document.createElement("div");
+        const shadowRoot = div.attachShadow({ mode: "closed" });
+
+        const iframe = document.createElement("iframe");
+
+        window.addEventListener("message", (messageEvent) => {
+            println(`Received a message: '${messageEvent.data}'`);
+            println(`Was it from the shadow root iframe? ${messageEvent.source === iframe.contentWindow}`);
+            done();
+        });
+
+        iframe.srcdoc = `
+            \u003cscript\u003e
+                window.parent.postMessage("Hello from iframe in the shadow root of the just inserted div!");
+            \u003c/script\u003e
+        `;
+        shadowRoot.appendChild(iframe);
+
+        document.body.appendChild(div);
+    });
+</script>