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

Reply via email to