Backed out 19 changesets (bug 1675349) for lint failures on browser_ext_browsingData_pluginData and test_archive CLOSED TREE

Backed out changeset 244e0f2b410c (bug 1675349)
Backed out changeset ba5724069dd4 (bug 1675349)
Backed out changeset 37fca259c7e9 (bug 1675349)
Backed out changeset f2b16caca1fc (bug 1675349)
Backed out changeset 28835d4935be (bug 1675349)
Backed out changeset eb913f58953a (bug 1675349)
Backed out changeset 19e3cb80f469 (bug 1675349)
Backed out changeset d9723f3a3a7e (bug 1675349)
Backed out changeset c888dfcdf70e (bug 1675349)
Backed out changeset 48f153341af6 (bug 1675349)
Backed out changeset 7fc67a9b2932 (bug 1675349)
Backed out changeset 1cee4d97f801 (bug 1675349)
Backed out changeset 59a0cb79c7c1 (bug 1675349)
Backed out changeset 43d349fa37b1 (bug 1675349)
Backed out changeset c84bfb6eae59 (bug 1675349)
Backed out changeset 38e9af69ae57 (bug 1675349)
Backed out changeset 3255c1ab3059 (bug 1675349)
Backed out changeset 2f3eaf9c342c (bug 1675349)
Backed out changeset 769e5c0db4c2 (bug 1675349)
This commit is contained in:
Bogdan Tara 2020-11-18 06:06:36 +02:00
Родитель 19001b764c
Коммит 56346a0425
324 изменённых файлов: 21211 добавлений и 420 удалений

Просмотреть файл

@ -455,6 +455,16 @@ module.exports = {
"dom/ipc/test.xhtml",
"dom/ipc/tests/test_process_error.xhtml",
"dom/notification/test/chrome/test_notification_system_principal.xhtml",
"dom/plugins/test/mochitest/test_busy_hang.xhtml",
"dom/plugins/test/mochitest/test_convertpoint.xhtml",
"dom/plugins/test/mochitest/test_crash_notify.xhtml",
"dom/plugins/test/mochitest/test_crash_notify_no_report.xhtml",
"dom/plugins/test/mochitest/test_crash_submit.xhtml",
"dom/plugins/test/mochitest/test_hang_submit.xhtml",
"dom/plugins/test/mochitest/test_hangui.xhtml",
"dom/plugins/test/mochitest/test_idle_hang.xhtml",
"dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xhtml",
"dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xhtml",
"dom/security/test/general/test_bug1277803.xhtml",
"dom/serviceworkers/test/test_serviceworkerinfo.xhtml",
"dom/serviceworkers/test/test_serviceworkermanager.xhtml",

Просмотреть файл

@ -10,6 +10,7 @@ support-files =
[test_listbox.xhtml]
[test_MathMLSpec.html]
[test_nsApplicationAcc.html]
[test_plugin.html]
[test_canvas.html]
[test_shadowroot.html]
support-files = test_shadowroot_subframe.html

Просмотреть файл

@ -461,8 +461,20 @@
// ////////////////////////////////////////////////////////////////////////
// HTML:embed (windowless/windowed plugins and media)
ok(!isAccessible("embed_plugin_windowless"), "(blocked) windowless plugin embed element is not accessible");
ok(!isAccessible("embed_plugin_windowed"), "(blocked) windowed plugin embed element is not accessible");
if (WIN) {
obj = {
role: ROLE_EMBEDDED_OBJECT,
states: STATE_UNAVAILABLE,
};
testElm("embed_plugin_windowless", obj);
obj = {
role: ROLE_EMBEDDED_OBJECT,
absentStates: STATE_UNAVAILABLE,
};
testElm("embed_plugin_windowed", obj);
}
obj = {
role: ROLE_GRAPHIC,
@ -1121,8 +1133,20 @@
// ////////////////////////////////////////////////////////////////////////
// HTML:object (windowless/windowed plugins and media) and HTML:param
ok(!isAccessible("object_plugin_windowless"), "(blocked) windowless plugin object element is not accessible");
ok(!isAccessible("object_plugin_windowed"), "(blocked) windowed plugin object element is not accessible");
if (WIN) {
obj = {
role: ROLE_EMBEDDED_OBJECT,
states: STATE_UNAVAILABLE,
children: [ ], // no child for HTML:param
};
testElm("object_plugin_windowless", obj);
obj = {
role: ROLE_EMBEDDED_OBJECT,
absentStates: STATE_UNAVAILABLE,
};
testElm("object_plugin_windowed", obj);
}
obj = {
role: ROLE_GRAPHIC,
@ -1457,6 +1481,7 @@
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
</head>

Просмотреть файл

@ -351,6 +351,7 @@
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
</head>

Просмотреть файл

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<title>Plugin tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript">
function doTest() {
if (!WIN) {
ok(true,
"It's Windows specific test. Feel free to extend the test.");
SimpleTest.finish();
return;
}
testStates("plugin-windowless", STATE_UNAVAILABLE);
testAccessibleTree("plugin-windowless", { EMBEDDED_OBJECT: [ ] });
testStates("plugin-windowless-fallback", STATE_UNAVAILABLE);
testAccessibleTree("plugin-windowless-fallback", { EMBEDDED_OBJECT: [ ] });
testStates("plugin-windowed", 0, 0, STATE_UNAVAILABLE);
testAccessibleTree("plugin-windowed", { EMBEDDED_OBJECT: [ { NOTHING: [] } ] });
testStates("plugin-windowed-fallback", 0, 0, STATE_UNAVAILABLE);
testAccessibleTree("plugin-windowed-fallback",
{ EMBEDDED_OBJECT: [ { NOTHING: [] } ] });
// make sure we handle content changes under the plugin.
getNode("fallback1").setAttribute("href", "5");
getNode("fallback2").setAttribute("href", "5");
SimpleTest.executeSoon(function() { SimpleTest.finish(); });
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
</head>
<body>
<a target="_blank"
title="Embed and object HTML tags should be given an accessible role of embedded object"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=485270">Bug 485270</a>
<a target="_blank"
title="Embedded object accessibles for inaccessible/windowless plugins should not expose a NULL child"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=816856">Bug 816856</a>
<a target="_blank"
title="Updating accessible tree for plugin with fallback shouldn't crash"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=881636">Bug 881636</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<embed id="plugin-windowless" type="application/x-test"
width="300" height="300"></embed>
<embed id="plugin-windowed" type="application/x-test" wmode="window"
width="300" height="300"></embed>
<embed id="plugin-windowless-fallback" type="application/x-test"
width="300" height="300"><a id="fallback1">foo</a></embed>
<embed id="plugin-windowed-fallback" type="application/x-test" wmode="window"
width="300" height="300"><a id="fallback2">foo</a></embed>
</body>
</html>

Просмотреть файл

@ -49,6 +49,7 @@
gQueue.push(new takeFocusInvoker("aria-link2"));
gQueue.push(new takeFocusInvoker("link"));
gQueue.push(new takeFocusInvoker("item2"));
gQueue.push(new takeFocusInvoker("plugin"));
gQueue.push(new takeFocusInvoker(document));
gQueue.push(new takeFocusInvoker("lb_item2"));
gQueue.push(new takeFocusInvoker(document));
@ -59,8 +60,13 @@
gQueue.invoke(); // Will call SimpleTest.finish();
}
function waitForPlugin() {
window.setTimeout((isAccessible("plugin") ? doTest : waitForPlugin), 0);
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
addA11yLoadEvent(waitForPlugin);
</script>
</head>
@ -76,6 +82,11 @@
title="nsIAccessible::takeFocus testing">
Mozilla Bug 452710
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=646361"
title="No focus event fired on document when focus is set to the document while focused in a plugin">
Mozilla Bug 646361
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=706067"
title="Make takeFocus work on widget items">
@ -97,6 +108,8 @@
<div role="option" id="item3">item3</div>
</div>
<embed id="plugin" type="application/x-test" width="200" height="200" wmode="window"></embed>
<select id="listbox" size="5">
<option id="lb_item1">item1</option>
<option id="lb_item2">item2</option>

Просмотреть файл

@ -276,11 +276,6 @@ class PluginChild extends JSWindowActorChild {
overlay.removeAttribute("notext");
}
if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_BLOCK_ALL) {
overlay.setAttribute("blockall", "blockall");
return OVERLAY_DISPLAY.HIDDEN;
}
// The hit test below only works with correct layout information,
// don't do it if layout needs flush.
// We also don't want to access scrollWidth/scrollHeight if
@ -389,8 +384,6 @@ class PluginChild extends JSWindowActorChild {
return "PluginVulnerableUpdatable";
case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
return "PluginVulnerableNoUpdate";
case Ci.nsIObjectLoadingContent.PLUGIN_BLOCK_ALL:
return "PluginBlockAll";
default:
// Not all states map to a handler
return null;
@ -482,7 +475,6 @@ class PluginChild extends JSWindowActorChild {
this.onPluginCrashed(pluginElement, event);
break;
case "PluginBlockAll":
case "PluginNotFound": {
/* NOP */
break;
@ -725,7 +717,6 @@ class PluginChild extends JSWindowActorChild {
event.originalTarget.getAttribute("anonid") != "closeIcon" &&
event.originalTarget.id != "closeIcon" &&
!overlay.hasAttribute("dismissed") &&
!overlay.hasAttribute("blockall") &&
event.button == 0 &&
event.isTrusted
) {

Просмотреть файл

@ -1728,6 +1728,65 @@ add_task(async function test_select_input_text_password() {
*/
});
add_task(async function test_click_to_play_blocked_plugin() {
await test_contextmenu(
"#test-plugin",
[
"context-navigation",
null,
[
"context-back",
false,
"context-forward",
false,
"context-reload",
true,
"context-bookmarkpage",
true,
],
null,
"---",
null,
"context-ctp-play",
true,
"context-ctp-hide",
true,
"---",
null,
"context-savepage",
true,
...(hasPocket ? ["context-pocket", true] : []),
"---",
null,
"context-sendpagetodevice",
true,
[],
null,
"---",
null,
"context-viewbgimage",
false,
"context-selectall",
true,
"---",
null,
"context-viewsource",
true,
"context-viewinfo",
true,
],
{
maybeScreenshotsPresent: true,
preCheckContextMenuFn() {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
},
postCheckContextMenuFn() {
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
},
}
);
});
add_task(async function test_longdesc() {
await test_contextmenu("#test-longdesc", [
"context-viewimage",

Просмотреть файл

@ -78,6 +78,7 @@ if ("ShadowRoot" in this) {
<a id="test-image-link" href="#"><img src="ctxmenu-image.png"></a>
<input id="test-select-input-text" type="text" value="input">
<input id="test-select-input-text-type-password" type="password" value="password">
<embed id="test-plugin" style="width: 200px; height: 200px;" type="application/x-test"></embed>
<img id="test-longdesc" src="ctxmenu-image.png" longdesc="http://www.mozilla.org"></embed>
<iframe id="test-srcdoc" width="98" height="98" srcdoc="Hello World" style="border: 1px solid black"></iframe>
<svg id="svg-with-link" width=10 height=10><a xlink:href="http://example.com/"><circle cx="50%" cy="50%" r="50%" fill="blue"/></a></svg>

Просмотреть файл

@ -304,6 +304,12 @@ const startupPhases = {
condition: WIN,
stat: 1,
},
{
// bug 1586808
path: "UserPlugins.parent:",
condition: WIN,
stat: 1,
},
{
path: "XREAppFeat:formautofill@mozilla.org.xpi",
condition: !WIN,

Просмотреть файл

@ -0,0 +1 @@
[]

Просмотреть файл

@ -0,0 +1,11 @@
[
{
"matchFilename": "libnptest\\.so|nptest\\.dll|Test\\.plugin",
"versionRange": [
{
"severity": "2"
}
],
"blockID": "p9999"
}
]

Просмотреть файл

@ -0,0 +1,12 @@
[
{
"matchFilename": "libnptest\\.so|nptest\\.dll|Test\\.plugin",
"versionRange": [
{
"severity": "2"
}
],
"blockID": "p9999",
"infoURL": "http://test.url.com/"
}
]

Просмотреть файл

@ -0,0 +1,12 @@
[
{
"matchFilename": "libnptest\\.so|nptest\\.dll|Test\\.plugin",
"versionRange": [
{
"severity": "0",
"vulnerabilityStatus": "2"
}
],
"blockID": "p9999"
}
]

Просмотреть файл

@ -0,0 +1,12 @@
[
{
"matchFilename": "libnptest\\.so|nptest\\.dll|Test\\.plugin",
"versionRange": [
{
"severity": "0",
"vulnerabilityStatus": "1"
}
],
"blockID": "p9999"
}
]

Просмотреть файл

@ -3,23 +3,95 @@ prefs =
plugin.load_flash_only=false
support-files =
BlocklistTestProxy.jsm
blockNoPlugins-plugins.json
blockPluginHard-plugins.json
blockPluginInfoURL-plugins.json
blockPluginVulnerableNoUpdate-plugins.json
blockPluginVulnerableUpdatable-plugins.json
browser_clearplugindata.html
browser_clearplugindata_noage.html
empty_file.html
head.js
plugin_add_dynamically.html
plugin_alternate_content.html
plugin_big.html
plugin_both.html
plugin_both2.html
plugin_bug744745.html
plugin_bug749455.html
plugin_bug787619.html
plugin_bug797677.html
plugin_favorfallback.html
plugin_hidden_to_visible.html
plugin_iframe.html
plugin_outsideScrollArea.html
plugin_overlay_styles.html
plugin_simple_blank.swf
plugin_shouldShowOverlay.html
plugin_small.html
plugin_small_2.html
plugin_syncRemoved.html
plugin_test.html
plugin_test2.html
plugin_two_types.html
plugin_unknown.html
plugin_crashCommentAndURL.html
plugin_zoom.html
[browser_bug743421.js]
tags = blocklist
[browser_bug744745.js]
[browser_bug787619.js]
[browser_bug797677.js]
[browser_bug812562.js]
tags = blocklist
[browser_bug818118.js]
[browser_clearplugindata.js]
tags = blocklist
[browser_CTP_context_menu.js]
skip-if = fission || toolkit == "gtk" # Fails with Fission, and we're unlikely to spend time to fix it. fails intermittently on Linux (bug 909342)
tags = blocklist
[browser_CTP_crashreporting.js]
skip-if = !crashreporter || verify || os == 'win' # bug 1442837
tags = blocklist
[browser_CTP_drag_drop.js]
tags = blocklist
[browser_CTP_favorfallback.js]
[browser_CTP_hide_overlay.js]
tags = blocklist
[browser_CTP_iframe.js]
tags = blocklist
[browser_CTP_nonplugins.js]
skip-if = verify
tags = blocklist
[browser_CTP_outsideScrollArea.js]
tags = blocklist
[browser_CTP_overlay_styles.js]
[browser_CTP_resize.js]
tags = blocklist
[browser_CTP_shouldShowOverlay.js]
[browser_CTP_zoom.js]
tags = blocklist
[browser_blocking.js]
tags = blocklist
[browser_iterate_hidden_plugins.js]
[browser_plugin_framed_domain.js]
[browser_pluginnotification.js]
tags = blocklist
[browser_plugin_reloading.js]
tags = blocklist
[browser_blocklist_content.js]
skip-if = !e10s
tags = blocklist
[browser_enable_DRM_prompt.js]
skip-if = (os == 'win' && processor == 'aarch64') # bug 1533164
[browser_private_browsing_eme_persistent_state.js]
[browser_globalplugin_crashinfobar.js]
skip-if = !crashreporter
[browser_pluginCrashCommentAndURL.js]
skip-if = fission || !crashreporter # Fails with Fission, and we're unlikely to spend time to fix it.
[browser_pluginCrashReportNonDeterminism.js]
skip-if = !crashreporter
[browser_private_clicktoplay.js]
[browser_subframe_access_hidden_plugins.js]
skip-if = fission # Fails with Fission, and we're unlikely to spend time to fix it.

Просмотреть файл

@ -0,0 +1,91 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
// Test that the activate action in content menus for CTP plugins works
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let bindingPromise = BrowserTestUtils.waitForContentEvent(
gBrowser.selectedBrowser,
"PluginBindingAttached",
true,
null,
true
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
await bindingPromise;
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
// check plugin state
let pluginInfo = await promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(!pluginInfo.activated, "plugin should not be activated");
// Display a context menu on the test plugin so we can test
// activation menu options.
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("contextmenu", left, top, 2, 1, 0);
});
popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(popupNotification, "Should have a click-to-play notification");
ok(popupNotification.dismissed, "notification should be dismissed");
// fixes a occasional test timeout on win7 opt
await promiseForCondition(() => document.getElementById("context-ctp-play"));
let actMenuItem = document.getElementById("context-ctp-play");
ok(actMenuItem, "Should have a context menu entry for activating the plugin");
// Activate the plugin via the context menu
EventUtils.synthesizeMouseAtCenter(actMenuItem, {});
await promiseForCondition(
() =>
!PopupNotifications.panel.dismissed &&
PopupNotifications.panel.firstElementChild
);
// Activate the plugin
PopupNotifications.panel.firstElementChild.button.click();
// check plugin state
pluginInfo = await promiseForPluginInfo("test", gBrowser.selectedBrowser);
ok(pluginInfo.activated, "plugin should be activated");
});

Просмотреть файл

@ -0,0 +1,263 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
const SERVER_URL =
"http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
const PLUGIN_PAGE = gTestRoot + "plugin_big.html";
const PLUGIN_SMALL_PAGE = gTestRoot + "plugin_small.html";
/**
* Takes an nsIPropertyBag and converts it into a JavaScript Object. It
* will also convert any nsIPropertyBag's within the nsIPropertyBag
* recursively.
*
* @param aBag
* The nsIPropertyBag to convert.
* @return Object
* Keyed on the names of the nsIProperty's within the nsIPropertyBag,
* and mapping to their values.
*/
function convertPropertyBag(aBag) {
let result = {};
for (let { name, value } of aBag.enumerator) {
if (value instanceof Ci.nsIPropertyBag) {
value = convertPropertyBag(value);
}
result[name] = value;
}
return result;
}
add_task(async function setup() {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
// crash reports. This test needs them enabled. The test also needs a mock
// report server, and fortunately one is already set up by toolkit/
// crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
// which CrashSubmit.jsm uses as a server override.
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
let serverURL = env.get("MOZ_CRASHREPORTER_URL");
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
registerCleanupFunction(function cleanUp() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
env.set("MOZ_CRASHREPORTER_URL", serverURL);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
window.focus();
});
});
/**
* Test that plugin crash submissions still work properly after
* click-to-play activation.
*/
add_task(async function() {
await BrowserTestUtils.withNewTab(PLUGIN_PAGE, async function(browser) {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(browser);
let pluginInfo = await promiseForPluginInfo("test", browser);
ok(!pluginInfo.activated, "Plugin should not be activated");
// Simulate clicking the "Allow Always" button.
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
browser
);
await promiseForNotificationShown(notification, browser);
PopupNotifications.panel.firstElementChild.button.click();
// Prepare a crash report topic observer that only returns when
// the crash report has been successfully sent.
let crashReportChecker = (subject, data) => {
return data == "success";
};
let crashReportPromise = TestUtils.topicObserved(
"crash-report-status",
crashReportChecker
);
await SpecialPowers.spawn(browser, [], async function() {
let plugin = content.document.getElementById("test");
await ContentTaskUtils.waitForCondition(() => {
return plugin.activated;
}, "Waited too long for plugin to activate.");
try {
Cu.waiveXrays(plugin).crash();
} catch (e) {}
// Wait for the shadow DOM to be connected.
await ContentTaskUtils.waitForCondition(
() => plugin.openOrClosedShadowRoot,
"Need plugin shadow root"
);
let getUI = id => {
return plugin.openOrClosedShadowRoot.getElementById(id);
};
// Now wait until the plugin crash report UI shows itself, which is
// asynchronous.
let statusDiv;
await ContentTaskUtils.waitForCondition(() => {
statusDiv = getUI("submitStatus");
return statusDiv?.getAttribute("status") == "please";
}, "Waited too long for plugin to show crash report UI");
// Make sure the UI matches our expectations...
let style = content.getComputedStyle(getUI("pleaseSubmit"));
if (style.display != "block") {
throw new Error(
`Submission UI visibility is not correct. ` +
`Expected block style, got ${style.display}.`
);
}
// Fill the crash report in with some test values that we'll test for in
// the parent.
getUI("submitComment").value = "a test comment";
let optIn = getUI("submitURLOptIn");
if (!optIn.checked) {
throw new Error("URL opt-in should default to true.");
}
// Submit the report.
optIn.click();
getUI("submitButton").click();
// And wait for the parent to say that the crash report was submitted
// successfully. This can take time on debug builds.
await ContentTaskUtils.waitForCondition(
() => {
return statusDiv.getAttribute("status") == "success";
},
"Timed out waiting for plugin binding to be in success state",
100,
200
);
});
let [subject] = await crashReportPromise;
ok(
subject instanceof Ci.nsIPropertyBag,
"The crash report subject should be an nsIPropertyBag."
);
let crashData = convertPropertyBag(subject);
ok(crashData.serverCrashID, "Should have a serverCrashID set.");
// Remove the submitted report file after ensuring it exists.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath(Services.crashmanager._submittedDumpsDir);
file.append(crashData.serverCrashID + ".txt");
ok(file.exists(), "Submitted report file should exist");
file.remove(false);
ok(crashData.extra, "Extra data should exist");
is(
crashData.extra.PluginUserComment,
"a test comment",
"Comment in extra data should match comment in textbox"
);
is(
crashData.extra.PluginContentURL,
undefined,
"URL should be absent from extra data when opt-in not checked"
);
});
});
/**
* Test that plugin crash submissions still work properly after
* click-to-play with the notification bar.
*/
add_task(async function() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: PLUGIN_SMALL_PAGE,
},
async function(browser) {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(browser);
let pluginInfo = await promiseForPluginInfo("test", browser);
ok(pluginInfo.activated, "Plugin should be activated from previous test");
// Prepare a crash report topic observer that only returns when
// the crash report has been successfully sent.
let crashReportChecker = (subject, data) => {
return data == "success";
};
let crashReportPromise = TestUtils.topicObserved(
"crash-report-status",
crashReportChecker
);
await SpecialPowers.spawn(browser, [], async function() {
let plugin = content.document.getElementById("test");
await ContentTaskUtils.waitForCondition(() => {
return plugin.activated;
}, "Waited too long for plugin to activate.");
try {
Cu.waiveXrays(plugin).crash();
} catch (e) {}
});
// Wait for the notification bar to be displayed.
let notification = await waitForNotificationBar(
"plugin-crashed",
browser
);
// Then click the button to submit the crash report.
let buttons = notification.querySelectorAll(".notification-button");
is(buttons.length, 2, "Should have two buttons.");
// The "Submit Crash Report" button should be the second one.
let submitButton = buttons[1];
submitButton.click();
let [subject] = await crashReportPromise;
ok(
subject instanceof Ci.nsIPropertyBag,
"The crash report subject should be an nsIPropertyBag."
);
let crashData = convertPropertyBag(subject);
ok(crashData.serverCrashID, "Should have a serverCrashID set.");
// Remove the submitted report file after ensuring it exists.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath(Services.crashmanager._submittedDumpsDir);
file.append(crashData.serverCrashID + ".txt");
ok(file.exists(), "Submitted report file should exist");
file.remove(false);
is(
crashData.extra.PluginContentURL,
undefined,
"URL should be absent from extra data when opt-in not checked"
);
}
);
});

Просмотреть файл

@ -0,0 +1,159 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gNewWindow = null;
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gNewWindow.close();
await BrowserTestUtils.waitForEvent(gNewWindow, "unload", true);
gNewWindow = null;
window.focus();
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
await promisePopupNotification("click-to-play-plugins");
});
add_task(async function() {
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
// XXX technically can't load fire before we get this call???
await BrowserTestUtils.waitForEvent(gNewWindow, "load", true);
await promisePopupNotification(
"click-to-play-plugins",
gNewWindow.gBrowser.selectedBrowser
);
ok(
PopupNotifications.getNotification(
"click-to-play-plugins",
gNewWindow.gBrowser.selectedBrowser
),
"Should have a click-to-play notification in the tab in the new window"
);
ok(
!PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
),
"Should not have a click-to-play notification in the old window now"
);
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.swapBrowsersAndCloseOther(
gBrowser.selectedTab,
gNewWindow.gBrowser.selectedTab
);
await promisePopupNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(
PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
),
"Should have a click-to-play notification in the initial tab again"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
});
add_task(async function() {
await promisePopupNotification("click-to-play-plugins");
gNewWindow = gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
await promiseWaitForFocus(gNewWindow);
await promisePopupNotification(
"click-to-play-plugins",
gNewWindow.gBrowser.selectedBrowser
);
});
add_task(async function() {
ok(
PopupNotifications.getNotification(
"click-to-play-plugins",
gNewWindow.gBrowser.selectedBrowser
),
"Should have a click-to-play notification in the tab in the new window"
);
ok(
!PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
),
"Should not have a click-to-play notification in the old window now"
);
let pluginInfo = await promiseForPluginInfo(
"test",
gNewWindow.gBrowser.selectedBrowser
);
ok(!pluginInfo.activated, "plugin should not be activated");
await SpecialPowers.spawn(
gNewWindow.gBrowser.selectedBrowser,
[],
async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
}
);
let condition = () =>
!PopupNotifications.getNotification(
"click-to-play-plugins",
gNewWindow.gBrowser.selectedBrowser
).dismissed && gNewWindow.PopupNotifications.panel.firstElementChild;
await promiseForCondition(condition);
});
add_task(async function() {
// Click the activate button on doorhanger to make sure it works
gNewWindow.PopupNotifications.panel.firstElementChild.button.click();
let pluginInfo = await promiseForPluginInfo(
"test",
gNewWindow.gBrowser.selectedBrowser
);
ok(pluginInfo.activated, "plugin should be activated");
});

