Bug 1311576 fix webrequest filter for tabId and windowId, r=kmag
MozReview-Commit-ID: FzW53LXktWz
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -71,17 +71,20 @@ extensions.on("page-shutdown", (type, co
if (tab) {
gBrowser.removeTab(tab);
}
}
}
});
extensions.on("fill-browser-data", (type, browser, data) => {
- data.tabId = browser ? TabManager.getBrowserId(browser) : -1;
+ let gBrowser = browser && browser.ownerGlobal.gBrowser;
+ let tab = gBrowser && gBrowser.getTabForBrowser(browser);
+ data.tabId = tab ? TabManager.getId(tab) : -1;
+ data.windowId = tab ? WindowManager.getId(tab.ownerGlobal) : -1;
});
/* eslint-enable mozilla/balanced-listeners */
global.currentWindow = function(context) {
let {xulWindow} = context;
if (xulWindow && context.viewType != "background") {
return xulWindow;
}
@@ -135,17 +138,17 @@ let tabListener = {
} else {
this.emitRemoved(tab, false);
}
break;
}
},
handleWindowOpen(window) {
- if (window.arguments[0] instanceof window.XULElement) {
+ if (window.arguments && window.arguments[0] instanceof window.XULElement) {
// If the first window argument is a XUL element, it means the
// window is about to adopt a tab from another window to replace its
// initial tab.
//
// Note that this event handler depends on running before the
// delayed startup code in browser.js, which is currently triggered
// by the first MozAfterPaint event. That code handles finally
// adopting the tab, and clears it from the arguments list in the
--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -22,39 +22,46 @@ function WebRequestEventManager(context,
let name = `webRequest.${eventName}`;
let register = (callback, filter, info) => {
let listener = data => {
// Prevent listening in on requests originating from system principal to
// prevent tinkering with OCSP, app and addon updates, etc.
if (data.isSystemPrincipal) {
return;
}
+ let browserData = {};
+ extensions.emit("fill-browser-data", data.browser, browserData);
+ if (filter.tabId != null && browserData.tabId != filter.tabId) {
+ return;
+ }
+ if (filter.windowId != null && browserData.windowId != filter.windowId) {
+ return;
+ }
let data2 = {
requestId: data.requestId,
url: data.url,
originUrl: data.originUrl,
method: data.method,
+ tabId: browserData.tabId,
type: data.type,
timeStamp: Date.now(),
frameId: ExtensionManagement.getFrameId(data.windowId),
parentFrameId: ExtensionManagement.getParentFrameId(data.parentWindowId, data.windowId),
};
const maybeCached = ["onResponseStarted", "onBeforeRedirect", "onCompleted", "onErrorOccurred"];
if (maybeCached.includes(eventName)) {
data2.fromCache = !!data.fromCache;
}
if ("ip" in data) {
data2.ip = data.ip;
}
- extensions.emit("fill-browser-data", data.browser, data2);
-
let optional = ["requestHeaders", "responseHeaders", "statusCode", "statusLine", "error", "redirectUrl",
"requestBody"];
for (let opt of optional) {
if (opt in data) {
data2[opt] = data[opt];
}
}
--- a/toolkit/components/extensions/test/mochitest/head_webrequest.js
+++ b/toolkit/components/extensions/test/mochitest/head_webrequest.js
@@ -154,36 +154,33 @@ function background(events) {
let expected = getExpected(details);
if (!expected) {
return result;
}
let expectedEvent = expected.events[0] == name;
if (expectedEvent) {
expected.events.shift();
} else {
- expectedEvent = expected.optional_events[0] == name;
- if (expectedEvent) {
- expected.optional_events.shift();
- }
+ // e10s vs. non-e10s errors can end with either onCompleted or onErrorOccurred
+ expectedEvent = expected.optional_events.includes(name);
}
browser.test.assertTrue(expectedEvent, `received ${name}`);
browser.test.assertEq(expected.type, details.type, "resource type is correct");
browser.test.assertEq(expected.origin || defaultOrigin, details.originUrl, "origin is correct");
if (name == "onBeforeRequest") {
// Save some values to test request consistency in later events.
browser.test.assertTrue(details.tabId !== undefined, `tabId ${details.tabId}`);
browser.test.assertTrue(details.requestId !== undefined, `requestId ${details.requestId}`);
// Validate requestId if it's already set, this happens with redirects.
if (expected.test.requestId !== undefined) {
browser.test.assertEq("string", typeof expected.test.requestId, `requestid ${expected.test.requestId} is string`);
browser.test.assertEq("string", typeof details.requestId, `requestid ${details.requestId} is string`);
browser.test.assertEq("number", typeof parseInt(details.requestId, 10), "parsed requestid is number");
- browser.test.assertNotEq(expected.test.requestId, details.requestId,
- `last requestId ${expected.test.requestId} different from this one ${details.requestId}`);
+ browser.test.assertEq(expected.test.requestId, details.requestId, "redirects will keep the same requestId");
} else {
// Save any values we want to validate in later events.
expected.test.requestId = details.requestId;
expected.test.tabId = details.tabId;
}
// Tests we don't need to do every event.
browser.test.assertTrue(details.type.toUpperCase() in browser.webRequest.ResourceType, `valid resource type ${details.type}`);
} else {
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -91,16 +91,18 @@ skip-if = (os == 'android') # Android do
[test_ext_i18n.html]
skip-if = (os == 'android') # Bug 1258975 on android.
[test_ext_web_accessible_resources.html]
skip-if = (os == 'android') # Bug 1258975 on android.
[test_ext_webrequest_background_events.html]
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
[test_ext_webrequest_basic.html]
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_filter.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
[test_ext_webrequest_suspend.html]
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
[test_ext_webrequest_upload.html]
skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
[test_ext_webnavigation.html]
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
[test_ext_webnavigation_filters.html]
skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_filter.html
@@ -0,0 +1,181 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+ <script type="text/javascript" src="head.js"></script>
+ <script type="text/javascript" src="head_webrequest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<script>
+"use strict";
+
+let windowData, testWindow;
+
+add_task(function* setup() {
+ testWindow = window.open("about:blank", "_blank", "width=100,height=100");
+ yield waitForLoad(testWindow);
+
+ // Fetch the windowId and tabId we need to filter with WebRequest.
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ permissions: [
+ "tabs",
+ ],
+ },
+ background() {
+ browser.windows.getCurrent({populate: true}).then(window => {
+ browser.test.log(`current window ${window.id} tabs: ${JSON.stringify(window.tabs.map(tab => [tab.id, tab.url]))}`);
+ browser.test.sendMessage("windowData", {windowId: window.id, tabId: window.tabs[0].id});
+ });
+ },
+ });
+ yield extension.startup();
+ windowData = yield extension.awaitMessage("windowData");
+ info(`window is ${JSON.stringify(windowData)}`);
+ yield extension.unload();
+});
+
+add_task(function* test_webRequest_filter_window() {
+ yield SpecialPowers.pushPrefEnv({
+ set: [["dom.serviceWorkers.testing.enabled", true]],
+ });
+
+ let events = {
+ "onBeforeRequest": [{urls: ["<all_urls>"], windowId: windowData.windowId}],
+ "onBeforeSendHeaders": [{urls: ["<all_urls>"], windowId: windowData.windowId}, ["requestHeaders"]],
+ "onSendHeaders": [{urls: ["<all_urls>"], windowId: windowData.windowId}, ["requestHeaders"]],
+ "onBeforeRedirect": [{urls: ["<all_urls>"], windowId: windowData.windowId}],
+ "onHeadersReceived": [{urls: ["<all_urls>"], windowId: windowData.windowId}, ["responseHeaders"]],
+ "onResponseStarted": [{urls: ["<all_urls>"], windowId: windowData.windowId}],
+ "onCompleted": [{urls: ["<all_urls>"], windowId: windowData.windowId}, ["responseHeaders"]],
+ "onErrorOccurred": [{urls: ["<all_urls>"], windowId: windowData.windowId}],
+ };
+ let expect = {
+ "file_image_bad.png": {
+ optional_events: ["onBeforeRedirect", "onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders"],
+ type: "main_frame",
+ },
+ };
+
+ let extension = makeExtension(events);
+ yield extension.startup();
+ extension.sendMessage("set-expected", {expect, origin: location.href});
+ yield extension.awaitMessage("continue");
+
+ // We should not get events for a new window load.
+ let newWindow = window.open("file_image_good.png", "_blank", "width=100,height=100");
+ yield waitForLoad(newWindow);
+ newWindow.close();
+
+ // We should not get background events.
+ let registration = yield navigator.serviceWorker.register("webrequest_worker.js?test0", {scope: "."});
+
+ // We should get events for the reload.
+ testWindow.location = "file_image_bad.png";
+ yield extension.awaitMessage("done");
+
+ yield registration.unregister();
+ yield extension.unload();
+});
+
+add_task(function* test_webRequest_filter_tab() {
+ yield SpecialPowers.pushPrefEnv({
+ set: [["dom.serviceWorkers.testing.enabled", true]],
+ });
+
+ let events = {
+ "onBeforeRequest": [{urls: ["<all_urls>"], tabId: windowData.tabId}],
+ "onBeforeSendHeaders": [{urls: ["<all_urls>"], tabId: windowData.tabId}, ["requestHeaders"]],
+ "onSendHeaders": [{urls: ["<all_urls>"], tabId: windowData.tabId}, ["requestHeaders"]],
+ "onBeforeRedirect": [{urls: ["<all_urls>"], tabId: windowData.tabId}],
+ "onHeadersReceived": [{urls: ["<all_urls>"], tabId: windowData.tabId}, ["responseHeaders"]],
+ "onResponseStarted": [{urls: ["<all_urls>"], tabId: windowData.tabId}],
+ "onCompleted": [{urls: ["<all_urls>"], tabId: windowData.tabId}, ["responseHeaders"]],
+ "onErrorOccurred": [{urls: ["<all_urls>"], tabId: windowData.tabId}],
+ };
+ let expect = {
+ "file_image_good.png": {
+ optional_events: ["onBeforeRedirect", "onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders"],
+ type: "main_frame",
+ cached: true,
+ },
+ };
+
+ let extension = makeExtension(events);
+ yield extension.startup();
+ extension.sendMessage("set-expected", {expect, origin: location.href});
+ yield extension.awaitMessage("continue");
+
+ // We should not get events for a new window load.
+ let newWindow = window.open("file_image_good.png", "_blank", "width=100,height=100");
+ yield waitForLoad(newWindow);
+ newWindow.close();
+
+ // We should not get background events.
+ let registration = yield navigator.serviceWorker.register("webrequest_worker.js?test1", {scope: "."});
+
+ // We should get events for the reload.
+ testWindow.location = "file_image_good.png";
+ yield extension.awaitMessage("done");
+
+ yield registration.unregister();
+ yield extension.unload();
+});
+
+
+add_task(function* test_webRequest_filter_background() {
+ yield SpecialPowers.pushPrefEnv({
+ set: [["dom.serviceWorkers.testing.enabled", true]],
+ });
+
+ let events = {
+ "onBeforeRequest": [{urls: ["<all_urls>"], tabId: -1}],
+ "onBeforeSendHeaders": [{urls: ["<all_urls>"], tabId: -1}, ["requestHeaders"]],
+ "onSendHeaders": [{urls: ["<all_urls>"], tabId: -1}, ["requestHeaders"]],
+ "onBeforeRedirect": [{urls: ["<all_urls>"], tabId: -1}],
+ "onHeadersReceived": [{urls: ["<all_urls>"], tabId: -1}, ["responseHeaders"]],
+ "onResponseStarted": [{urls: ["<all_urls>"], tabId: -1}],
+ "onCompleted": [{urls: ["<all_urls>"], tabId: -1}, ["responseHeaders"]],
+ "onErrorOccurred": [{urls: ["<all_urls>"], tabId: -1}],
+ };
+ let expect = {
+ "webrequest_worker.js": {
+ type: "script",
+ },
+ "example.txt": {
+ status: 404,
+ events: ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", "onHeadersReceived", "onResponseStarted"],
+ optional_events: ["onCompleted", "onErrorOccurred"],
+ type: "other",
+ origin: SimpleTest.getTestFileURL("webrequest_worker.js?test2"),
+ },
+ };
+
+ let extension = makeExtension(events);
+ yield extension.startup();
+ extension.sendMessage("set-expected", {expect, origin: location.href});
+ yield extension.awaitMessage("continue");
+
+ // We should not get events for a window.
+ testWindow.location = "file_image_bad.png";
+
+ // We should get events for the background page.
+ let registration = yield navigator.serviceWorker.register(SimpleTest.getTestFileURL("webrequest_worker.js?test2"), {scope: "."});
+ yield extension.awaitMessage("done");
+ yield registration.unregister();
+
+ yield extension.unload();
+});
+
+add_task(function* teardown() {
+ testWindow.close();
+});
+</script>
+</head>
+<body>
+
+</body>
+</html>