Bug 1318800 fix systemPrincipal checks so top level tab loads work with webrequests, r?kmag
MozReview-Commit-ID: D5b8Qs839bP
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -13,16 +13,17 @@ support-files =
file_iframe_document.sjs
file_bypass_cache.sjs
file_language_fr_en.html
file_language_ja.html
file_language_tlh.html
file_dummy.html
searchSuggestionEngine.xml
searchSuggestionEngine.sjs
+ ../../../../../toolkit/components/extensions/test/mochitest/head_webrequest.js
[browser_ext_browserAction_context.js]
[browser_ext_browserAction_disabled.js]
[browser_ext_browserAction_pageAction_icon.js]
[browser_ext_browserAction_pageAction_icon_permissions.js]
[browser_ext_browserAction_popup.js]
[browser_ext_browserAction_popup_preload.js]
[browser_ext_browserAction_popup_resize.js]
@@ -88,16 +89,17 @@ support-files =
[browser_ext_tabs_reload.js]
[browser_ext_tabs_reload_bypass_cache.js]
[browser_ext_tabs_sendMessage.js]
[browser_ext_tabs_cookieStoreId.js]
[browser_ext_tabs_update.js]
[browser_ext_tabs_zoom.js]
[browser_ext_tabs_update_url.js]
[browser_ext_topwindowid.js]
+[browser_ext_webRequest.js]
[browser_ext_webNavigation_frameId0.js]
[browser_ext_webNavigation_getFrames.js]
[browser_ext_windows.js]
[browser_ext_windows_create.js]
tags = fullscreen
[browser_ext_windows_create_params.js]
[browser_ext_windows_create_tabId.js]
[browser_ext_windows_create_url.js]
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -1,12 +1,11 @@
[DEFAULT]
tags = webextensions in-process-webextensions
-
[browser_ext_legacy_extension_context_contentscript.js]
[browser_ext_omnibox.js]
[browser_ext_webNavigation_urlbar_transitions.js]
[browser_ext_windows_allowScriptsToClose.js]
[browser_ext_windows_events.js]
[include:browser-common.ini]
[parent:browser-common.ini]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_webRequest.js
@@ -0,0 +1,95 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+/* globals makeExtension */
+"use strict";
+
+Services.scriptloader.loadSubScript(new URL("head_webrequest.js", gTestPath).href,
+ this);
+
+Cu.import("resource:///modules/HiddenFrame.jsm", this);
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function createHiddenBrowser(url) {
+ let frame = new HiddenFrame();
+ return new Promise(resolve =>
+ frame.get().then(subframe => {
+ let doc = subframe.document;
+ let browser = doc.createElementNS(XUL_NS, "browser");
+ browser.setAttribute("type", "content");
+ browser.setAttribute("disableglobalhistory", "true");
+ browser.setAttribute("src", url);
+
+ doc.documentElement.appendChild(browser);
+ resolve({frame: frame, browser: browser});
+ }));
+}
+
+let extension;
+let dummy = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/file_dummy.html";
+
+add_task(function* setup() {
+ // SelfSupport has a tendency to fire when running this test alone, without
+ // a good way to turn it off we just set the url to ""
+ yield SpecialPowers.pushPrefEnv({
+ set: [["browser.selfsupport.url", ""]],
+ });
+ extension = makeExtension();
+ yield extension.startup();
+});
+
+add_task(function* test_newWindow() {
+ let expect = {
+ "file_dummy.html": {
+ type: "main_frame",
+ },
+ };
+ // NOTE: When running solo, favicon will be loaded at some point during
+ // the tests in this file, so all tests ignore it. When running with
+ // other tests in this directory, favicon gets loaded at some point before
+ // we run, and we never see the request, thus it cannot be handled as part
+ // of expect above.
+ extension.sendMessage("set-expected", {expect, ignore: ["favicon.ico"]});
+ yield extension.awaitMessage("continue");
+
+ let openedWindow = yield BrowserTestUtils.openNewBrowserWindow();
+ yield BrowserTestUtils.openNewForegroundTab(openedWindow.gBrowser, dummy + "?newWindow");
+
+ yield extension.awaitMessage("done");
+ yield BrowserTestUtils.closeWindow(openedWindow);
+});
+
+add_task(function* test_newTab() {
+ // again, in this window
+ let expect = {
+ "file_dummy.html": {
+ type: "main_frame",
+ },
+ };
+ extension.sendMessage("set-expected", {expect, ignore: ["favicon.ico"]});
+ yield extension.awaitMessage("continue");
+ let tab = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser, dummy + "?newTab");
+
+ yield extension.awaitMessage("done");
+ yield BrowserTestUtils.removeTab(tab);
+});
+
+add_task(function* test_subframe() {
+ let expect = {
+ "file_dummy.html": {
+ type: "main_frame",
+ },
+ };
+ // test a content subframe attached to hidden window
+ extension.sendMessage("set-expected", {expect, ignore: ["favicon.ico"]});
+ yield extension.awaitMessage("continue");
+ let frameInfo = yield createHiddenBrowser(dummy + "?subframe");
+ yield extension.awaitMessage("done");
+ // cleanup
+ frameInfo.browser.remove();
+ frameInfo.frame.destroy();
+});
+
+add_task(function* teardown() {
+ yield extension.unload();
+});
+
--- a/toolkit/components/extensions/test/mochitest/head_webrequest.js
+++ b/toolkit/components/extensions/test/mochitest/head_webrequest.js
@@ -8,24 +8,26 @@ let commonEvents = {
"onHeadersReceived": [{urls: ["<all_urls>"]}, ["blocking", "responseHeaders"]],
"onResponseStarted": [{urls: ["<all_urls>"]}],
"onCompleted": [{urls: ["<all_urls>"]}, ["responseHeaders"]],
"onErrorOccurred": [{urls: ["<all_urls>"]}],
};
function background(events) {
let expect;
+ let ignore;
let defaultOrigin;
browser.test.onMessage.addListener((msg, expected) => {
if (msg !== "set-expected") {
return;
}
expect = expected.expect;
defaultOrigin = expected.origin;
+ ignore = expected.ignore;
let promises = [];
// Initialize some stuff we'll need in the tests.
for (let entry of Object.values(expect)) {
// a place for the test infrastructure to store some state.
entry.test = {};
// Each entry in expected gets a Promise that will be resolved in the
// last event for that entry. This will either be onCompleted, or the
// last entry if an events list was provided.
@@ -51,16 +53,19 @@ function background(events) {
let url = new URL(details.url);
let filename;
if (url.protocol == "data:") {
// pathname is everything after protocol.
filename = url.pathname;
} else {
filename = url.pathname.split("/").pop();
}
+ if (ignore && ignore.includes(filename)) {
+ return;
+ }
let expected = expect[filename];
if (!expected) {
browser.test.fail(`unexpected request ${filename}`);
return;
}
// Save filename for redirect verification.
expected.test.filename = filename;
return expected;
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
@@ -9,16 +9,22 @@
<script type="text/javascript" src="head_webrequest.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script>
"use strict";
let extension;
add_task(function* setup() {
+ // SelfSupport has a tendency to fire when running this test alone, without
+ // a good way to turn it off we just set the url to ""
+ yield SpecialPowers.pushPrefEnv({
+ set: [["browser.selfsupport.url", ""]],
+ });
+
// Clear the image cache, since it gets in the way otherwise.
let imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools);
let cache = imgTools.getImgCacheForDocument(document);
cache.clearCache(false);
extension = makeExtension();
yield extension.startup();
});
@@ -229,16 +235,55 @@ add_task(function* test_webRequest_tabId
};
extension.sendMessage("set-expected", {expect, origin: location.href});
yield extension.awaitMessage("continue");
let a = addLink("file_WebRequest_page3.html?trigger=a");
a.click();
yield extension.awaitMessage("done");
});
+add_task(function* test_webRequest_tabId_browser() {
+ async function background(url) {
+ let tabId;
+ browser.test.onMessage.addListener(async (msg, expected) => {
+ await browser.tabs.remove(tabId);
+ browser.test.sendMessage("done");
+ });
+
+ let tab = await browser.tabs.create({url});
+ tabId = tab.id;
+ }
+
+ let tabExt = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: [
+ "tabs",
+ ],
+ },
+ background: `(${background})('${SimpleTest.getTestFileURL("file_sample.html")}?nocache=${Math.random()}')`,
+ });
+
+ let expect = {
+ "file_sample.html": {
+ type: "main_frame",
+ },
+ };
+ // expecting origin == undefined
+ extension.sendMessage("set-expected", {expect});
+ yield extension.awaitMessage("continue");
+
+ // open a tab from a system principal
+ yield tabExt.startup();
+
+ yield extension.awaitMessage("done");
+ tabExt.sendMessage("done");
+ yield tabExt.awaitMessage("done");
+ yield tabExt.unload();
+});
+
add_task(function* test_webRequest_frames() {
let expect = {
"text/plain,webRequestTest": {
type: "sub_frame",
events: ["onBeforeRequest", "onCompleted"],
},
"text/plain,webRequestTest_bad": {
type: "sub_frame",
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -619,20 +619,26 @@ HttpObserverManager = {
};
if (loadInfo) {
let originPrincipal = loadInfo.triggeringPrincipal;
if (originPrincipal.URI) {
data.originUrl = originPrincipal.URI.spec;
}
+ // If there is no loadingPrincipal, check that the request is not going to
+ // inherit a system principal. triggeringPrincipal is the context that
+ // initiated the load, but is not necessarily the principal that the
+ // request results in, only rely on that if no other principal is available.
let {isSystemPrincipal} = Services.scriptSecurityManager;
-
- data.isSystemPrincipal = (isSystemPrincipal(loadInfo.triggeringPrincipal) ||
- isSystemPrincipal(loadInfo.loadingPrincipal));
+ let isTopLevel = !loadInfo.loadingPrincipal && !!data.browser;
+ data.isSystemPrincipal = !isTopLevel &&
+ isSystemPrincipal(loadInfo.loadingPrincipal ||
+ loadInfo.principalToInherit ||
+ loadInfo.triggeringPrincipal);
if (loadInfo.frameOuterWindowID) {
Object.assign(data, {
windowId: loadInfo.frameOuterWindowID,
parentWindowId: loadInfo.outerWindowID,
});
} else {
Object.assign(data, {