LibWeb: Add internals.loadURL() to start UI-process-style loads

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.
This commit is contained in:
sideshowbarker 2026-06-17 08:06:17 +09:00 committed by Andreas Kling
parent d4fc8d027e
commit 427a66d448
3 changed files with 17 additions and 0 deletions

View file

@ -7,6 +7,7 @@
#include <AK/JsonObject.h>
#include <AK/NumericLimits.h>
#include <LibCore/EventLoop.h>
#include <LibCore/TimeZone.h>
#include <LibGfx/Cursor.h>
#include <LibHTTP/HSTS/ParsedHSTSPolicy.h>
@ -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<InternalAnimationTimeline> Internals::create_internal_animation_timeline()
{
auto& realm = this->realm();

View file

@ -74,6 +74,7 @@ public:
WebIDL::ExceptionOr<bool> dispatch_user_activated_event(DOM::EventTarget&, DOM::Event& event);
void spoof_current_url(String const& url);
void load_url(String const& url);
GC::Ref<InternalAnimationTimeline> create_internal_animation_timeline();

View file

@ -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);