mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-09 04:39:03 +02:00
Currently there is a tight coupling between registered APIs because they share the same global scope, and the dependencies between the modules that use these globals are not explicit. Consequently, it would be possible for APIs to break when the registered APIs run in separate processes, because then there are separate global scopes. To mitigate this issue, this patch isolates the global namespaces of API registrations in different environments, starting with the "chrome" process. Content and addon processes will follow later. A new JSM is introduced to avoid hidden dependencies between ext-*.js and the script loader. ExtensionUtils.jsm would be a natural choice for this shared utility method, but cannot be used because its local `EventEmitter` implementation conflicts with the `EventEmitter` import in ext-tabs.js. So, this patch provides isolation of global variables declared through `globals.XXX = ...`, but does not provide isolation for `Cu.import`-ed logic. Ideally `Cu.import` should always use its second argument to prevent inadvertent namespace pollution. MozReview-Commit-ID: 1DTZaKOaeSE --HG-- extra : rebase_source : 1376a1325fd9bf186e09e1dbe83467f3ad94516f
119 lines
3.8 KiB
JavaScript
119 lines
3.8 KiB
JavaScript
"use strict";
|
|
|
|
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "MatchPattern",
|
|
"resource://gre/modules/MatchPattern.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "WebRequest",
|
|
"resource://gre/modules/WebRequest.jsm");
|
|
|
|
Cu.import("resource://gre/modules/ExtensionManagement.jsm");
|
|
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
|
var {
|
|
SingletonEventManager,
|
|
runSafeSync,
|
|
} = ExtensionUtils;
|
|
|
|
// EventManager-like class specifically for WebRequest. Inherits from
|
|
// SingletonEventManager. Takes care of converting |details| parameter
|
|
// when invoking listeners.
|
|
function WebRequestEventManager(context, eventName) {
|
|
let name = `webRequest.${eventName}`;
|
|
let register = (callback, filter, info) => {
|
|
let listener = data => {
|
|
if (!data.browser) {
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
data2.ip = data.ip;
|
|
}
|
|
|
|
// Fills in tabId typically.
|
|
let result = {};
|
|
extensions.emit("fill-browser-data", data.browser, data2, result);
|
|
if (result.cancel) {
|
|
return;
|
|
}
|
|
|
|
let optional = ["requestHeaders", "responseHeaders", "statusCode", "statusLine", "error", "redirectUrl",
|
|
"requestBody"];
|
|
for (let opt of optional) {
|
|
if (opt in data) {
|
|
data2[opt] = data[opt];
|
|
}
|
|
}
|
|
|
|
return runSafeSync(context, callback, data2);
|
|
};
|
|
|
|
let filter2 = {};
|
|
filter2.urls = new MatchPattern(filter.urls);
|
|
if (filter.types) {
|
|
filter2.types = filter.types;
|
|
}
|
|
if (filter.tabId) {
|
|
filter2.tabId = filter.tabId;
|
|
}
|
|
if (filter.windowId) {
|
|
filter2.windowId = filter.windowId;
|
|
}
|
|
|
|
let info2 = [];
|
|
if (info) {
|
|
for (let desc of info) {
|
|
if (desc == "blocking" && !context.extension.hasPermission("webRequestBlocking")) {
|
|
Cu.reportError("Using webRequest.addListener with the blocking option " +
|
|
"requires the 'webRequestBlocking' permission.");
|
|
} else {
|
|
info2.push(desc);
|
|
}
|
|
}
|
|
}
|
|
|
|
WebRequest[eventName].addListener(listener, filter2, info2);
|
|
return () => {
|
|
WebRequest[eventName].removeListener(listener);
|
|
};
|
|
};
|
|
|
|
return SingletonEventManager.call(this, context, name, register);
|
|
}
|
|
|
|
WebRequestEventManager.prototype = Object.create(SingletonEventManager.prototype);
|
|
|
|
extensions.registerSchemaAPI("webRequest", "addon_parent", context => {
|
|
return {
|
|
webRequest: {
|
|
onBeforeRequest: new WebRequestEventManager(context, "onBeforeRequest").api(),
|
|
onBeforeSendHeaders: new WebRequestEventManager(context, "onBeforeSendHeaders").api(),
|
|
onSendHeaders: new WebRequestEventManager(context, "onSendHeaders").api(),
|
|
onHeadersReceived: new WebRequestEventManager(context, "onHeadersReceived").api(),
|
|
onBeforeRedirect: new WebRequestEventManager(context, "onBeforeRedirect").api(),
|
|
onResponseStarted: new WebRequestEventManager(context, "onResponseStarted").api(),
|
|
onErrorOccurred: new WebRequestEventManager(context, "onErrorOccurred").api(),
|
|
onCompleted: new WebRequestEventManager(context, "onCompleted").api(),
|
|
handlerBehaviorChanged: function() {
|
|
// TODO: Flush all caches.
|
|
},
|
|
},
|
|
};
|
|
});
|