Skip to content

Preserve sticky user activation across same-origin navigations - #63952

Open
kate-k-lee wants to merge 1 commit into
WebKit:mainfrom
kate-k-lee:eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects
Open

Preserve sticky user activation across same-origin navigations#63952
kate-k-lee wants to merge 1 commit into
WebKit:mainfrom
kate-k-lee:eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects

Conversation

@kate-k-lee

@kate-k-lee kate-k-lee commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

db9860c

Preserve sticky user activation across same-origin navigations
https://bugs.webkit.org/show_bug.cgi?id=313716

Reviewed by NOBODY (OOPS!).

Implement sticky user activation carry-over per whatwg/html#11454,
centralized in LocalDOMWindow::carryOverStickyActivationFromPreviousWindow
and applied at two entry points:

* DocumentWriter::begin: carry sticky activation onto a same-origin
  destination, suppressed when the redirect chain crossed origins
  (guards A -> B -> A confused-deputy patterns).
* FrameLoader::open(CachedFrameBase&): apply the same rule on bfcache
  reactivation; no network load, so the redirect suppressor is N/A.

Migrate sticky and history-action activation from timestamp-derived
flags to explicit booleans on LocalDOMWindow, per the spec's updated
data model. m_lastActivationTimestamp continues to drive transient
activation only. notifyActivated, its propagation, consume-history-
action, and WebPage::updateUserActivationTimestamps update the
booleans alongside the timestamp.

Gated behind StickyUserActivationAcrossSameOriginNavigationsEnabled
(testable, off by default, auto-enabled in WebKitTestRunner). The
data-model migration is observationally equivalent and not gated.

navigation-state-reset-sameorigin.html now contains FAIL because
sticky activation is preserved across same-origin subframe navigations
per the spec change; revert the expected.txt once the WPT is imported.

5db185b

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ❌ 🧪 win-tests
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🧪 jsc-x86-64 ✅ 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-wk2-stress ✅ 🧪 api-gtk
✅ 🛠 vision-sim ✅ 🧪 mac-intel-wk2 ✅ 🛠 playstation
✅ 🧪 vision-wk2 ✅ 🛠 mac-safer-cpp ✅ 🛠 jsc-armv7
✅ 🛠 tv ✅ 🧪 mac-site-isolation ✅ 🧪 jsc-armv7-tests
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@kate-k-lee kate-k-lee self-assigned this Apr 30, 2026
@kate-k-lee kate-k-lee added the New Bugs Unclassified bugs are placed in this component until the correct component can be determined. label Apr 30, 2026
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Apr 30, 2026
@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #98696 (73cedee)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

Comment thread Source/WebCore/loader/DocumentWriter.cpp Outdated
@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

iOS Safer C++ Build #17028 (73cedee)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

Comment thread Source/WebCore/loader/DocumentWriter.cpp Outdated
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 73cedee to 998a01e Compare April 30, 2026 17:23
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 998a01e to d163889 Compare April 30, 2026 17:31
@kate-k-lee
kate-k-lee requested a review from lukewarlow April 30, 2026 17:40
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from d163889 to 869b58d Compare May 5, 2026 09:14
@kate-k-lee kate-k-lee changed the title [DRAFT] Preserve sticky user activation across same-origin navigations Preserve sticky user activation across same-origin navigations May 5, 2026
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 869b58d to b9584ea Compare May 6, 2026 05:32
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from b9584ea to cc4b6a6 Compare May 6, 2026 17:50
@kate-k-lee
kate-k-lee marked this pull request as ready for review May 6, 2026 22:58
@kate-k-lee
kate-k-lee requested a review from annevk May 6, 2026 22:59
@@ -7032,6 +7028,8 @@ imported/w3c/web-platform-tests/html/user-activation/navigation-state-reset-cros
imported/w3c/web-platform-tests/html/user-activation/navigation-state-reset-sameorigin.html [ Skip ]
imported/w3c/web-platform-tests/html/user-activation/user-activation-interface.html [ Skip ]
imported/w3c/web-platform-tests/html/user-activation/activation-same-and-cross-origin.sub.html [ Skip ]
imported/w3c/web-platform-tests/html/user-activation/navigate-to-crossorigin-redirect.html [ Skip ]
imported/w3c/web-platform-tests/html/user-activation/navigate-to-sameorigin.html [ Skip ]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it fail on iOS?

@kate-k-lee kate-k-lee May 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@annevk

Both tests rely on test_driver.click() to give the popup window user activation before navigating it. PR #63430 enabled popup-window click dispatch via eventSender, but only for the non-iOS path. the iOS WK2 path goes through iController.singleTapAtPoint, which targets the main test view only and has no popup-view-aware equivalent, so it was not covered by that fix. As a result, on iOS the test's precondition never holds. The popup never reaches the activated state, and the assertions about preserving sticky activation across navigation can't be exercised. The tests fail at the activation setup step, not at the behavior we're shipping.

Also, this matches a pre-existing convention in LayoutTests/platform/ios/TestExpectations, which already groups several user-activation WPTs under the comment:
# UserActivation tests rely on test_driver.click() which is not supported on iOS

The two new tests (navigate-to-sameorigin.html, navigate-to-crossorigin-redirect.html) are skipped under that same group for the same reason.

@@ -5,5 +5,5 @@ Tests that navigating a same-origin child frame resets its activation states.
Click inside the yellow area.


PASS Post-navigation state reset.
FAIL Post-navigation state reset. assert_false: expected false got true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs some kind of explanation as to why this is not a regression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the careful review.

My reading of the spec PR discussion is that sticky activation preservation is intended to apply per-frame, including iframes. In particular, the response in LINK to the question of restricting it to top-level only leans against that restriction:
"I'm less sure about this. My instinct was to just do whatever was easiest to spec/implement, which in this case was to allow it to work in iframes."
and in LINK
"On iframes, it seems simpler to just allow those navigations to carry over sticky activation."

Based on those, my implementation in DocumentWriter::begin() applies uniformly to both top-level and iframe navigations.

About navigation-state-reset-sameorigin.html: this test exercises a same-origin iframe navigation (not top-level) and asserts that sticky activation is reset — which I read as reflecting the pre-spec-change behavior. Under my reading of the new spec, sticky activation should be preserved in iframe navigations as well, so the test's existing assertion no longer holds. The expected.txt update to FAIL documents this transitional state until WPT upstream is updated to match the new spec.

If you read the spec discussion differently, please let us know — happy to revisit the scope.
Thanks again!

&& previousWindow && previousWindow->hasStickyActivation() && existingDocument) {
bool wasRedirected = false;
if (RefPtr documentLoader = frameLoader->documentLoader())
wasRedirected = documentLoader->originalURL() != documentLoader->responseURL();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not robust. In theory the URL could be the same, but a redirect could have taken place due to a cookie or some such.

I'm also not sure this is the correct place to make this overall check. Maybe @youennf can give some pointers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. I hadn't accounted for that case. I'll revisit the redirect detection and follow up with an updated patch.

Thanks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@annevk

Addressed both concerns in the latest push:

  1. Redirect detection is no longer based on URL equality between originalURL() and responseURL(). The check now uses NetworkLoadMetrics::hasCrossOriginRedirect, which is set to true whenever any step in the redirect chain crosses an origin boundary (regardless of whether the final URL happens to match the start URL). This correctly handles A → B → A patterns and stops blocking legitimate same-origin internal redirects.

  2. Additionally added a check that the navigation is renderer-initiated. Browser-initiated navigations (address bar typing, bookmarks, history navigation, embedder API loads) now suppress carry-over via DocumentLoader::isRequestFromClientOrUserInput(). This aligns with Chromium's behavior.

Regarding your second comment (whether DocumentWriter::begin() is the right place for this check) — with the URL-equality removed, the check now reads only from the navigation's own DocumentLoader (initiator flag, redirect metrics) and the previous Document/Window (origin, sticky activation). All of this is per-Document state that is naturally available at navigation commit time. Happy to revisit the location if you still see a better fit.

Not in this PR (planned follow-up): The spec discussion also calls for the carry-over to apply when a document is reactivated from the back/forward cache, so that behavior remains consistent between bfcache hits and misses. This PR only updates the "create new document" path (DocumentWriter::begin()); WebKit's bfcache restore path is a separate code site that I plan to address in a follow-up once the spec text for the reactivate algorithm is finalized.

@kate-k-lee kate-k-lee removed the merging-blocked Applied to prevent a change from being merged label May 14, 2026
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from cc4b6a6 to 162f6c9 Compare May 14, 2026 17:42
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 162f6c9 to fb801cd Compare May 14, 2026 18:19
@kate-k-lee
kate-k-lee requested a review from annevk May 15, 2026 03:42
@kate-k-lee
kate-k-lee marked this pull request as draft May 18, 2026 06:06
@kate-k-lee

Copy link
Copy Markdown
Contributor Author

Moving this to draft. Plan to (1) add bfcache restore coverage, and (2) drop the Chromium-aligned bits that aren't actually in the spec text (whatwg/html#11454), keeping the implementation strictly spec-faithful. Will re-request review once both are sorted. Thanks!

@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from fb801cd to db9860c Compare May 21, 2026 16:26
@kate-k-lee
kate-k-lee marked this pull request as ready for review May 22, 2026 03:27
@kate-k-lee

Copy link
Copy Markdown
Contributor Author

@annevk
This PR was temporarily moved back to draft while I addressed the review feedback and made additional changes. It is now ready for review again.

Thanks,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This WPT now requires preserving sticky activation in subframes too — will update WebKit accordingly:
https://github.com/web-platform-tests/wpt/pull/60008/changes

@annevk
annevk requested review from youennf and removed request for annevk June 1, 2026 07:43
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from db9860c to 2075bcb Compare June 29, 2026 08:07
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Jun 29, 2026
@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

iOS Safer C++ Build #35491 (2075bcb)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #116892 (2075bcb)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@kate-k-lee
kate-k-lee marked this pull request as draft June 30, 2026 05:01
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 2075bcb to 6c25c8c Compare July 8, 2026 18:25
@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

iOS Safer C++ Build #38185 (6c25c8c)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@webkit-ews-buildbot

Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #119354 (6c25c8c)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

https://bugs.webkit.org/show_bug.cgi?id=313716

Reviewed by NOBODY (OOPS!).

Implement sticky user activation carry-over per whatwg/html#11454,
centralized in LocalDOMWindow::carryOverStickyActivationFromPreviousWindow
and applied at two entry points:

- DocumentWriter::begin carries sticky activation onto a same-origin
  destination, suppressed when the redirect chain crossed origins
  (guards A -> B -> A confused-deputy patterns).
- FrameLoader::open(CachedFrameBase&) applies the same rule on bfcache
  reactivation; no network load, so the redirect suppressor is N/A.

Builds on the explicit sticky/history-action activation booleans on
LocalDOMWindow (bug 316317); carry-over sets m_hasStickyActivation on
the destination window when the source had sticky activation and the
navigation stayed same-origin. Only sticky activation is carried over,
not transient or history-action.

Gated behind StickyUserActivationAcrossSameOriginNavigationsEnabled
(testable, off by default, auto-enabled in WebKitTestRunner).

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/html/user-activation/navigate-to-crossorigin-redirect-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/user-activation/navigate-to-sameorigin-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/html/user-activation/navigation-state-reset-sameorigin-expected.txt:
* LayoutTests/platform/ios/TestExpectations:
* Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml:
* Source/WebCore/loader/DocumentWriter.cpp:
* Source/WebCore/loader/FrameLoader.cpp:
* Source/WebCore/page/LocalDOMWindow.cpp:
* Source/WebCore/page/LocalDOMWindow.h:
@kate-k-lee
kate-k-lee force-pushed the eng/Preserve-sticky-user-activation-across-same-origin-navigations-block-carry-over-through-cross-origin-redirects branch from 6c25c8c to 5db185b Compare July 9, 2026 03:50
@kate-k-lee
kate-k-lee marked this pull request as ready for review July 9, 2026 07:34
@kate-k-lee

Copy link
Copy Markdown
Contributor Author

Hi @youennf
could you please take a look at the implementation changes for the proposed HTML spec update in whatwg/html#11454 ?

The spec PR has already been reviewed by @annevk and is expected to be merged soon. I’ve updated the implementation accordingly, and the new behavior is currently guarded as default-off/testable, so it should not affect existing behavior by default.

Your review would be appreciated when you have a chance. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merging-blocked Applied to prevent a change from being merged New Bugs Unclassified bugs are placed in this component until the correct component can be determined.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants