Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 872a0ddf5a180cb467546a9eacf7c875d3d767bb
https://github.com/WebKit/WebKit/commit/872a0ddf5a180cb467546a9eacf7c875d3d767bb
Author: Sihui Liu <[email protected]>
Date: 2026-09-17 (Thu, 17 Sep 2026)
Changed paths:
A
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav-expected.txt
A
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html
A
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/resources/slow.py
M Source/WebCore/loader/FrameLoader.cpp
M Source/WebCore/loader/FrameLoader.h
M Source/WebCore/loader/NavigationScheduler.cpp
M Source/WebCore/page/LocalFrame.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp
M Source/WebKit/WebProcess/WebPage/WebPage.cpp
M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm
Log Message:
-----------
[Site Isolation] Stranded async back/forward state drops unrelated
back/forward navigations
https://bugs.webkit.org/show_bug.cgi?id=324368
rdar://187604112
Reviewed by Basuke Suzuki.
Under UseUIProcessForBackForwardItemLoading, FrameLoader kept a tri-state
m_asyncBackForwardNavigationState { None, Pending, Cancelled } that served two
unrelated use cases:
(a) Read by WebPage::goToBackForwardItem(), to make the web process ignore the
next GoToBackForwardItem message it
receives when the state is Cancelled (and Cancelled is set when a local load
starts).
(b) Read by LocalFrame::preventsParentFromBeingComplete(), to make the parent
frame avoid marking load complete while
the state is not None. This is needed because a freshly created child frame
whose back/forward load is delegated to the
UI process still reports isComplete() on its initial empty document.
This patch removes the Cancelled state and use case (a) for 3 reasons:
1. This leads to the opposite behavior of what spec asks for. During a
traversal a navigable's "ongoing navigation" is
"traversal", and per the navigate algorithm "Any attempts to navigate a
navigable that is currently traversing are
ignored"; setting it also aborts navigations already in flight. So when a
traversal and a navigation of the same
navigable overlap, the traversal wins and the navigation is dropped, as
asserted by
cross-document-traversal-cross-document-nav.html ("traversal wins and nav is
ignored"). WebKit's Cancelled state did the
reverse: the navigation won and the traversal's reply was discarded.
2. The state is not stored at the target frame and it does not work as
expected. It is set on the frame that calls
history.back(), but the UI process sends GoToBackForwardItem to all frames
whose itemSequenceNumber have changed. So in
a case where a cross-site iframe calls history.back() that navigates the
top-level context, and the frame decides to
cancel it by starting a new load, the Cancelled flag is set in the subframe
process while the navigation request goes to
the main frame process, i.e. the request won't be ignored.
3. The state is not tied to a specific navigation, so it gets applied to a
different one. When history.back() is
answered, the web process starts the load and
FrameLoader::loadWithDocumentLoader() sets Cancelled -- which here does
not mean the navigation was cancelled, but that it has already been handled and
a duplicate GoToBackForwardItem should
be ignored. The frame then stays Cancelled until didBeginDocument(), where
m_asyncBackForwardNavigationState is set to
None. Between loadWithDocumentLoader() and didBeginDocument(), every
GoToBackForwardItem message is dropped, whichever
navigation it belongs to. Two things go wrong with this implementation:
- didBeginDocument() may never run, and then nothing clears the flag. In
ProcessSwap.PageCacheWhenNavigatingFromJS the
document commits in another process, so the apple.com page enters the
back/forward cache still Cancelled; the later
history.forward() that targets it is dropped before the page is even restored,
and the client is never notified.
- A genuinely new request can arrive inside the window, e.g. the user pressing
Forward while a JS history.back() is
still in flight, and is discarded.
The tri-state has brought more trouble than benefits in the current
implementation, so this patch removes the Cancelled
state and converts the member to a boolean
m_isWaitingForDelegatedBackForwardLoad to keep use case (b) working, and
stops taking that state for a JS-initiated traversal in
ScheduledHistoryNavigation::fire(). If it turns out some state
does need to be held during a pending back-forward navigation, that should be a
separate implementation designed for the
case at hand.
ProcessSwap.PageCacheWhenNavigatingFromJS and
SiteIsolation.CrossProcessHistoryTraversalForwardInSubframeAfterGoMinus2
covers cases in reason 3 -- they fail without the fix when Site Isolation is
on. The new WPT test mirrors an existing
test to cover the spec rule in reason 1, and it passes both before and after
this fix.
Tests: ProcessSwap.PageCacheWhenNavigatingFromJS
SiteIsolation.CrossProcessHistoryTraversalForwardInSubframeAfterGoMinus2
http/wpt/site-isolation/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html
*
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav-expected.txt:
Added.
*
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/cross-document-traversal-cross-document-nav.html:
Added.
*
LayoutTests/http/wpt/site-isolation/overlapping-navigations-and-traversals/resources/slow.py:
Added.
(main):
* Source/WebCore/loader/FrameLoader.cpp:
(WebCore::FrameLoader::didBeginDocument):
(WebCore::FrameLoader::loadWithDocumentLoader):
(WebCore::FrameLoader::checkLoadCompleteForThisFrame):
(WebCore::FrameLoader::continueFragmentScrollAfterNavigationPolicy):
(WebCore::FrameLoader::setWaitingForDelegatedBackForwardLoad):
(WebCore::FrameLoader::clearWaitingForDelegatedBackForwardLoad):
(WebCore::FrameLoader::setPendingAsyncBackForwardNavigation): Deleted.
(WebCore::FrameLoader::clearAsyncBackForwardNavigationState): Deleted.
(WebCore::FrameLoader::cancelPendingAsyncBackForwardNavigation): Deleted.
* Source/WebCore/loader/FrameLoader.h:
* Source/WebCore/loader/NavigationScheduler.cpp:
* Source/WebCore/page/LocalFrame.cpp:
(WebCore::LocalFrame::preventsParentFromBeingComplete const):
* Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp:
(WebKit::WebLocalFrameLoaderClient::dispatchDecidePolicyForBackForwardNavigationAction):
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::goToBackForwardItem):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm:
(TestWebKitAPI::(SiteIsolation,
CrossProcessHistoryTraversalForwardInSubframeAfterGoMinus2)):
Canonical link: https://commits.webkit.org/321361@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications