Bug 1962710 - Part 2: Fire NavigateEvent for same document navigation. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D249241
This commit is contained in:
Andreas Farre
2025-05-19 09:01:13 +00:00
committed by afarre@mozilla.com
parent 51b4a22fa0
commit d2e41c93c1
4 changed files with 96 additions and 30 deletions

View File

@@ -8691,6 +8691,29 @@ bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
aState.mNewURIHasRef;
}
static bool IsSamePrincipalForDocumentURI(nsIPrincipal* aCurrentPrincipal,
nsIURI* aCurrentURI,
nsIURI* aNewURI) {
if (!StaticPrefs::dom_security_setdocumenturi()) {
return true;
}
nsCOMPtr<nsIURI> principalURI = aCurrentPrincipal->GetURI();
if (aCurrentPrincipal->GetIsNullPrincipal()) {
nsCOMPtr<nsIPrincipal> precursor =
aCurrentPrincipal->GetPrecursorPrincipal();
if (precursor) {
principalURI = precursor->GetURI();
}
}
return !nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
aNewURI) &&
!nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
aCurrentURI) &&
!nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(aCurrentURI,
aNewURI);
}
nsresult nsDocShell::HandleSameDocumentNavigation(
nsDocShellLoadState* aLoadState, SameDocumentNavigationState& aState,
bool& aSameDocument) {
@@ -8707,13 +8730,6 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
RefPtr<Document> doc = GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
doc->DoNotifyPossibleTitleChange();
// Store the pending uninvoked directives if it is a same document navigation.
// We need to set it here, in case the navigation happens before the document
// has actually finished loading.
doc->FragmentDirective()->SetTextDirectives(
std::move(aState.mTextDirectives));
nsCOMPtr<nsIURI> currentURI = mCurrentURI;
@@ -8725,33 +8741,57 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
("Upgraded URI to %s", newURI->GetSpecOrDefault().get()));
}
if (StaticPrefs::dom_security_setdocumenturi()) {
// check if aLoadState->URI(), principalURI, mCurrentURI are same origin
// skip handling otherwise
nsCOMPtr<nsIPrincipal> origPrincipal = doc->NodePrincipal();
nsCOMPtr<nsIURI> principalURI = origPrincipal->GetURI();
if (origPrincipal->GetIsNullPrincipal()) {
nsCOMPtr<nsIPrincipal> precursor = origPrincipal->GetPrecursorPrincipal();
if (precursor) {
principalURI = precursor->GetURI();
}
}
if (nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
newURI) ||
nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(principalURI,
mCurrentURI) ||
nsScriptSecurityManager::IsHttpOrHttpsAndCrossOrigin(mCurrentURI,
// check if documentPrincipal, mCurrentURI, and aLoadState->URI() are same
// origin skip handling otherwise
if (!IsSamePrincipalForDocumentURI(doc->NodePrincipal(), mCurrentURI,
newURI)) {
aSameDocument = false;
MOZ_LOG(gSHLog, LogLevel::Debug,
("nsDocShell[%p]: possible violation of the same origin policy "
"during same document navigation",
this));
return NS_OK;
}
if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) {
// https://html.spec.whatwg.org/#navigate-fragid
// Step 1
if (RefPtr<Navigation> navigation = window->Navigation()) {
// Step 2
RefPtr<nsIStructuredCloneContainer> destinationNavigationAPIState =
mActiveEntry ? mActiveEntry->GetNavigationState() : nullptr;
// Step 3
if (aLoadState->GetNavigationAPIState()) {
destinationNavigationAPIState = aLoadState->GetNavigationAPIState();
}
AutoJSAPI jsapi;
if (jsapi.Init(window)) {
RefPtr<Element> sourceElement = aLoadState->GetSourceElement();
// Step 4
bool shouldContinue = navigation->FirePushReplaceReloadNavigateEvent(
jsapi.cx(), aLoadState->GetNavigationType(), newURI,
/* aIsSameDocument */ true,
Some(aLoadState->UserNavigationInvolvement()), sourceElement,
/* aFormDataEntryList */ Nothing(),
/* aNavigationAPIState */ destinationNavigationAPIState,
/* aClassicHistoryAPIState */ nullptr);
// Step 5
if (!shouldContinue) {
return NS_OK;
}
}
}
}
doc->DoNotifyPossibleTitleChange();
// Store the pending uninvoked directives if it is a same document
// navigation. We need to set it here, in case the navigation happens before
// the document has actually finished loading.
doc->FragmentDirective()->SetTextDirectives(
std::move(aState.mTextDirectives));
#ifdef DEBUG
if (aState.mSameExceptHashes) {
bool sameExceptHashes = false;

View File

@@ -15,6 +15,7 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/NavigationBinding.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "nsCOMPtr.h"
#include "nsCharsetSource.h"

View File

@@ -755,6 +755,20 @@ bool nsDocShellLoadState::LoadIsFromSessionHistory() const {
: !!mSHEntry;
}
nsIStructuredCloneContainer* nsDocShellLoadState::GetNavigationAPIState()
const {
return mNavigationAPIState;
}
void nsDocShellLoadState::SetNavigationAPIState(
nsIStructuredCloneContainer* aNavigationAPIState) {
mNavigationAPIState = aNavigationAPIState;
}
NavigationType nsDocShellLoadState::GetNavigationType() const {
return LoadReplace() ? NavigationType::Replace : NavigationType::Push;
}
void nsDocShellLoadState::MaybeStripTrackerQueryStrings(
BrowsingContext* aContext) {
MOZ_ASSERT(aContext);

View File

@@ -8,6 +8,7 @@
#define nsDocShellLoadState_h__
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/NavigationBinding.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/UserNavigationInvolvement.h"
@@ -195,6 +196,14 @@ class nsDocShellLoadState final {
bool LoadIsFromSessionHistory() const;
nsIStructuredCloneContainer* GetNavigationAPIState() const;
// This is used as the parameter for https://html.spec.whatwg.org/#navigate,
// but it's currently missing. See bug 1966674
void SetNavigationAPIState(nsIStructuredCloneContainer* aNavigationAPIState);
mozilla::dom::NavigationType GetNavigationType() const;
const nsString& Target() const;
void SetTarget(const nsAString& aTarget);
@@ -552,6 +561,8 @@ class nsDocShellLoadState final {
mozilla::UniquePtr<mozilla::dom::LoadingSessionHistoryInfo>
mLoadingSessionHistoryInfo;
nsCOMPtr<nsIStructuredCloneContainer> mNavigationAPIState;
// Target for load, like _content, _blank etc.
nsString mTarget;