Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 7a422d312c3cce60bdee0963a7cb205bb9a72e1f
https://github.com/WebKit/WebKit/commit/7a422d312c3cce60bdee0963a7cb205bb9a72e1f
Author: Basuke Suzuki <[email protected]>
Date: 2026-07-02 (Thu, 02 Jul 2026)
Changed paths:
M Source/WebCore/loader/EmptyClients.cpp
M Source/WebCore/loader/EmptyFrameLoaderClient.h
M Source/WebCore/loader/LocalFrameLoaderClient.h
M Source/WebCore/loader/NavigationScheduler.cpp
M Source/WebKit/Platform/Curl.cmake
M Source/WebKit/Sources.txt
A Source/WebKit/UIProcess/SessionHistoryTraversalQueue.cpp
A Source/WebKit/UIProcess/SessionHistoryTraversalQueue.h
M Source/WebKit/UIProcess/WebPageProxy.cpp
M Source/WebKit/UIProcess/WebPageProxy.h
M Source/WebKit/UIProcess/WebPageProxy.messages.in
M Source/WebKit/WebKit.xcodeproj/project.pbxproj
M Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.h
M Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h
M Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm
M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm
Log Message:
-----------
[NavigationScheduler] history.back/forward/go(n) coalescing across processes
via UIProcess session history traversal queue
https://bugs.webkit.org/show_bug.cgi?id=317229
rdar://179857636
Reviewed by Charlie Wolfe.
Follow-up to https://bugs.webkit.org/show_bug.cgi?id=317077.
Per HTML's "traverse the history by a delta" algorithm, history.back/
forward/go(n) appends a task to the top-level traversable's session
history traversal queue. The previous fix (bug 317077) implemented
per-WebProcess coalescing by forwarding to the top frame's
NavigationScheduler when reachable in this WebProcess. Under Site
Isolation, when the top frame is a RemoteFrame (a cross-site iframe
initiates the traversal), the queue lives above any single WebProcess
and the originating scheduler can't see traversals from other
processes targeting the same traversable.
Symptom: two cross-site iframes in different WebProcesses each call
history.back() in the same task; both navigations execute and the
user sees an extra intermediate document load that the spec says
should not occur.
Introduce SessionHistoryTraversalQueue (defined in its own
UIProcess/SessionHistoryTraversalQueue.{h,cpp} rather than nested in
WebPageProxy), owned by WebPageProxy (top-level traversable proxy).
The queue accumulates pending delta
across all WebProcesses targeting this page and flushes on a 0-delay
timer, calling goToBackForwardItemAtIndex with the net delta (no-op
when delta == 0, matching "going nowhere"). NavigationScheduler's
existing per-WebProcess aggregation in scheduleHistoryNavigation now
gains a second branch: when the top frame is in another process
(top frame downcasts to RemoteFrame), forward via a new
LocalFrameLoaderClient hook (dispatchEnqueueHistoryTraversalDelta)
that posts WebPageProxy::EnqueueHistoryTraversalDelta to the
UIProcess. The originating frame's pending m_redirect and
in-progress load are completed/cancelled the same way the LocalFrame
top branch does in 317077, so an iframe's pending
ScheduledLocationChange doesn't race the queued traversal.
Trust model note: EnqueueHistoryTraversalDelta accepts an int32_t
delta from any WebProcess and forwards it to
goToBackForwardItemAtIndex on flush. This is the same trust boundary
as the existing GoToBackForwardItemAtIndex IPC; Site Isolation does
not introduce a new attack vector here. The eventual
WebBackForwardList lookup clamps to the available range, so an
out-of-range delta degrades to a no-op rather than memory unsafety.
This is the observable-coalescing approximation; the spec-faithful
"sequential apply + synchronous queue jumping" is left for a future
epic. The class name (SessionHistoryTraversalQueue) leaves room for
that evolution.
Out of scope here: spec-correct top-level reload semantics for
history.go(0), which remains implemented as a per-frame reload —
tracked alongside bug 317077.
Drive-by cleanup carried in this follow-up: drop the unused
FrameLoadType parameter from both this new IPC and the sibling
GoToBackForwardItemAtIndex IPC (introduced for 317077). Both call
sites in NavigationScheduler always pass IndexedBackForward and the
UIProcess methods always forward the same constant; the parameter
was dead weight. The FrameLoaderClient hooks
(dispatchGoToBackForwardItemAtIndex, dispatchEnqueueHistoryTraversalDelta)
are simplified to match.
Test plan: SiteIsolation.CrossProcessHistoryTraversalCoalesce builds
a 3-entry main-frame history (a, b, c) where each page hosts two
cross-site iframes (webkit.org and apple.com) in distinct
WebProcesses. main-frame postMessage triggers both iframes to call
history.back() in the same JS turn; the two
EnqueueHistoryTraversalDelta IPCs land in the same UIProcess flush
window and combine into one goToBackForwardItem(-2), so main goes
c->a in a single navigation (BFList: backList=0, forwardList=2). The
test is sensitive: temporarily disabling the new RemoteFrame branch
in NavigationScheduler causes the BFList state assertions to fail.
The bug 317077 API tests (WKBackForwardList.* synchronous coalescing
suite) and the SI history regression set under SiteIsolation.* do
not regress.
* Source/WebCore/loader/EmptyClients.cpp:
(WebCore::EmptyFrameLoaderClient::dispatchEnqueueHistoryTraversalDelta):
* Source/WebCore/loader/EmptyFrameLoaderClient.h:
* Source/WebCore/loader/LocalFrameLoaderClient.h:
* Source/WebCore/loader/NavigationScheduler.cpp:
(WebCore::NavigationScheduler::scheduleHistoryNavigation):
* Source/WebKit/Platform/Curl.cmake: Touch to force a CMake re-run so
Win/PlayStation incremental builds pick up new Sources.txt files.
* Source/WebKit/Sources.txt:
* Source/WebKit/UIProcess/SessionHistoryTraversalQueue.cpp: Added.
(WebKit::SessionHistoryTraversalQueue::SessionHistoryTraversalQueue):
(WebKit::SessionHistoryTraversalQueue::~SessionHistoryTraversalQueue):
(WebKit::SessionHistoryTraversalQueue::enqueueDelta):
(WebKit::SessionHistoryTraversalQueue::cancel):
(WebKit::SessionHistoryTraversalQueue::flush):
* Source/WebKit/UIProcess/SessionHistoryTraversalQueue.h: Added.
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
(WebKit::WebPageProxy::close):
(WebKit::WebPageProxy::enqueueHistoryTraversalDelta):
* Source/WebKit/UIProcess/WebPageProxy.h:
* Source/WebKit/UIProcess/WebPageProxy.messages.in:
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp:
(WebKit::WebLocalFrameLoaderClient::dispatchEnqueueHistoryTraversalDelta):
* Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.h:
* Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h:
* Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm:
(WebFrameLoaderClient::dispatchEnqueueHistoryTraversalDelta):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm:
(TEST(SiteIsolation, CrossProcessHistoryTraversalCoalesce)):
Canonical link: https://commits.webkit.org/316426@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications