Bug 1733052 - Part 2: Revise popup abuse level if there is a valid transient user activation; r=smaug

This is a intermediate solution to make popup block could work with new user
activation model (timer base). I think this should cover most of async case for
`window.open()`. For long term, we still need to clean up the popup state which
is tracked by bug 1656444.

Differential Revision: https://phabricator.services.mozilla.com/D126879
This commit is contained in:
Edgar Chen 2021-10-04 09:17:18 +00:00
parent fcc31b8da9
commit 1e75e43ecc
3 changed files with 88 additions and 2 deletions

View File

@ -2161,6 +2161,7 @@ PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
return PopupBlocker::openAllowed;
}
RefPtr<Document> doc = GetExtantDocument();
PopupBlocker::PopupControlState abuse = aControl;
switch (abuse) {
case PopupBlocker::openControlled:
@ -2171,7 +2172,8 @@ PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
}
break;
case PopupBlocker::openAbused:
if (IsPopupAllowed()) {
if (IsPopupAllowed() ||
(doc && doc->HasValidTransientUserGestureActivation())) {
// Skip PopupBlocker::openBlocked
abuse = PopupBlocker::openControlled;
}
@ -2194,7 +2196,7 @@ PopupBlocker::PopupControlState BrowsingContext::RevisePopupAbuseLevel(
// If we're currently in-process, attempt to consume transient user gesture
// activations.
if (RefPtr<Document> doc = GetExtantDocument()) {
if (doc) {
// HACK: Some pages using bogus library + UA sniffing call window.open()
// from a blank iframe, only on Firefox, see bug 1685056.
//

View File

@ -18,3 +18,4 @@ support-files = file_useractivation_sandbox_transient_popup.html
[test_clipboard_noeditor.html]
[test_popup_blocker_mouse_event.html]
[test_popup_blocker_pointer_event.html]
[test_popup_blocker_async_callback.html]

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for triggering popup by mouse events</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="target" style="width: 50px; height: 50px; background: green"></div>
<script>
SimpleTest.requestFlakyTimeout("Need to test setTimeout");
function startTest(aTestAsyncFun, aAllowPopup = true) {
return new Promise(aResolve => {
let target = document.getElementById("target");
target.addEventListener("click", (e) => {
aTestAsyncFun(() => {
let w = window.open("about:blank");
is(!!w, aAllowPopup, `Should ${aAllowPopup ? "allow" : "block"} popup`);
if (w) {
w.close();
}
aResolve();
});
}, {once: true});
synthesizeMouseAtCenter(target, {type: "mousedown"});
synthesizeMouseAtCenter(target, {type: "mouseup"});
});
}
add_task(async function init() {
await SpecialPowers.pushPrefEnv({"set": [
["dom.disable_open_during_load", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
]});
});
[
// setTimeout
function testSetTimout(aCallback) {
setTimeout(aCallback, 500);
},
// fetch
function testFetch(aCallback) {
fetch("../dummy.html").then(aCallback);
},
// requestStorageAccess
function testRequestStorageAccess(aCallback) {
document.requestStorageAccess().then(aCallback);
},
// serviceWorker.getRegistration
function testGetServiceWorkerRegistration(aCallback) {
navigator.serviceWorker.getRegistration("/app").then(aCallback);
},
].forEach(testAsyncFun => {
add_task(async function() {
info(`start ${testAsyncFun.name}`);
SpecialPowers.wrap(document).clearUserGestureActivation();
await startTest(testAsyncFun);
await new Promise(aResolve => SimpleTest.executeSoon(aResolve));
});
});
// Test popup should be blocked if user transient is timeout
add_task(async function timeout() {
info(`start user transient timeout`);
await SpecialPowers.pushPrefEnv({"set": [
["dom.user_activation.transient.timeout", 1000],
]});
SpecialPowers.wrap(document).clearUserGestureActivation();
await startTest((aCallback) => {
setTimeout(aCallback, 2000);
}, false);
await new Promise(aResolve => SimpleTest.executeSoon(aResolve));
});
</script>
</body>
</html>