From 427a66d44859b2a3ae1e98a2143b556bd85c7020 Mon Sep 17 00:00:00 2001 From: sideshowbarker Date: Wed, 17 Jun 2026 08:06:17 +0900 Subject: [PATCH] LibWeb: Add internals.loadURL() to start UI-process-style loads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an internals.loadURL(url) that defers Page::load so it starts outside the calling task and can land between session-history traversal- queue steps — as a load requested by ConnectionFromClient::load_url in the UI process can, but as a load started from script never does. Use case: Some session-history races are reachable only when a load request arrives from the UI process between event-loop pumps — while the session history traversal queue is mid-drain. A load started from script enters navigate() inside the calling task, and claims the ongoing navigation up front — so it can never land in that window. And so, without this function, we can’t write tests for those kinds of races. --- Libraries/LibWeb/Internals/Internals.cpp | 12 ++++++++++++ Libraries/LibWeb/Internals/Internals.h | 1 + Libraries/LibWeb/Internals/Internals.idl | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/Libraries/LibWeb/Internals/Internals.cpp b/Libraries/LibWeb/Internals/Internals.cpp index 9ed6c07b3d..329817742b 100644 --- a/Libraries/LibWeb/Internals/Internals.cpp +++ b/Libraries/LibWeb/Internals/Internals.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -445,6 +446,17 @@ void Internals::spoof_current_url(String const& url_string) HTML::relevant_settings_object(window.associated_document()).creation_url = url.release_value(); } +void Internals::load_url(String const& url_string) +{ + auto url = DOMURL::parse(url_string); + + VERIFY(url.has_value()); + + Core::deferred_invoke([page = GC::make_root(page()), url = url.release_value()] { + page->load(url); + }); +} + GC::Ref Internals::create_internal_animation_timeline() { auto& realm = this->realm(); diff --git a/Libraries/LibWeb/Internals/Internals.h b/Libraries/LibWeb/Internals/Internals.h index db0402d730..ac8ddbb747 100644 --- a/Libraries/LibWeb/Internals/Internals.h +++ b/Libraries/LibWeb/Internals/Internals.h @@ -74,6 +74,7 @@ public: WebIDL::ExceptionOr dispatch_user_activated_event(DOM::EventTarget&, DOM::Event& event); void spoof_current_url(String const& url); + void load_url(String const& url); GC::Ref create_internal_animation_timeline(); diff --git a/Libraries/LibWeb/Internals/Internals.idl b/Libraries/LibWeb/Internals/Internals.idl index f6502e173c..f5b3b2e26a 100644 --- a/Libraries/LibWeb/Internals/Internals.idl +++ b/Libraries/LibWeb/Internals/Internals.idl @@ -63,6 +63,10 @@ interface Internals { boolean dispatchUserActivatedEvent(EventTarget target, Event event); undefined spoofCurrentURL(USVString url); + // Loads a URL in the top-level traversable — deferred so it starts outside the calling task and can land between + // session-history traversal-queue steps, as can one requested by ConnectionFromClient::load_url in the UI process. + undefined loadURL(USVString url); + InternalAnimationTimeline createInternalAnimationTimeline(); undefined simulateDragStart(double x, double y, DOMString mimeType, DOMString contents);