Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: c584246121e006a3bf3bbc39e3a9f9a3444bb0f3
https://github.com/WebKit/WebKit/commit/c584246121e006a3bf3bbc39e3a9f9a3444bb0f3
Author: Basuke Suzuki <[email protected]>
Date: 2026-09-22 (Tue, 22 Sep 2026)
Changed paths:
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap-subframe.sub-expected.txt
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap-subframe.sub.html
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap.sub-expected.txt
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap.sub.html
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-reentrant-navigation.sub-expected.txt
A
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-reentrant-navigation.sub.html
A
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-canceller-then-navigate.html
A
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-canceller.html
A
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-destination.html
M LayoutTests/platform/ios-site-isolation/TestExpectations
M LayoutTests/platform/mac-site-isolation/TestExpectations
M Source/WebCore/Headers.cmake
M Source/WebCore/WebCore.xcodeproj/project.pbxproj
M Source/WebCore/loader/FrameLoader.cpp
M Source/WebCore/loader/FrameLoader.h
M Source/WebCore/loader/NavigationAction.h
A Source/WebCore/loader/PendingNavigateEventIdentifier.h
M Source/WebKit/Scripts/webkit/messages.py
M Source/WebKit/Scripts/webkit/tests/MessageArgumentDescriptions.cpp
M Source/WebKit/Shared/NavigationActionData.h
M Source/WebKit/Shared/NavigationActionData.serialization.in
M Source/WebKit/Shared/WTFArgumentCoders.serialization.in
M Source/WebKit/UIProcess/WebPageProxy.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp
M Source/WebKit/WebProcess/WebPage/WebFrame.cpp
M Source/WebKit/WebProcess/WebPage/WebFrame.h
M Source/WebKit/WebProcess/WebPage/WebPage.cpp
M Source/WebKit/WebProcess/WebPage/WebPage.h
M Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Log Message:
-----------
[Navigation API] preventDefault() must cancel a cross-site process-swapping
navigation under Site Isolation
https://bugs.webkit.org/show_bug.cgi?id=318357
rdar://181141493
Reviewed by Alex Christensen.
Under Site Isolation the client approves a cross-site navigation as
NavigationPolicyDecision::LoadWillContinueInAnotherProcess, an approval that
needs a process swap
rather than a denial. FrameLoader::continueLoadAfterNavigationPolicy computes
canContinue as
`decision == ContinueLoad`, so it lumps that in with IgnoreLoad and returns
early, past the point
where the push/replace navigate event is dispatched. The event never fires and
preventDefault() has
nothing to cancel, for subframes as well as the main frame.
The event cannot simply move earlier: 302468@main deliberately delayed it until
after the client's
policy decision, and policy-decision-deny-prevents-navigate-event.html pins
that ordering. It
has to fire between the decision and the swap, so the UI process has to wait
for the source process
there.
Rather than deferring the swap and having the source process send a separate
message to resume it,
the wait is one sendWithAsyncReply: when receivedNavigationActionPolicyDecision
decides to swap it
asks the source process to run the pending navigate event, and only calls
continueNavigationInNewProcess from the reply. A preventDefault() has no
in-flight load to unwind;
it comes back as PolicyAction::Ignore and takes the same path as any other
policy-denied
navigation.
The request names the pending navigate event rather than the frame, because
script can run while
the decision is outstanding and move the frame on to another navigation, whose
own pending event is
not this decision's to dispatch. NavigationAction mints the identifier when it
stores the event and
takePendingDispatchNavigateEvent() will not hand the event over without it, so
that check cannot be
dropped by a later edit. The identifier is absent when there is nothing to
dispatch, so pages that
do not use the Navigation API need no extra round trip. The navigationID cannot
serve here, since
the UI process assigns it in the very reply this dispatch gates. The reply says
whether the event
cancelled the navigation rather than whether to proceed, so that losing it
leaves the swap going.
Worth recording: only one of the navigate event's dispatch sites is deferred
past the policy
decision, the lambda in loadURL, so only link activations, iframe.src and
navigation.navigate()
reach any of this. NavigationScheduler dispatches up front for the location
changes it schedules
and sets skipNavigateEvent, which makes that lambda a no-op, and reload,
fragment, POST submission
and traversal all dispatch before the check.
Also worth recording: the identity check above is not reachable from a test.
The UI process keeps
one navigation policy listener per frame and setUpPolicyListenerProxy()
resolves the previous one
with ignore(), so a second navigation drops the first check before its decision
can come back. Only
the two messages crossing reaches it, which a delegate cannot force.
Process selection, the destination process' shutdown preventing scope and, for
a back/forward
target, takeSuspendedPage() all happen before the answer, so a preventDefault()
loses that
suspended page rather than returning it to the cache. Moving those after the
answer needs the
suspended page carried across the reply and is left for a follow-up.
Tests: http/wpt/site-isolation/navigation-api/
preventdefault-cancels-cross-site-swap.sub.html
preventdefault-cancels-cross-site-swap-subframe.sub.html
preventdefault-reentrant-navigation.sub.html
The upstream navigate-anchor-cross-origin.html calls done() synchronously from
the handler, so it
passes whenever the event merely fires even if the navigation then proceeds.
The new tests keep the
document alive past the point where the destination could have committed, and
the subframe variants
drive the cancellation from a same-origin subframe so that a navigation which
was not cancelled
fails an assertion instead of losing the test.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap-subframe.sub-expected.txt:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap-subframe.sub.html:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap.sub-expected.txt:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-cancels-cross-site-swap.sub.html:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-reentrant-navigation.sub-expected.txt:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/preventdefault-reentrant-navigation.sub.html:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-canceller-then-navigate.html:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-canceller.html:
Added.
*
LayoutTests/http/wpt/site-isolation/navigation-api/resources/preventdefault-destination.html:
Added.
* LayoutTests/platform/ios-site-isolation/TestExpectations:
* LayoutTests/platform/mac-site-isolation/TestExpectations:
* Source/WebCore/Headers.cmake:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/loader/FrameLoader.cpp:
(WebCore::FrameLoader::dispatchPendingNavigateEventAfterNavigationPolicy):
* Source/WebCore/loader/FrameLoader.h:
* Source/WebCore/loader/NavigationAction.h:
(WebCore::NavigationAction::setPendingDispatchNavigateEvent):
(WebCore::NavigationAction::pendingDispatchNavigateEventIdentifier):
(WebCore::NavigationAction::takePendingDispatchNavigateEvent):
(WebCore::NavigationAction::hasPendingDispatchNavigateEvent): Deleted.
* Source/WebCore/loader/PendingNavigateEventIdentifier.h: Added.
* Source/WebKit/Scripts/webkit/messages.py:
* Source/WebKit/Scripts/webkit/tests/MessageArgumentDescriptions.cpp:
* Source/WebKit/Shared/NavigationActionData.h:
* Source/WebKit/Shared/NavigationActionData.serialization.in:
* Source/WebKit/Shared/WTFArgumentCoders.serialization.in:
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedNavigationActionPolicyDecision):
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::createWindow):
* Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::navigationActionData):
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
* Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp:
(WebKit::WebLocalFrameLoaderClient::didSameDocumentNavigationForFrameViaJS):
(WebKit::WebLocalFrameLoaderClient::dispatchDecidePolicyForNewWindowAction):
* Source/WebKit/WebProcess/WebPage/WebFrame.cpp:
(WebKit::WebFrame::dispatchPendingNavigateEventAfterNavigationPolicy):
* Source/WebKit/WebProcess/WebPage/WebFrame.h:
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::dispatchPendingNavigateEventForProcessSwap):
* Source/WebKit/WebProcess/WebPage/WebPage.h:
* Source/WebKit/WebProcess/WebPage/WebPage.messages.in:
Canonical link: https://commits.webkit.org/321637@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications