michael@0: // -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: // This Source Code Form is subject to the terms of the Mozilla Public michael@0: // License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: // file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: this.EXPORTED_SYMBOLS = ["RemoteAddonsParent"]; michael@0: michael@0: const Ci = Components.interfaces; michael@0: const Cc = Components.classes; michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import('resource://gre/modules/Services.jsm'); michael@0: michael@0: /** michael@0: * This code listens for nsIContentPolicy hooks firing in child michael@0: * processes. It then fires all hooks in the parent process and michael@0: * returns the result to the child. michael@0: */ michael@0: let ContentPolicyParent = { michael@0: /** michael@0: * Some builtin policies will have already run in the child, and michael@0: * there's no reason to run them in the parent. This is a list of michael@0: * those policies. We assume that all child processes have the same michael@0: * set of built-in policies. michael@0: */ michael@0: _policiesToIgnore: [], michael@0: michael@0: init: function() { michael@0: let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] michael@0: .getService(Ci.nsIMessageBroadcaster); michael@0: ppmm.addMessageListener("Addons:ContentPolicy:IgnorePolicies", this); michael@0: ppmm.addMessageListener("Addons:ContentPolicy:Run", this); michael@0: michael@0: Services.obs.addObserver(this, "xpcom-category-entry-added", true); michael@0: Services.obs.addObserver(this, "xpcom-category-entry-removed", true); michael@0: }, michael@0: michael@0: observe: function(aSubject, aTopic, aData) { michael@0: switch (aTopic) { michael@0: case "xpcom-category-entry-added": michael@0: case "xpcom-category-entry-removed": michael@0: if (aData == "content-policy") michael@0: this.updatePolicies(); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * There's no need for the child process to inform us about the michael@0: * shouldLoad hook if we don't have any policies in the parent to michael@0: * run. This code iterates over the parent's policies, looking for michael@0: * ones that should not be ignored. Based on that, it tells the michael@0: * children whether it needs to be informed about the shouldLoad michael@0: * hook. michael@0: */ michael@0: updatePolicies: function() { michael@0: let needHook = false; michael@0: michael@0: let services = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager) michael@0: .enumerateCategory("content-policy"); michael@0: while (services.hasMoreElements()) { michael@0: let item = services.getNext(); michael@0: let name = item.QueryInterface(Components.interfaces.nsISupportsCString).toString(); michael@0: michael@0: if (this._policiesToIgnore.indexOf(name) == -1) { michael@0: needHook = true; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] michael@0: .getService(Ci.nsIMessageBroadcaster); michael@0: ppmm.broadcastAsyncMessage("Addons:ContentPolicy:NeedHook", { needed: needHook }); michael@0: }, michael@0: michael@0: receiveMessage: function (aMessage) { michael@0: switch (aMessage.name) { michael@0: case "Addons:ContentPolicy:IgnorePolicies": michael@0: this._policiesToIgnore = aMessage.data.policies; michael@0: this.updatePolicies(); michael@0: break; michael@0: michael@0: case "Addons:ContentPolicy:Run": michael@0: return this.shouldLoad(aMessage.data, aMessage.objects); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: shouldLoad: function(aData, aObjects) { michael@0: let services = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager) michael@0: .enumerateCategory("content-policy"); michael@0: while (services.hasMoreElements()) { michael@0: let item = services.getNext(); michael@0: let name = item.QueryInterface(Components.interfaces.nsISupportsCString).toString(); michael@0: if (this._policiesToIgnore.indexOf(name) != -1) michael@0: continue; michael@0: michael@0: let policy = Cc[name].getService(Ci.nsIContentPolicy); michael@0: try { michael@0: let result = policy.shouldLoad(aData.contentType, michael@0: aObjects.contentLocation, michael@0: aObjects.requestOrigin, michael@0: aObjects.node, michael@0: aData.mimeTypeGuess, michael@0: null); michael@0: if (result != Ci.nsIContentPolicy.ACCEPT && result != 0) michael@0: return result; michael@0: } catch (e) {} michael@0: } michael@0: michael@0: return Ci.nsIContentPolicy.ACCEPT; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), michael@0: }; michael@0: michael@0: let RemoteAddonsParent = { michael@0: initialized: false, michael@0: michael@0: init: function() { michael@0: if (this.initialized) michael@0: return; michael@0: michael@0: this.initialized = true; michael@0: michael@0: ContentPolicyParent.init(); michael@0: }, michael@0: };