Bug 1684490 - Check an in-process window context for user interaction. r=smaug,edgar
In the case we click a link from inside the frame, we don't want to check for activation from the parent window but ourselves. It feels like using the sourceWindowContext for these checks is always the right thing to do, but it's not always possible if we set the location.href from an out-of-process parent. In this case, we fall back to consuming user activation on the iframe itself. This is tested in browbrowser_protocol_ask_dialog.js when run with fission enabled. We could consider making the user activation stuff more multiprocess-friendly, but it's not clear to me it's worth it for this particular edge case. Differential Revision: https://phabricator.services.mozilla.com/D100578
This commit is contained in:
@@ -9916,9 +9916,32 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
||||
nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
|
||||
&doesNotReturnData);
|
||||
if (doesNotReturnData) {
|
||||
WindowContext* parentContext =
|
||||
mBrowsingContext->GetParentWindowContext();
|
||||
MOZ_ASSERT(parentContext);
|
||||
// The context to check user-interaction with for the purposes of
|
||||
// popup-blocking.
|
||||
//
|
||||
// We generally want to check the context that initiated the navigation.
|
||||
WindowContext* sourceWindowContext = [&] {
|
||||
const MaybeDiscardedBrowsingContext& sourceBC =
|
||||
aLoadState->SourceBrowsingContext();
|
||||
if (!sourceBC.IsNullOrDiscarded()) {
|
||||
if (WindowContext* wc = sourceBC.get()->GetCurrentWindowContext()) {
|
||||
return wc;
|
||||
}
|
||||
}
|
||||
return mBrowsingContext->GetParentWindowContext();
|
||||
}();
|
||||
|
||||
MOZ_ASSERT(sourceWindowContext);
|
||||
// FIXME: We can't check user-interaction against an OOP window. This is
|
||||
// the next best thing we can really do. The load state keeps whether
|
||||
// the navigation had a user interaction in process
|
||||
// (aLoadState->HasValidUserGestureActivation()), but we can't really
|
||||
// consume it, which we want to prevent popup-spamming from the same
|
||||
// click event.
|
||||
WindowContext* context =
|
||||
sourceWindowContext->IsInProcess()
|
||||
? sourceWindowContext
|
||||
: mBrowsingContext->GetCurrentWindowContext();
|
||||
const bool popupBlocked = [&] {
|
||||
const bool active = mBrowsingContext->IsActive();
|
||||
|
||||
@@ -9927,15 +9950,15 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
||||
//
|
||||
// We consume the flag now even if there's no user activation.
|
||||
const bool hasFreePass = [&] {
|
||||
if (!active || !parentContext->SameOriginWithTop()) {
|
||||
if (!active || !context->SameOriginWithTop()) {
|
||||
return false;
|
||||
}
|
||||
nsGlobalWindowInner* win =
|
||||
parentContext->TopWindowContext()->GetInnerWindow();
|
||||
context->TopWindowContext()->GetInnerWindow();
|
||||
return win && win->TryOpenExternalProtocolIframe();
|
||||
}();
|
||||
|
||||
if (parentContext->ConsumeTransientUserGestureActivation()) {
|
||||
if (context->ConsumeTransientUserGestureActivation()) {
|
||||
// If the user has interacted with the page, consume it.
|
||||
return false;
|
||||
}
|
||||
@@ -9948,7 +9971,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parentContext->CanShowPopup()) {
|
||||
if (sourceWindowContext->CanShowPopup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9968,7 +9991,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsContentUtils::ReportToConsoleByWindowID(
|
||||
message, nsIScriptError::warningFlag, "DOM"_ns,
|
||||
parentContext->InnerWindowId());
|
||||
context->InnerWindowId());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user