Repository: servo/servo
File: components/script/dom/html/htmliframeelement.rs (Rust)

Code before:
            }
        }

        // Step 2.1. Let url be the result of running the shared attribute processing steps
        // for iframe and frame elements given element and initialInsertion.
        let Some(url) = self.shared_attribute_processing_steps_for_iframe_and_frame_elements()
        else {
            // Step 2.2. If url is null, then return.
            return;
        };

        // Step 2.3. If url matches about:blank and initialInsertion is true, then:
        if url.matches_about_blank() && mode == ProcessingMode::FirstTime {
            // Step 2.3.1. Run the iframe load event steps given element.
            //
            // Note: we are not actually calling that method. That's because
            // `iframe_load_event_steps` currently doesn't adhere to the spec
            // at all. In this case, WPT tests only care about the load event,
            // so we can fire that. Following https://github.com/servo/servo/issues/31973
            // we should call `iframe_load_event_steps` once it is spec-compliant.
            self.upcast::<EventTarget>()
                .fire_event(atom!("load"), can_gc);
            // We should **not** send a load event in `iframe_load_event_steps`.
            // Therefore, we should mark this as a navigation, since we have already
            // synchronously fired the load event.
            self.note_pending_navigation();
            // Step 2.3.2. Return.
            return;
        }

        // Step 2.4: Let referrerPolicy be the current state of element's referrerpolicy content
        // attribute.
        let document = self.owner_document();
        let referrer_policy_token = self.ReferrerPolicy();

        // Note: despite not being explicitly stated in the spec steps, this falls back to
        // document's referrer policy here because it satisfies the expectations that when unset,
        // the iframe should inherit the referrer policy of its parent
        let referrer_policy = match ReferrerPolicy::from(&*referrer_policy_token.str()) {
            ReferrerPolicy::EmptyString => document.get_referrer_policy(),
            policy => policy,
        };

        // TODO(#25748):
        // By spec, we return early if there's an ancestor browsing context
        // "whose active document's url, ignoring fragments, is equal".
        // However, asking about ancestor browsing contexts is more nuanced than
        // it sounds and not implemented here.
        // Within a single origin, we can do it by walking window proxies,
        // and this check covers only that single-origin case, protecting
        // against simple typo self-includes but nothing more elaborate.

Review comment (suggestion):
This is the problem causing the timeouts, I'm pretty sure. I don't have time right now to make a minimal reproduction to demonstrate it, but the tests:
1. create an iframe
2. after the iframe's load event occurs, do `iframe.contentDocument.write(...); iframe.contentDocument.close()`, which should trigger a new load event on the iframe after all parsing and loading is complete
3. wait for the iframe's new load event

Since that will pass through iframe_load_event_steps, and pending_navigation is true, we don't dispatch the second load event.

Code after:
        }

        let window = self.owner_window();

        // https://html.spec.whatwg.org/multipage/#attr-iframe-name
        // Note: the spec says to set the name 'when the nested browsing context is created'.
        // The current implementation sets the name on the window,
        // when the iframe attributes are first processed.
        if mode == ProcessingMode::FirstTime {
            if let Some(window) = self.GetContentWindow() {
                window.set_name(
                    element
                        .get_name()
                        .map_or(DOMString::from(""), |n| DOMString::from(&*n)),
                );
            }
        }

        // Step 2.1. Let url be the result of running the shared attribute processing steps
        // for iframe and frame elements given element and initialInsertion.
        let Some(url) = self.shared_attribute_processing_steps_for_iframe_and_frame_elements()
        else {
            // Step 2.2. If url is null, then return.
            return;
        };

        // Step 2.3. If url matches about:blank and initialInsertion is true, then:
        if url.matches_about_blank() && mode == ProcessingMode::FirstTime {
            // We should **not** send a load event in `iframe_load_event_steps`.
            self.already_fired_synchronous_load_event.set(true);
            // Step 2.3.1. Run the iframe load event steps given element.
            //
            // Note: we are not actually calling that method. That's because
            // `iframe_load_event_steps` currently doesn't adhere to the spec
            // at all. In this case, WPT tests only care about the load event,
            // so we can fire that. Following https://github.com/servo/servo/issues/31973
            // we should call `iframe_load_event_steps` once it is spec-compliant.
            self.upcast::<EventTarget>()
                .fire_event(atom!("load"), can_gc);
            // Step 2.3.2. Return.
            return;
        }

        // Step 2.4: Let referrerPolicy be the current state of element's referrerpolicy content
        // attribute.
        let document = self.owner_document();
        let referrer_policy_token = self.ReferrerPolicy();

        // Note: despite not being explicitly stated in the spec steps, this falls back to
        // document's referrer policy here because it satisfies the expectations that when unset,
        // the iframe should inherit the referrer policy of its parent