Commit 2718cd65 authored by Rob Wu's avatar Rob Wu
Browse files

Bug 1638007 - Check windowId/tabId before urls r=mixedpuppy

Differential Revision: https://phabricator.services.mozilla.com/D77174
parent d4fa56c9
......@@ -4,10 +4,6 @@
"use strict";
// This file expects tabTracker to be defined in the global scope (e.g.
// by ext-utils.js).
/* global tabTracker */
ChromeUtils.defineModuleGetter(
this,
"WebRequest",
......@@ -25,27 +21,7 @@ function registerEvent(
remoteTab = null
) {
let listener = async data => {
let browserData = { tabId: -1, windowId: -1 };
if (data.browser) {
browserData = tabTracker.getBrowserData(data.browser);
}
if (filter.tabId != null && browserData.tabId != filter.tabId) {
return;
}
if (filter.windowId != null && browserData.windowId != filter.windowId) {
return;
}
let event = data.serialize(eventName);
event.tabId = browserData.tabId;
if (data.originAttributes) {
event.incognito = data.originAttributes.privateBrowsingId > 0;
if (extension.hasPermission("cookies")) {
event.cookieStoreId = getCookieStoreIdForOriginAttributes(
data.originAttributes
);
}
}
let event = data.serialize(eventName, extension);
if (data.registerTraceableChannel) {
// If this is a primed listener, no tabParent was passed in here,
// but the convert() callback later in this function will be called
......@@ -78,10 +54,10 @@ function registerEvent(
if (filter.types) {
filter2.types = filter.types;
}
if (filter.tabId) {
if (filter.tabId !== undefined) {
filter2.tabId = filter.tabId;
}
if (filter.windowId) {
if (filter.windowId !== undefined) {
filter2.windowId = filter.windowId;
}
if (filter.incognito !== undefined) {
......
......@@ -227,13 +227,13 @@ add_task(async function test_api() {
type: "main_frame",
frameId: 0,
parentFrameId: -1,
incognito: false,
thirdParty: false,
ip: null,
frameAncestors: [],
urlClassification: { firstParty: [], thirdParty: [] },
requestSize: 0,
responseSize: 0,
incognito: false,
},
],
result: {
......
......@@ -6,10 +6,19 @@ var { WebRequest } = ChromeUtils.import(
var { PromiseUtils } = ChromeUtils.import(
"resource://gre/modules/PromiseUtils.jsm"
);
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
const server = createHttpServer({ hosts: ["example.com"] });
server.registerDirectory("/data/", do_get_file("data"));
add_task(async function setup() {
// When WebRequest.jsm is used directly instead of through ext-webRequest.js,
// ExtensionParent.apiManager is not automatically initialized. Do it here.
await ExtensionParent.apiManager.lazyInit();
});
add_task(async function test_ancestors_exist() {
let deferred = PromiseUtils.defer();
function onBeforeRequest(details) {
......
......@@ -4,6 +4,10 @@ var { WebRequest } = ChromeUtils.import(
"resource://gre/modules/WebRequest.jsm"
);
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
const server = createHttpServer({ hosts: ["example.com"] });
server.registerPathHandler("/", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
......@@ -70,6 +74,12 @@ function onResponseStarted(details) {
equal(countAfter, 1, "onResponseStarted hit once");
}
add_task(async function setup() {
// When WebRequest.jsm is used directly instead of through ext-webRequest.js,
// ExtensionParent.apiManager is not automatically initialized. Do it here.
await ExtensionParent.apiManager.lazyInit();
});
add_task(async function filter_urls() {
// First load the URL so that we set cookie foopy=1.
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
......
......@@ -4,6 +4,10 @@ var { WebRequest } = ChromeUtils.import(
"resource://gre/modules/WebRequest.jsm"
);
var { ExtensionParent } = ChromeUtils.import(
"resource://gre/modules/ExtensionParent.jsm"
);
const server = createHttpServer({ hosts: ["example.com"] });
server.registerDirectory("/data/", do_get_file("data"));
......@@ -42,6 +46,12 @@ const expected_urls = [
BASE + "/file_style_redirect.css",
];
function resetExpectations() {
requested.length = 0;
sendHeaders.length = 0;
completed.length = 0;
}
function removeDupes(list) {
let j = 0;
for (let i = 1; i < list.length; i++) {
......@@ -66,6 +76,10 @@ function compareLists(list1, list2, kind) {
add_task(async function setup() {
// Disable rcwn to make cache behavior deterministic.
Services.prefs.setBoolPref("network.http.rcwn.enabled", false);
// When WebRequest.jsm is used directly instead of through ext-webRequest.js,
// ExtensionParent.apiManager is not automatically initialized. Do it here.
await ExtensionParent.apiManager.lazyInit();
});
add_task(async function filter_urls() {
......@@ -90,6 +104,7 @@ add_task(async function filter_urls() {
});
add_task(async function filter_types() {
resetExpectations();
let filter = { types: ["stylesheet"] };
WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]);
......@@ -109,3 +124,51 @@ add_task(async function filter_types() {
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
WebRequest.onResponseStarted.removeListener(onResponseStarted);
});
add_task(async function filter_windowId() {
resetExpectations();
// Check that adding windowId will exclude non-matching requests.
// test_ext_webrequest_filter.html provides coverage for matching requests.
let filter = { urls: new MatchPatternSet(["*://*/*_style_*"]), windowId: 0 };
WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]);
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, filter, [
"blocking",
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, [], "requested");
compareLists(sendHeaders, [], "sendHeaders");
compareLists(completed, [], "completed");
WebRequest.onBeforeRequest.removeListener(onBeforeRequest);
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
WebRequest.onResponseStarted.removeListener(onResponseStarted);
});
add_task(async function filter_tabId() {
resetExpectations();
// Check that adding tabId will exclude non-matching requests.
// test_ext_webrequest_filter.html provides coverage for matching requests.
let filter = { urls: new MatchPatternSet(["*://*/*_style_*"]), tabId: 0 };
WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]);
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, filter, [
"blocking",
]);
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
let contentPage = await ExtensionTestUtils.loadContentPage(URL);
await contentPage.close();
compareLists(requested, [], "requested");
compareLists(sendHeaders, [], "sendHeaders");
compareLists(completed, [], "completed");
WebRequest.onBeforeRequest.removeListener(onBeforeRequest);
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
WebRequest.onResponseStarted.removeListener(onResponseStarted);
});
......@@ -18,11 +18,21 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
WebRequestUpload: "resource://gre/modules/WebRequestUpload.jsm",
SecurityInfo: "resource://gre/modules/SecurityInfo.jsm",
});
// WebRequest.jsm's only consumer is ext-webRequest.js, so we can depend on
// the apiManager.global being initialized.
XPCOMUtils.defineLazyGetter(this, "tabTracker", () => {
return ExtensionParent.apiManager.global.tabTracker;
});
XPCOMUtils.defineLazyGetter(this, "getCookieStoreIdForOriginAttributes", () => {
return ExtensionParent.apiManager.global.getCookieStoreIdForOriginAttributes;
});
function runLater(job) {
Services.tm.dispatchToMainThread(job);
}
......@@ -32,11 +42,12 @@ function parseFilter(filter) {
filter = {};
}
// FIXME: Support windowId filtering.
return {
urls: filter.urls || null,
types: filter.types || null,
incognito: filter.incognito !== undefined ? filter.incognito : null,
tabId: filter.tabId ?? null,
windowId: filter.windowId ?? null,
incognito: filter.incognito ?? null,
};
}
......@@ -225,7 +236,7 @@ const OPTIONAL_PROPERTIES = [
"responseSize",
];
function serializeRequestData(eventName) {
function serializeRequestData(eventName, extension) {
let data = {
requestId: this.requestId,
url: this.url,
......@@ -234,11 +245,19 @@ function serializeRequestData(eventName) {
method: this.method,
type: this.type,
timeStamp: Date.now(),
frameId: this.windowId,
tabId: this.tabId,
frameId: this.frameId,
parentFrameId: this.parentWindowId,
incognito: this.incognito,
thirdParty: this.thirdParty,
};
if (extension) {
if (extension.hasPermission("cookies")) {
data.cookieStoreId = this.cookieStoreId;
}
}
if (MAYBE_CACHED_EVENTS.has(eventName)) {
data.fromCache = !!this.fromCache;
}
......@@ -703,22 +722,21 @@ HttpObserverManager = {
},
getRequestData(channel, extraData) {
let originAttributes =
channel.loadInfo && channel.loadInfo.originAttributes;
let originAttributes = channel.loadInfo?.originAttributes;
let data = {
requestId: String(channel.id),
url: channel.finalURL,
method: channel.method,
browser: channel.browserElement,
type: channel.type,
fromCache: channel.fromCache,
originAttributes,
incognito: originAttributes?.privateBrowsingId > 0,
thirdParty: channel.thirdParty,
originUrl: channel.originURL || undefined,
documentUrl: channel.documentURL || undefined,
windowId: channel.windowId,
tabId: this.getBrowserData(channel).tabId,
frameId: channel.windowId,
parentWindowId: channel.parentWindowId,
frameAncestors: channel.frameAncestors || undefined,
......@@ -733,6 +751,12 @@ HttpObserverManager = {
urlClassification: channel.urlClassification,
};
if (originAttributes) {
data.cookieStoreId = getCookieStoreIdForOriginAttributes(
originAttributes
);
}
return Object.assign(data, extraData);
},
......@@ -769,6 +793,19 @@ HttpObserverManager = {
"onBeforeRedirect",
]),
getBrowserData(wrapper) {
let browserData = wrapper._browserData;
if (!browserData) {
if (wrapper.browserElement) {
browserData = tabTracker.getBrowserData(wrapper.browserElement);
} else {
browserData = { tabId: -1, windowId: -1 };
}
wrapper._browserData = browserData;
}
return browserData;
},
runChannelListener(channel, kind, extraData = null) {
let handlerResults = [];
let requestHeaders;
......@@ -783,6 +820,15 @@ HttpObserverManager = {
let commonData = null;
let requestBody;
this.listeners[kind].forEach((opts, callback) => {
if (opts.filter.tabId !== null || opts.filter.windowId !== null) {
const { tabId, windowId } = this.getBrowserData(channel);
if (
(opts.filter.tabId !== null && tabId != opts.filter.tabId) ||
(opts.filter.windowId !== null && windowId != opts.filter.windowId)
) {
return;
}
}
if (!channel.matches(opts.filter, opts.policy, extraData)) {
return;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment