Bug 1368102: Part 5 - Move static content script matching into C++. r?mixedpuppy,zombie
MozReview-Commit-ID: Co04MoscqMx
--- a/toolkit/components/extensions/ExtensionPolicyService.cpp
+++ b/toolkit/components/extensions/ExtensionPolicyService.cpp
@@ -3,47 +3,81 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ExtensionPolicyService.h"
#include "mozilla/extensions/WebExtensionContentScript.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozIExtensionProcessScript.h"
#include "nsEscape.h"
#include "nsGkAtoms.h"
+#include "nsIChannel.h"
+#include "nsIContentPolicy.h"
+#include "nsIDocument.h"
+#include "nsILoadInfo.h"
+#include "nsNetUtil.h"
+#include "nsPIDOMWindow.h"
+#include "nsXULAppAPI.h"
namespace mozilla {
using namespace extensions;
#define DEFAULT_BASE_CSP \
"script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; " \
"object-src 'self' https://* moz-extension: blob: filesystem:;"
#define DEFAULT_DEFAULT_CSP \
"script-src 'self'; object-src 'self';"
+#define OBS_TOPIC_PRELOAD_SCRIPT "web-extension-preload-content-script"
+#define OBS_TOPIC_LOAD_SCRIPT "web-extension-load-content-script"
+
+
+static mozIExtensionProcessScript&
+ProcessScript()
+{
+ static nsCOMPtr<mozIExtensionProcessScript> sProcessScript;
+
+ if (MOZ_UNLIKELY(!sProcessScript)) {
+ sProcessScript = do_GetService("@mozilla.org/webextensions/extension-process-script;1");
+ MOZ_RELEASE_ASSERT(sProcessScript);
+ ClearOnShutdown(&sProcessScript);
+ }
+ return *sProcessScript;
+}
+
/*****************************************************************************
* ExtensionPolicyService
*****************************************************************************/
/* static */ ExtensionPolicyService&
ExtensionPolicyService::GetSingleton()
{
static RefPtr<ExtensionPolicyService> sExtensionPolicyService;
if (MOZ_UNLIKELY(!sExtensionPolicyService)) {
sExtensionPolicyService = new ExtensionPolicyService();
ClearOnShutdown(&sExtensionPolicyService);
}
return *sExtensionPolicyService.get();
}
+ExtensionPolicyService::ExtensionPolicyService()
+{
+ mObs = services::GetObserverService();
+ MOZ_RELEASE_ASSERT(mObs);
+
+ RegisterObservers();
+}
+
WebExtensionPolicy*
ExtensionPolicyService::GetByURL(const URLInfo& aURL)
{
if (aURL.Scheme() == nsGkAtoms::moz_extension) {
return GetByHost(aURL.Host());
}
return nullptr;
@@ -109,16 +143,144 @@ ExtensionPolicyService::DefaultCSP(nsASt
rv = Preferences::GetString("extensions.webextensions.default-content-security-policy", &aDefaultCSP);
if (NS_FAILED(rv)) {
aDefaultCSP.AssignLiteral(DEFAULT_DEFAULT_CSP);
}
}
/*****************************************************************************
+ * Content script management
+ *****************************************************************************/
+
+void
+ExtensionPolicyService::RegisterObservers()
+{
+ mObs->AddObserver(this, "content-document-global-created", false);
+ mObs->AddObserver(this, "document-element-inserted", false);
+ if (XRE_IsContentProcess()) {
+ mObs->AddObserver(this, "http-on-opening-request", false);
+ }
+}
+
+void
+ExtensionPolicyService::UnregisterObservers()
+{
+ mObs->RemoveObserver(this, "content-document-global-created");
+ mObs->RemoveObserver(this, "document-element-inserted");
+ if (XRE_IsContentProcess()) {
+ mObs->RemoveObserver(this, "http-on-opening-request");
+ }
+}
+
+nsresult
+ExtensionPolicyService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+ if (!strcmp(aTopic, "content-document-global-created")) {
+ nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(aSubject);
+ if (win) {
+ CheckWindow(win);
+ }
+ } else if (!strcmp(aTopic, "document-element-inserted")) {
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
+ if (doc) {
+ CheckDocument(doc);
+ }
+ } else if (!strcmp(aTopic, "http-on-opening-request")) {
+ nsCOMPtr<nsIChannel> chan = do_QueryInterface(aSubject);
+ if (chan) {
+ CheckRequest(chan);
+ }
+ }
+ return NS_OK;
+}
+
+// Checks a request for matching content scripts, and begins pre-loading them
+// if necessary.
+void
+ExtensionPolicyService::CheckRequest(nsIChannel* aChannel)
+{
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ if (!loadInfo) {
+ return;
+ }
+
+ auto loadType = loadInfo->GetExternalContentPolicyType();
+ if (loadType != nsIContentPolicy::TYPE_DOCUMENT &&
+ loadType != nsIContentPolicy::TYPE_SUBDOCUMENT) {
+ return;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ if (NS_FAILED(aChannel->GetURI(getter_AddRefs(uri)))) {
+ return;
+ }
+
+ CheckContentScripts({uri.get(), loadInfo}, true);
+}
+
+// Checks a document, just after the document element has been inserted, for
+// matching content scripts or extension principals, and loads them if
+// necessary.
+void
+ExtensionPolicyService::CheckDocument(nsIDocument* aDocument)
+{
+ nsCOMPtr<nsPIDOMWindowOuter> win = aDocument->GetWindow();
+ if (win) {
+ CheckContentScripts(win.get(), false);
+ }
+}
+
+// Checks for loads of about:blank into new window globals, and loads any
+// matching content scripts. about:blank loads do not trigger document element
+// inserted events, so they're the only load type that are special cased this
+// way.
+void
+ExtensionPolicyService::CheckWindow(nsPIDOMWindowOuter* aWindow)
+{
+ // We only care about non-initial document loads here. The initial
+ // about:blank document will usually be re-used to load another document.
+ nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+ if (!doc || doc->IsInitialDocument()) {
+ return;
+ }
+
+ nsCOMPtr<nsIURI> aboutBlank;
+ NS_ENSURE_SUCCESS_VOID(NS_NewURI(getter_AddRefs(aboutBlank),
+ "about:blank"));
+
+ nsCOMPtr<nsIURI> uri = doc->GetDocumentURI();
+ bool equal;
+ if (NS_FAILED(uri->EqualsExceptRef(aboutBlank, &equal)) || !equal) {
+ return;
+ }
+
+ CheckContentScripts(aWindow, false);
+}
+
+void
+ExtensionPolicyService::CheckContentScripts(const DocInfo& aDocInfo, bool aIsPreload)
+{
+ for (auto iter = mExtensions.Iter(); !iter.Done(); iter.Next()) {
+ RefPtr<WebExtensionPolicy> policy = iter.Data();
+
+ for (auto& script : policy->ContentScripts()) {
+ if (script->Matches(aDocInfo)) {
+ if (aIsPreload) {
+ ProcessScript().PreloadContentScript(script);
+ } else {
+ ProcessScript().LoadContentScript(script, aDocInfo.GetWindow());
+ }
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
* nsIAddonPolicyService
*****************************************************************************/
nsresult
ExtensionPolicyService::GetBaseCSP(nsAString& aBaseCSP)
{
BaseCSP(aBaseCSP);
return NS_OK;
@@ -207,15 +369,16 @@ ExtensionPolicyService::ExtensionURIToAd
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTION(ExtensionPolicyService, mExtensions, mExtensionHosts)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtensionPolicyService)
NS_INTERFACE_MAP_ENTRY(nsIAddonPolicyService)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAddonPolicyService)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(ExtensionPolicyService)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ExtensionPolicyService)
} // namespace mozilla
--- a/toolkit/components/extensions/ExtensionPolicyService.h
+++ b/toolkit/components/extensions/ExtensionPolicyService.h
@@ -7,30 +7,44 @@
#define mozilla_ExtensionPolicyService_h
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "nsIAddonPolicyService.h"
#include "nsIAtom.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
#include "nsISupports.h"
#include "nsPointerHashKeys.h"
#include "nsRefPtrHashtable.h"
+class nsIChannel;
+class nsIObserverService;
+class nsIDocument;
+class nsIPIDOMWindowOuter;
+
namespace mozilla {
+namespace extensions {
+ class DocInfo;
+}
+using extensions::DocInfo;
using extensions::WebExtensionPolicy;
class ExtensionPolicyService final : public nsIAddonPolicyService
+ , public nsIObserver
{
public:
- NS_DECL_CYCLE_COLLECTION_CLASS(ExtensionPolicyService)
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ExtensionPolicyService,
+ nsIAddonPolicyService)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIADDONPOLICYSERVICE
+ NS_DECL_NSIOBSERVER
static ExtensionPolicyService& GetSingleton();
static already_AddRefed<ExtensionPolicyService> GetInstance()
{
RefPtr<ExtensionPolicyService> service = &GetSingleton();
return service.forget();
}
@@ -61,17 +75,28 @@ public:
void BaseCSP(nsAString& aDefaultCSP) const;
void DefaultCSP(nsAString& aDefaultCSP) const;
protected:
virtual ~ExtensionPolicyService() = default;
private:
- ExtensionPolicyService() = default;
+ ExtensionPolicyService();
+
+ void RegisterObservers();
+ void UnregisterObservers();
+
+ void CheckRequest(nsIChannel* aChannel);
+ void CheckDocument(nsIDocument* aDocument);
+ void CheckWindow(nsPIDOMWindowOuter* aWindow);
+
+ void CheckContentScripts(const DocInfo& aDocInfo, bool aIsPreload);
nsRefPtrHashtable<nsPtrHashKey<const nsIAtom>, WebExtensionPolicy> mExtensions;
nsRefPtrHashtable<nsCStringHashKey, WebExtensionPolicy> mExtensionHosts;
+
+ nsCOMPtr<nsIObserverService> mObs;
};
} // namespace mozilla
#endif // mozilla_ExtensionPolicyService_h
--- a/toolkit/components/extensions/WebExtensionContentScript.h
+++ b/toolkit/components/extensions/WebExtensionContentScript.h
@@ -43,16 +43,24 @@ public:
nsIPrincipal* Principal() const;
const URLInfo& PrincipalURL() const;
bool IsTopLevel() const;
uint64_t FrameID() const;
+ nsPIDOMWindowOuter* GetWindow() const
+ {
+ if (mObj.is<Window>()) {
+ return mObj.as<Window>();
+ }
+ return nullptr;
+ }
+
private:
void SetURL(const URLInfo& aURL);
const URLInfo mURL;
mutable Maybe<const URLInfo> mPrincipalURL;
mutable Maybe<bool> mIsTopLevel;
mutable Maybe<nsCOMPtr<nsIPrincipal>> mPrincipal;
--- a/toolkit/components/extensions/extension-process-script.js
+++ b/toolkit/components/extensions/extension-process-script.js
@@ -21,21 +21,25 @@ XPCOMUtils.defineLazyModuleGetter(this,
"resource://gre/modules/MessageChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChild",
"resource://gre/modules/ExtensionChild.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionContent",
"resource://gre/modules/ExtensionContent.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPageChild",
"resource://gre/modules/ExtensionPageChild.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
- "resource://gre/modules/ExtensionUtils.jsm");
+
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "console", () => ExtensionUtils.getConsole());
-XPCOMUtils.defineLazyGetter(this, "getInnerWindowID", () => ExtensionUtils.getInnerWindowID);
+
+const {
+ DefaultWeakMap,
+ getInnerWindowID,
+} = ExtensionUtils;
// We need to avoid touching Services.appinfo here in order to prevent
// the wrong version from being cached during xpcshell test startup.
const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
const isContentProcess = appinfo.processType == appinfo.PROCESS_TYPE_CONTENT;
function parseScriptOptions(options) {
return {
@@ -57,39 +61,31 @@ function parseScriptOptions(options) {
class ScriptMatcher {
constructor(extension, matcher) {
this.extension = extension;
this.matcher = matcher;
this._script = null;
}
- get matchAboutBlank() {
- return this.matcher.matchAboutBlank;
- }
-
get script() {
if (!this._script) {
this._script = new ExtensionContent.Script(this.extension.realExtension,
this.matcher);
}
return this._script;
}
preload() {
let {script} = this;
script.loadCSS();
script.compileScripts();
}
- matchesLoadInfo(uri, loadInfo) {
- return this.matcher.matchesLoadInfo(uri, loadInfo);
- }
-
matchesWindow(window) {
return this.matcher.matchesWindow(window);
}
injectInto(window) {
return this.script.injectInto(window);
}
}
@@ -152,16 +148,20 @@ class ExtensionGlobal {
case "WebNavigation:GetFrame":
return ExtensionContent.handleWebNavigationGetFrame(this.global, data.options);
case "WebNavigation:GetAllFrames":
return ExtensionContent.handleWebNavigationGetAllFrames(this.global);
}
}
}
+let stubExtensions = new WeakMap();
+let scriptMatchers = new DefaultWeakMap(matcher => new ScriptMatcher(stubExtensions.get(matcher.extension),
+ matcher));
+
// Responsible for creating ExtensionContexts and injecting content
// scripts into them when new documents are created.
DocumentManager = {
globals: new Map(),
// Initialize listeners that we need regardless of whether extensions are
// enabled.
earlyInit() {
@@ -171,42 +171,16 @@ DocumentManager = {
// Initialize listeners that we need when any extension is enabled.
init() {
Services.obs.addObserver(this, "document-element-inserted");
},
uninit() {
Services.obs.removeObserver(this, "document-element-inserted");
},
- // Initialize listeners that we need when any extension content script is
- // enabled.
- initMatchers() {
- if (isContentProcess) {
- Services.obs.addObserver(this, "http-on-opening-request");
- }
- },
- uninitMatchers() {
- if (isContentProcess) {
- Services.obs.removeObserver(this, "http-on-opening-request");
- }
- },
-
- // Initialize listeners that we need when any about:blank content script is
- // enabled.
- //
- // Loads of about:blank are special, and do not trigger "document-element-inserted"
- // observers. So if we have any scripts that match about:blank, we also need
- // to observe "content-document-global-created".
- initAboutBlankMatchers() {
- Services.obs.addObserver(this, "content-document-global-created");
- },
- uninitAboutBlankMatchers() {
- Services.obs.removeObserver(this, "content-document-global-created");
- },
-
extensionProcessInitialized: false,
initExtensionProcess() {
if (this.extensionProcessInitialized || !ExtensionManagement.isExtensionProcess) {
return;
}
this.extensionProcessInitialized = true;
for (let global of this.globals.keys()) {
@@ -238,156 +212,63 @@ DocumentManager = {
initExtension(extension) {
if (this.extensionCount === 0) {
this.init();
this.initExtensionProcess();
}
this.extensionCount++;
- for (let script of extension.scripts) {
- this.addContentScript(script);
- }
-
this.injectExtensionScripts(extension);
},
uninitExtension(extension) {
- for (let script of extension.scripts) {
- this.removeContentScript(script);
- }
-
this.extensionCount--;
if (this.extensionCount === 0) {
this.uninit();
}
},
-
extensionCount: 0,
- matchAboutBlankCount: 0,
-
- contentScripts: new Set(),
-
- addContentScript(script) {
- if (this.contentScripts.size == 0) {
- this.initMatchers();
- }
-
- if (script.matchAboutBlank) {
- if (this.matchAboutBlankCount == 0) {
- this.initAboutBlankMatchers();
- }
- this.matchAboutBlankCount++;
- }
-
- this.contentScripts.add(script);
- },
- removeContentScript(script) {
- this.contentScripts.delete(script);
-
- if (this.contentScripts.size == 0) {
- this.uninitMatchers();
- }
-
- if (script.matchAboutBlank) {
- this.matchAboutBlankCount--;
- if (this.matchAboutBlankCount == 0) {
- this.uninitAboutBlankMatchers();
- }
- }
- },
// Listeners
observers: {
- async "content-document-global-created"(window) {
- // We only care about about:blank here, since it doesn't trigger
- // "document-element-inserted".
- if ((window.location && window.location.href !== "about:blank") ||
- // Make sure we only load into frames that belong to tabs, or other
- // special areas that we want to load content scripts into.
- !this.globals.has(getMessageManager(window))) {
- return;
- }
-
- // We can't tell for certain whether the final document will actually be
- // about:blank at this point, though, so wait for the DOM to finish
- // loading and check again before injecting scripts.
- await new Promise(resolve => window.addEventListener(
- "DOMContentLoaded", resolve, {once: true, capture: true}));
-
- if (window.location.href === "about:blank") {
- this.injectWindowScripts(window);
- }
- },
-
"document-element-inserted"(document) {
let window = document.defaultView;
if (!document.location || !window ||
// Make sure we only load into frames that belong to tabs, or other
// special areas that we want to load content scripts into.
!this.globals.has(getMessageManager(window))) {
return;
}
- this.injectWindowScripts(window);
this.loadInto(window);
},
- "http-on-opening-request"(subject, topic, data) {
- // If this request is a docshell load, check whether any of our scripts
- // are likely to be loaded into it, and begin preloading the ones that
- // are.
- let {loadInfo} = subject.QueryInterface(Ci.nsIChannel);
- if (loadInfo) {
- let {externalContentPolicyType: type} = loadInfo;
- if (type === Ci.nsIContentPolicy.TYPE_DOCUMENT ||
- type === Ci.nsIContentPolicy.TYPE_SUBDOCUMENT) {
- this.preloadScripts(subject.URI, loadInfo);
- }
- }
- },
-
"tab-content-frameloader-created"(global) {
this.initGlobal(global);
},
},
observe(subject, topic, data) {
this.observers[topic].call(this, subject, topic, data);
},
// Script loading
injectExtensionScripts(extension) {
for (let window of this.enumerateWindows()) {
- for (let script of extension.scripts) {
+ for (let script of extension.policy.contentScripts) {
if (script.matchesWindow(window)) {
- script.injectInto(window);
+ scriptMatchers.get(script).injectInto(window);
}
}
}
},
- injectWindowScripts(window) {
- for (let script of this.contentScripts) {
- if (script.matchesWindow(window)) {
- script.injectInto(window);
- }
- }
- },
-
- preloadScripts(uri, loadInfo) {
- for (let script of this.contentScripts) {
- if (script.matchesLoadInfo(uri, loadInfo)) {
- script.preload();
- }
- }
- },
-
/**
* Checks that all parent frames for the given withdow either have the
* same add-on ID, or are special chrome-privileged documents such as
* about:addons or developer tools panels.
*
* @param {Window} window
* The window to check.
* @param {string} addonId
@@ -490,16 +371,18 @@ class StubExtension {
startup() {
// Extension.jsm takes care of this in the parent.
if (isContentProcess) {
let uri = Services.io.newURI(this.data.resourceURL);
ExtensionManagement.startupExtension(this.uuid, uri, this);
} else {
this.policy = WebExtensionPolicy.getByID(this.id);
}
+
+ stubExtensions.set(this.policy, this);
}
shutdown() {
if (isContentProcess) {
ExtensionManagement.shutdownExtension(this);
}
if (this._realExtension) {
this._realExtension.shutdown();
@@ -592,10 +475,36 @@ ExtensionManager = {
case "Schema:Add": {
this.schemaJSON.set(data.url, data.schema);
break;
}
}
},
};
+function ExtensionProcessScript() {
+ if (!ExtensionProcessScript.singleton) {
+ ExtensionProcessScript.singleton = this;
+ }
+ return ExtensionProcessScript.singleton;
+}
+
+ExtensionProcessScript.singleton = null;
+
+ExtensionProcessScript.prototype = {
+ classID: Components.ID("{21f9819e-4cdf-49f9-85a0-850af91a5058}"),
+ QueryInterface: XPCOMUtils.generateQI([Ci.mozIExtensionProcessScript]),
+
+ preloadContentScript(contentScript) {
+ scriptMatchers.get(contentScript).preload();
+ },
+
+ loadContentScript(contentScript, window) {
+ if (DocumentManager.globals.has(getMessageManager(window))) {
+ scriptMatchers.get(contentScript).injectInto(window);
+ }
+ },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ExtensionProcessScript]);
+
DocumentManager.earlyInit();
ExtensionManager.init();
--- a/toolkit/components/extensions/extensions-toolkit.manifest
+++ b/toolkit/components/extensions/extensions-toolkit.manifest
@@ -2,8 +2,12 @@
category webextension-scripts toolkit chrome://extensions/content/ext-toolkit.js
category webextension-scripts-content toolkit chrome://extensions/content/ext-c-toolkit.js
category webextension-scripts-devtools toolkit chrome://extensions/content/ext-c-toolkit.js
category webextension-scripts-addon toolkit chrome://extensions/content/ext-c-toolkit.js
category webextension-schemas events chrome://extensions/content/schemas/events.json
category webextension-schemas native_host_manifest chrome://extensions/content/schemas/native_host_manifest.json
category webextension-schemas types chrome://extensions/content/schemas/types.json
+
+
+component {21f9819e-4cdf-49f9-85a0-850af91a5058} extension-process-script.js
+contract @mozilla.org/webextensions/extension-process-script;1 {21f9819e-4cdf-49f9-85a0-850af91a5058}
--- a/toolkit/components/extensions/jar.mn
+++ b/toolkit/components/extensions/jar.mn
@@ -1,15 +1,14 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
toolkit.jar:
% content extensions %content/extensions/
- content/extensions/extension-process-script.js
content/extensions/ext-alarms.js
content/extensions/ext-backgroundPage.js
content/extensions/ext-browser-content.js
content/extensions/ext-contextualIdentities.js
content/extensions/ext-cookies.js
content/extensions/ext-downloads.js
content/extensions/ext-extension.js
content/extensions/ext-geolocation.js
--- a/toolkit/components/extensions/moz.build
+++ b/toolkit/components/extensions/moz.build
@@ -26,29 +26,36 @@ EXTRA_JS_MODULES += [
'LegacyExtensionsUtils.jsm',
'MessageChannel.jsm',
'NativeMessaging.jsm',
'ProxyScriptContext.jsm',
'Schemas.jsm',
]
EXTRA_COMPONENTS += [
+ 'extension-process-script.js',
'extensions-toolkit.manifest',
]
TESTING_JS_MODULES += [
'ExtensionTestCommon.jsm',
'ExtensionXPCShellUtils.jsm',
]
DIRS += [
'schemas',
'webrequest',
]
+XPIDL_SOURCES += [
+ 'mozIExtensionProcessScript.idl',
+]
+
+XPIDL_MODULE = 'webextensions'
+
EXPORTS.mozilla = [
'ExtensionPolicyService.h',
]
EXPORTS.mozilla.extensions = [
'MatchGlob.h',
'MatchPattern.h',
'WebExtensionContentScript.h',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/mozIExtensionProcessScript.idl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface mozIDOMWindowProxy;
+
+[scriptable,uuid(6b09dc51-6caa-4ca7-9d6d-30c87258a630)]
+interface mozIExtensionProcessScript : nsISupports
+{
+ void preloadContentScript(in nsISupports contentScript);
+
+ void loadContentScript(in nsISupports contentScript, in mozIDOMWindowProxy window);
+
+};
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -96,17 +96,17 @@ XPCOMUtils.defineLazyGetter(this, "CertU
let certUtils = {};
Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils);
return certUtils;
});
XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
PREF_WEBEXT_PERM_PROMPTS, false);
-Services.ppmm.loadProcessScript("chrome://extensions/content/extension-process-script.js", true);
+Services.ppmm.loadProcessScript("data:,Components.classes['@mozilla.org/webextensions/extension-process-script;1'].getService()", true);
const INTEGER = /^[1-9]\d*$/;
this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ];
const CATEGORY_PROVIDER_MODULE = "addon-provider-module";
// A list of providers to load by default