LibWeb: Don't rely on SHTQ::process() in process_the_iframe_attributes

`HTMLIFrameElement::inserted()` does following:
1. Init a new navigable. This step appends a task on session history
   traversal queue (SHTQ) that creates a new nested history.
2. Process iframe's attributes

Processing of iframe's attributes might result in synchronous
navigation that fails to get active SHE if SHTQ task that creates
new nested history is not yet completed.

Before this change, a workaround involved forcing the processing of
SHTQ, which was terrible hack because it could occur in the middle of
another SHTQ task.

This change removes the need for "force SHTQ processing" by ensuring
that the processing of iframe's attributes is always executed after
the iframe's navigable nested history has been created.
This commit is contained in:
Aliaksandr Kalenik 2024-04-04 18:49:40 +02:00 committed by Alexander Kalenik
commit 11011cf250
Notes: sideshowbarker 2024-07-17 07:35:03 +09:00
4 changed files with 21 additions and 8 deletions

View file

@ -60,12 +60,13 @@ void HTMLIFrameElement::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()) {
// 1. Create a new child navigable for element.
MUST(create_new_child_navigable());
// 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.
MUST(create_new_child_navigable([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.
}
}

View file

@ -255,8 +255,10 @@ void HTMLObjectElement::run_object_representation_handler_steps(Optional<ByteStr
// * If the resource type is an XML MIME type, or if the resource type does not start with "image/"
if (resource_type.has_value() && (is_xml_mime_type(*resource_type) || !resource_type->starts_with("image/"sv))) {
// If the object element's content navigable is null, then create a new child navigable for the element.
if (!m_content_navigable)
if (!m_content_navigable) {
MUST(create_new_child_navigable());
set_content_navigable_initialized();
}
// NOTE: Creating a new nested browsing context can fail if the document is not attached to a browsing context
if (!m_content_navigable)

View file

@ -59,7 +59,7 @@ JS::GCPtr<NavigableContainer> NavigableContainer::navigable_container_with_conte
}
// https://html.spec.whatwg.org/multipage/document-sequences.html#create-a-new-child-navigable
WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable()
WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable(JS::SafeFunction<void()> afterSessionHistoryUpdate)
{
// 1. Let parentNavigable be element's node navigable.
auto parent_navigable = navigable();
@ -110,7 +110,7 @@ WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable()
auto traversable = parent_navigable->traversable_navigable();
// 12. Append the following session history traversal steps to traversable:
traversable->append_session_history_traversal_steps([traversable, navigable, parent_navigable, history_entry] {
traversable->append_session_history_traversal_steps([traversable, navigable, parent_navigable, history_entry, afterSessionHistoryUpdate = move(afterSessionHistoryUpdate)] {
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
auto parent_doc_state = parent_navigable->active_session_history_entry()->document_state();
@ -137,6 +137,10 @@ WebIDL::ExceptionOr<void> NavigableContainer::create_new_child_navigable()
// 6. Update for navigable creation/destruction given traversable
traversable->update_for_navigable_creation_or_destruction();
if (afterSessionHistoryUpdate) {
afterSessionHistoryUpdate();
}
});
return {};
@ -300,6 +304,9 @@ void NavigableContainer::destroy_the_child_navigable()
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#potentially-delays-the-load-event
bool NavigableContainer::currently_delays_the_load_event() const
{
if (!m_content_navigable_initialized)
return true;
if (!m_potentially_delays_the_load_event)
return false;

View file

@ -62,16 +62,19 @@ protected:
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
void navigate_an_iframe_or_frame(URL::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional<String> srcdoc_string = {});
WebIDL::ExceptionOr<void> create_new_child_navigable();
WebIDL::ExceptionOr<void> create_new_child_navigable(JS::SafeFunction<void()> afterSessionHistoryUpdate = {});
// https://html.spec.whatwg.org/multipage/document-sequences.html#content-navigable
JS::GCPtr<Navigable> m_content_navigable { nullptr };
void set_potentially_delays_the_load_event(bool value) { m_potentially_delays_the_load_event = value; }
void set_content_navigable_initialized() { m_content_navigable_initialized = true; }
private:
virtual bool is_navigable_container() const override { return true; }
bool m_potentially_delays_the_load_event { true };
bool m_content_navigable_initialized { false };
};
}