Bug 1242871 - add an originUrl property to every webRequest event details object + tests (extended & fixed + nits). r?kmag
MozReview-Commit-ID: 6PeCwTeCuFs
--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -29,16 +29,17 @@ function WebRequestEventManager(context,
let tabId = TabManager.getBrowserId(data.browser);
if (tabId == -1) {
return;
}
let data2 = {
requestId: data.requestId,
url: data.url,
+ originUrl: data.originUrl,
method: data.method,
type: data.type,
timeStamp: Date.now(),
frameId: ExtensionManagement.getFrameId(data.windowId),
parentFrameId: ExtensionManagement.getParentFrameId(data.parentWindowId, data.windowId),
};
if ("ip" in data) {
--- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
@@ -23,10 +23,21 @@
<script src="nonexistent_script_url.js"></script>
<iframe src="file_WebRequest_page2.html" width="200" height="200"></iframe>
<iframe src="redirection.sjs" width="200" height="200"></iframe>
<iframe src="data:text/plain,webRequestTest" width="200" height="200"></iframe>
<iframe src="data:text/plain,webRequestTest_bad" width="200" height="200"></iframe>
<iframe src="https://invalid.localhost/" width="200" height="200"></iframe>
+<a href="file_WebRequest_page3.html?trigger=a" target="webrequest_link">link</a>
+<form method="post" action="file_WebRequest_page3.html?trigger=form" target="webrequest_form"></form>
+<script>
+"use strict";
+for (let a of document.links) {
+ a.click();
+}
+for (let f of document.forms) {
+ f.submit();
+}
+</script>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+<script>
+"use strict";
+window.close();
+</script>
+</head>
+</html>
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -1,14 +1,15 @@
[DEFAULT]
skip-if = buildapp == 'mulet' || asan
support-files =
head.js
file_WebRequest_page1.html
file_WebRequest_page2.html
+ file_WebRequest_page3.html
file_WebNavigation_page1.html
file_WebNavigation_page2.html
file_WebNavigation_page3.html
file_image_good.png
file_image_bad.png
file_image_redirect.png
file_style_good.css
file_style_bad.css
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
@@ -93,33 +93,40 @@ function compareLists(list1, list2, kind
is(String(list1), String(list2), `${kind} URLs correct`);
}
function backgroundScript() {
let checkCompleted = true;
let savedTabId = -1;
function shouldRecord(url) {
- return url.startsWith(BASE) || /^data:.*\bwebRequestTest|\/invalid\./.test(url);
+ return url.startsWith(BASE) && !url.includes("_page3.html") ||
+ /^data:.*\bwebRequestTest|\/invalid\./.test(url);
}
let statuses = [
{url: /_script_good\b/, code: 200, line: /^HTTP\/1.1 200 OK\b/i},
{url: /\bredirection\b/, code: 302, line: /^HTTP\/1.1 302\b/},
{url: /\bnonexistent_script_/, code: 404, line: /^HTTP\/1.1 404 Not Found\b/i},
];
function checkStatus(details) {
for (let {url, code, line} of statuses) {
if (url.test(details.url)) {
browser.test.assertEq(code, details.statusCode, `HTTP status code ${code} for ${details.url} (found ${details.statusCode})`);
browser.test.assertTrue(line.test(details.statusLine), `HTTP status line ${line} for ${details.url} (found ${details.statusLine})`);
}
}
}
+ function checkOrigin(details) {
+ let isCorrectOrigin = details.url.includes("_page1.html") ? details.originUrl.endsWith("/test_ext_webrequest.html")
+ : /\/file_WebRequest_page\d\.html\b/.test(details.originUrl);
+ browser.test.assertTrue(isCorrectOrigin, `originUrl for ${details.url} is correct (${details.originUrl})`);
+ }
+
function checkType(details) {
let expected_type = "???";
if (details.url.includes("style")) {
expected_type = "stylesheet";
} else if (details.url.includes("image")) {
expected_type = "image";
} else if (details.url.includes("script")) {
expected_type = "script";
@@ -275,16 +282,17 @@ function backgroundScript() {
let ids = requestIDs.get(details.url);
if (ids) {
ids.add(details.requestId);
} else {
requestIDs.set(details.url, new Set([details.requestId]));
}
checkResourceType(details.type);
+ checkOrigin(details);
if (shouldRecord(details.url)) {
recorded.requested.push(details.url);
if (savedTabId == -1) {
browser.test.assertTrue(details.tabId !== undefined, "tab ID defined");
savedTabId = details.tabId;
}
@@ -306,16 +314,17 @@ function backgroundScript() {
return {cancel: true};
}
return {};
}
function onBeforeSendHeaders(details) {
browser.test.log(`onBeforeSendHeaders ${details.url}`);
checkRequestId(details);
+ checkOrigin(details);
checkResourceType(details.type);
processHeaders("request", details);
if (shouldRecord(details.url)) {
recorded.beforeSendHeaders.push(details.url);
browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
checkType(details);
@@ -326,16 +335,17 @@ function backgroundScript() {
return {redirectUrl: details.url.replace("_redirect.", "_good.")};
}
return {requestHeaders: details.requestHeaders};
}
function onBeforeRedirect(details) {
browser.test.log(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`);
checkRequestId(details, "redirect");
+ checkOrigin(details);
checkResourceType(details.type);
if (shouldRecord(details.url)) {
recorded.beforeRedirect.push(details.url);
browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
checkType(details);
checkStatus(details);
@@ -349,16 +359,17 @@ function backgroundScript() {
}
return {};
}
function onRecord(kind, details) {
browser.test.log(`${kind} ${details.requestId} ${details.url}`);
checkResourceType(details.type);
checkRequestId(details, kind);
+ checkOrigin(details);
if (kind in recorded && shouldRecord(details.url)) {
recorded[kind].push(details.url);
}
}
function onSendHeaders(details) {
onRecord("sendHeaders", details);
checkHeaders("request", details);
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -120,33 +120,28 @@ var ContentPolicyManager = {
Services.ppmm.addMessageListener("WebRequest:ShouldLoad", this);
Services.mm.addMessageListener("WebRequest:ShouldLoad", this);
},
receiveMessage(msg) {
let browser = msg.target instanceof Ci.nsIDOMXULElement ? msg.target : null;
+ let requestId = RequestId.create();
for (let id of msg.data.ids) {
let callback = this.policies.get(id);
if (!callback) {
// It's possible that this listener has been removed and the
// child hasn't learned yet.
continue;
}
let response = null;
let listenerKind = "onStop";
- let data = {
- url: msg.data.url,
- windowId: msg.data.windowId,
- parentWindowId: msg.data.parentWindowId,
- type: msg.data.type,
- browser: browser,
- requestId: RequestId.create(),
- };
+ let data = Object.assign({requestId, browser}, msg.data);
+ delete data.ids;
try {
response = callback(data);
if (response) {
if (response.cancel) {
listenerKind = "onError";
data.error = "NS_ERROR_ABORT";
return {cancel: true};
}
@@ -510,42 +505,61 @@ HttpObserverManager = {
let requestHeaderNames;
let responseHeaderNames;
let includeStatus = kind === "headersReceived" ||
kind === "onRedirect" ||
kind === "onStart" ||
kind === "onStop";
+ let commonData = null;
+ let uri = channel.URI;
for (let [callback, opts] of listeners.entries()) {
- if (!this.shouldRunListener(policyType, channel.URI, opts.filter)) {
+ if (!this.shouldRunListener(policyType, uri, opts.filter)) {
continue;
}
- let data = {
- requestId: RequestId.get(channel),
- url: channel.URI.spec,
- method: channel.requestMethod,
- browser: browser,
- type: WebRequestCommon.typeForPolicyType(policyType),
- windowId: loadInfo ? loadInfo.outerWindowID : 0,
- parentWindowId: loadInfo ? loadInfo.parentOuterWindowID : 0,
- };
+ if (!commonData) {
+ commonData = {
+ requestId: RequestId.get(channel),
+ url: uri.spec,
+ method: channel.requestMethod,
+ browser: browser,
+ type: WebRequestCommon.typeForPolicyType(policyType),
+ };
- let httpChannel = channel.QueryInterface(Ci.nsIHttpChannelInternal);
- try {
- data.ip = httpChannel.remoteAddress;
- } catch (e) {
- // The remoteAddress getter throws if the address is unavailable,
- // but ip is an optional property so just ignore the exception.
+ if (loadInfo) {
+ let originPrincipal = loadInfo.triggeringPrincipal || loadInfo.loadingPrincipal;
+ if (originPrincipal && originPrincipal.URI) {
+ commonData.originUrl = originPrincipal.URI.spec;
+ }
+ Object.assign(commonData, {
+ windowId: loadInfo.outerWindowID,
+ parentWindowId: loadInfo.parentOuterWindowID,
+ });
+ } else {
+ Object.assign(commonData, {
+ windowId: 0,
+ parentWindowId: 0,
+ });
+ }
+
+ if (channel instanceof Ci.nsIHttpChannelInternal) {
+ try {
+ commonData.ip = channel.remoteAddress;
+ } catch (e) {
+ // The remoteAddress getter throws if the address is unavailable,
+ // but ip is an optional property so just ignore the exception.
+ }
+ }
+ if (extraData) {
+ Object.assign(commonData, extraData);
+ }
}
-
- if (extraData) {
- Object.assign(data, extraData);
- }
+ let data = Object.assign({}, commonData);
if (opts.requestHeaders) {
data.requestHeaders = this.getHeaders(channel, "visitRequestHeaders", kind);
requestHeaderNames = data.requestHeaders.map(h => h.name);
}
if (opts.responseHeaders) {
data.responseHeaders = this.getHeaders(channel, "visitResponseHeaders", kind);
responseHeaderNames = data.responseHeaders.map(h => h.name);
}
--- a/toolkit/modules/addons/WebRequestContent.js
+++ b/toolkit/modules/addons/WebRequestContent.js
@@ -153,17 +153,19 @@ var ContentPolicy = {
}
}
let data = {ids,
url,
type: WebRequestCommon.typeForPolicyType(policyType),
windowId,
parentWindowId};
-
+ if (requestOrigin) {
+ data.originUrl = requestOrigin.spec;
+ }
if (block) {
let rval = mm.sendSyncMessage("WebRequest:ShouldLoad", data);
if (rval.length == 1 && rval[0].cancel) {
return Ci.nsIContentPolicy.REJECT;
}
} else {
mm.sendAsyncMessage("WebRequest:ShouldLoad", data);
}