tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a50088adb2eded22a03c6c60227df8716e8770eb
parent 5a4a19e0909b3c15f73c09f422234fd293fdaa8e
Author: Adam Vandolder <avandolder@mozilla.com>
Date:   Fri, 12 Dec 2025 23:46:48 +0000

Bug 2005793 - Check if the Navigation API Key needs to be copied for a replace load again after a redirect. r=dom-core,smaug

Differential Revision: https://phabricator.services.mozilla.com/D276305

Diffstat:
Mdocshell/base/CanonicalBrowsingContext.cpp | 51++++++++++++++++++++++++++++++++++-----------------
Mdocshell/base/CanonicalBrowsingContext.h | 2++
Atesting/web-platform/tests/navigation-api/navigation-history-entry/entries-after-server-redirect-replace.html | 26++++++++++++++++++++++++++
3 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp @@ -634,23 +634,8 @@ CanonicalBrowsingContext::CreateLoadingSessionHistoryEntryForLoad( } MOZ_DIAGNOSTIC_ASSERT(entry); - // https://html.spec.whatwg.org/#finalize-a-cross-document-navigation - // 9. If entryToReplace is null, then: ... - // Otherwise: ... - // 4. If historyEntry's document state's origin is same origin with - // entryToReplace's document state's origin, then set - // historyEntry's navigation API key to entryToReplace's - // navigation API key. - if (mActiveEntry && - aLoadState->GetNavigationType() == NavigationType::Replace) { - nsCOMPtr<nsIURI> uri = mActiveEntry->GetURIOrInheritedForAboutBlank(); - nsCOMPtr<nsIURI> targetURI = entry->GetURIOrInheritedForAboutBlank(); - bool sameOrigin = - NS_SUCCEEDED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI( - targetURI, uri, false, false)); - if (sameOrigin) { - entry->SetNavigationKey(mActiveEntry->Info().NavigationKey()); - } + if (aLoadState->GetNavigationType() == NavigationType::Replace) { + MaybeReuseNavigationKeyFromActiveEntry(entry); } UniquePtr<LoadingSessionHistoryInfo> loadingInfo; @@ -772,6 +757,11 @@ CanonicalBrowsingContext::ReplaceLoadingSessionHistoryEntryForLoad( loadingEntry->SetDocshellID(GetHistoryID()); loadingEntry->SetIsDynamicallyAdded(CreatedDynamically()); + if (aInfo->mTriggeringNavigationType && + *aInfo->mTriggeringNavigationType == NavigationType::Replace) { + MaybeReuseNavigationKeyFromActiveEntry(loadingEntry); + } + auto result = MakeUnique<LoadingSessionHistoryInfo>(loadingEntry, aInfo); MOZ_LOG_FMT( gNavigationAPILog, LogLevel::Debug, @@ -825,6 +815,33 @@ void CanonicalBrowsingContext::GetContiguousEntriesForLoad( } } +void CanonicalBrowsingContext::MaybeReuseNavigationKeyFromActiveEntry( + SessionHistoryEntry* aEntry) { + MOZ_ASSERT(aEntry); + + // https://html.spec.whatwg.org/#finalize-a-cross-document-navigation + // 9. If entryToReplace is null, then: ... + // Otherwise: ... + // 4. If historyEntry's document state's origin is same origin with + // entryToReplace's document state's origin, then set + // historyEntry's navigation API key to entryToReplace's + // navigation API key. + if (!mActiveEntry) { + return; + } + + nsCOMPtr<nsIURI> uri = mActiveEntry->GetURIOrInheritedForAboutBlank(); + nsCOMPtr<nsIURI> targetURI = aEntry->GetURIOrInheritedForAboutBlank(); + bool sameOrigin = + NS_SUCCEEDED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI( + targetURI, uri, false, false)); + if (!sameOrigin) { + return; + } + + aEntry->SetNavigationKey(mActiveEntry->Info().NavigationKey()); +} + using PrintPromise = CanonicalBrowsingContext::PrintPromise; #ifdef NS_PRINTING // Clients must call StaticCloneForPrintingCreated or diff --git a/docshell/base/CanonicalBrowsingContext.h b/docshell/base/CanonicalBrowsingContext.h @@ -587,6 +587,8 @@ class CanonicalBrowsingContext final : public BrowsingContext { void GetContiguousEntriesForLoad(LoadingSessionHistoryInfo& aLoadingInfo, const RefPtr<SessionHistoryEntry>& aEntry); + void MaybeReuseNavigationKeyFromActiveEntry(SessionHistoryEntry* aEntry); + EntryList* GetActiveEntries(); // XXX(farre): Store a ContentParent pointer here rather than mProcessId? diff --git a/testing/web-platform/tests/navigation-api/navigation-history-entry/entries-after-server-redirect-replace.html b/testing/web-platform/tests/navigation-api/navigation-history-entry/entries-after-server-redirect-replace.html @@ -0,0 +1,26 @@ +<!doctype html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="i" src="/common/blank.html"></iframe> +<script> +promise_test(async t => { + // Wait for after the load event so that the navigation doesn't get converted + // into a replace navigation. + await new Promise(resolve => window.onload = () => t.step_timeout(resolve, 0)); + + let url = i.contentWindow.navigation.currentEntry.url; + let key = i.contentWindow.navigation.currentEntry.key; + + // Do a redirected cross-document replace navigation in the iframe. + i.contentWindow.navigation.navigate( + "/common/redirect.py?location=/common/blank.html?redirected", + {history: "replace"}); + await new Promise(resolve => i.onload = resolve); + + assert_equals(i.contentWindow.navigation.entries().length, 1); + assert_equals(i.contentWindow.navigation.currentEntry.url, url + "?redirected"); + assert_equals(i.contentWindow.navigation.currentEntry.key, key); +}, "A navigation to a redirected page ends up on the page redirected to"); +</script> +</body>