--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -28,16 +28,17 @@ function WebRequestEventManager(context,
}
let tabId = TabManager.getBrowserId(data.browser);
if (tabId == -1) {
return;
}
let data2 = {
+ requestId: data.requestId,
url: data.url,
method: data.method,
type: data.type,
timeStamp: Date.now(),
frameId: ExtensionManagement.getFrameId(data.windowId),
parentFrameId: ExtensionManagement.getParentFrameId(data.parentWindowId, data.windowId),
};
--- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
@@ -6,24 +6,26 @@
<link rel="stylesheet" href="file_style_good.css">
<link rel="stylesheet" href="file_style_bad.css">
<link rel="stylesheet" href="file_style_redirect.css">
</head>
<body>
<div id="test">Sample text</div>
+<img id="img_redirect" src="file_image_redirect.png">
<img id="img_good" src="file_image_good.png">
<img id="img_bad" src="file_image_bad.png">
-<img id="img_redirect" src="file_image_redirect.png">
<script src="file_script_good.js"></script>
<script src="file_script_bad.js"></script>
<script src="file_script_redirect.js"></script>
<script src="file_script_xhr.js"></script>
<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>
+
</body>
</html>
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
@@ -26,17 +26,19 @@ const expected_requested = [BASE + "/fil
BASE + "/file_image_redirect.png",
BASE + "/file_script_good.js",
BASE + "/file_script_bad.js",
BASE + "/file_script_redirect.js",
BASE + "/file_script_xhr.js",
BASE + "/file_WebRequest_page2.html",
BASE + "/nonexistent_script_url.js",
BASE + "/redirection.sjs",
- BASE + "/xhr_resource"];
+ BASE + "/dummy_page.html",
+ BASE + "/xhr_resource",
+ "data:text/plain,webRequestTest"];
const expected_beforeSendHeaders = [BASE + "/file_WebRequest_page1.html",
BASE + "/file_style_good.css",
BASE + "/file_style_redirect.css",
BASE + "/file_image_good.png",
BASE + "/file_image_redirect.png",
BASE + "/file_script_good.js",
BASE + "/file_script_redirect.js",
@@ -48,26 +50,28 @@ const expected_beforeSendHeaders = [BASE
BASE + "/xhr_resource"];
const expected_sendHeaders = expected_beforeSendHeaders.filter(u => !/_redirect\./.test(u))
.concat(BASE + "/redirection.sjs");
const expected_redirect = expected_beforeSendHeaders.filter(u => /_redirect\./.test(u))
.concat(BASE + "/redirection.sjs");
-const expected_complete = [BASE + "/file_WebRequest_page1.html",
+const expected_response = [BASE + "/file_WebRequest_page1.html",
BASE + "/file_style_good.css",
BASE + "/file_image_good.png",
BASE + "/file_script_good.js",
BASE + "/file_script_xhr.js",
BASE + "/file_WebRequest_page2.html",
BASE + "/nonexistent_script_url.js",
BASE + "/dummy_page.html",
BASE + "/xhr_resource"];
+const expected_complete = expected_response.concat("data:text/plain,webRequestTest");
+
function removeDupes(list) {
let j = 0;
for (let i = 1; i < list.length; i++) {
if (list[i] != list[j]) {
j++;
if (i != j) {
list[j] = list[i];
}
@@ -80,57 +84,77 @@ function compareLists(list1, list2, kind
list1.sort();
removeDupes(list1);
list2.sort();
removeDupes(list2);
is(String(list1), String(list2), `${kind} URLs correct`);
}
function backgroundScript() {
- const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
-
let checkCompleted = true;
let savedTabId = -1;
+ function shouldRecord(url) {
+ return url.startsWith(BASE) || /^data:.*\bwebRequestTest\b/.test(url);
+ }
+
function checkType(details) {
let expected_type = "???";
if (details.url.indexOf("style") != -1) {
expected_type = "stylesheet";
} else if (details.url.indexOf("image") != -1) {
expected_type = "image";
} else if (details.url.indexOf("script") != -1) {
expected_type = "script";
} else if (details.url.indexOf("page1") != -1) {
expected_type = "main_frame";
- } else if (/page2|redirection|dummy_page/.test(details.url)) {
+ } else if (/page2|redirection|dummy_page|data:text\/(?:plain|html),/.test(details.url)) {
expected_type = "sub_frame";
} else if (details.url.indexOf("xhr") != -1) {
expected_type = "xmlhttprequest";
}
browser.test.assertEq(details.type, expected_type, "resource type is correct");
}
+ let requestIDs = new Map();
+ let idDisposalEvents = new Set(["completed", "error", "redirect"]);
+ function checkRequestId(details, event = "unknown") {
+ let ids = requestIDs.get(details.url);
+ browser.test.assertTrue(ids && ids.has(details.requestId), `correct requestId for ${details.url} (${details.requestId} in [${ids && [...ids].join(", ")}])`);
+ if (ids && idDisposalEvents.has(event)) {
+ ids.delete(details.requestId);
+ }
+ }
+
let frameIDs = new Map();
let recorded = {requested: [],
beforeSendHeaders: [],
beforeRedirect: [],
sendHeaders: [],
responseStarted: [],
completed: []};
function checkResourceType(type) {
let key = type.toUpperCase();
- browser.test.assertTrue(key in browser.webRequest.ResourceType);
+ browser.test.assertTrue(key in browser.webRequest.ResourceType, `valid resource type ${key}`);
}
function onBeforeRequest(details) {
- browser.test.log(`onBeforeRequest ${details.url}`);
+ browser.test.log(`onBeforeRequest ${details.requestId} ${details.url}`);
+
+ browser.test.assertTrue(details.requestId > 0, `valid requestId ${details.requestId}`);
+ let ids = requestIDs.get(details.url);
+ if (ids) {
+ ids.add(details.requestId);
+ } else {
+ requestIDs.set(details.url, new Set([details.requestId]));
+ }
checkResourceType(details.type);
- if (details.url.startsWith(BASE)) {
+ if (shouldRecord(details.url)) {
recorded.requested.push(details.url);
if (savedTabId == -1) {
browser.test.assertTrue(details.tabId !== undefined, "tab ID defined");
savedTabId = details.tabId;
}
browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
@@ -150,36 +174,38 @@ function backgroundScript() {
if (details.url.indexOf("_bad.") != -1) {
return {cancel: true};
}
return {};
}
function onBeforeSendHeaders(details) {
browser.test.log(`onBeforeSendHeaders ${details.url}`);
+ checkRequestId(details);
checkResourceType(details.type);
- if (details.url.startsWith(BASE)) {
+ if (shouldRecord(details.url)) {
recorded.beforeSendHeaders.push(details.url);
browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
checkType(details);
let id = frameIDs.get(details.url);
browser.test.assertEq(id, details.frameId, "frame ID same in onBeforeSendHeaders as onBeforeRequest");
}
if (details.url.indexOf("_redirect.") != -1) {
return {redirectUrl: details.url.replace("_redirect.", "_good.")};
}
return {};
}
function onBeforeRedirect(details) {
browser.test.log(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`);
+ checkRequestId(details, "redirect");
checkResourceType(details.type);
- if (details.url.startsWith(BASE)) {
+ if (shouldRecord(details.url)) {
recorded.beforeRedirect.push(details.url);
browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
checkType(details);
let id = frameIDs.get(details.url);
browser.test.assertEq(id, details.frameId, "frame ID same in onBeforeRedirect as onBeforeRequest");
frameIDs.set(details.redirectUrl, details.frameId);
@@ -187,34 +213,39 @@ function backgroundScript() {
if (details.url.indexOf("_redirect.") != -1) {
let expectedUrl = details.url.replace("_redirect.", "_good.");
browser.test.assertEq(details.redirectUrl, expectedUrl, "correct redirectUrl value");
}
return {};
}
function onRecord(kind, details) {
+ browser.test.log(`${kind} ${details.url}`);
checkResourceType(details.type);
- if (details.url.startsWith(BASE)) {
+ checkRequestId(details, kind);
+ if (shouldRecord(details.url)) {
recorded[kind].push(details.url);
}
}
let completedUrls = {
responseStarted: new Set(),
completed: new Set(),
};
function checkIpAndRecord(kind, details) {
onRecord(kind, details);
// When resources are cached, the ip property is not present,
// so only check for the ip property the first time around.
if (checkCompleted && !completedUrls[kind].has(details.url)) {
- browser.test.assertEq(details.ip, "127.0.0.1", "correct ip");
+ // We can only tell IPs for HTTP requests.
+ if (/^https?:/.test(details.url)) {
+ browser.test.assertEq(details.ip, "127.0.0.1", "correct ip");
+ }
completedUrls[kind].add(details.url);
}
}
browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: ["<all_urls>"]}, ["blocking"]);
browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: ["<all_urls>"]}, ["blocking"]);
browser.webRequest.onSendHeaders.addListener(onRecord.bind(null, "sendHeaders"), {urls: ["<all_urls>"]});
browser.webRequest.onBeforeRedirect.addListener(onBeforeRedirect, {urls: ["<all_urls>"]});
@@ -238,17 +269,17 @@ function backgroundScript() {
function* test_once(skipCompleted) {
let extensionData = {
manifest: {
permissions: [
"webRequest",
"webRequestBlocking",
],
},
- background: "(" + backgroundScript.toString() + ")()",
+ background: `const BASE = ${JSON.stringify(BASE)}; (${backgroundScript.toString()})()`,
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
let [, resourceTypes] = yield Promise.all([extension.startup(), extension.awaitMessage("ready")]);
info("webrequest extension loaded");
if (skipCompleted) {
extension.sendMessage("skipCompleted");
@@ -292,17 +323,17 @@ function* test_once(skipCompleted) {
extension.sendMessage("getResults");
let recorded = yield extension.awaitMessage("results");
compareLists(recorded.requested, expected_requested, "requested");
compareLists(recorded.beforeSendHeaders, expected_beforeSendHeaders, "beforeSendHeaders");
compareLists(recorded.sendHeaders, expected_sendHeaders, "sendHeaders");
compareLists(recorded.beforeRedirect, expected_redirect, "beforeRedirect");
- compareLists(recorded.responseStarted, expected_complete, "responseStarted");
+ compareLists(recorded.responseStarted, expected_response, "responseStarted");
compareLists(recorded.completed, expected_complete, "completed");
yield extension.unload();
info("webrequest extension unloaded");
}
// Run the test twice to make sure it works with caching.
add_task(function*() { yield test_once(false); });
--- a/toolkit/modules/addons/MatchPattern.jsm
+++ b/toolkit/modules/addons/MatchPattern.jsm
@@ -10,17 +10,18 @@ Cu.import("resource://gre/modules/XPCOMU
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
this.EXPORTED_SYMBOLS = ["MatchPattern"];
/* globals MatchPattern */
-const PERMITTED_SCHEMES = ["http", "https", "file", "ftp", "app"];
+const PERMITTED_SCHEMES = ["http", "https", "file", "ftp", "app", "data"];
+const PERMITTED_SCHEMES_REGEXP = PERMITTED_SCHEMES.join("|");
// This function converts a glob pattern (containing * and possibly ?
// as wildcards) to a regular expression.
function globToRegexp(pat, allowQuestion) {
// Escape everything except ? and *.
pat = pat.replace(/[.+^${}()|[\]\\]/g, "\\$&");
if (allowQuestion) {
@@ -37,17 +38,17 @@ function globToRegexp(pat, allowQuestion
function SingleMatchPattern(pat) {
if (pat == "<all_urls>") {
this.schemes = PERMITTED_SCHEMES;
this.host = "*";
this.path = new RegExp(".*");
} else if (!pat) {
this.schemes = [];
} else {
- let re = new RegExp("^(http|https|file|ftp|app|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+|)(/.*)$");
+ let re = new RegExp(`^(${PERMITTED_SCHEMES_REGEXP}|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+|)(/.*)$`);
let match = re.exec(pat);
if (!match) {
Cu.reportError(`Invalid match pattern: '${pat}'`);
this.schemes = [];
return;
}
if (match[1] == "*") {
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -16,20 +16,54 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebRequestCommon",
"resource://gre/modules/WebRequestCommon.jsm");
-// TODO
-// Figure out how to handle requestId. Gecko seems to have no such thing. (Bug 1163862)
-// We also don't know the method for content policy. (Bug 1163862)
-// We don't even have a window ID for HTTP observer stuff. (Bug 1163861)
+function attachToChannel(channel, key, data) {
+ if (channel instanceof Ci.nsIWritablePropertyBag2) {
+ let wrapper = {value: data};
+ wrapper.wrappedJSObject = wrapper;
+ channel.setPropertyAsInterface(key, wrapper);
+ }
+}
+
+function extractFromChannel(channel, key) {
+ if (channel instanceof Ci.nsIPropertyBag2 && channel.hasKey(key)) {
+ let data = channel.get(key);
+ if (data && data.wrappedJSObject) {
+ data = data.wrappedJSObject;
+ }
+ return "value" in data ? data.value : data;
+ }
+ return null;
+}
+
+var RequestId = {
+ count: 1,
+ KEY: "mozilla.webRequest.requestId",
+ create(channel = null) {
+ let id = this.count++;
+ if (channel) {
+ attachToChannel(channel, this.KEY, id);
+ }
+ return id;
+ },
+
+ get(channel) {
+ return channel && extractFromChannel(channel, this.KEY) || this.create(channel);
+ },
+};
+
+function runLater(job) {
+ Services.tm.currentThread.dispatch(job, Ci.nsIEventTarget.DISPATCH_NORMAL);
+}
function parseFilter(filter) {
if (!filter) {
filter = {};
}
// FIXME: Support windowId filtering.
return {urls: filter.urls || null, types: filter.types || null};
@@ -48,16 +82,18 @@ function parseExtra(extra, allowed) {
for (let al of allowed) {
if (extra && extra.indexOf(al) != -1) {
result[al] = true;
}
}
return result;
}
+var HttpObserverManager;
+
var ContentPolicyManager = {
policyData: new Map(),
policies: new Map(),
idMap: new Map(),
nextId: 0,
init() {
Services.ppmm.initialProcessData.webRequestContentPolicies = this.policyData;
@@ -72,42 +108,60 @@ var ContentPolicyManager = {
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 data = {
+ url: msg.data.url,
+ windowId: msg.data.windowId,
+ parentWindowId: msg.data.parentWindowId,
+ type: msg.data.type,
+ browser: browser,
+ requestId: RequestId.create(),
+ };
try {
- response = callback({
- url: msg.data.url,
- windowId: msg.data.windowId,
- parentWindowId: msg.data.parentWindowId,
- type: msg.data.type,
- browser: browser,
- });
+ response = callback(data);
+ if (response && response.cancel) {
+ return {cancel: true};
+ }
+
+ // FIXME: Need to handle redirection here. (Bug 1163862)
} catch (e) {
Cu.reportError(e);
+ } finally {
+ runLater(() => this.runChannelListener("onStop", data));
}
-
- if (response && response.cancel) {
- return {cancel: true};
- }
-
- // FIXME: Need to handle redirection here. (Bug 1163862)
}
return {};
},
+ runChannelListener(kind, data) {
+ let listeners = HttpObserverManager.listeners[kind];
+ let uri = BrowserUtils.makeURI(data.url);
+ let policyType = data.type;
+ for (let [callback, opts] of listeners.entries()) {
+ if (!HttpObserverManager.shouldRunListener(policyType, uri, opts.filter)) {
+ continue;
+ }
+ callback(data);
+ }
+ },
+
addListener(callback, opts) {
+ // Clone opts, since we're going to modify them for IPC.
+ opts = Object.assign({}, opts);
let id = this.nextId++;
opts.id = id;
if (opts.filter.urls) {
+ opts.filter = Object.assign({}, opts.filter);
opts.filter.urls = opts.filter.urls.serialize();
}
Services.ppmm.broadcastAsyncMessage("WebRequest:AddContentPolicy", opts);
this.policyData.set(id, opts);
this.policies.set(id, callback);
this.idMap.set(callback, id);
@@ -146,18 +200,16 @@ StartStopListener.prototype = {
return result;
},
onDataAvailable(...args) {
return this.orig.onDataAvailable(...args);
},
};
-var HttpObserverManager;
-
var ChannelEventSink = {
_classDescription: "WebRequest channel event sink",
_classID: Components.ID("115062f8-92f1-11e5-8b7f-080027b0f7ec"),
_contractID: "@mozilla.org/webrequest/channel-event-sink;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink,
Ci.nsIFactory]),
@@ -173,17 +225,17 @@ var ChannelEventSink = {
unregister() {
let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
catMan.deleteCategoryEntry("net-channel-event-sinks", this._contractID, false);
},
// nsIChannelEventSink implementation
asyncOnChannelRedirect(oldChannel, newChannel, flags, redirectCallback) {
- Services.tm.currentThread.dispatch(() => redirectCallback.onRedirectVerifyCallback(Cr.NS_OK), Ci.nsIEventTarget.DISPATCH_NORMAL);
+ runLater(() => redirectCallback.onRedirectVerifyCallback(Cr.NS_OK));
try {
HttpObserverManager.onChannelReplaced(oldChannel, newChannel);
} catch (e) {
// we don't wanna throw: it would abort the redirection
}
},
// nsIFactory implementation
@@ -198,26 +250,27 @@ var ChannelEventSink = {
ChannelEventSink.init();
HttpObserverManager = {
modifyInitialized: false,
examineInitialized: false,
redirectInitialized: false,
listeners: {
+ opening: new Map(),
modify: new Map(),
afterModify: new Map(),
headersReceived: new Map(),
onRedirect: new Map(),
onStart: new Map(),
onStop: new Map(),
},
addOrRemove() {
- let needModify = this.listeners.modify.size || this.listeners.afterModify.size;
+ let needModify = this.listeners.opening.size || this.listeners.modify.size || this.listeners.afterModify.size;
if (needModify && !this.modifyInitialized) {
this.modifyInitialized = true;
Services.obs.addObserver(this, "http-on-modify-request", false);
} else if (!needModify && this.modifyInitialized) {
this.modifyInitialized = false;
Services.obs.removeObserver(this, "http-on-modify-request");
}
@@ -284,32 +337,37 @@ HttpObserverManager = {
};
channel[method](visitor);
return headers;
},
observe(subject, topic, data) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
-
- if (topic == "http-on-modify-request") {
- this.modify(channel, topic, data);
- } else if (topic == "http-on-examine-response" ||
- topic == "http-on-examine-cached-response" ||
- topic == "http-on-examine-merged-response") {
- this.examine(channel, topic, data);
+ switch (topic) {
+ case "http-on-modify-request":
+ this.modify(channel, topic, data);
+ break;
+ case "http-on-examine-response":
+ case "http-on-examine-cached-response":
+ case "http-on-examine-merged-response":
+ this.examine(channel, topic, data);
+ break;
}
},
shouldRunListener(policyType, uri, filter) {
return WebRequestCommon.typeMatches(policyType, filter.types) &&
WebRequestCommon.urlMatches(uri, filter.urls);
},
runChannelListener(channel, loadContext, kind, extraData = null) {
+ if (channel.status === Cr.NS_ERROR_ABORT) {
+ return false;
+ }
let listeners = this.listeners[kind];
let browser = loadContext ? loadContext.topFrameElement : null;
let loadInfo = channel.loadInfo;
let policyType = loadInfo ?
loadInfo.externalContentPolicyType :
Ci.nsIContentPolicy.TYPE_OTHER;
let requestHeaders;
@@ -321,16 +379,17 @@ HttpObserverManager = {
kind === "onStop";
for (let [callback, opts] of listeners.entries()) {
if (!this.shouldRunListener(policyType, channel.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,
};
@@ -367,17 +426,17 @@ HttpObserverManager = {
} catch (e) {
Cu.reportError(e);
}
if (!result || !opts.blocking) {
return true;
}
if (result.cancel) {
- channel.cancel();
+ channel.cancel(Cr.NS_ERROR_ABORT);
return false;
}
if (result.redirectUrl) {
channel.redirectTo(BrowserUtils.makeURI(result.redirectUrl));
return false;
}
if (opts.requestHeaders && result.requestHeaders) {
// Start by clearing everything.
@@ -402,17 +461,18 @@ HttpObserverManager = {
}
return true;
},
modify(channel, topic, data) {
let loadContext = this.getLoadContext(channel);
- if (this.runChannelListener(channel, loadContext, "modify")) {
+ if (this.runChannelListener(channel, loadContext, "opening") &&
+ this.runChannelListener(channel, loadContext, "modify")) {
this.runChannelListener(channel, loadContext, "afterModify");
}
},
examine(channel, topic, data) {
let loadContext = this.getLoadContext(channel);
if (this.listeners.onStart.size || this.listeners.onStop.size) {
@@ -445,19 +505,21 @@ HttpObserverManager = {
};
var onBeforeRequest = {
addListener(callback, filter = null, opt_extraInfoSpec = null) {
// FIXME: Add requestBody support.
let opts = parseExtra(opt_extraInfoSpec, ["blocking"]);
opts.filter = parseFilter(filter);
ContentPolicyManager.addListener(callback, opts);
+ HttpObserverManager.addListener("opening", callback, opts);
},
removeListener(callback) {
+ HttpObserverManager.removeListener("opening", callback);
ContentPolicyManager.removeListener(callback);
},
};
function HttpEvent(internalEvent, options) {
this.internalEvent = internalEvent;
this.options = options;
}
@@ -477,17 +539,17 @@ HttpEvent.prototype = {
var onBeforeSendHeaders = new HttpEvent("modify", ["requestHeaders", "blocking"]);
var onSendHeaders = new HttpEvent("afterModify", ["requestHeaders"]);
var onHeadersReceived = new HttpEvent("headersReceived", ["blocking", "responseHeaders"]);
var onBeforeRedirect = new HttpEvent("onRedirect", ["responseHeaders"]);
var onResponseStarted = new HttpEvent("onStart", ["responseHeaders"]);
var onCompleted = new HttpEvent("onStop", ["responseHeaders"]);
var WebRequest = {
- // Handled via content policy.
+ // http-on-modify observer for HTTP(S), content policy for the other protocols (notably, data:)
onBeforeRequest: onBeforeRequest,
// http-on-modify observer.
onBeforeSendHeaders: onBeforeSendHeaders,
// http-on-modify observer.
onSendHeaders: onSendHeaders,
--- a/toolkit/modules/addons/WebRequestContent.js
+++ b/toolkit/modules/addons/WebRequestContent.js
@@ -12,16 +12,18 @@ var Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MatchPattern",
"resource://gre/modules/MatchPattern.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebRequestCommon",
"resource://gre/modules/WebRequestCommon.jsm");
+const IS_HTTP = /^https?:/;
+
var ContentPolicy = {
_classDescription: "WebRequest content policy",
_classID: Components.ID("938e5d24-9ccc-4b55-883e-c252a41f7ce9"),
_contractID: "@mozilla.org/webrequest/policy;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy,
Ci.nsIFactory,
Ci.nsISupportsWeakReference]),
@@ -73,16 +75,22 @@ var ContentPolicy = {
unregister() {
let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
catMan.deleteCategoryEntry("content-policy", this._contractID, false);
},
shouldLoad(policyType, contentLocation, requestOrigin,
node, mimeTypeGuess, extra, requestPrincipal) {
+ let url = contentLocation.spec;
+ if (IS_HTTP.test(url)) {
+ // We'll handle this in our parent process HTTP observer.
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
let block = false;
let ids = [];
for (let [id, {blocking, filter}] of this.contentPolicies.entries()) {
if (WebRequestCommon.typeMatches(policyType, filter.types) &&
WebRequestCommon.urlMatches(contentLocation, filter.urls)) {
if (blocking) {
block = true;
}
@@ -141,17 +149,17 @@ var ContentPolicy = {
} catch (e) {
if (e.result != Cr.NS_NOINTERFACE) {
throw e;
}
}
}
let data = {ids,
- url: contentLocation.spec,
+ url,
type: WebRequestCommon.typeForPolicyType(policyType),
windowId,
parentWindowId};
if (block) {
let rval = mm.sendSyncMessage("WebRequest:ShouldLoad", data);
if (rval.length == 1 && rval[0].cancel) {
return Ci.nsIContentPolicy.REJECT;
--- a/toolkit/modules/tests/browser/browser_WebRequest.js
+++ b/toolkit/modules/tests/browser/browser_WebRequest.js
@@ -112,16 +112,17 @@ const expected_requested = [BASE + "/fil
BASE + "/file_image_redirect.png",
BASE + "/file_script_good.js",
BASE + "/file_script_bad.js",
BASE + "/file_script_redirect.js",
BASE + "/file_script_xhr.js",
BASE + "/file_WebRequest_page2.html",
BASE + "/nonexistent_script_url.js",
BASE + "/WebRequest_redirection.sjs",
+ BASE + "/dummy_page.html",
BASE + "/xhr_resource"];
const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html",
BASE + "/file_style_good.css",
BASE + "/file_style_redirect.css",
BASE + "/file_image_good.png",
BASE + "/file_image_redirect.png",
BASE + "/file_script_good.js",