Просмотреть файл

@ -8,6 +8,7 @@ var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Shockwave Flash");
Services.prefs.clearUserPref("plugins.favorfallback.mode");
Services.prefs.clearUserPref("plugins.favorfallback.rules");
});
@ -15,6 +16,10 @@ add_task(async function() {
add_task(async function() {
Services.prefs.setCharPref("plugins.favorfallback.mode", "follow-ctp");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_CLICKTOPLAY,
"Shockwave Flash"
);
});
/* The expected behavior of each testcase is documented with its markup
@ -76,8 +81,8 @@ add_task(async function() {
);
is(
ctpPlugin.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_ALTERNATE,
"Plugins always use alternate content"
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Plugin is CTP"
);
}

Просмотреть файл

@ -0,0 +1,149 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_CLICKTOPLAY,
"Second Test Plug-in"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
// Tests that the overlay can be hidden for plugins using the close icon.
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
let closeIcon = plugin.openOrClosedShadowRoot.getElementById("closeIcon");
let bounds = closeIcon.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
Assert.ok(
!overlay.classList.contains("visible"),
"overlay should be hidden."
);
});
});
// Test that the overlay cannot be interacted with after the user closes the overlay
add_task(async function() {
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_CLICKTOPLAY,
"Second Test Plug-in"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
let closeIcon = plugin.openOrClosedShadowRoot.getElementById("closeIcon");
let closeIconBounds = closeIcon.getBoundingClientRect();
let overlayBounds = overlay.getBoundingClientRect();
let overlayLeft = (overlayBounds.left + overlayBounds.right) / 2;
let overlayTop = (overlayBounds.left + overlayBounds.right) / 2;
let closeIconLeft = (closeIconBounds.left + closeIconBounds.right) / 2;
let closeIconTop = (closeIconBounds.top + closeIconBounds.bottom) / 2;
let utils = content.windowUtils;
// Simulate clicking on the close icon.
utils.sendMouseEvent(
"mousedown",
closeIconLeft,
closeIconTop,
0,
1,
0,
false,
0,
0
);
utils.sendMouseEvent(
"mouseup",
closeIconLeft,
closeIconTop,
0,
1,
0,
false,
0,
0
);
// Simulate clicking on the overlay.
utils.sendMouseEvent(
"mousedown",
overlayLeft,
overlayTop,
0,
1,
0,
false,
0,
0
);
utils.sendMouseEvent(
"mouseup",
overlayLeft,
overlayTop,
0,
1,
0,
false,
0,
0
);
Assert.ok(
overlay.hasAttribute("dismissed") &&
!overlay.classList.contains("visible"),
"Overlay should be hidden"
);
});
let notification = PopupNotifications.getNotification(
"click-to-play-plugins"
);
ok(notification.dismissed, "No notification should be shown");
});

Просмотреть файл

@ -0,0 +1,61 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_iframe.html"
);
// Tests that the overlays are visible and actionable if the plugin is in an iframe.
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let frame = content.document.getElementById("frame");
let doc = frame.contentDocument;
let plugin = doc.getElementById("test");
await ContentTaskUtils.waitForCondition(
() => plugin.openOrClosedShadowRoot?.getElementById("main"),
"Wait for plugin shadow root"
);
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
plugin && overlay.classList.contains("visible"),
"Test 1, Plugin overlay should exist, not be hidden"
);
let closeIcon = plugin.openOrClosedShadowRoot.getElementById("closeIcon");
let bounds = closeIcon.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = doc.defaultView.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
Assert.ok(
!overlay.classList.contains("visible"),
"Test 1, Plugin overlay should exist, be hidden"
);
});
});

Просмотреть файл

@ -0,0 +1,83 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_DISABLED, "Test Plug-in");
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_two_types.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
// Test that the click-to-play notification is not shown for non-plugin object elements
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
let pluginRemovedPromise = BrowserTestUtils.waitForContentEvent(
gBrowser.selectedBrowser,
"PluginRemoved",
true,
null,
true
);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let plugin = content.document.getElementById("secondtestA");
plugin.remove();
plugin = content.document.getElementById("secondtestB");
plugin.remove();
let image = content.document.createElement("object");
image.type = "image/png";
image.data = "moz.png";
content.document.body.appendChild(image);
});
await pluginRemovedPromise;
popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(popupNotification, "Test 2, Should have a click-to-play notification");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let plugin = content.document.getElementById("test");
plugin.remove();
});
popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gBrowser.selectedBrowser
);
ok(
popupNotification,
"Test 3, Should still have a click-to-play notification"
);
});

Просмотреть файл

@ -9,6 +9,11 @@ var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
@ -22,13 +27,22 @@ add_task(async function() {
let newTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"Test 1, Should not have a click-to-play notification"
);
});
// Test that the plugin "blockall" overlay is always present but hidden,
// regardless of whether the overlay is fully, partially, or not in the
// viewport.
// Test that the click-to-play overlay is not hidden for elements
// partially or fully outside the viewport.
// fully in viewport
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
@ -40,7 +54,7 @@ add_task(async function() {
let p = doc.createElement("embed");
p.setAttribute("id", "test");
p.setAttribute("type", "application/x-shockwave-flash");
p.setAttribute("type", "application/x-test");
p.style.left = "0";
p.style.bottom = "200px";
@ -50,16 +64,20 @@ add_task(async function() {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(overlay);
Assert.ok(!overlay.getAttribute("visible"));
Assert.ok(overlay.getAttribute("blockall") == "blockall");
Assert.ok(
overlay &&
overlay.classList.contains("visible") &&
overlay.getAttribute("sizing") != "blank",
"Test 2, overlay should be visible."
);
});
});
// partially in viewport
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
@ -71,7 +89,7 @@ add_task(async function() {
let p = doc.createElement("embed");
p.setAttribute("id", "test");
p.setAttribute("type", "application/x-shockwave-flash");
p.setAttribute("type", "application/x-test");
p.style.left = "0";
p.style.bottom = "-410px";
@ -81,16 +99,20 @@ add_task(async function() {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(overlay);
Assert.ok(!overlay.getAttribute("visible"));
Assert.ok(overlay.getAttribute("blockall") == "blockall");
Assert.ok(
overlay &&
overlay.classList.contains("visible") &&
overlay.getAttribute("sizing") != "blank",
"Test 3, overlay should be visible."
);
});
});
// not in viewport
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
@ -102,7 +124,7 @@ add_task(async function() {
let p = doc.createElement("embed");
p.setAttribute("id", "test");
p.setAttribute("type", "application/x-shockwave-flash");
p.setAttribute("type", "application/x-test");
p.style.left = "-600px";
p.style.bottom = "0";
@ -112,11 +134,13 @@ add_task(async function() {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(overlay);
Assert.ok(!overlay.getAttribute("visible"));
Assert.ok(overlay.getAttribute("blockall") == "blockall");
Assert.ok(
!overlay || overlay.getAttribute("sizing") == "blank",
"Test 4, overlay should be blank."
);
});
});

Просмотреть файл

@ -0,0 +1,111 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* This test ensures that the click-to-play "Activate Plugin" overlay
* is shown in the right style (which is dependent on its size).
*/
const rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
const gTestcases = {
// 10x10
testcase1: {
sizing: "blank",
notext: null,
},
// 40x40
testcase2: {
sizing: "tiny",
notext: "notext",
},
// 100x70
testcase3: {
sizing: "reduced",
notext: "notext",
},
// 200x200
testcase4: {
sizing: null,
notext: "notext",
},
// 300x300
testcase5: {
sizing: null,
notext: null,
},
};
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
gBrowser.removeCurrentTab();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"Sanity check, should not have a click-to-play notification"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_overlay_styles.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [gTestcases], async function(
testcases
) {
let doc = content.document;
for (let testcaseId of Object.keys(testcases)) {
let plugin = doc.querySelector(`#${testcaseId} > object`);
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(overlay, `overlay exists in ${testcaseId}`);
let expectations = testcases[testcaseId];
Assert.ok(
overlay.classList.contains("visible"),
`The expected visibility is correct in ${testcaseId}`
);
Assert.ok(
overlay.getAttribute("sizing") == expectations.sizing,
`The expected sizing is correct in ${testcaseId}`
);
Assert.ok(
overlay.getAttribute("notext") == expectations.notext,
`The expected notext is correct in ${testcaseId}`
);
}
});
});

Просмотреть файл

@ -0,0 +1,152 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
let newTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"Test 1, Should not have a click-to-play notification"
);
await promiseTabLoadEvent(newTab, gTestRoot + "plugin_small.html"); // 10x10 plugin
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
});
// Test that the overlay is hidden for "small" plugin elements and is shown
// once they are resized to a size that can hold the overlay
add_task(async function() {
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(popupNotification, "Test 2, Should have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
!overlay || overlay.getAttribute("sizing") == "blank",
"Test 2, overlay should be blank."
);
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
plugin.style.width = "300px";
});
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
!overlay || overlay.getAttribute("sizing") == "blank",
"Test 3, overlay should be blank."
);
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
plugin.style.height = "300px";
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
content.document.getElementById("test").clientTop;
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay && overlay.getAttribute("sizing") != "blank",
"Test 4, overlay should be visible."
);
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
plugin.style.width = "10px";
plugin.style.height = "10px";
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
content.document.getElementById("test").clientTop;
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
!overlay || overlay.getAttribute("sizing") == "blank",
"Test 5, overlay should be blank."
);
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
plugin.style.height = "300px";
plugin.style.width = "300px";
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
content.document.getElementById("test").clientTop;
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay && overlay.getAttribute("sizing") != "blank",
"Test 6, overlay should be visible."
);
});
});

Просмотреть файл

@ -0,0 +1,76 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* This test ensures that the click-to-play "Activate Plugin" overlay
* is shown when expected.
* All testcases are in the plugin_shouldShowOverlay.html file.
*
* Note: Technically, the overlay is *always* shown. When this test was
* originally written, the meaning of "shown" was "shown with the contents",
* as opposed to "shown as blank". The behavior hasn't changed, but the naming
* has: now, a "shown as blank" overlay no longer receives a ".hidden" class.
* It receives a sizing="blank" attribute.
*/
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
gBrowser.removeCurrentTab();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"Sanity check, should not have a click-to-play notification"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_shouldShowOverlay.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let testcases = doc.querySelectorAll(".testcase");
for (let testcase of testcases) {
let plugin = testcase.querySelector("object");
Assert.ok(plugin, `plugin exists in ${testcase.id}`);
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(overlay, `overlay exists in ${testcase.id}`);
let expectedVisibility = testcase.getAttribute("shouldshow") == "true";
Assert.ok(
(overlay.getAttribute("sizing") != "blank") == expectedVisibility,
`The expected visibility is correct in ${testcase.id}`
);
}
});
});

Просмотреть файл

@ -11,6 +11,11 @@ var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
FullZoom.reset(); // must be called before closing the tab we zoomed!
gBrowser.removeCurrentTab();
@ -25,6 +30,17 @@ add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"Test 1, Should not have a click-to-play notification"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_zoom.html"
@ -32,6 +48,8 @@ add_task(async function() {
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
});
// Enlarges the zoom level 4 times and tests that the overlay is
@ -51,10 +69,8 @@ add_task(async function() {
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay &&
!overlay.classList.contains("visible") &&
overlay.getAttribute("blockall") == "blockall",
"Overlay should be present for zoom change count " + args.count
overlay && overlay.classList.contains("visible"),
"Overlay should be visible for zoom change count " + args.count
);
});
}

Просмотреть файл

@ -0,0 +1,433 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
function updateAllTestPlugins(aState) {
setTestPluginEnabledState(aState, "Test Plug-in");
setTestPluginEnabledState(aState, "Second Test Plug-in");
}
function promisePluginActivated() {
return SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
return ContentTaskUtils.waitForCondition(
() => content.document.getElementById("test").activated,
"Wait for plugin to be activated"
);
});
}
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
updateAllTestPlugins(Ci.nsIPluginTag.STATE_ENABLED);
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
// Prime the content process
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>hi</html>"
);
});
// Tests a vulnerable, updatable plugin
add_task(async function() {
// enable hard blocklisting of test
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginVulnerableUpdatable",
gTestBrowser
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE"
);
ok(!pluginInfo.activated, "Test 18a, Plugin should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay && overlay.classList.contains("visible"),
"Test 18a, Plugin overlay should exist, not be hidden"
);
let updateLink = plugin.openOrClosedShadowRoot.getElementById(
"checkForUpdatesLink"
);
Assert.ok(
updateLink.style.visibility != "hidden",
"Test 18a, Plugin should have an update link"
);
});
let promise = BrowserTestUtils.waitForEvent(
gBrowser.tabContainer,
"TabOpen",
true
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let updateLink = plugin.openOrClosedShadowRoot.getElementById(
"checkForUpdatesLink"
);
let bounds = updateLink.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
await promise;
promise = BrowserTestUtils.waitForEvent(
gBrowser.tabContainer,
"TabClose",
true
);
gBrowser.removeCurrentTab();
await promise;
});
add_task(async function() {
// clicking the update link should not activate the plugin
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 18a, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE"
);
ok(!pluginInfo.activated, "Test 18b, Plugin should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay && overlay.classList.contains("visible"),
"Test 18b, Plugin overlay should exist, not be hidden"
);
});
});
// Tests a vulnerable plugin with no update
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginVulnerableNoUpdate",
gTestBrowser
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 18c, Should have a click-to-play notification");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
"Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE"
);
ok(!pluginInfo.activated, "Test 18c, Plugin should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(
overlay && overlay.classList.contains("visible"),
"Test 18c, Plugin overlay should exist, not be hidden"
);
let updateLink = plugin.openOrClosedShadowRoot.getElementById(
"checkForUpdatesLink"
);
Assert.ok(
updateLink && updateLink.style.display != "block",
"Test 18c, Plugin should not have an update link"
);
});
// check that click "Allow" works with blocked plugins
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
await promisePluginActivated();
pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE,
"Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE"
);
ok(pluginInfo.activated, "Test 18c, Plugin should be activated");
let enabledState = getTestPluginEnabledState();
ok(
enabledState,
"Test 18c, Plugin enabled state should be STATE_CLICKTOPLAY"
);
});
// continue testing "Always allow", make sure it sticks.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 18d, Waited too long for plugin to activate");
clearAllPluginPermissions();
});
// clicking the in-content overlay of a vulnerable plugin should bring
// up the notification and not directly activate the plugin
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 18f, Should have a click-to-play notification");
ok(notification.dismissed, "Test 18f, notification should start dismissed");
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18f, Waited too long for plugin to activate");
var oldEventCallback = notification.options.eventCallback;
let promise = promiseForCondition(() => oldEventCallback == null);
notification.options.eventCallback = function() {
if (oldEventCallback) {
oldEventCallback();
}
oldEventCallback = null;
};
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
await promise;
ok(notification, "Test 18g, Should have a click-to-play notification");
ok(!notification.dismissed, "Test 18g, notification should be open");
pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
});
// Test that "always allow"-ing a plugin will not allow it when it becomes
// blocklisted.
add_task(async function() {
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 24a, Should have a click-to-play notification");
// Plugin should start as CTP
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 24a, plugin fallback type should be PLUGIN_CLICK_TO_PLAY"
);
ok(!pluginInfo.activated, "Test 24a, Plugin should not be active.");
// simulate "allow"
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
await promisePluginActivated();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 24a, Plugin should be active.");
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginVulnerableUpdatable",
gTestBrowser
);
});
// the plugin is now blocklisted, so it should not automatically load
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 24b, Should have a click-to-play notification");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"Test 24b, plugin fallback type should be PLUGIN_VULNERABLE_UPDATABLE"
);
ok(!pluginInfo.activated, "Test 24b, Plugin should not be active.");
// simulate "allow"
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
await promisePluginActivated();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 24b, Plugin should be active.");
clearAllPluginPermissions();
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
});
// Plugin sync removal test. Note this test produces a notification drop down since
// the plugin we add has zero dims.
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_syncRemoved.html"
);
// Maybe there some better trick here, we need to wait for the page load, then
// wait for the js to execute in the page.
await waitForMs(500);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins"
);
ok(
notification,
"Test 25: There should be a plugin notification even if the plugin was immediately removed"
);
ok(
notification.dismissed,
"Test 25: The notification should be dismissed by default"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>hi</html>"
);
});
// Tests a page with a blocked plugin in it and make sure the infoURL property
// the blocklist file gets used.
add_task(async function() {
clearAllPluginPermissions();
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginInfoURL",
gTestBrowser
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins"
);
// Since the plugin notification is dismissed by default, reshow it.
await promiseForNotificationShown(notification);
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED,
"Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
Assert.ok(!plugin.activated, "Plugin should not be activated.");
});
});

Просмотреть файл

@ -0,0 +1,149 @@
var gTestBrowser = null;
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gChromeRoot = getRootDirectory(gTestPath);
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
// Prime the blocklist service, the remote service doesn't launch on startup.
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
});
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let test = content.document.getElementById("test");
Assert.ok(test.activated, "task 1a: test plugin should be activated!");
});
});
// Load a fresh page, load a new plugin blocklist, then load the same page again.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>GO!</html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard", gTestBrowser);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let test = content.document.getElementById("test");
ok(!test.activated, "task 2a: test plugin shouldn't activate!");
});
});
// Unload the block list and lets do this again, only this time lets
// hack around in the content blocklist service maliciously.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>GO!</html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
// Hack the planet! Load our blocklist shim, so we can mess with blocklist
// return results in the content process. Active until we close our tab.
let base = gChromeRoot.slice(0, -1);
let actor = {
child: {
moduleURI: `${base}/BlocklistTestProxy.jsm`,
observer: ["webnavigation-create"],
},
};
ChromeUtils.registerProcessActor("BlocklistTestProxy", actor);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let test = content.document.getElementById("test");
Assert.ok(test.activated, "task 3a: test plugin should be activated!");
});
registerCleanupFunction(async function() {
let dp =
gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.domProcess;
await dp.getActor("BlocklistTestProxy").sendQuery("unload");
ChromeUtils.unregisterProcessActor("BlocklistTestProxy", actor);
});
});
// Load a fresh page, load a new plugin blocklist, then load the same page again.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>GO!</html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockPluginHard", gTestBrowser);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let test = content.document.getElementById("test");
Assert.ok(!test.activated, "task 4a: test plugin shouldn't activate!");
});
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
});

Просмотреть файл

@ -0,0 +1,135 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
let newTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_CLICKTOPLAY,
"Second Test Plug-in"
);
// Prime the blocklist service, the remote service doesn't launch on startup.
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
});
// Tests that navigation within the page and the window.history API doesn't break click-to-play state.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_add_dynamically.html"
);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(!notification, "Test 1a, Should not have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
});
await promisePopupNotification("click-to-play-plugins");
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementsByTagName("embed")[0];
Assert.ok(!plugin.activated, "Test 1b, Plugin should not be activated");
});
// Click the activate button on doorhanger to make sure it works
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementsByTagName("embed")[0];
Assert.ok(plugin.activated, "Test 1b, Plugin should be activated");
});
});
add_task(async function() {
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 1c, Should still have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
let plugin = content.document.getElementsByTagName("embed")[1];
Assert.ok(
plugin.activated,
"Test 1c, Newly inserted plugin in activated page should be activated"
);
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementsByTagName("embed")[1];
Assert.ok(plugin.activated, "Test 1d, Plugin should be activated");
let promise = ContentTaskUtils.waitForEvent(content, "hashchange");
content.location += "#anchorNavigation";
await promise;
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
let plugin = content.document.getElementsByTagName("embed")[2];
Assert.ok(plugin.activated, "Test 1e, Plugin should be activated");
});
});
add_task(async function() {
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementsByTagName("embed")[2];
Assert.ok(plugin.activated, "Test 1f, Plugin should be activated");
content.history.replaceState({}, "", "replacedState");
new XPCNativeWrapper(XPCNativeWrapper.unwrap(content).addPlugin());
plugin = content.document.getElementsByTagName("embed")[3];
Assert.ok(plugin.activated, "Test 1g, Plugin should be activated");
});
});

Просмотреть файл

@ -0,0 +1,55 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let promisePluginBindingAttached = BrowserTestUtils.waitForContentEvent(
gTestBrowser,
"PluginBindingAttached",
true,
null,
true
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_bug744745.html"
);
await promisePluginBindingAttached;
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
if (!plugin) {
Assert.ok(false, "plugin element not available.");
return;
}
// We can't use MochiKit's routine
let style = content.getComputedStyle(plugin);
Assert.ok(
"opacity" in style && style.opacity == 1,
"plugin style properly configured."
);
});
});

Просмотреть файл

@ -0,0 +1,74 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
var gWrapperClickCount = 0;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
let testRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
testRoot + "plugin_bug787619.html"
);
// Due to layout being async, "PluginBindAttached" may trigger later.
// This forces a layout flush, thus triggering it, and schedules the
// test so it is definitely executed afterwards.
await promiseUpdatePluginBindings(gTestBrowser);
// check plugin state
let pluginInfo = await promiseForPluginInfo("plugin");
ok(!pluginInfo.activated, "1a plugin should not be activated");
// click the overlay to prompt
let promise = promisePopupNotification("click-to-play-plugins");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("plugin");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
await promise;
// check plugin state
pluginInfo = await promiseForPluginInfo("plugin");
ok(!pluginInfo.activated, "1b plugin should not be activated");
let condition = () =>
!PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed && PopupNotifications.panel.firstElementChild;
await promiseForCondition(condition);
PopupNotifications.panel.firstElementChild.button.click();
// check plugin state
pluginInfo = await promiseForPluginInfo("plugin");
ok(pluginInfo.activated, "plugin should be activated");
is(gWrapperClickCount, 0, "wrapper should not have received any clicks");
});

Просмотреть файл

@ -7,6 +7,12 @@ var gConsoleErrors = 0;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
Services.console.unregisterListener(errorListener);
gBrowser.removeCurrentTab();
window.focus();

Просмотреть файл

@ -0,0 +1,133 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [["browser.navigation.requireUserInteraction", false]],
});
registerCleanupFunction(async function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
// Prime the blocklist service, the remote service doesn't launch on startup.
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
});
// Tests that the going back will reshow the notification for click-to-play
// blocklisted plugins
add_task(async function() {
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginVulnerableUpdatable",
gTestBrowser
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
popupNotification,
"test part 1: Should have a click-to-play notification"
);
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"plugin should be marked as VULNERABLE"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
Assert.ok(
!!content.document.getElementById("test"),
"test part 1: plugin should not be activated"
);
});
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
});
add_task(async function() {
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
!popupNotification,
"test part 2: Should not have a click-to-play notification"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
Assert.ok(
!content.document.getElementById("test"),
"test part 2: plugin should not be activated"
);
});
let obsPromise = TestUtils.topicObserved(
"PopupNotifications-updateNotShowing"
);
let overlayPromise = promisePopupNotification("click-to-play-plugins");
gTestBrowser.goBack();
await obsPromise;
await overlayPromise;
});
add_task(async function() {
await promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(
popupNotification,
"test part 3: Should have a click-to-play notification"
);
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE,
"plugin should be marked as VULNERABLE"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
Assert.ok(
!!content.document.getElementById("test"),
"test part 3: plugin should not be activated"
);
});
});

Просмотреть файл

@ -0,0 +1,53 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
gBrowser.removeCurrentTab();
window.focus();
gTestBrowser = null;
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_both.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(popupNotification, "should have a click-to-play notification");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"plugin should be click to play"
);
ok(!pluginInfo.activated, "plugin should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], () => {
let unknown = content.document.getElementById("unknown");
ok(unknown, "should have unknown plugin in page");
});
});

Просмотреть файл

@ -0,0 +1,29 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Plugin Clear Site Data sanitize test</title>
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
<script type="application/javascript">
function testSteps() {
// Make sure clearing by timerange is supported.
var p = document.getElementById("plugin1");
p.setSitesWithDataCapabilities(true);
p.setSitesWithData(
"foo.com:0:5," +
"bar.com:0:100," +
"baz.com:1:5," +
"qux.com:1:100"
);
}
</script>
</head>
<body onload="testSteps();"></body>
</html>

Просмотреть файл

@ -0,0 +1,122 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var gTestBrowser = null;
// Test clearing plugin data using Sanitizer.jsm.
const testURL1 = gTestRoot + "browser_clearplugindata.html";
const testURL2 = gTestRoot + "browser_clearplugindata_noage.html";
const { Sanitizer } = ChromeUtils.import("resource:///modules/Sanitizer.jsm");
const pluginHostIface = Ci.nsIPluginHost;
var pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
pluginHost.QueryInterface(pluginHostIface);
var pluginTag = getTestPlugin();
function stored(needles) {
let something = pluginHost.siteHasData(this.pluginTag, null);
if (!needles) {
return something;
}
if (!something) {
return false;
}
for (let i = 0; i < needles.length; ++i) {
if (!pluginHost.siteHasData(this.pluginTag, needles[i])) {
return false;
}
}
return true;
}
add_task(async function() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
if (gTestBrowser) {
gBrowser.removeCurrentTab();
}
window.focus();
gTestBrowser = null;
});
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
});
function setPrefs(cookies, pluginData) {
let itemPrefs = Services.prefs.getBranch("privacy.cpd.");
itemPrefs.setBoolPref("history", false);
itemPrefs.setBoolPref("downloads", false);
itemPrefs.setBoolPref("cache", false);
itemPrefs.setBoolPref("cookies", cookies);
itemPrefs.setBoolPref("formdata", false);
itemPrefs.setBoolPref("offlineApps", false);
itemPrefs.setBoolPref("passwords", false);
itemPrefs.setBoolPref("sessions", false);
itemPrefs.setBoolPref("siteSettings", false);
itemPrefs.setBoolPref("pluginData", pluginData);
}
async function testClearingData(url) {
// Load page to set data for the plugin.
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
await promiseTabLoadEvent(gBrowser.selectedTab, url);
await promiseUpdatePluginBindings(gTestBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
// Clear 20 seconds ago.
// In the case of testURL2 the plugin will throw
// NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED, which should result in us
// clearing all data regardless of age.
let now_uSec = Date.now() * 1000;
let range = [now_uSec - 20 * 1000000, now_uSec];
await Sanitizer.sanitize(null, { range, ignoreTimespan: false });
if (url == testURL1) {
ok(stored(["bar.com", "qux.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["baz.com"]), "Data cleared for baz.com");
// Clear everything.
await Sanitizer.sanitize(null, { ignoreTimespan: false });
}
ok(!stored(null), "All data cleared");
gBrowser.removeCurrentTab();
gTestBrowser = null;
}
add_task(async function() {
// Test when sanitizing cookies.
await setPrefs(true, false);
await testClearingData(testURL1);
await testClearingData(testURL2);
// Test when sanitizing pluginData.
await setPrefs(false, true);
await testClearingData(testURL1);
await testClearingData(testURL2);
});

Просмотреть файл

@ -0,0 +1,29 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Plugin Clear Site Data sanitize test without age</title>
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
<script type="application/javascript">
function testSteps() {
// Make sure clearing by timerange is disabled.
var p = document.getElementById("plugin1");
p.setSitesWithDataCapabilities(false);
p.setSitesWithData(
"foo.com:0:5," +
"bar.com:0:100," +
"baz.com:1:5," +
"qux.com:1:100"
);
}
</script>
</head>
<body onload="testSteps();"></body>
</html>

Просмотреть файл

@ -0,0 +1,82 @@
"use strict";
const TEST_PLUGIN_NAME = "Test Plug-in";
const HIDDEN_CTP_PLUGIN_PREF = "plugins.navigator.hidden_ctp_plugin";
/**
* If a plugin is click-to-play and named in HIDDEN_CTP_PLUGIN_PREF,
* then the plugin should be hidden in the navigator.plugins list by default
* when iterating.
*/
add_task(async function setup() {
// We'll make the Test Plugin click-to-play.
let originalPluginState = getTestPluginEnabledState();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
registerCleanupFunction(() => {
setTestPluginEnabledState(originalPluginState);
});
// And then make the plugin hidden.
await SpecialPowers.pushPrefEnv({
set: [
[HIDDEN_CTP_PLUGIN_PREF, TEST_PLUGIN_NAME],
["plugins.show_infobar", true],
],
});
});
/**
* Tests that if a plugin is click-to-play and in the
* HIDDEN_CTP_PLUGIN_PREF list, then it shouldn't be visible
* when iterating navigator.plugins.
*/
add_task(async function test_plugin_is_hidden_on_iteration() {
// The plugin should not be visible when we iterate
// navigator.plugins.
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: "http://example.com",
},
async function(browser) {
await SpecialPowers.spawn(browser, [TEST_PLUGIN_NAME], async function(
pluginName
) {
let plugins = Array.from(content.navigator.plugins);
Assert.ok(
plugins.every(p => p.name != pluginName),
"Should not find Test Plugin"
);
});
}
);
// Now clear the HIDDEN_CTP_PLUGIN_PREF temporarily and
// make sure we can see the plugin again.
await SpecialPowers.pushPrefEnv({
set: [[HIDDEN_CTP_PLUGIN_PREF, ""]],
});
// Note that I have to do this in a new tab since navigator
// caches navigator.plugins after an initial read.
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: "http://example.com",
},
async function(browser) {
await SpecialPowers.spawn(browser, [TEST_PLUGIN_NAME], async function(
pluginName
) {
let plugins = Array.from(content.navigator.plugins);
Assert.ok(
plugins.some(p => p.name == pluginName),
"Should have found the Test Plugin"
);
});
}
);
await SpecialPowers.popPrefEnv();
});

Просмотреть файл

@ -0,0 +1,315 @@
/* global gBrowser */
ChromeUtils.import("resource://gre/modules/CrashSubmit.jsm", this);
const SERVER_URL =
"http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
var config = {};
add_task(async function() {
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
// crash reports. This test needs them enabled. The test also needs a mock
// report server, and fortunately one is already set up by toolkit/
// crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
// which CrashSubmit.jsm uses as a server override.
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
// Crash immediately
Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 0);
registerCleanupFunction(async function() {
Services.prefs.clearUserPref("dom.ipc.plugins.timeoutSecs");
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
env.set("MOZ_CRASHREPORTER_URL", serverUrl);
env = null;
config = null;
gTestBrowser = null;
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
config = {
shouldSubmissionUIBeVisible: true,
comment: "",
urlOptIn: false,
};
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
let pluginCrashed = promisePluginCrashed();
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_crashCommentAndURL.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
// Wait for the plugin to crash
await pluginCrashed;
let crashReportStatus = TestUtils.topicObserved(
"crash-report-status",
onSubmitStatus
);
// Test that the crash submission UI is actually visible and submit the crash report.
await SpecialPowers.spawn(gTestBrowser, [config], async function(aConfig) {
let doc = content.document;
let plugin = doc.getElementById("plugin");
let pleaseSubmit = plugin.openOrClosedShadowRoot.getElementById(
"pleaseSubmit"
);
let submitButton = plugin.openOrClosedShadowRoot.getElementById(
"submitButton"
);
// Test that we don't send the URL when urlOptIn is false.
plugin.openOrClosedShadowRoot.getElementById("submitURLOptIn").checked =
aConfig.urlOptIn;
submitButton.click();
Assert.equal(
content.getComputedStyle(pleaseSubmit).display == "block",
aConfig.shouldSubmissionUIBeVisible,
"The crash UI should be visible"
);
});
await crashReportStatus;
});
add_task(async function() {
config = {
shouldSubmissionUIBeVisible: true,
comment: "a test comment",
urlOptIn: true,
};
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
let pluginCrashed = promisePluginCrashed();
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_crashCommentAndURL.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
// Wait for the plugin to crash
await pluginCrashed;
let crashReportStatus = TestUtils.topicObserved(
"crash-report-status",
onSubmitStatus
);
// Test that the crash submission UI is actually visible and submit the crash report.
await SpecialPowers.spawn(gTestBrowser, [config], async function(aConfig) {
let doc = content.document;
let plugin = doc.getElementById("plugin");
let pleaseSubmit = plugin.openOrClosedShadowRoot.getElementById(
"pleaseSubmit"
);
let submitButton = plugin.openOrClosedShadowRoot.getElementById(
"submitButton"
);
// Test that we send the URL when urlOptIn is true.
plugin.openOrClosedShadowRoot.getElementById("submitURLOptIn").checked =
aConfig.urlOptIn;
plugin.openOrClosedShadowRoot.getElementById("submitComment").value =
aConfig.comment;
submitButton.click();
Assert.equal(
content.getComputedStyle(pleaseSubmit).display == "block",
aConfig.shouldSubmissionUIBeVisible,
"The crash UI should be visible"
);
});
await crashReportStatus;
});
add_task(async function() {
config = {
shouldSubmissionUIBeVisible: false,
comment: "",
urlOptIn: true,
};
// Deferred promise object used by the test to wait for the crash handler
let crashDeferred = PromiseUtils.defer();
// Clear out any minidumps we create from plugin crashes, this is needed
// because we do not submit the crash otherwise the submission process would
// have deleted the crash dump files for us.
let crashObserver = (subject, topic, data) => {
if (topic != "plugin-crashed") {
return;
}
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
let additionalDumps = propBag.getPropertyAsACString("additionalMinidumps");
Services.crashmanager.ensureCrashIsPresent(minidumpID).then(() => {
let minidumpDir = Services.dirsvc.get("UAppData", Ci.nsIFile);
minidumpDir.append("Crash Reports");
minidumpDir.append("pending");
let pluginDumpFile = minidumpDir.clone();
pluginDumpFile.append(minidumpID + ".dmp");
let extraFile = minidumpDir.clone();
extraFile.append(minidumpID + ".extra");
pluginDumpFile.remove(false);
extraFile.remove(false);
if (additionalDumps.length) {
const names = additionalDumps.split(",");
for (const name of names) {
let additionalDumpFile = minidumpDir.clone();
additionalDumpFile.append(minidumpID + "-" + name + ".dmp");
additionalDumpFile.remove(false);
}
}
crashDeferred.resolve();
});
};
Services.obs.addObserver(crashObserver, "plugin-crashed");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
let pluginCrashed = promisePluginCrashed();
// Make sure that the plugin container is too small to display the crash submission UI
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot +
"plugin_crashCommentAndURL.html?" +
encodeURIComponent(JSON.stringify({ width: 300, height: 300 }))
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
// Wait for the plugin to crash
await pluginCrashed;
// Test that the crash submission UI is not visible and do not submit a crash report.
await SpecialPowers.spawn(gTestBrowser, [config], async function(aConfig) {
let doc = content.document;
let plugin = doc.getElementById("plugin");
let pleaseSubmit = plugin.openOrClosedShadowRoot.getElementById(
"pleaseSubmit"
);
Assert.equal(
!!pleaseSubmit &&
content.getComputedStyle(pleaseSubmit).display == "block",
aConfig.shouldSubmissionUIBeVisible,
"Plugin crash UI should not be visible"
);
});
await crashDeferred.promise;
Services.obs.removeObserver(crashObserver, "plugin-crashed");
});
function promisePluginCrashed() {
return new ContentTask.spawn(gTestBrowser, {}, async function() {
await new Promise(resolve => {
addEventListener(
"PluginCrashReporterDisplayed",
function onPluginCrashed() {
removeEventListener("PluginCrashReporterDisplayed", onPluginCrashed);
resolve();
}
);
});
});
}
function onSubmitStatus(aSubject, aData) {
if (aData === "submitting") {
return false;
}
is(aData, "success", "The crash report should be submitted successfully");
let propBag = aSubject.QueryInterface(Ci.nsIPropertyBag);
if (aData == "success") {
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
ok(!!remoteID, "serverCrashID should be set");
// Remove the submitted report file.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath(Services.crashmanager._submittedDumpsDir);
file.append(remoteID + ".txt");
ok(file.exists(), "Submitted report file should exist");
file.remove(false);
}
let extra = getPropertyBagValue(propBag, "extra");
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
let val = getPropertyBagValue(extra, "PluginUserComment");
if (config.comment) {
is(
val,
config.comment,
"Comment in extra data should match comment in textbox"
);
} else {
ok(
val === undefined,
"Comment should be absent from extra data when textbox is empty"
);
}
val = getPropertyBagValue(extra, "PluginContentURL");
if (config.urlOptIn) {
is(
val,
gBrowser.currentURI.spec,
"URL in extra data should match browser URL when opt-in checked"
);
} else {
ok(
val === undefined,
"URL should be absent from extra data when opt-in not checked"
);
}
return true;
}
function getPropertyBagValue(bag, key) {
try {
var val = bag.getProperty(key);
} catch (e) {
if (e.result != Cr.NS_ERROR_FAILURE) {
throw e;
}
}
return val;
}

Просмотреть файл

@ -0,0 +1,321 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const { PromiseUtils } = ChromeUtils.import(
"resource://gre/modules/PromiseUtils.jsm"
);
const { PluginManager } = ChromeUtils.import(
"resource:///actors/PluginParent.jsm"
);
/**
* With e10s, plugins must run in their own process. This means we have
* three processes at a minimum when we're running a plugin:
*
* 1) The main browser, or "chrome" process
* 2) The content process hosting the plugin instance
* 3) The plugin process
*
* If the plugin process crashes, we cannot be sure if the chrome process
* will hear about it first, or the content process will hear about it
* first. Because of how IPC works, that's really up to the operating system,
* and we assume any guarantees about it, so we have to account for both
* possibilities.
*
* This test exercises the browser's reaction to both possibilities.
*/
const CRASH_URL =
"http://example.com/browser/browser/base/content/test/plugins/plugin_crashCommentAndURL.html";
/**
* In order for our test to work, we need to be able to put a plugin
* in a very specific state. Specifically, we need it to match the
* :-moz-handler-crashed pseudoselector. The only way I can find to
* do that is by actually crashing the plugin. So we wait for the
* plugin to crash and show the "please" state (since that will
* only show if both the message from the parent has been received
* AND the PluginCrashed event has fired).
*
* Once in that state, we try to rewind the clock a little bit - we clear
* out the crashData cache in the PluginContent with a message, and we also
* override the pluginFallbackState of the <object> to fool PluginContent
* into believing that the plugin is in a particular state.
*
* @param browser
* The browser that has loaded the CRASH_URL that we need to
* prepare to be in the special state.
* @param pluginFallbackState
* The value we should override the <object>'s pluginFallbackState
* with.
* @return Promise
* The Promise resolves when the plugin has officially been put into
* the crash reporter state, and then "rewound" to have the "status"
* attribute of the statusDiv removed. The resolved Promise returns
* the run ID for the crashed plugin. It rejects if we never get into
* the crash reporter state.
*/
function preparePlugin(browser, pluginFallbackState) {
return SpecialPowers.spawn(browser, [pluginFallbackState], async function(
contentPluginFallbackState
) {
let plugin = content.document.getElementById("plugin");
// CRASH_URL will load a plugin that crashes immediately. We
// wait until the plugin has finished being put into the crash
// state.
let statusDiv;
await ContentTaskUtils.waitForCondition(() => {
statusDiv = plugin.openOrClosedShadowRoot.getElementById("submitStatus");
return statusDiv && statusDiv.getAttribute("status") == "please";
}, "Timed out waiting for plugin to be in crash report state");
// "Rewind", by wiping out the status attribute...
statusDiv.removeAttribute("status");
// Somehow, I'm able to get away with overriding the getter for
// this XPCOM object. Probably because I've got chrome privledges.
Object.defineProperty(plugin, "pluginFallbackType", {
get() {
return contentPluginFallbackState;
},
});
return plugin.runID;
}).then(runID => {
let { currentWindowGlobal } = browser.frameLoader.browsingContext;
currentWindowGlobal
.getActor("Plugin")
.sendAsyncMessage("PluginParent:Test:ClearCrashData");
return runID;
});
}
// Bypass click-to-play
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
// Deferred promise object used by the test to wait for the crash handler
let crashDeferred = null;
// Clear out any minidumps we create from plugins - we really don't care
// about them.
let crashObserver = (subject, topic, data) => {
if (topic != "plugin-crashed") {
return;
}
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
let additionalMinidumps = propBag.getPropertyAsACString(
"additionalMinidumps"
);
Services.crashmanager.ensureCrashIsPresent(minidumpID).then(() => {
let minidumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
minidumpDir.append("minidumps");
let pluginDumpFile = minidumpDir.clone();
pluginDumpFile.append(minidumpID + ".dmp");
let extraFile = minidumpDir.clone();
extraFile.append(minidumpID + ".extra");
ok(pluginDumpFile.exists(), "Found minidump");
ok(extraFile.exists(), "Found extra file");
pluginDumpFile.remove(false);
extraFile.remove(false);
if (additionalMinidumps.length) {
const names = additionalMinidumps.split(",");
for (const name of names) {
let additionalDumpFile = minidumpDir.clone();
additionalDumpFile.append(minidumpID + "-" + name + ".dmp");
additionalDumpFile.remove(false);
}
}
crashDeferred.resolve();
});
};
Services.obs.addObserver(crashObserver, "plugin-crashed");
// plugins.testmode will make PluginParent:Test:ClearCrashData work.
Services.prefs.setBoolPref("plugins.testmode", true);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("plugins.testmode");
Services.obs.removeObserver(crashObserver, "plugin-crashed");
});
/**
* In this case, the chrome process hears about the crash first.
*/
add_task(async function testChromeHearsPluginCrashFirst() {
// Setup the crash observer promise
crashDeferred = PromiseUtils.defer();
// Open a remote window so that we can run this test even if e10s is not
// enabled by default.
let win = await BrowserTestUtils.openNewBrowserWindow({ remote: true });
let browser = win.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(browser, CRASH_URL);
await BrowserTestUtils.browserLoaded(browser);
// In this case, we want the <object> to match the -moz-handler-crashed
// pseudoselector, but we want it to seem still active, because the
// content process is not yet supposed to know that the plugin has
// crashed.
await preparePlugin(browser, Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE);
// In this case, the parent responds immediately when the child asks
// for crash data. in `testContentHearsCrashFirst we will delay the
// response (simulating what happens if the parent doesn't know about
// the crash yet).
await SpecialPowers.spawn(browser, [], async function() {
// At this point, the content process should have heard the
// plugin crash message from the parent, and we are OK to emit
// the PluginCrashed event.
let plugin = content.document.getElementById("plugin");
let statusDiv = plugin.openOrClosedShadowRoot.getElementById(
"submitStatus"
);
if (statusDiv.getAttribute("status") == "please") {
Assert.ok(false, "Did not expect plugin to be in crash report mode yet.");
return;
}
// Now we need the plugin to seem crashed to the child actor, without
// actually crashing the plugin again. We hack around this by overriding
// the pluginFallbackType again.
Object.defineProperty(plugin, "pluginFallbackType", {
get() {
return Ci.nsIObjectLoadingContent.PLUGIN_CRASHED;
},
});
let event = new content.PluginCrashedEvent("PluginCrashed", {
pluginName: "",
pluginDumpID: "",
submittedCrashReport: false,
bubbles: true,
cancelable: true,
});
plugin.dispatchEvent(event);
// The plugin child actor will go fetch crash info in the parent. Wait
// for it to come back:
await ContentTaskUtils.waitForCondition(
() => statusDiv.getAttribute("status") == "please"
);
Assert.equal(
statusDiv.getAttribute("status"),
"please",
"Should have been showing crash report UI"
);
});
await BrowserTestUtils.closeWindow(win);
await crashDeferred.promise;
});
/**
* In this case, the content process hears about the crash first.
*/
add_task(async function testContentHearsCrashFirst() {
// Setup the crash observer promise
crashDeferred = PromiseUtils.defer();
// Open a remote window so that we can run this test even if e10s is not
// enabled by default.
let win = await BrowserTestUtils.openNewBrowserWindow({ remote: true });
let browser = win.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(browser, CRASH_URL);
await BrowserTestUtils.browserLoaded(browser);
// In this case, we want the <object> to match the -moz-handler-crashed
// pseudoselector, and we want the plugin to seem crashed, since the
// content process in this case has heard about the crash first.
let runID = await preparePlugin(
browser,
Ci.nsIObjectLoadingContent.PLUGIN_CRASHED
);
// We resolve this promise when we're ready to tell the child from the parent.
let allowParentToRespond = PromiseUtils.defer();
// This promise is resolved as soon as we're contacted by the child.
// It forces the parent not to respond until `allowParentToRespond` has been
// resolved.
let parentRequestPromise = new Promise(resolve => {
PluginManager.mockResponse(browser, function(data) {
resolve(data);
return allowParentToRespond.promise.then(() => {
return { pluginName: "", runID, state: "please" };
});
});
});
await SpecialPowers.spawn(browser, [], async function() {
// At this point, the content process has not yet heard from the
// parent about the crash report. Let's ensure that by making sure
// we're not showing the plugin crash report UI.
let plugin = content.document.getElementById("plugin");
let statusDiv = plugin.openOrClosedShadowRoot.getElementById(
"submitStatus"
);
if (statusDiv.getAttribute("status") == "please") {
Assert.ok(false, "Did not expect plugin to be in crash report mode yet.");
}
let event = new content.PluginCrashedEvent("PluginCrashed", {
pluginName: "",
pluginDumpID: "",
submittedCrashReport: false,
bubbles: true,
cancelable: true,
});
plugin.dispatchEvent(event);
});
let receivedData = await parentRequestPromise;
is(receivedData.runID, runID, "Should get a request for the same crash.");
await SpecialPowers.spawn(browser, [], function() {
let plugin = content.document.getElementById("plugin");
let statusDiv = plugin.openOrClosedShadowRoot.getElementById(
"submitStatus"
);
Assert.notEqual(
statusDiv.getAttribute("status"),
"please",
"Should not yet be showing crash report UI"
);
});
// Now allow the parent to respond to the child with crash info:
allowParentToRespond.resolve();
await SpecialPowers.spawn(browser, [], async function() {
// At this point, the content process will have heard the message
// from the parent and reacted to it. We should be showing the plugin
// crash report UI now.
let plugin = content.document.getElementById("plugin");
let statusDiv = plugin.openOrClosedShadowRoot.getElementById(
"submitStatus"
);
await ContentTaskUtils.waitForCondition(() => {
return statusDiv && statusDiv.getAttribute("status") == "please";
});
Assert.equal(
statusDiv.getAttribute("status"),
"please",
"Should have been showing crash report UI"
);
});
await BrowserTestUtils.closeWindow(win);
await crashDeferred.promise;
});

Просмотреть файл

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"https://example.com/"
);
/**
* Verify that giving permission to a plugin works based on the toplevel
* page's principal, so that permissions meant for framed plugins persist
* correctly for the duration of the session.
*/
add_task(async function test_toplevel_frame_permission() {
await BrowserTestUtils.withNewTab(
gTestRoot + "empty_file.html",
async browser => {
// Add a cross-origin iframe and return when it's loaded.
await SpecialPowers.spawn(browser.browsingContext, [], async function() {
let doc = content.document;
let iframe = doc.createElement("iframe");
let loadPromise = ContentTaskUtils.waitForEvent(iframe, "load");
iframe.src = doc.location.href.replace(".com/", ".org/");
doc.body.appendChild(iframe);
// Note that we cannot return (rather than await) loadPromise, because
// it resolves with the event, which isn't structured-clonable.
await loadPromise;
});
// Show a plugin notification from the iframe's actor:
let { currentWindowGlobal } = browser.browsingContext.children[0];
let actor = currentWindowGlobal.getActor("Plugin");
const kHost = Cc["@mozilla.org/plugin/host;1"].getService(
Ci.nsIPluginHost
);
const { PLUGIN_CLICK_TO_PLAY } = Ci.nsIObjectLoadingContent;
let plugin = kHost.getPluginTags()[0];
actor.showClickToPlayNotification(
browser,
{ id: plugin.id, fallbackType: PLUGIN_CLICK_TO_PLAY },
false /* showNow */
);
// Check that it is associated with the toplevel origin (.com), not
// the subframe's origin (.org):
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
browser
);
is(
notification.options.principal.host,
"example.com",
"Should use top host for permission prompt!"
);
}
);
});

Просмотреть файл

@ -0,0 +1,113 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var gTestBrowser = null;
function updateAllTestPlugins(aState) {
setTestPluginEnabledState(aState, "Test Plug-in");
setTestPluginEnabledState(aState, "Second Test Plug-in");
}
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gTestBrowser = null;
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
// Prime the blocklist service, the remote service doesn't launch on startup.
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
});
// Tests that a click-to-play plugin retains its activated state upon reloading
add_task(async function() {
clearAllPluginPermissions();
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 1, Should have a click-to-play notification");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 2, plugin fallback type should be PLUGIN_CLICK_TO_PLAY"
);
// run the plugin
await promisePlayObject("test");
await promiseUpdatePluginBindings(gTestBrowser);
pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.displayedType,
Ci.nsIObjectLoadingContent.TYPE_PLUGIN,
"Test 3, plugin should have started"
);
ok(pluginInfo.activated, "Test 4, plugin node should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let npobj1 = Cu.waiveXrays(plugin).getObjectValue();
// eslint-disable-next-line no-self-assign
plugin.src = plugin.src;
let pluginsDiffer = false;
try {
Cu.waiveXrays(plugin).checkObjectValue(npobj1);
} catch (e) {
pluginsDiffer = true;
}
Assert.ok(pluginsDiffer, "Test 5, plugins differ.");
});
pluginInfo = await promiseForPluginInfo("test");
ok(
pluginInfo.activated,
"Test 6, Plugin should have retained activated state."
);
is(
pluginInfo.displayedType,
Ci.nsIObjectLoadingContent.TYPE_PLUGIN,
"Test 7, plugin should have started"
);
});

Просмотреть файл

@ -0,0 +1,626 @@
var gTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var gTestBrowser = null;
function updateAllTestPlugins(aState) {
setTestPluginEnabledState(aState, "Test Plug-in");
setTestPluginEnabledState(aState, "Second Test Plug-in");
}
add_task(async function() {
registerCleanupFunction(async function() {
clearAllPluginPermissions();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
setTestPluginEnabledState(
Ci.nsIPluginTag.STATE_ENABLED,
"Second Test Plug-in"
);
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockNoPlugins",
gTestBrowser
);
gTestBrowser = null;
gBrowser.removeCurrentTab();
window.focus();
});
});
add_task(async function() {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gTestBrowser = gBrowser.selectedBrowser;
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
// Prime the blocklist service, the remote service doesn't launch on startup.
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html></html>"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
});
// Tests a page with an unknown plugin in it.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_unknown.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("unknown");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED,
"Test 1a, plugin fallback type should be PLUGIN_UNSUPPORTED"
);
});
// Test that the doorhanger is shown when the user clicks on the overlay
// after having previously blocked the plugin.
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Plugin should not be activated");
// Simulate clicking the "Allow" button.
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Plugin should be activated");
// Simulate clicking the "Block" button.
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.secondaryButton.click();
pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Plugin should not be activated");
let browserLoaded = BrowserTestUtils.browserLoaded(gTestBrowser);
gTestBrowser.reload();
await browserLoaded;
notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
// Simulate clicking the overlay
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.openOrClosedShadowRoot
.getElementById("main")
.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
ok(!notification.dismissed, "A plugin notification should be shown.");
clearAllPluginPermissions();
});
// Tests that going back will reshow the notification for click-to-play plugins
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>hi</html>"
);
// make sure the notification is gone
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(!notification, "Test 11b, Should not have a click-to-play notification");
gTestBrowser.webNavigation.goBack();
await promisePopupNotification("click-to-play-plugins");
});
// Tests that the "Allow Always" permission works for click-to-play plugins
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 12a, Plugin should not be activated");
// Simulate clicking the "Allow" button.
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
await promiseForNotificationShown(notification);
PopupNotifications.panel.firstElementChild.button.click();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 12a, Plugin should be activated");
});
// Test that the "Always" permission, when set for just the Test plugin,
// does not also allow the Second Test plugin.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_two_types.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
await promisePopupNotification("click-to-play-plugins");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let test = content.document.getElementById("test");
let secondtestA = content.document.getElementById("secondtestA");
let secondtestB = content.document.getElementById("secondtestB");
Assert.ok(
test.activated && !secondtestA.activated && !secondtestB.activated,
"Content plugins are set up"
);
});
clearAllPluginPermissions();
});
// Tests that the plugin's "activated" property is true for working plugins
// with click-to-play disabled.
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_ENABLED);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test2.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("test1");
ok(pluginInfo.activated, "Test 14, Plugin should be activated");
});
// Tests that the overlay is shown instead of alternate content when
// plugins are click to play.
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_alternate_content.html"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let mainBox = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(!!mainBox, "Test 15, Plugin overlay should exist");
});
});
// Tests that mContentType is used for click-to-play plugins, and not the
// inspected type.
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_bug749455.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 17, Should have a click-to-play notification");
});
// Tests that clicking the icon of the overlay activates the doorhanger
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
await asyncSetAndUpdateBlocklist(gTestRoot + "blockNoPlugins", gTestBrowser);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
ok(
PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed,
"Test 19a, Doorhanger should start out dismissed"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let icon = plugin.openOrClosedShadowRoot.getElementById("icon");
let bounds = icon.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
let condition = () =>
!PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed;
await promiseForCondition(condition);
});
// Tests that clicking the text of the overlay activates the plugin
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
ok(
PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed,
"Test 19c, Doorhanger should start out dismissed"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let text = plugin.openOrClosedShadowRoot.getElementById("clickToPlay");
let bounds = text.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
let condition = () =>
!PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed;
await promiseForCondition(condition);
});
// Tests that clicking the box of the overlay activates the doorhanger
// (just to be thorough)
add_task(async function() {
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 18g, Plugin should not be activated");
ok(
PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed,
"Test 19e, Doorhanger should start out dismissed"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", 50, 50, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", 50, 50, 0, 1, 0, false, 0, 0);
});
let condition = () =>
!PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser)
.dismissed && PopupNotifications.panel.firstElementChild;
await promiseForCondition(condition);
PopupNotifications.panel.firstElementChild.button.click();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 19e, Plugin should not be activated");
clearAllPluginPermissions();
});
// Tests that a plugin in a div that goes from style="display: none" to
// "display: block" can be clicked to activate.
add_task(async function() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_hidden_to_visible.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 20a, Should have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let overlay = plugin.openOrClosedShadowRoot.getElementById("main");
Assert.ok(!!overlay, "Test 20a, Plugin overlay should exist");
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let mainBox = plugin.openOrClosedShadowRoot.getElementById("main");
let overlayRect = mainBox.getBoundingClientRect();
Assert.ok(
overlayRect.width == 0 && overlayRect.height == 0,
"Test 20a, plugin should have an overlay with 0px width and height"
);
});
let pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 20b, plugin should not be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let div = doc.getElementById("container");
Assert.equal(
div.style.display,
"none",
"Test 20b, container div should be display: none"
);
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let div = doc.getElementById("container");
div.style.display = "block";
});
await SpecialPowers.spawn(gTestBrowser, [], async function() {
// Waiting for layout to flush and the overlay layout to compute
await new Promise(resolve => content.requestAnimationFrame(resolve));
await new Promise(resolve => content.requestAnimationFrame(resolve));
let doc = content.document;
let plugin = doc.getElementById("test");
let mainBox = plugin.openOrClosedShadowRoot.getElementById("main");
let overlayRect = mainBox.getBoundingClientRect();
Assert.ok(
overlayRect.width == 200 && overlayRect.height == 200,
"Test 20c, plugin should have overlay dims of 200px"
);
});
pluginInfo = await promiseForPluginInfo("test");
ok(!pluginInfo.activated, "Test 20b, plugin should not be activated");
ok(notification.dismissed, "Test 20c, Doorhanger should start out dismissed");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
let bounds = plugin.getBoundingClientRect();
let left = (bounds.left + bounds.right) / 2;
let top = (bounds.top + bounds.bottom) / 2;
let utils = content.windowUtils;
utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
});
let condition = () =>
!notification.dismissed && !!PopupNotifications.panel.firstElementChild;
await promiseForCondition(condition);
PopupNotifications.panel.firstElementChild.button.click();
pluginInfo = await promiseForPluginInfo("test");
ok(pluginInfo.activated, "Test 20c, plugin should be activated");
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
Assert.ok(
!plugin.openOrClosedShadowRoot,
"Test 20c, CTP UA Widget Shadow Root is removed"
);
});
clearAllPluginPermissions();
});
// Tests that a click-to-play plugin resets its activated state when changing types
add_task(async function() {
clearAllPluginPermissions();
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(notification, "Test 22, Should have a click-to-play notification");
// Plugin should start as CTP
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 23, plugin fallback type should be PLUGIN_CLICK_TO_PLAY"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
plugin.type = null;
// We currently don't properly change state just on type change,
// so rebind the plugin to tree. bug 767631
plugin.parentNode.appendChild(plugin);
});
pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.displayedType,
Ci.nsIObjectLoadingContent.TYPE_NULL,
"Test 23, plugin should be TYPE_NULL"
);
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let doc = content.document;
let plugin = doc.getElementById("test");
plugin.type = "application/x-test";
plugin.parentNode.appendChild(plugin);
});
pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.displayedType,
Ci.nsIObjectLoadingContent.TYPE_NULL,
"Test 23, plugin should be TYPE_NULL"
);
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
"Test 23, plugin fallback type should be PLUGIN_CLICK_TO_PLAY"
);
ok(!pluginInfo.activated, "Test 23, plugin node should not be activated");
});
// Plugin sync removal test. Note this test produces a notification drop down since
// the plugin we add has zero dims.
add_task(async function blockPluginSyncRemoved() {
updateAllTestPlugins(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_syncRemoved.html"
);
// Maybe there some better trick here, we need to wait for the page load, then
// wait for the js to execute in the page.
await waitForMs(500);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins"
);
ok(
notification,
"Test 25: There should be a plugin notification even if the plugin was immediately removed"
);
ok(
notification.dismissed,
"Test 25: The notification should be dismissed by default"
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
"data:text/html,<html>hi</html>"
);
});
// Tests a page with a blocked plugin in it and make sure the infoURL property
// the blocklist file gets used.
add_task(async function blockPluginInfoURL() {
clearAllPluginPermissions();
await asyncSetAndUpdateBlocklist(
gTestRoot + "blockPluginInfoURL",
gTestBrowser
);
await promiseTabLoadEvent(
gBrowser.selectedTab,
gTestRoot + "plugin_test.html"
);
// Work around for delayed PluginBindingAttached
info("Waiting for plugin bindings");
await promiseUpdatePluginBindings(gTestBrowser);
let notification = PopupNotifications.getNotification(
"click-to-play-plugins"
);
info("Waiting for notification to be shown");
// Since the plugin notification is dismissed by default, reshow it.
await promiseForNotificationShown(notification);
info("Waiting for plugin info");
let pluginInfo = await promiseForPluginInfo("test");
is(
pluginInfo.pluginFallbackType,
Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED,
"Test 26, plugin fallback type should be PLUGIN_BLOCKLISTED"
);
ok(!pluginInfo.activated, "Plugin should be activated.");
});

Просмотреть файл

@ -0,0 +1,268 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var gPrivateWindow = null;
var gPrivateBrowser = null;
function finishTest() {
clearAllPluginPermissions();
gBrowser.removeCurrentTab();
if (gPrivateWindow) {
gPrivateWindow.close();
}
window.focus();
}
let createPrivateWindow = async function createPrivateWindow(url) {
gPrivateWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
ok(!!gPrivateWindow, "should have created a private window.");
gPrivateBrowser = gPrivateWindow.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(gPrivateBrowser, url);
await BrowserTestUtils.browserLoaded(gPrivateBrowser, false, url);
info("loaded " + url);
};
add_task(async function test() {
registerCleanupFunction(function() {
clearAllPluginPermissions();
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
getTestPlugin("Second Test Plug-in").enabledState =
Ci.nsIPluginTag.STATE_ENABLED;
});
// This test works under the assumption that private browsing windows
// share permissions with regular windows. Setting a pref to revert to this
// behavior. The test should be updated and the pref overwrite removed.
// See Bug 1588457
await SpecialPowers.pushPrefEnv({
set: [["permissions.isolateBy.privateBrowsing", false]],
});
let newTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
let promise = BrowserTestUtils.browserLoaded(gTestBrowser);
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
getTestPlugin("Second Test Plug-in").enabledState =
Ci.nsIPluginTag.STATE_CLICKTOPLAY;
await promise;
});
add_task(async function test1a() {
await createPrivateWindow(gHttpTestRoot + "plugin_test.html");
});
add_task(async function test1b() {
let popupNotification = gPrivateWindow.PopupNotifications.getNotification(
"click-to-play-plugins",
gPrivateBrowser
);
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
await SpecialPowers.spawn(gPrivateBrowser, [], function() {
let plugin = content.document.getElementById("test");
ok(!plugin.activated, "Test 1b, Plugin should not be activated");
});
// Check the button status
let promiseShown = BrowserTestUtils.waitForEvent(
gPrivateWindow.PopupNotifications.panel,
"Shown"
);
popupNotification.reshow();
await promiseShown;
is(
gPrivateWindow.PopupNotifications.panel.firstElementChild.checkbox.hidden,
true,
"'Remember' checkbox should be hidden in private windows"
);
let promises = [
BrowserTestUtils.browserLoaded(
gTestBrowser,
false,
gHttpTestRoot + "plugin_test.html"
),
BrowserTestUtils.waitForEvent(window, "activate"),
];
gPrivateWindow.close();
BrowserTestUtils.loadURI(gTestBrowser, gHttpTestRoot + "plugin_test.html");
await Promise.all(promises);
await SimpleTest.promiseFocus(window);
});
add_task(async function test2a() {
// enable test plugin on this site
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(popupNotification, "Test 2a, Should have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], function() {
let plugin = content.document.getElementById("test");
ok(!plugin.activated, "Test 2a, Plugin should not be activated");
});
// Simulate clicking the "Allow Now" button.
let promiseShown = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"Shown"
);
popupNotification.reshow();
await promiseShown;
PopupNotifications.panel.firstElementChild.button.click();
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let condition = () => plugin.activated;
await ContentTaskUtils.waitForCondition(
condition,
"Test 2a, Waited too long for plugin to activate"
);
});
});
add_task(async function test2c() {
let topicObserved = TestUtils.topicObserved(
"PopupNotifications-updateNotShowing"
);
await createPrivateWindow(gHttpTestRoot + "plugin_test.html");
await topicObserved;
let popupNotification = await TestUtils.waitForCondition(() => {
return gPrivateWindow.PopupNotifications.getNotification(
"click-to-play-plugins",
gPrivateBrowser
);
}, "Waiting for click-to-play-plugins notification in the private window");
ok(popupNotification, "Test 2c, Should have a click-to-play notification");
await SpecialPowers.spawn(gPrivateBrowser, [], function() {
let plugin = content.document.getElementById("test");
ok(plugin.activated, "Test 2c, Plugin should be activated");
});
// Check the button status
let promiseShown = BrowserTestUtils.waitForEvent(
gPrivateWindow.PopupNotifications.panel,
"Shown"
);
popupNotification.reshow();
await promiseShown;
is(
gPrivateWindow.PopupNotifications.panel.firstElementChild.secondaryButton
.hidden,
false,
"Test 2c, Activated plugin in a private window should have visible 'Block' button."
);
is(
gPrivateWindow.PopupNotifications.panel.firstElementChild.checkbox.hidden,
true,
"Test 2c, Activated plugin in a private window should not have visible 'Remember' checkbox."
);
clearAllPluginPermissions();
let promises = [
BrowserTestUtils.browserLoaded(
gTestBrowser,
false,
gHttpTestRoot + "plugin_test.html"
),
BrowserTestUtils.waitForEvent(window, "activate"),
];
gPrivateWindow.close();
BrowserTestUtils.loadURI(gTestBrowser, gHttpTestRoot + "plugin_test.html");
await Promise.all(promises);
await SimpleTest.promiseFocus(window);
});
add_task(async function test3a() {
// enable test plugin on this site
let popupNotification = PopupNotifications.getNotification(
"click-to-play-plugins",
gTestBrowser
);
ok(popupNotification, "Test 3a, Should have a click-to-play notification");
await SpecialPowers.spawn(gTestBrowser, [], function() {
let plugin = content.document.getElementById("test");
ok(!plugin.activated, "Test 3a, Plugin should not be activated");
});
// Simulate clicking the "Allow" button.
let promiseShown = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"Shown"
);
popupNotification.reshow();
await promiseShown;
PopupNotifications.panel.firstElementChild.button.click();
await SpecialPowers.spawn(gTestBrowser, [], async function() {
let plugin = content.document.getElementById("test");
let condition = () => plugin.activated;
await ContentTaskUtils.waitForCondition(
condition,
"Test 3a, Waited too long for plugin to activate"
);
});
});
add_task(async function test3c() {
let topicObserved = TestUtils.topicObserved(
"PopupNotifications-updateNotShowing"
);
await createPrivateWindow(gHttpTestRoot + "plugin_test.html");
await topicObserved;
let popupNotification = await TestUtils.waitForCondition(() => {
return gPrivateWindow.PopupNotifications.getNotification(
"click-to-play-plugins",
gPrivateBrowser
);
}, "Waiting for click-to-play-plugins notification in the private window");
ok(popupNotification, "Test 3c, Should have a click-to-play notification");
// Check the button status
let promiseShown = BrowserTestUtils.waitForEvent(
gPrivateWindow.PopupNotifications.panel,
"Shown"
);
popupNotification.reshow();
await promiseShown;
is(
gPrivateWindow.PopupNotifications.panel.firstElementChild.secondaryButton
.hidden,
false,
"Test 3c, Activated plugin in a private window should have visible 'Block' button."
);
is(
gPrivateWindow.PopupNotifications.panel.firstElementChild.checkbox.hidden,
true,
"Test 3c, Activated plugin in a private window should not have visible 'Remember' checkbox."
);
BrowserTestUtils.loadURI(
gPrivateBrowser,
gHttpTestRoot + "plugin_two_types.html"
);
await BrowserTestUtils.browserLoaded(gPrivateBrowser);
finishTest();
});

Просмотреть файл

@ -0,0 +1,94 @@
"use strict";
const TEST_PLUGIN_NAME = "Test Plug-in";
const HIDDEN_CTP_PLUGIN_PREF = "plugins.navigator.hidden_ctp_plugin";
const DOMAIN_1 = "http://example.com";
const DOMAIN_2 = "http://mochi.test:8888";
/**
* If a plugin is click-to-play and named in HIDDEN_CTP_PLUGIN_PREF,
* then the plugin should be hidden in the navigator.plugins list by
* default. However, if a plugin has been allowed on a top-level
* document, we should let subframes of that document access
* navigator.plugins.
*/
add_task(async function setup() {
// We'll make the Test Plugin click-to-play.
let originalPluginState = getTestPluginEnabledState();
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
registerCleanupFunction(() => {
setTestPluginEnabledState(originalPluginState);
clearAllPluginPermissions();
});
// And then make the plugin hidden.
await SpecialPowers.pushPrefEnv({
set: [[HIDDEN_CTP_PLUGIN_PREF, TEST_PLUGIN_NAME]],
});
});
add_task(async function test_plugin_accessible_in_subframe() {
// Let's make it so that DOMAIN_1 allows the test plugin to
// be activated. This permission will be cleaned up inside
// our registerCleanupFunction when the test ends.
let ssm = Services.scriptSecurityManager;
let principal = ssm.createContentPrincipalFromOrigin(DOMAIN_1);
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(
Ci.nsIPluginHost
);
let permString = pluginHost.getPermissionStringForType("application/x-test");
Services.perms.addFromPrincipal(
principal,
permString,
Ci.nsIPermissionManager.ALLOW_ACTION,
Ci.nsIPermissionManager.EXPIRE_NEVER,
0 /* expireTime */
);
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: DOMAIN_1,
},
async function(browser) {
await SpecialPowers.spawn(
browser,
[[TEST_PLUGIN_NAME, DOMAIN_2]],
async function([pluginName, domain2]) {
Assert.ok(
content.navigator.plugins[pluginName],
"Top-level document should find Test Plugin"
);
// Now manually create a subframe hosted at domain2...
let subframe = content.document.createElement("iframe");
subframe.src = domain2;
let loadedPromise = ContentTaskUtils.waitForEvent(subframe, "load");
content.document.body.appendChild(subframe);
await loadedPromise;
// Make sure that the HiddenPlugin event never fires in content.
let sawEvent = false;
docShell.chromeEventHandler.addEventListener(
"HiddenPlugin",
function onHiddenPlugin(e) {
sawEvent = true;
docShell.chromeEventHandler.removeEventListener(
"HiddenPlugin",
onHiddenPlugin,
true
);
},
true
);
Assert.ok(
subframe.contentWindow.navigator.plugins[pluginName],
"Subframe should find Test Plugin"
);
Assert.ok(!sawEvent, "Should not have seen the HiddenPlugin event.");
}
);
}
);
});

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
function addPlugin(aId, aType = "application/x-test") {
var embed = document.createElement("embed");
embed.setAttribute("id", aId);
embed.style.width = "200px";
embed.style.height = "200px";
embed.setAttribute("type", aType);
return document.body.appendChild(embed);
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!-- bug 739575 -->
<html>
<head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<object id="test" type="application/x-test" style="height: 200px; width:200px">
<p><a href="about:blank">you should not see this link when plugins are click-to-play</a></p>
</object>
</body></html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 500px; height: 500px" type="application/x-test">
</body>
</html>

Просмотреть файл

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
<embed id="test" style="width: 100px; height: 100px" type="application/x-test">
</body>
</html>

Просмотреть файл

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 100px; height: 100px" type="application/x-test">
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
</body>
</html>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/></head>
<body>
<style>
.x {
opacity: 0 !important;
}
</style>
<object id="test" class="x" type="application/x-test" width=200 height=200></object>
</body>
</html>

Просмотреть файл

@ -0,0 +1,8 @@
<!-- bug 749455 -->
<html>
<head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<embed src="plugin_bug749455.html" type="application/x-test" width="100px" height="100px"></embed>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/></head>
<body>
<a id="wrapper">
<embed id="plugin" style="width: 200px; height: 200px" type="application/x-test">
</a>
</body>
</html>

Просмотреть файл

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript">
function crash() {
var plugin = document.getElementById("plugin");
var argStr = decodeURIComponent(window.location.search.substr(1));
if (argStr) {
var args = JSON.parse(argStr);
for (var key in args)
plugin.setAttribute(key, args[key]);
}
try {
plugin.crash();
} catch (err) {}
}
</script>
</head>
<body onload="crash();">
<embed id="plugin" type="application/x-test"
width="400" height="400"
drawmode="solid" color="FF00FFFF">
</embed>
</body>
</html>

Просмотреть файл

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="container" style="display: none">
<object id="test" type="application/x-test" style="width: 200px; height: 200px;"></object>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<iframe id="frame" with="400" height="400" src="plugin_test.html">
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="testcase1" class="testcase">
<object width="10" height="10" type="application/x-test"></object>
</div>
<div id="testcase2" class="testcase">
<object width="40" height="40" type="application/x-test"></object>
</div>
<div id="testcase3" class="testcase">
<object width="100" height="70" type="application/x-test"></object>
</div>
<div id="testcase4" class="testcase">
<object width="200" height="200" type="application/x-test"></object>
</div>
<div id="testcase5" class="testcase">
<object width="300" height="300" type="application/x-test"></object>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
object {
width: 200px;
height: 200px;
}
.testcase {
position: relative;
margin-bottom: 5px;
}
.cover {
position: absolute;
width: 20px;
height: 20px;
background-color: green;
}
</style>
</head>
<body>
<div id="testcase1" class="testcase" shouldshow="true"
style="top: -100px">
<!-- Should show overlay even though the top part is outside
of the page. -->
<object type="application/x-test"></object>
</div>
<div id="testcase2" class="testcase" shouldshow="true"
style="left: -100px">
<!-- Should show overlay even though the left part is outside
of the page. -->
<object type="application/x-test"></object>
</div>
<div id="testcase3" class="testcase" shouldshow="false"
style="left: -210px">
<!-- The object is entirely outside of the page, so the overlay
should NOT show. -->
<object type="application/x-test"></object>
</div>
<div id="testcase4" class="testcase" shouldshow="true">
<!-- Should show overlay even though the top-left corner is covered. -->
<div class="cover" style="top: 0; left: 0"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase5" class="testcase" shouldshow="true">
<!-- Should show overlay even though the top-right corner is covered. -->
<div class="cover" style="top: 0; left: 180px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase6" class="testcase" shouldshow="true">
<!-- Should show overlay even though the bottom-left corner is covered. -->
<div class="cover" style="top: 180px; left: 0"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase7" class="testcase" shouldshow="true">
<!-- Should show overlay even though the bottom-right corner is covered. -->
<div class="cover" style="top: 180px; left: 180px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase8" class="testcase" shouldshow="true">
<!-- Should show overlay even though the center is covered. -->
<div class="cover" style="top: 90px; left: 90px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase9" class="testcase" shouldshow="true">
<!-- Should show overlay even though multiple points are covered,
but not all of them. -->
<div class="cover" style="top: 0; left: 0"></div>
<div class="cover" style="top: 0; left: 180px"></div>
<div class="cover" style="top: 180px; left: 0"></div>
<div class="cover" style="top: 180px; left: 180px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase10" class="testcase" shouldshow="true">
<!-- Another case where 4 are covered, but not all. -->
<div class="cover" style="top: 90px; left: 90px"></div>
<div class="cover" style="top: 0; left: 180px"></div>
<div class="cover" style="top: 180px; left: 0"></div>
<div class="cover" style="top: 180px; left: 180px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase11" class="testcase" shouldshow="false">
<!-- All corners and center are covered here, so in this
case the overlay should NOT show. -->
<div class="cover" style="top: 0; left: 0"></div>
<div class="cover" style="top: 0; left: 180px"></div>
<div class="cover" style="top: 180px; left: 0"></div>
<div class="cover" style="top: 180px; left: 180px"></div>
<div class="cover" style="top: 90px; left: 90px"></div>
<object type="application/x-test"></object>
</div>
<div id="testcase12" class="testcase" shouldshow="false">
<!-- All corners and center are covered here, by a single
element. In this case the overlay should NOT show. -->
<div class="cover" style="width: 200px; height:200px"></div>
<object type="application/x-test"></object>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 10px; height: 10px" type="application/x-test">
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test" style="width: 10px; height: 10px" type="application/x-second-test">
</body>
</html>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<body>
<script type="text/javascript">
// create an embed, insert it in the doc and immediately remove it
var embed = document.createElement("embed");
embed.setAttribute("id", "test");
embed.setAttribute("type", "application/x-test");
embed.setAttribute("style", "width: 0px; height: 0px;");
document.body.appendChild(embed);
window.getComputedStyle(embed).top;
document.body.remove(embed);
</script>

Просмотреть файл

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="test1" style="width: 200px; height: 200px" type="application/x-test">
<embed id="test2" style="width: 200px; height: 200px" type="application/x-test">
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/></head>
<body>
<embed id="test" style="width: 200px; height: 200px" type="application/x-test"/>
<embed id="secondtestA" style="width: 200px; height: 200px" type="application/x-second-test"/>
<embed id="secondtestB" style="width: 200px; height: 200px" type="application/x-second-test"/>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<embed id="unknown" style="width: 100px; height: 100px" type="application/x-unknown">
</body>
</html>

Просмотреть файл

@ -23,6 +23,9 @@ skip-if = os != 'mac'
[browser_policy_bookmarks.js]
[browser_policy_cookie_settings.js]
[browser_policy_disable_feedback_commands.js]
[browser_policy_disable_flash_plugin.js]
skip-if = (processor == 'aarch64' && os == 'win')
reason = Plugins are not supported on Windows/AArch64
[browser_policy_disable_fxaccounts.js]
skip-if = (verify && debug && (os == 'mac'))
[browser_policy_disable_masterpassword.js]

Просмотреть файл

@ -0,0 +1,164 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const labelTextAskToActivate = "Ask to Activate";
const labelTextNeverActivate = "Never Activate";
function restore_prefs() {
Services.prefs.clearUserPref("plugin.state.flash");
}
registerCleanupFunction(restore_prefs);
async function assert_flash_locked_status(win, locked, expectedLabelText) {
let addonCard = await BrowserTestUtils.waitForCondition(async () => {
let doc = win.getHtmlBrowser().contentDocument;
await win.htmlBrowserLoaded;
return doc.querySelector(`addon-card[addon-id*="Shockwave Flash"]`);
}, "Get HTML about:addons card for flash plugin");
const pluginOptions = addonCard.querySelector("plugin-options");
const pluginAction = pluginOptions.querySelector("panel-item[checked]");
ok(
pluginAction.textContent.includes(expectedLabelText),
`Got plugin action "${expectedLabelText}"`
);
// All other buttons (besides the checked one and the expand action)
// are expected to be disabled if locked is true.
for (const item of pluginOptions.querySelectorAll("panel-item")) {
const actionName = item.getAttribute("action");
if (actionName.includes("always")) {
ok(item.hidden, `Plugin action "${actionName}" should be hidden.`);
} else if (
!item.hasAttribute("checked") &&
actionName !== "expand" &&
actionName !== "preferences"
) {
is(
item.shadowRoot.querySelector("button").disabled,
locked,
`Plugin action "${actionName}" should be ${
locked ? "disabled" : "enabled"
}`
);
}
}
}
async function test_flash_status({ expectedLabelText, locked }) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
const win = await BrowserOpenAddonsMgr("addons://list/plugin");
await assert_flash_locked_status(win, locked, expectedLabelText);
BrowserTestUtils.removeTab(tab);
is(
Services.prefs.prefIsLocked("plugin.state.flash"),
locked,
"Flash pref lock state should match policy lock state"
);
}
add_task(async function test_enabled() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {
Default: true,
},
},
});
await test_flash_status({
expectedLabelText: labelTextAskToActivate,
locked: false,
});
restore_prefs();
});
add_task(async function test_enabled_locked() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {
Default: true,
Locked: true,
},
},
});
await test_flash_status({
expectedLabelText: labelTextAskToActivate,
locked: true,
});
restore_prefs();
});
add_task(async function test_disabled() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {
Default: false,
},
},
});
await test_flash_status({
expectedLabelText: labelTextNeverActivate,
locked: false,
});
restore_prefs();
});
add_task(async function test_disabled_locked() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {
Default: false,
Locked: true,
},
},
});
await test_flash_status({
expectedLabelText: labelTextNeverActivate,
locked: true,
});
restore_prefs();
});
add_task(async function test_ask() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {},
},
});
await test_flash_status({
expectedLabelText: labelTextAskToActivate,
locked: false,
});
restore_prefs();
});
add_task(async function test_ask_locked() {
await setupPolicyEngineWithJson({
policies: {
FlashPlugin: {
Locked: true,
},
},
});
await test_flash_status({
expectedLabelText: labelTextAskToActivate,
locked: true,
});
restore_prefs();
});

Просмотреть файл

@ -82,6 +82,7 @@ skip-if = (os == 'mac') # macosx1014 due to 1479256
[browser_ext_browsingData_indexedDB.js]
[browser_ext_browsingData_localStorage.js]
[browser_ext_browsingData_pluginData.js]
skip-if = (os == 'mac' && debug) # Plugin test causes Mac window to lose active state and times out other tests.
[browser_ext_browsingData_serviceWorkers.js]
[browser_ext_chrome_settings_overrides_home.js]
[browser_ext_commands_execute_browser_action.js]

Просмотреть файл

@ -9,18 +9,59 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIPluginHost"
);
// Returns the chrome side nsIPluginTag for the test plugin.
function getTestPlugin() {
let tags = pluginHost.getPluginTags();
let plugin = tags.find(tag => tag.name == "Test Plug-in");
if (!plugin) {
ok(false, "Unable to find plugin");
}
return plugin;
}
const TEST_ROOT = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://127.0.0.1:8888/"
);
const TEST_URL = TEST_ROOT + "file_clearplugindata.html";
const REFERENCE_DATE = Date.now();
const PLUGIN_TAG = getTestPlugin();
/* Due to layout being async, "PluginBindAttached" may trigger later. This
returns a Promise that resolves once we've forced a layout flush, which
triggers the PluginBindAttached event to fire. This trick only works if
there is some sort of plugin in the page.
*/
function promiseUpdatePluginBindings(browser) {
return SpecialPowers.spawn(browser, [], async function() {
let doc = content.document;
let elems = doc.getElementsByTagName("embed");
if (elems && elems.length) {
elems[0].clientTop; // eslint-disable-line no-unused-expressions
}
});
}
function stored(needles) {
let something = pluginHost.siteHasData(PLUGIN_TAG, null);
if (!needles) {
return something;
}
if (!something) {
return false;
}
if (needles.every(value => pluginHost.siteHasData(PLUGIN_TAG, value))) {
return true;
}
return false;
}
add_task(async function testPluginData() {
function background() {
browser.test.onMessage.addListener(async (msg, options) => {
// Plugins are disabled. We are simply testing that these async APIs
// complete without exceptions.
if (msg == "removePluginData") {
await browser.browsingData.removePluginData(options);
} else {
@ -38,67 +79,105 @@ add_task(async function testPluginData() {
});
async function testRemovalMethod(method) {
// NB: Since pplugins are disabled, there is never any data to clear.
// We are really testing that these operations are no-ops.
// Clear plugin data with no since value.
// Load page to set data for the plugin.
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
extension.sendMessage(method, {});
await extension.awaitMessage("pluginDataRemoved");
ok(!stored(null), "All data cleared");
BrowserTestUtils.removeTab(tab);
// Clear pluginData with recent since value.
// Load page to set data for the plugin.
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
extension.sendMessage(method, { since: REFERENCE_DATE - 20000 });
await extension.awaitMessage("pluginDataRemoved");
ok(stored(["bar.com", "qux.com"]), "Data stored for sites");
ok(!stored(["foo.com"]), "Data cleared for foo.com");
ok(!stored(["baz.com"]), "Data cleared for baz.com");
BrowserTestUtils.removeTab(tab);
// Clear pluginData with old since value.
// Load page to set data for the plugin.
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
extension.sendMessage(method, { since: REFERENCE_DATE - 1000000 });
await extension.awaitMessage("pluginDataRemoved");
ok(!stored(null), "All data cleared");
BrowserTestUtils.removeTab(tab);
// Clear pluginData for specific hosts.
// Load page to set data for the plugin.
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
extension.sendMessage(method, { hostnames: ["bar.com", "baz.com"] });
await extension.awaitMessage("pluginDataRemoved");
ok(stored(["foo.com", "qux.com"]), "Data stored for sites");
ok(!stored(["bar.com"]), "Data cleared for bar.com");
ok(!stored(["baz.com"]), "Data cleared for baz.com");
BrowserTestUtils.removeTab(tab);
// Clear pluginData for no hosts.
// Load page to set data for the plugin.
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
await promiseUpdatePluginBindings(gBrowser.selectedBrowser);
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
extension.sendMessage(method, { hostnames: [] });
await extension.awaitMessage("pluginDataRemoved");
ok(
stored(["foo.com", "bar.com", "baz.com", "qux.com"]),
"Data stored for sites"
);
BrowserTestUtils.removeTab(tab);
}
waitForExplicitFinish();
PLUGIN_TAG.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
await extension.startup();
await testRemovalMethod("removePluginData");
await testRemovalMethod("remove");
await extension.unload();
ok(true, "should get to the end without throwing an exception");
finish();
});

Просмотреть файл

@ -4,11 +4,27 @@
-->
<html>
<head>
<title>Plugin Clear Site Data disabled test</title>
<title>Plugin Clear Site Data sanitize test</title>
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
</head>
<body></body>
<script type="application/javascript">
"use strict";
// Make sure clearing by timerange is supported.
let p = document.getElementById("plugin1");
p.setSitesWithDataCapabilities(true);
p.setSitesWithData(
"foo.com:0:5," +
"bar.com:0:100," +
"baz.com:1:5," +
"qux.com:1:100"
);
</script>
</html>

Просмотреть файл

@ -9735,11 +9735,18 @@ uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType(
return nsIObjectLoadingContent::TYPE_DOCUMENT;
}
bool isPlugin = nsPluginHost::GetSpecialType(aMIMEType) !=
nsPluginHost::eSpecialType_None;
if (isPlugin) {
// ShouldPlay will handle checking for disabled plugins
return nsIObjectLoadingContent::TYPE_PLUGIN;
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
if (pluginHost) {
nsCOMPtr<nsIPluginTag> tag = PluginTagForType(aMIMEType, aNoFakePlugin);
if (tag) {
if (!aNoFakePlugin &&
nsCOMPtr<nsIFakePluginTag>(do_QueryInterface(tag))) {
return nsIObjectLoadingContent::TYPE_FAKE_PLUGIN;
}
// ShouldPlay will handle checking for disabled plugins
return nsIObjectLoadingContent::TYPE_PLUGIN;
}
}
return nsIObjectLoadingContent::TYPE_NULL;

Просмотреть файл

@ -65,9 +65,6 @@ interface nsIObjectLoadingContent : nsISupports
const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10;
// The plugin is click-to-play, but the user won't see overlays
const unsigned long PLUGIN_CLICK_TO_PLAY_QUIET = 11;
// Plugins are no longer supported. The plugin should not load and should
// be represented by a transparent element.
const unsigned long PLUGIN_BLOCK_ALL = 12;
// Plugins-specific permission indicating that we want to prompt the user
// to decide whether they want to allow a plugin, but to do so in a less

Просмотреть файл

@ -96,7 +96,6 @@
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_plugins.h"
#include "mozilla/StaticPrefs_security.h"
#include "nsChannelClassifier.h"
#include "nsFocusManager.h"
@ -1293,8 +1292,6 @@ EventStates nsObjectLoadingContent::ObjectState() const {
return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
case eFallbackVulnerableNoUpdate:
return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
case eFallbackBlockAllPlugins:
return NS_EVENT_STATE_HANDLER_NOPLUGINS;
}
}
MOZ_ASSERT_UNREACHABLE("unknown type?");
@ -2084,11 +2081,11 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
// reason click-to-play instead. Items resolved as Image/Document
// will not be checked for previews, as well as invalid plugins
// (they will not have the mContentType set).
FallbackType noPlayReason;
if (!mActivated && IsPluginType(mType) && !ShouldPlay(noPlayReason)) {
LOG(("OBJLC [%p]: Marking plugin as do-not-play", this));
FallbackType clickToPlayReason;
if (!mActivated && IsPluginType(mType) && !ShouldPlay(clickToPlayReason)) {
LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
mType = eType_Null;
fallbackType = noPlayReason;
fallbackType = clickToPlayReason;
}
if (!mActivated && IsPluginType(mType)) {
@ -2236,9 +2233,8 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
NS_ASSERTION(!mFrameLoader && !mInstanceOwner,
"switched to type null but also loaded something");
// Don't fire error events if we're falling back to click-to-play or if we
// are blocking all plugins; pretend like this is a really slow-loading
// plug-in instead.
// Don't fire error events if we're falling back to click-to-play; instead
// pretend like this is a really slow-loading plug-in instead.
if (fallbackType != eFallbackClickToPlay &&
fallbackType != eFallbackClickToPlayQuiet) {
MaybeFireErrorEvent();
@ -2608,11 +2604,11 @@ void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
}
// Create/destroy plugin problem UAWidget.
const EventStates pluginProblemState =
NS_EVENT_STATE_HANDLER_BLOCKED | NS_EVENT_STATE_HANDLER_CRASHED |
NS_EVENT_STATE_TYPE_CLICK_TO_PLAY |
NS_EVENT_STATE_VULNERABLE_UPDATABLE |
NS_EVENT_STATE_VULNERABLE_NO_UPDATE | NS_EVENT_STATE_HANDLER_NOPLUGINS;
const EventStates pluginProblemState = NS_EVENT_STATE_HANDLER_BLOCKED |
NS_EVENT_STATE_HANDLER_CRASHED |
NS_EVENT_STATE_TYPE_CLICK_TO_PLAY |
NS_EVENT_STATE_VULNERABLE_UPDATABLE |
NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
bool hadProblemState = !(aOldState & pluginProblemState).IsEmpty();
bool hasProblemState = !(newState & pluginProblemState).IsEmpty();
@ -2621,14 +2617,6 @@ void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
thisEl->NotifyUAWidgetTeardown();
} else if (!hadProblemState && hasProblemState) {
thisEl->AttachAndSetUAShadowRoot();
// When blocking all plugins, we do not want the element to have focus
// so relinquish focus if we are in that state.
if (PluginFallbackType() == eFallbackBlockAllPlugins) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && fm->GetFocusedElement() == thisEl) {
fm->ClearFocus(doc->GetWindow());
}
}
}
} else if (aOldType != mType) {
// If our state changed, then we already recreated frames
@ -2781,8 +2769,7 @@ nsNPAPIPluginInstance* nsObjectLoadingContent::ScriptRequestPluginInstance(
// an event. Fallback types >= eFallbackClickToPlay are plugin-replacement
// types, see header.
if (callerIsContentJS && !mScriptRequested && InActiveDocument(thisContent) &&
mType == eType_Null && mFallbackType >= eFallbackClickToPlay &&
mFallbackType <= eFallbackClickToPlayQuiet) {
mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
nsCOMPtr<nsIRunnable> ev =
new nsSimplePluginEvent(thisContent, u"PluginScripted"_ns);
nsresult rv = NS_DispatchToCurrentThread(ev);
@ -2888,8 +2875,7 @@ void nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) {
nsTArray<nsINodeList*> childNodes;
if (thisContent->IsHTMLElement(nsGkAtoms::object) &&
(aType == eFallbackUnsupported || aType == eFallbackDisabled ||
aType == eFallbackBlocklisted || aType == eFallbackAlternate ||
aType == eFallbackBlockAllPlugins)) {
aType == eFallbackBlocklisted || aType == eFallbackAlternate)) {
for (nsIContent* child = thisContent->GetFirstChild(); child;) {
// When we advance to our next child, we don't want to traverse subtrees
// under descendant <object> and <embed> elements; those will handle
@ -3038,8 +3024,7 @@ void nsObjectLoadingContent::PlayPlugin(SystemCallerGuarantee,
// If we're in a click-to-play state, reload.
// Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
// header
if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay &&
mFallbackType <= eFallbackClickToPlayQuiet) {
if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
aRv = LoadObject(true, true);
}
}
@ -3146,11 +3131,162 @@ bool nsObjectLoadingContent::ShouldBlockContent() {
}
bool nsObjectLoadingContent::ShouldPlay(FallbackType& aReason) {
MOZ_ASSERT(!BrowserTabsRemoteAutostart() || !XRE_IsParentProcess());
nsresult rv;
// We no longer support plugins. Always fall back to our placeholder.
aReason = eFallbackBlockAllPlugins;
return false;
if (BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
// We no longer support loading plugins in the parent process.
aReason = eFallbackDisabled;
return false;
}
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
// Order of checks:
// * Assume a default of click-to-play
// * If globally disabled, per-site permissions cannot override.
// * If blocklisted, override the reason with the blocklist reason
// * Check if the flash blocking status for this page denies flash from
// loading.
// * Check per-site permissions and follow those if specified.
// * Honor per-plugin disabled permission
// * Blocklisted plugins are forced to CtP
// * Check per-plugin permission and follow that.
aReason = eFallbackClickToPlay;
uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
pluginHost->GetStateForType(mContentType, nsPluginHost::eExcludeNone,
&enabledState);
if (nsIPluginTag::STATE_DISABLED == enabledState) {
aReason = eFallbackDisabled;
return false;
}
// Before we check permissions, get the blocklist state of this plugin to set
// the fallback reason correctly. In the content process this will involve
// an ipc call to chrome.
uint32_t blocklistState = nsIBlocklistService::STATE_BLOCKED;
pluginHost->GetBlocklistStateForType(mContentType, nsPluginHost::eExcludeNone,
&blocklistState);
if (blocklistState == nsIBlocklistService::STATE_BLOCKED) {
// no override possible
aReason = eFallbackBlocklisted;
return false;
}
if (blocklistState ==
nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
aReason = eFallbackVulnerableUpdatable;
} else if (blocklistState ==
nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
aReason = eFallbackVulnerableNoUpdate;
}
// Document and window lookup
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
MOZ_ASSERT(thisContent);
Document* ownerDoc = thisContent->OwnerDoc();
nsCOMPtr<nsPIDOMWindowOuter> window = ownerDoc->GetWindow();
if (!window) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> topWindow = window->GetInProcessTop();
NS_ENSURE_TRUE(topWindow, false);
nsCOMPtr<Document> topDoc = topWindow->GetDoc();
NS_ENSURE_TRUE(topDoc, false);
// Check the flash blocking status for this page (this applies to Flash only)
FlashClassification documentClassification = FlashClassification::Unknown;
if (IsFlashMIME(mContentType)) {
documentClassification = ownerDoc->DocumentFlashClassification();
}
if (documentClassification == FlashClassification::Denied) {
aReason = eFallbackDisabled;
return false;
}
// Check the permission manager for permission based on the principal of
// the toplevel content.
nsCOMPtr<nsIPermissionManager> permissionManager =
services::GetPermissionManager();
NS_ENSURE_TRUE(permissionManager, false);
// For now we always say that the system principal uses click-to-play since
// that maintains current behavior and we have tests that expect this. What
// we really should do is disable plugins entirely in pages that use the
// system principal, i.e. in chrome pages. That way the click-to-play code
// here wouldn't matter at all. Bug 775301 is tracking this.
if (!topDoc->NodePrincipal()->IsSystemPrincipal()) {
nsAutoCString permissionString;
rv = pluginHost->GetPermissionStringForType(
mContentType, nsPluginHost::eExcludeNone, permissionString);
NS_ENSURE_SUCCESS(rv, false);
uint32_t permission;
rv = permissionManager->TestPermissionFromPrincipal(
topDoc->NodePrincipal(), permissionString, &permission);
NS_ENSURE_SUCCESS(rv, false);
switch (permission) {
case nsIPermissionManager::ALLOW_ACTION:
if (PreferFallback(false /* isPluginClickToPlay */)) {
aReason = eFallbackAlternate;
return false;
}
return true;
case nsIPermissionManager::DENY_ACTION:
aReason = eFallbackDisabled;
return false;
case PLUGIN_PERMISSION_PROMPT_ACTION_QUIET:
if (PreferFallback(true /* isPluginClickToPlay */)) {
aReason = eFallbackAlternate;
} else {
aReason = eFallbackClickToPlayQuiet;
}
return false;
case nsIPermissionManager::PROMPT_ACTION:
if (PreferFallback(true /* isPluginClickToPlay */)) {
// False is already returned in this case, but
// it's important to correctly set aReason too.
aReason = eFallbackAlternate;
}
return false;
case nsIPermissionManager::UNKNOWN_ACTION:
break;
default:
MOZ_ASSERT(false);
return false;
}
}
// No site-specific permissions. Vulnerable plugins are automatically CtP
if (blocklistState ==
nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
return false;
}
if (PreferFallback(enabledState == nsIPluginTag::STATE_CLICKTOPLAY)) {
aReason = eFallbackAlternate;
return false;
}
// On the following switch we don't need to handle the case where
// documentClassification is FlashClassification::Denied because
// that's already handled above.
switch (enabledState) {
case nsIPluginTag::STATE_ENABLED:
return true;
case nsIPluginTag::STATE_CLICKTOPLAY:
if (documentClassification == FlashClassification::Allowed) {
return true;
}
return false;
}
MOZ_CRASH("Unexpected enabledState");
}
bool nsObjectLoadingContent::FavorFallbackMode(bool aIsPluginClickToPlay) {

Просмотреть файл

@ -104,8 +104,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
// The plugin is click-to-play, but the user won't see overlays
eFallbackClickToPlayQuiet =
nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY_QUIET,
// Plugins are no longer supported. Content is just a transparent rect.
eFallbackBlockAllPlugins = nsIObjectLoadingContent::PLUGIN_BLOCK_ALL,
};
nsObjectLoadingContent();

Просмотреть файл

@ -22,6 +22,7 @@ support-files =
file_bug1303838_target_ibaz.html
file_bug1303838_with_iframe.html
file_messagemanager_unload.html
file_pluginAudio.html
file_use_counter_bfcache.html
file_use_counter_bfcache_helper.html
file_use_counter_outer.html

Просмотреть файл

@ -6,9 +6,11 @@ if (!gMultiProcessBrowser) {
}
const kBaseURI = "http://mochi.test:8888/browser/dom/base/test/empty.html";
const kPluginJS = "chrome://mochitests/content/browser/dom/base/test/plugin.js";
var testURLs = [
"http://mochi.test:8888/browser/dom/base/test/file_audioLoop.html",
"http://mochi.test:8888/browser/dom/base/test/file_audioLoopInIframe.html",
"http://mochi.test:8888/browser/dom/base/test/file_pluginAudio.html",
"http://mochi.test:8888/browser/dom/base/test/file_webaudio_startstop.html",
];
@ -22,6 +24,8 @@ const kMinTimeoutBackground = 100 * 1000 * 1000;
const kDelay = 10;
Services.scriptloader.loadSubScript(kPluginJS, this);
async function runTest(url) {
let currentTab = gBrowser.selectedTab;
let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kBaseURI);

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<embed type="application/x-test" width="200" height="200"></embed>
<script>
var plugin = document.querySelector("embed");
onload = function() {
plugin.startAudioPlayback();
};
function stopAudio() {
plugin.stopAudioPlayback();
}
function pluginMuted() {
return plugin.audioMuted();
}
function toggleMuteState(muted) {
return SpecialPowers.toggleMuteState(muted, window.top);
}
</script>

Просмотреть файл

@ -201,6 +201,7 @@ support-files =
referrerHelper.js
file_audioLoop.html
file_webaudio_startstop.html
file_pluginAudio.html
referrer_helper.js
referrer_testserver.sjs
script_postmessages_fileList.js

Просмотреть файл

@ -294,9 +294,6 @@ class EventStates {
#define NS_EVENT_STATE_MOZINERT NS_DEFINE_EVENT_STATE_MACRO(54)
// Topmost Modal <dialog> element in top layer
#define NS_EVENT_STATE_TOPMOST_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(55)
// Handler for empty element that represents plugin instances in builds
// where plugin support is removed..
#define NS_EVENT_STATE_HANDLER_NOPLUGINS NS_DEFINE_EVENT_STATE_MACRO(56)
/**
* NOTE: do not go over 63 without updating EventStates::InternalType!
*/

Просмотреть файл

@ -163,18 +163,7 @@ nsresult HTMLEmbedElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
bool HTMLEmbedElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
int32_t* aTabIndex) {
// If we have decided that this is a blocked plugin then do not allow focus.
if ((Type() == eType_Null) &&
(PluginFallbackType() == eFallbackBlockAllPlugins)) {
if (aTabIndex) {
*aTabIndex = -1;
}
*aIsFocusable = false;
return false;
}
// Has non-plugin content: let the plugin decide what to do in terms of
// Has plugin content: let the plugin decide what to do in terms of
// internal focus from mouse clicks
if (aTabIndex) {
*aTabIndex = TabIndex();

Просмотреть файл

@ -289,17 +289,6 @@ bool HTMLObjectElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
return false;
}
// If we have decided that this is a blocked plugin then do not allow focus.
if ((Type() == eType_Null) &&
(PluginFallbackType() == eFallbackBlockAllPlugins)) {
if (aTabIndex) {
*aTabIndex = -1;
}
*aIsFocusable = false;
return false;
}
const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::tabindex);
bool isFocusable = attrVal && attrVal->Type() == nsAttrValue::eInteger;

Просмотреть файл

@ -0,0 +1,162 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=545812
Test plugins with DOM full-screen API:
* Request for full-screen is denied when windowed plugin in current doc is present.
* Request for full-screen is denied when windowed plugin in subdocument is present.
* Request for full-screen is not denied when the only plugin present is windowless.
* Adding an existing (out-of-doc) windowed plugin to a full-screen document causes document to exit full-screen.
* Create windowed plugin and adding it to full-screen document caused exit from full-screen.
* On non-Windows, plugins can only be windowless, so the presence of plugins
should have no effect on request for full-screen.
-->
<head>
<title>Test for Bug 545812</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="plugin-utils.js"></script>
<script type="application/javascript">
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
<style>
body:fullscreen, div:fullscreen {
background-color: red;
}
</style>
</head>
<body>
<!-- Windowed plugin, focusing should revoke full-screen. -->
<embed id="windowed-plugin" type="application/x-test" style="width:200px;height:100px;" wmode="window"></embed>
<!-- Windowless plugin, focusing should not revoke full-screen. -->
<embed id="windowless-plugin" type="application/x-test" style="width:200px;height:100px;"></embed>
<!-- iframe contents:
<html><body><embed id='windowed-plugin' type='application/x-test' style='width:200px;height:100px;' wmode='window'></embed></body></html>
-->
<iframe id="subdoc-plugin" srcdoc="<html><body><embed id='windowed-plugin' type='application/x-test' style='width:200px;height:100px;' wmode='window'></embed></body></html>"></iframe>
<script type="application/javascript">
/** Test for Bug 545812 **/
function ok(condition, msg) {
opener.ok(condition, "[plugins] " + msg);
}
function is(a, b, msg) {
opener.is(a, b, "[plugins] " + msg);
}
function e(id) {
return document.getElementById(id);
}
function removeElement(element) {
element.remove();
}
const supportsWindowedMode = navigator.appVersion.includes("Windows");
var windowedPlugin = null;
function begin() {
// Delay test startup long enough for the windowed plugin in the subframe to
// start up and create its window.
opener.SimpleTest.executeSoon(function() {
opener.SimpleTest.executeSoon(function() {
startTest();
})
});
}
function startTest() {
ok(!document.fullscreenElement, "Should not be in full-screen mode initially");
document.body.requestFullscreen();
// Focus the windowed plugin. On non-Windows we should still enter
// full-screen mode, on Windows the pending request for full-screen should
// be denied.
e("windowed-plugin").focus();
if (!supportsWindowedMode) {
// If all plugins are effectively windowless, request for full-screen should be granted.
// Continue test in the "fullscreenchange" handler.
addFullscreenChangeContinuation("enter", windowlessFullScreenChange1);
} else {
// On Windows, request should be denied, carry on the test after receiving error event.
addFullscreenErrorContinuation(windowsTest);
}
}
function windowsTest() {
ok(!document.fullscreenElement, "Request for full-screen with focused windowed plugin should be denied.");
// Focus a regular html element, and re-request full-screen, request should be granted.
e("windowless-plugin").focus();
addFullscreenChangeContinuation("enter", windowsTest2);
document.body.requestFullscreen();
}
function windowsTest2() {
ok(document.fullscreenElement, "Request for full-screen with non-plugin focused should be granted.");
// Focus a windowed plugin, full-screen should be revoked.
addFullscreenChangeContinuation("exit", windowsTest3);
e("windowed-plugin").focus();
}
function windowsTest3() {
ok(!document.fullscreenElement, "Full-screen should have been revoked when windowed-plugin was focused.");
// Remove windowed plugins before closing the window
// to work around bug 1237853.
removeElement(e("windowed-plugin"));
removeElement(e("subdoc-plugin").contentDocument.getElementById("windowed-plugin"));
opener.nextTest();
}
var fullScreenChangeCount = 0;
function createWindowedPlugin() {
var p = document.createElement("embed");
p.setAttribute("type", "application/x-test");
p.setAttribute("wmode", "window");
return p;
}
function windowlessFullScreenChange1(event) {
ok(document.fullscreenElement, "Requests for full-screen with focused windowed plugins should be granted on non-Windows");
// Create a new windowed plugin, and add that to the document. Should *not* exit full-screen mode on MacOS/Linux.
windowedPlugin = createWindowedPlugin();
document.body.appendChild(windowedPlugin);
// Focus windowed plugin. Should not exit full-screen mode on MacOS/Linux.
windowedPlugin.focus();
setTimeout(
function() {
ok(document.fullscreenElement, "Adding & focusing a windowed plugin to document should not cause full-screen to exit on MacOS/Linux.");
addFullscreenChangeContinuation("exit", windowlessFullScreenChange2);
document.exitFullscreen();
}, 0);
}
function windowlessFullScreenChange2(event) {
ok(!document.fullscreenElement, "Should have left full-screen mode after calling document.exitFullscreen().");
opener.nextTest();
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Bug 341604</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
I have 2 plugin instances embedded in me.
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
<object type="application/x-test" width="200" height="200"></object>
</body>
</html>

Просмотреть файл

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Bug 341604</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
I am a document that should be handled by a plugin load.
</body>
</html>

Просмотреть файл

@ -0,0 +1 @@
Content-Type: application/x-test

Просмотреть файл

@ -125,6 +125,9 @@ support-files =
file_iframe_sandbox_e_if7.html
file_iframe_sandbox_e_if8.html
file_iframe_sandbox_e_if9.html
file_iframe_sandbox_f_if1.html
file_iframe_sandbox_f_if2.html
file_iframe_sandbox_f_if2.html^headers^
file_iframe_sandbox_fail.js
file_iframe_sandbox_form_fail.html
file_iframe_sandbox_form_pass.html
@ -457,6 +460,7 @@ support-files =
file_fullscreen-navigation.html
file_fullscreen-nested.html
file_fullscreen-prefixed.html
file_fullscreen-plugins.html
file_fullscreen-rollback.html
file_fullscreen-scrollbar.html
file_fullscreen-selector.html
@ -482,6 +486,8 @@ tags = openwindow
tags = openwindow
[test_iframe_sandbox_navigation2.html]
tags = openwindow
[test_iframe_sandbox_plugins.html]
skip-if = (toolkit == 'android') || debug # plugins not supported on android, bug 1388764 for debug
[test_iframe_sandbox_popups.html]
tags = openwindow
[test_iframe_sandbox_popups_inheritance.html]
@ -503,8 +509,8 @@ skip-if = fission
[test_named_options.html]
[test_nested_invalid_fieldsets.html]
[test_object_attributes_reflection.html]
[test_object_nav.html]
skip-if = ((os == 'win' || os == 'linux') && debug) # bug 1388764
[test_object_plugin_nav.html]
skip-if = (toolkit == 'android') || ((os == 'win' || os == 'linux') && debug) # plugins not supported on android, bug 1388764 for debug
[test_ol_attributes_reflection.html]
[test_option_defaultSelected.html]
[test_option_selected_state.html]

Просмотреть файл

@ -35,6 +35,7 @@ var gTestWindows = [
{ test: "file_fullscreen-esc-exit.html" },
{ test: "file_fullscreen-denied.html" },
{ test: "file_fullscreen-api.html" },
{ test: "file_fullscreen-plugins.html" },
{ test: "file_fullscreen-hidden.html" },
{ test: "file_fullscreen-svg-element.html" },
{ test: "file_fullscreen-navigation.html" },
@ -75,6 +76,38 @@ function nextTest() {
}
}
var gHeadlessSkipList = [
{ test: "file_fullscreen-plugins.html", reason: "bug 1409805" },
];
var gLinuxE10sSkipList = [
{ "test": "file_fullscreen-plugins.html", "reason": "bug 1330553" },
];
function shouldSkipTest(test) {
function checkList(list) {
for (let item of list) {
if (item.test == test) {
todo(false, `${test} skipped due to ${item.reason}`);
return true;
}
}
return false;
}
if (SpecialPowers.Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).isHeadless &&
checkList(gHeadlessSkipList)) {
return true;
}
if (!SpecialPowers.isMainProcess() &&
navigator.platform.includes('Linux') &&
checkList(gLinuxE10sSkipList)) {
return true;
}
return false;
}
function waitForEvent(eventTarget, eventName, checkFn, callback) {
eventTarget.addEventListener(eventName, function listener(event) {
if (checkFn && !checkFn(event)) {
@ -88,33 +121,38 @@ function waitForEvent(eventTarget, eventName, checkFn, callback) {
function runNextTest() {
if (gTestIndex < gTestWindows.length) {
let test = gTestWindows[gTestIndex];
let promise = ("prefs" in test)
? SpecialPowers.pushPrefEnv({"set": test.prefs})
: Promise.resolve();
promise.then(function() {
info(`Run test ${test.test}`);
testWindow = window.open(test.test, "", "width=500,height=500,scrollbars=yes");
// We'll wait for the window to load, then make sure our window is refocused
// before starting the test, which will get kicked off on "focus".
// This ensures that we're essentially back on the primary "desktop" on
// OS X Lion before we run the test.
waitForLoadAndPaint(testWindow, function() {
SimpleTest.waitForFocus(function() {
info("Were focused");
// For the platforms that support reporting occlusion state (e.g. Mac),
// we should wait until the docshell has been activated again,
// otherwise, the fullscreen request might be denied.
if (testWindow.document.hidden) {
info("Waiting for document to unhide");
waitForEvent(testWindow.document, "visibilitychange", (event) => {
return !testWindow.document.hidden;
}, testWindow.begin);
return;
}
testWindow.begin();
}, testWindow);
if (shouldSkipTest(test.test)) {
info(`Skip test ${test.test}`);
SimpleTest.executeSoon(runNextTest);
} else {
let promise = ("prefs" in test)
? SpecialPowers.pushPrefEnv({"set": test.prefs})
: Promise.resolve();
promise.then(function() {
info(`Run test ${test.test}`);
testWindow = window.open(test.test, "", "width=500,height=500,scrollbars=yes");
// We'll wait for the window to load, then make sure our window is refocused
// before starting the test, which will get kicked off on "focus".
// This ensures that we're essentially back on the primary "desktop" on
// OS X Lion before we run the test.
waitForLoadAndPaint(testWindow, function() {
SimpleTest.waitForFocus(function() {
info("Were focused");
// For the platforms that support reporting occlusion state (e.g. Mac),
// we should wait until the docshell has been activated again,
// otherwise, the fullscreen request might be denied.
if (testWindow.document.hidden) {
info("Waiting for document to unhide");
waitForEvent(testWindow.document, "visibilitychange", (event) => {
return !testWindow.document.hidden;
}, testWindow.begin);
return;
}
testWindow.begin();
}, testWindow);
});
});
});
}
gTestIndex++;
} else {
SimpleTest.finish();

Просмотреть файл

@ -0,0 +1,141 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=341604
Implement HTML5 sandbox attribute for IFRAMEs
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 341604 - plugins</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="plugin-utils.js"></script>
<script type="application/javascript">
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<script type="application/javascript">
/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
/** Plugin tests **/
SimpleTest.waitForExplicitFinish();
function doTest() {
// 1) test that a plugin can't be loaded with <embed> inside a sandboxed <iframe>
// (done by file_iframe_sandbox_f_if1.html loaded in if1 below)
// 2) test that a plugin can't be loaded with <object> inside a sandboxed <iframe>
// (done by file_iframe_sandbox_f_if1.html loaded in if1 below)
// 3) test that plugin can't be loaded by a sandboxed <iframe> with src pointing to
// a document that is handled by a plugin (done by if_2 below)
// 4) test that when a plugin is loaded in an unsandboxed iframe, a sandbox attribute
// is then added to the iframe and the document containing the plugin is reloaded,
// the plugin does not load in the sandboxed iframe (done with if_3 below)
// 5) test that when when a sandboxed iframe's sandbox attribute is removed,
// and a new document is loaded into the iframe, the plugin loads
// (done with if_4 below)
// these are all handled by checking how many instances of the test plugin are loaded
// when this script runs as the onload handler - there should be two instances,
// initially the one loaded directly by this page itself, and the one loaded during
// test #4 above.
var p = document.getElementById('plugin1');
var if_1 = document.getElementById('if_1');
p.startWatchingInstanceCount();
if_1.src = 'file_iframe_sandbox_f_if1.html';
}
function if_1_load() {
var if_1 = document.getElementById('if_1');
if (if_1.src == "about:blank")
return;
// need to wait for plugin to load, if the test fails...
SimpleTest.executeSoon(if_1_continue);
}
function if_1_continue() {
// instance count should be 0 (tests #1 and #2 above)
var p = document.getElementById('plugin1');
is(p.getInstanceCount(), 0, "plugins should not be loaded via <object> or <embed> by a sandboxed iframe");
var if_2 = document.getElementById('if_2');
if_2.src = 'file_iframe_sandbox_f_if2.html';
SimpleTest.executeSoon(if_2_continue);
}
function if_2_continue() {
// instance count should be 0 (test #3 above)
var p = document.getElementById('plugin1');
is(p.getInstanceCount(), 0, "plugins should not be loaded via a document of a type that requires a plugin embedded in a sandboxed iframe");
SimpleTest.executeSoon(if_3_test);
}
function if_3_test() {
var if_3 = document.getElementById('if_3');
// add sandbox attribute
if_3.sandbox = '';
if_3.src = 'file_iframe_sandbox_f_if1.html';
}
function if_3_load() {
if (if_3.src == "about:blank")
return;
SimpleTest.executeSoon(if_3_continue);
}
function if_3_continue() {
var p = document.getElementById('plugin1');
is(p.getInstanceCount(), 0, "plugins should not be loaded when a sandbox attribute is added" +
"to an iframe and a document containing a plugin is then loaded into the iframe");
SimpleTest.executeSoon(if_4_test);
}
function if_4_test() {
var if_4 = document.getElementById('if_4');
// remove sandbox attribute
if_4.removeAttribute('sandbox');
if_4.src = 'file_iframe_sandbox_f_if1.html';
}
function if_4_load() {
if (if_4.src == "about:blank")
return;
SimpleTest.executeSoon(if_4_continue);
}
function if_4_continue() {
var p = document.getElementById('plugin1');
// there are 2 plugin instances in file_iframe_sandbox_if1.html loaded by
// if_1, they should successfully load.
is(p.getInstanceCount(), 2, "plugins should be loaded when a sandbox attribute is removed " +
"from an iframe and a document containing a plugin is then loaded into the iframe");
p.stopWatchingInstanceCount();
SimpleTest.executeSoon(finish_test);
}
function finish_test() {
SimpleTest.finish();
}
addLoadEvent(doTest);
</script>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
<p id="display"></p>
<div id="content">
<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
<iframe id="if_1" sandbox='allow-same-origin' onLoad='if_1_load()' src="about:blank" height="400" width="400"></iframe>
<iframe id="if_2" sandbox='allow-same-origin' src="about:blank" height="400" width="400"></iframe>
<iframe id="if_3" src="about:blank" onload='if_3_load()' height="400" width="400"></iframe>
<iframe id="if_4" sandbox='allow-same-origin' onload='if_4_load()' src="about:blank" height="400" width="400"></iframe>
</div>
</body>
</html>

Просмотреть файл

@ -8,6 +8,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=720130
<title>Test for Bug 720130</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="plugin-utils.js"></script>
<script type="application/javascript">
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
</script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
@ -15,12 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=720130
<p id="display"></p>
<div id="content">
<input>
<object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAATklEQVRYhe3SIQ4AIBADwf7/04elBAtrVlSduGnSTDJ7cuT1PQJwwO+Hl7sAGAA07gjAAfgIBeAAoHFHAA7ARygABwCNOwJwAD5CATRgAYXh+kypw86nAAAAAElFTkSuQmCC"></object>
<object type="application/x-test"></object>
<button>foo</button>
<object type="application/x-shockwave-flash"></object>
<object tabindex='0' type="application/x-shockwave-flash"></object>
<object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAATklEQVRYhe3SIQ4AIBADwf7/04elBAtrVlSduGnSTDJ7cuT1PQJwwO+Hl7sAGAA07gjAAfgIBeAAoHFHAA7ARygABwCNOwJwAD5CATRgAYXh+kypw86nAAAAAElFTkSuQmCC"></object>
<object tabindex='0' data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAATklEQVRYhe3SIQ4AIBADwf7/04elBAtrVlSduGnSTDJ7cuT1PQJwwO+Hl7sAGAA07gjAAfgIBeAAoHFHAA7ARygABwCNOwJwAD5CATRgAYXh+kypw86nAAAAAElFTkSuQmCC"></object>
<object tabindex='0' type="application/x-test"></object>
</div>
<pre id="test">
<script type="application/javascript">
@ -48,14 +49,8 @@ function checkFocus() {
"third focused element should be the button");
break;
case 3:
ok(document.activeElement != document.getElementsByTagName('object')[1],
"fourth focused element should not be the plugin object");
ok(document.activeElement != document.getElementsByTagName('object')[2],
"fourth focused element should not be the plugin object with tabindex");
ok(document.activeElement != document.getElementsByTagName('object')[3],
"fourth focused element should not be the image object without tabindex");
is(document.activeElement, document.getElementsByTagName('object')[4],
"fourth focused element should be the image object with tabindex");
is(document.activeElement, document.getElementsByTagName('object')[1],
"fourth focused element should be the object");
break;
}
@ -69,7 +64,7 @@ function doTest() {
// Preliminary check: tabindex should be 0 on the object.
is(document.getElementsByTagName('object')[0].tabIndex, 0,
"the element shouldn't get focus while navigating in the document");
"the plugin shouldn't get focus while navigating in the document");
document.addEventListener("focus", function() {
checkFocus();
@ -80,7 +75,14 @@ function doTest() {
}
document.removeEventListener("focus", arguments.callee, true);
SimpleTest.finish();
// Just make sure that .focus() still works.
var o = document.getElementsByTagName('object')[0];
o.onfocus = function() {
SimpleTest.finish();
o.onfocus = null;
};
o.focus();
}, true);
synthesizeKey("KEY_Tab");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PluginFinder_h_
#define PluginFinder_h_
#include "nsIRunnable.h"
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsPluginTags.h"
#include "mozilla/StaticPrefs_dom.h"
#include "nsIAsyncShutdown.h"
class nsIFile;
class nsPluginHost;
class nsInvalidPluginTag : public nsISupports {
virtual ~nsInvalidPluginTag();
public:
explicit nsInvalidPluginTag(const char* aFullPath,
int64_t aLastModifiedTime = 0);
NS_DECL_THREADSAFE_ISUPPORTS
nsCString mFullPath;
int64_t mLastModifiedTime;
bool mSeen;
RefPtr<nsInvalidPluginTag> mPrev;
RefPtr<nsInvalidPluginTag> mNext;
};
static inline bool UnloadPluginsASAP() {
return mozilla::StaticPrefs::dom_ipc_plugins_unloadTimeoutSecs() == 0;
}
/**
* Class responsible for discovering plugins on disk, in part based
* on cached information stored in pluginreg.dat and in the prefs.
*
* This runnable is designed to be used as a one-shot. It's created
* when the pluginhost wants to find plugins, and the next time it
* wants to do so, it should create a new one.
*/
class PluginFinder final : public nsIRunnable, public nsIAsyncShutdownBlocker {
~PluginFinder() = default;
public:
explicit PluginFinder(bool aFlashOnly);
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSIASYNCSHUTDOWNBLOCKER
typedef std::function<void(
bool /* aPluginsChanged */, RefPtr<nsPluginTag> /* aNewPlugins */,
nsTArray<
std::pair<bool, RefPtr<nsPluginTag>>>&) /* aBlocklistRequestPairs */>
FoundPluginCallback;
typedef std::function<void(bool /* aPluginsChanged */)> PluginChangeCallback;
// The expectation is that one (and only one) of these gets called
// by the plugin host. We can't easily do the work in the constructor
// because in some cases we'll fail early (e.g. if we're called before
// the profile is ready) and want to signal that to the consumer via
// the nsresult return value, which we can't do in a constructor.
nsresult DoFullSearch(const FoundPluginCallback& aCallback);
nsresult HavePluginsChanged(const PluginChangeCallback& aCallback);
static nsresult WritePluginInfo(
bool aFlashOnly, nsPluginTag* aPlugins,
nsInvalidPluginTag* aInvalidPlugins = nullptr);
private:
nsPluginTag* FirstPluginWithPath(const nsCString& path);
bool ShouldAddPlugin(const nsPluginInfo& aInfo);
nsresult ReadFlashInfo();
static nsresult WriteFlashInfo(nsPluginTag* aPlugins);
static nsresult EnsurePluginReg();
nsresult ReadPluginInfo();
nsresult ReadPluginInfoFromDisk();
nsresult DeterminePluginDirs();
nsresult ScanPluginsDirectory(nsIFile* aPluginsDir, bool* aPluginsChanged);
nsresult FindPlugins();
void RemoveCachedPluginsInfo(const char* filePath, nsPluginTag** result);
nsTArray<nsCOMPtr<nsIFile>> mPluginDirs;
// The plugins we've found on disk (to be passed to the host)
RefPtr<nsPluginTag> mPlugins;
// The plugin whose metadata we found in cache
RefPtr<nsPluginTag> mCachedPlugins;
// Any invalid plugins our cache info made us aware of prior to actually
// examining the disk; this is a performance optimization to avoid trying
// to load files that aren't plugins on every browser startup.
RefPtr<nsInvalidPluginTag> mInvalidPlugins;
// The bool (shouldSoftBlock) indicates whether we should disable the plugin
// if it's soft-blocked in the blocklist
// The plugintag is a reference to the actual plugin whose blocklist state
// needs checking.
nsTArray<std::pair<bool, RefPtr<nsPluginTag>>> mPluginBlocklistRequests;
FoundPluginCallback mFoundPluginCallback;
PluginChangeCallback mChangeCallback;
RefPtr<nsPluginHost> mHost;
bool mFlashOnly;
bool mCreateList;
bool mPluginsChanged;
bool mFinishedFinding;
bool mCalledOnMainthread;
bool mShutdown;
};
#endif

Просмотреть файл

@ -23,6 +23,7 @@ EXPORTS += [
"nptypes.h",
"nsJSNPRuntime.h",
"nsNPAPIPluginInstance.h",
"nsPluginDirServiceProvider.h",
"nsPluginHost.h",
"nsPluginInstanceOwner.h",
"nsPluginLogging.h",
@ -39,6 +40,7 @@ UNIFIED_SOURCES += [
"nsPluginInstanceOwner.cpp",
"nsPluginStreamListenerPeer.cpp",
"nsPluginTags.cpp",
"PluginFinder.cpp",
]
SOURCES += [
@ -48,6 +50,7 @@ SOURCES += [
if CONFIG["OS_ARCH"] == "WINNT":
UNIFIED_SOURCES += [
"nsPluginDirServiceProvider.cpp",
"nsPluginNativeWindowWin.cpp",
"nsPluginsDirWin.cpp",
]

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPluginDirServiceProvider.h"
#include "nsCRT.h"
#include "nsIFile.h"
#include <windows.h>
#include "nsIWindowsRegKey.h"
using namespace mozilla;
/* static */ nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, aDirs);
GetPLIDDirectoriesWithRootKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
aDirs);
return NS_OK;
}
/* static */ nsresult GetPLIDDirectoriesWithRootKey(
uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs) {
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1");
NS_ENSURE_TRUE(regKey, NS_ERROR_FAILURE);
nsresult rv = regKey->Open(aKey, u"Software\\MozillaPlugins"_ns,
nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
return rv;
}
uint32_t childCount = 0;
regKey->GetChildCount(&childCount);
for (uint32_t index = 0; index < childCount; ++index) {
nsAutoString childName;
rv = regKey->GetChildName(index, childName);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIWindowsRegKey> childKey;
rv = regKey->OpenChild(childName, nsIWindowsRegKey::ACCESS_QUERY_VALUE,
getter_AddRefs(childKey));
if (NS_SUCCEEDED(rv) && childKey) {
nsAutoString path;
rv = childKey->ReadStringValue(u"Path"_ns, path);
if (NS_SUCCEEDED(rv)) {
// We deliberately do not do any further checks here on whether
// these are actually directories, whether they even exist, or
// whether they are duplicates. The pluginhost code will do them.
// This allows the whole process to avoid mainthread IO.
nsCOMPtr<nsIFile> localFile;
rv = NS_NewLocalFile(path, true, getter_AddRefs(localFile));
if (NS_SUCCEEDED(rv) && localFile) {
aDirs.AppendElement(localFile);
}
}
}
}
}
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPluginDirServiceProvider_h_
#define nsPluginDirServiceProvider_h_
#ifdef XP_WIN
# include "nsCOMPtr.h"
# include "nsTArray.h"
static nsresult GetPLIDDirectories(nsTArray<nsCOMPtr<nsIFile>>& aDirs);
static nsresult GetPLIDDirectoriesWithRootKey(
uint32_t aKey, nsTArray<nsCOMPtr<nsIFile>>& aDirs);
#endif // XP_WIN
#endif // nsPluginDirServiceProvider_h_

Просмотреть файл

@ -77,6 +77,8 @@
#include "mozilla/dom/Promise.h"
#include "PluginFinder.h"
#if defined(XP_WIN)
# include "nsIWindowMediator.h"
# include "nsIBaseWindow.h"
@ -180,6 +182,14 @@ class BlocklistPromiseHandler final
sPluginBlocklistStatesChangedSinceLastWrite = false;
RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
// XXXgijs This will wipe invalid plugin info. That's unfortunate, but
// there's no easy way around this - re-running FindPlugins will only
// keep invalid plugin info around long enough to use it if we force
// it to re-create plugin tags, and in any case can cause re-entrancy
// because it would do more async blocklist lookups. Just make sure
// we write the blocklist info.
PluginFinder::WritePluginInfo(host->mFlashOnly, host->mPlugins);
// We update blocklist info in content processes asynchronously
// by just sending a new plugin list to content.
host->IncrementChromeEpoch();
@ -255,11 +265,17 @@ nsPluginHost::nsPluginHost()
: mPluginsLoaded(false),
mOverrideInternalTypes(false),
mPluginsDisabled(false),
mFlashOnly(true),
mDoReloadOnceFindingFinished(false),
mAddedFinderShutdownBlocker(false),
mPluginEpoch(0) {
// check to see if pref is set at startup to let plugins take over in
// full page mode for certain image mime types that we handle internally
mOverrideInternalTypes =
Preferences::GetBool("plugin.override_internal_types", false);
if (xpc::IsInAutomation()) {
mFlashOnly = Preferences::GetBool("plugin.load_flash_only", true);
}
bool waylandBackend = false;
#if defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
@ -350,8 +366,56 @@ bool nsPluginHost::IsRunningPlugin(nsPluginTag* aPluginTag) {
}
nsresult nsPluginHost::ReloadPlugins() {
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins\n"));
return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins Begin\n"));
// If we're calling this from a content process, forward the reload request to
// the parent process. If plugins actually changed, it will notify us
// asynchronously later.
if (XRE_IsContentProcess()) {
Unused
<< mozilla::dom::ContentChild::GetSingleton()->SendMaybeReloadPlugins();
// In content processes, always signal that plugins have not changed. We
// will never know if they changed here unless we make slow synchronous
// calls. This information will hopefully only be wrong once, as if there
// has been a plugin update, we expect to have gotten notification from the
// parent process and everything should be updated by the next time this is
// called. See Bug 1337058 for more info.
return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
}
// this will create the initial plugin list out of cache
// if it was not created yet
if (!mPluginsLoaded) return LoadPlugins();
// We're already in the process of finding more plugins. Do it again once
// done (because maybe things have changed since we started looking).
if (mPendingFinder) {
mDoReloadOnceFindingFinished = true;
return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
}
// we are re-scanning plugins. New plugins may have been added, also some
// plugins may have been removed, so we should probably shut everything down
// but don't touch running (active and not stopped) plugins
// check if plugins changed, no need to do anything else
// if no changes to plugins have been made
// We're doing this on the main thread, and we checked mPendingFinder
// above, so we don't need to do anything else to ensure we don't re-enter.
// Future work may make this asynchronous and do the finding away from
// the mainthread for the reload case, too, (in which case we should use
// mPendingFinder instead of a local copy, and update PluginFinder) but at
// the moment this is less important than the initial finding on startup.
RefPtr<PluginFinder> pf = new PluginFinder(mFlashOnly);
bool pluginschanged;
MOZ_TRY(pf->HavePluginsChanged([&pluginschanged](bool aPluginsChanged) {
pluginschanged = aPluginsChanged;
}));
pf->Run();
// if no changed detected, return an appropriate error code
if (!pluginschanged) return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
return ActuallyReloadPlugins();
}
void nsPluginHost::ClearNonRunningPlugins() {
@ -573,8 +637,35 @@ void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag) {
}
}
// We have some options for unloading plugins if they have no instances.
//
// Unloading plugins immediately can be bad - some plugins retain state
// between instances even when there are none. This is largely limited to
// going from one page to another, so state is retained without an instance
// for only a very short period of time. In order to allow this to work
// we don't unload plugins immediately by default. This is supported
// via a hidden user pref though.
//
// Another reason not to unload immediately is that loading is expensive,
// and it is better to leave popular plugins loaded.
//
// Our default behavior is to try to unload a plugin after a pref-controlled
// delay once its last instance is destroyed. This seems like a reasonable
// compromise that allows us to reclaim memory while allowing short state
// retention and avoid perf hits for loading popular plugins.
if (!hasInstance) {
aPluginTag->TryUnloadPlugin(false);
if (UnloadPluginsASAP()) {
aPluginTag->TryUnloadPlugin(false);
} else {
if (aPluginTag->mUnloadTimer) {
aPluginTag->mUnloadTimer->Cancel();
} else {
aPluginTag->mUnloadTimer = NS_NewTimer();
}
uint32_t unloadTimeout = StaticPrefs::dom_ipc_plugins_unloadTimeoutSecs();
aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * unloadTimeout,
nsITimer::TYPE_ONE_SHOT);
}
}
}
@ -1737,6 +1828,27 @@ void nsPluginHost::SetChromeEpochForContent(uint32_t aEpoch) {
mPluginEpoch = aEpoch;
}
#ifdef XP_WIN
static void WatchRegKey(uint32_t aRoot, nsCOMPtr<nsIWindowsRegKey>& aKey) {
if (aKey) {
return;
}
aKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!aKey) {
return;
}
nsresult rv = aKey->Open(
aRoot, u"Software\\MozillaPlugins"_ns,
nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::ACCESS_NOTIFY);
if (NS_FAILED(rv)) {
aKey = nullptr;
return;
}
aKey->StartWatching(true);
}
#endif
already_AddRefed<nsIAsyncShutdownClient> GetProfileChangeTeardownPhase() {
nsCOMPtr<nsIAsyncShutdownService> asyncShutdownSvc =
services::GetAsyncShutdownService();
@ -1752,9 +1864,133 @@ already_AddRefed<nsIAsyncShutdownClient> GetProfileChangeTeardownPhase() {
return shutdownPhase.forget();
}
nsresult nsPluginHost::LoadPlugins() { return NS_OK; }
nsresult nsPluginHost::LoadPlugins() {
// This should only be run in the parent process. On plugin list change, we'll
// update observers in the content process as part of SetPluginsInContent
if (XRE_IsContentProcess()) {
return NS_OK;
}
// do not do anything if it is already done
// use ReloadPlugins() to enforce loading
if (mPluginsLoaded) return NS_OK;
void nsPluginHost::FindingFinished() {}
// Uh oh, someone's forcing us to load plugins, but we're already in the
// process of doing so. Schedule a reload for when we're done:
if (mPendingFinder) {
mDoReloadOnceFindingFinished = true;
return NS_OK;
}
if (mPluginsDisabled) return NS_OK;
#ifdef XP_WIN
WatchRegKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, mRegKeyHKLM);
WatchRegKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, mRegKeyHKCU);
#endif
// This is a runnable. The main part of its work will be done away from the
// main thread.
mPendingFinder = new PluginFinder(mFlashOnly);
mDoReloadOnceFindingFinished = false;
mAddedFinderShutdownBlocker = false;
RefPtr<nsPluginHost> self = this;
// Note that if we're in flash only mode, which is the default, then the
// callback will be called twice. Once for flash (or nothing, if we're not
// (yet) aware of flash being present), and then again after we've actually
// looked for it on disk.
nsresult rv = mPendingFinder->DoFullSearch(
[self](bool aPluginsChanged, RefPtr<nsPluginTag> aPlugins,
const nsTArray<std::pair<bool, RefPtr<nsPluginTag>>>&
aBlocklistRequests) {
MOZ_ASSERT(NS_IsMainThread(),
"Callback should only be called on the main thread.");
self->mPluginsLoaded = true;
if (aPluginsChanged) {
self->ClearNonRunningPlugins();
while (aPlugins) {
RefPtr<nsPluginTag> pluginTag = aPlugins;
aPlugins = aPlugins->mNext;
self->AddPluginTag(pluginTag);
}
self->IncrementChromeEpoch();
self->BroadcastPluginsToContent();
}
// Do blocklist queries immediately after.
for (auto pair : aBlocklistRequests) {
RefPtr<nsPluginTag> pluginTag = pair.second;
bool shouldSoftblock = pair.first;
self->UpdatePluginBlocklistState(pluginTag, shouldSoftblock);
}
if (aPluginsChanged) {
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(nullptr, "plugins-list-updated",
nullptr);
}
}
});
// Deal with the profile not being ready yet by returning NS_OK - we'll get
// the data later.
if (NS_FAILED(rv)) {
mPendingFinder = nullptr;
if (rv == NS_ERROR_NOT_AVAILABLE) {
return NS_OK;
}
return rv;
}
bool dispatched = false;
// If we're only looking for flash (the default), try to do so away from
// the main thread. Note that in this case, the callback may have been called
// already, from the cached plugin info.
if (mFlashOnly) {
// First add the shutdown blocker, to avoid the potential for race
// conditions.
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase =
GetProfileChangeTeardownPhase();
if (shutdownPhase) {
rv = shutdownPhase->AddBlocker(mPendingFinder,
NS_LITERAL_STRING_FROM_CSTRING(__FILE__),
__LINE__, u""_ns);
mAddedFinderShutdownBlocker = NS_SUCCEEDED(rv);
}
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = target->Dispatch(mPendingFinder, nsIEventTarget::DISPATCH_NORMAL);
dispatched = NS_SUCCEEDED(rv);
}
// If we somehow failed to dispatch, remove the shutdown blocker.
if (mAddedFinderShutdownBlocker && !dispatched) {
shutdownPhase->RemoveBlocker(mPendingFinder);
mAddedFinderShutdownBlocker = false;
}
}
if (!dispatched) {
mPendingFinder->Run();
// We're running synchronously, so just remove the pending finder now.
mPendingFinder = nullptr;
}
return NS_OK;
}
void nsPluginHost::FindingFinished() {
if (mAddedFinderShutdownBlocker) {
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase =
GetProfileChangeTeardownPhase();
shutdownPhase->RemoveBlocker(mPendingFinder);
mAddedFinderShutdownBlocker = false;
}
mPendingFinder = nullptr;
if (mDoReloadOnceFindingFinished) {
Unused << ReloadPlugins();
}
}
nsresult nsPluginHost::SetPluginsInContent(
uint32_t aPluginEpoch, nsTArray<mozilla::plugins::PluginTag>& aPlugins,
@ -2653,7 +2889,9 @@ bool nsPluginHost::CanUsePluginForMIMEType(const nsACString& aMIMEType) {
if (nsPluginHost::GetSpecialType(aMIMEType) ==
nsPluginHost::eSpecialType_Flash ||
MimeTypeIsAllowedForFakePlugin(NS_ConvertUTF8toUTF16(aMIMEType)) ||
aMIMEType.LowerCaseEqualsLiteral("application/x-test")) {
aMIMEType.LowerCaseEqualsLiteral("application/x-test") ||
aMIMEType.LowerCaseEqualsLiteral("application/x-second-test") ||
aMIMEType.LowerCaseEqualsLiteral("application/x-third-test")) {
return true;
}

Просмотреть файл

@ -59,6 +59,8 @@ struct _NPP;
typedef _NPP* NPP;
#endif
class PluginFinder;
class nsPluginHost final : public nsIPluginHost,
public nsIObserver,
public nsITimerCallback,
@ -66,6 +68,7 @@ class nsPluginHost final : public nsIPluginHost,
public nsINamed {
friend class nsPluginTag;
friend class nsFakePluginTag;
friend class PluginFinder;
virtual ~nsPluginHost();
public:
@ -312,6 +315,7 @@ class nsPluginHost final : public nsIPluginHost,
void ClearNonRunningPlugins();
nsresult ActuallyReloadPlugins();
// Callback into the host from PluginFinder once it's done.
void FindingFinished();
RefPtr<nsPluginTag> mPlugins;
@ -329,6 +333,14 @@ class nsPluginHost final : public nsIPluginHost,
// set by pref plugin.disable
bool mPluginsDisabled;
// set by pref plugin.load_flash_only
bool mFlashOnly;
// Only one plugin finding operation should be run at a time.
RefPtr<PluginFinder> mPendingFinder;
bool mDoReloadOnceFindingFinished;
bool mAddedFinderShutdownBlocker;
// Any instances in this array will have valid plugin objects via GetPlugin().
// When removing an instance it might not die - be sure to null out it's
// plugin.

Просмотреть файл

@ -3,12 +3,12 @@ HTTP load 48856-1.html
HTTP load 110650-1.html
skip-if(!haveTestPlugin) HTTP script 539897-1.html
asserts-if(winWidget&&browserIsRemote,0-1) skip-if(!haveTestPlugin) HTTP script 540114-1.html
skip-if(!haveTestPlugin) HTTP load 570884.html
HTTP load 570884.html
# This test relies on the reading of screenX/Y forcing a round trip to
# the X server, which is a bad assumption for <browser remote>.
# Plugin arch is going to change anyway with OOP content so skipping
# this test for now is OK.
skip-if(!haveTestPlugin||http.platform!="X11") HTTP load 598862.html
skip-if(!haveTestPlugin) HTTP load 626602-1.html
HTTP load 626602-1.html
HTTP load 752340.html
HTTP load 843086.xhtml

Просмотреть файл

@ -0,0 +1,9 @@
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>1028200 subpageA</h1>
<iframe id="iframe2" src="1028200-subpageA1.html" width="400" height="400"></iframe>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>1028200 subpageA1</h1>
<embed id="plugin1" type="application/x-test" />
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше