Bug 1964955 - Make sure NavigateEvent.intercept can execute. r=smaug

Intercept was prevented by four things:

1) the return value of FirePushReplaceReloadNavigateEvent for
   pushState was used inverted.
2) the event was created untrusted
3) the wrong flag was being checked to see if the event was in the
   process of being dispatched.
4) wrong uri equality method was used.

Differential Revision: https://phabricator.services.mozilla.com/D248222
This commit is contained in:
Andreas Farre
2025-05-07 14:22:59 +00:00
committed by afarre@mozilla.com
parent 74378bf229
commit 6ab0d18691
5 changed files with 34 additions and 19 deletions

View File

@@ -11405,19 +11405,23 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
// https://html.spec.whatwg.org/#shared-history-push/replace-state-steps
// Step 8
if (nsCOMPtr<nsPIDOMWindowInner> window = document->GetInnerWindow()) {
if (RefPtr<Navigation> navigation = window->Navigation();
navigation &&
navigation->FirePushReplaceReloadNavigateEvent(
aCx, aReplace ? NavigationType::Replace : NavigationType::Push,
newURI,
/* aIsSameDocument */ true, /* aUserInvolvement */ Nothing(),
/* aSourceElement */ nullptr, /* aFormDataEntryList */ Nothing(),
/* aNavigationAPIState */ nullptr, scContainer)) {
return NS_OK;
if (RefPtr<Navigation> navigation = window->Navigation()) {
bool shouldContinue = navigation->FirePushReplaceReloadNavigateEvent(
aCx, aReplace ? NavigationType::Replace : NavigationType::Push,
newURI,
/* aIsSameDocument */ true, /* aUserInvolvement */ Nothing(),
/* aSourceElement */ nullptr, /* aFormDataEntryList */ Nothing(),
/* aNavigationAPIState */ nullptr, scContainer);
// Step 9
if (!shouldContinue) {
return NS_OK;
}
}
}
// Step 8: call "URL and history update steps"
// Step 10
// Run #url-and-history-update-steps
rv = UpdateURLAndHistory(document, newURI, scContainer,
aReplace ? NavigationHistoryBehavior::Replace
: NavigationHistoryBehavior::Push,

View File

@@ -127,6 +127,7 @@ static void MaybeReportWarningToConsole(Document* aDocument,
"PreviousInterceptCallOptionOverriddenWarning", params);
}
// https://html.spec.whatwg.org/#dom-navigateevent-intercept
void NavigateEvent::Intercept(const NavigationInterceptOptions& aOptions,
ErrorResult& aRv) {
// Step 1
@@ -141,7 +142,7 @@ void NavigateEvent::Intercept(const NavigationInterceptOptions& aOptions,
}
// Step 3
if (!HasBeenDispatched()) {
if (!IsBeingDispatched()) {
aRv.ThrowInvalidStateError("Event has never been dispatched");
return;
}
@@ -252,8 +253,8 @@ AbortController* NavigateEvent::AbortController() const {
return mAbortController;
}
bool NavigateEvent::HasBeenDispatched() const {
return mEvent->mFlags.mDispatchedAtLeastOnce;
bool NavigateEvent::IsBeingDispatched() const {
return mEvent->mFlags.mIsBeingDispatched;
}
// https://html.spec.whatwg.org/#navigateevent-finish

View File

@@ -99,7 +99,7 @@ class NavigateEvent final : public Event {
dom::AbortController* AbortController() const;
bool HasBeenDispatched() const;
bool IsBeingDispatched() const;
MOZ_CAN_RUN_SCRIPT
void Finish(bool aDidFulfill);

View File

@@ -604,7 +604,14 @@ static bool HasUAVisualTransition(Maybe<Document&>) { return false; }
static bool EqualsExceptRef(nsIURI* aURI, nsIURI* aOtherURI) {
bool equalsExceptRef = false;
return aURI && aOtherURI &&
NS_SUCCEEDED(aURI->EqualsExceptRef(aOtherURI, &equalsExceptRef));
NS_SUCCEEDED(aURI->EqualsExceptRef(aOtherURI, &equalsExceptRef)) &&
equalsExceptRef;
}
static bool Equals(nsIURI* aURI, nsIURI* aOtherURI) {
bool equals = false;
return aURI && aOtherURI && NS_SUCCEEDED(aURI->Equals(aOtherURI, &equals)) &&
equals;
}
static bool HasIdenticalFragment(nsIURI* aURI, nsIURI* aOtherURI) {
@@ -764,6 +771,9 @@ bool Navigation::InnerFireNavigateEvent(
// delay it until here.
RefPtr<NavigateEvent> event = NavigateEvent::Constructor(
this, u"navigate"_ns, init, aClassicHistoryAPIState, abortController);
// Here we're running #concept-event-create from https://dom.spec.whatwg.org/
// which explicitly sets event's isTrusted attribute to true.
event->SetTrusted(true);
// Step 26
mOngoingNavigateEvent = event;
@@ -829,7 +839,8 @@ bool Navigation::InnerFireNavigateEvent(
docShell->UpdateURLAndHistory(
document, aDestination->GetURI(), event->ClassicHistoryAPIState(),
*NavigationUtils::NavigationHistoryBehavior(aNavigationType),
document->GetDocumentURI(), aDestination->SameDocument());
document->GetDocumentURI(),
Equals(aDestination->GetURI(), document->GetDocumentURI()));
}
break;
case NavigationType::Reload:
@@ -1045,7 +1056,7 @@ void Navigation::AbortOngoingNavigation(JSContext* aCx,
}
// Step 6
if (event->HasBeenDispatched()) {
if (event->IsBeingDispatched()) {
event->PreventDefault();
}

View File

@@ -1,5 +1,4 @@
[intercept-history-pushState.html]
prefs: [dom.navigation.webidl.enabled: true]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[event.intercept() should proceed if the given promise resolves]
expected: FAIL