Bug 1451519 Convert specialpowers to a webextension r=kmag
authorAndrew Swan <aswan@mozilla.com>
Wed, 27 Jun 2018 13:10:51 -0700
changeset 424476 c1335d07ea3484288561dea88e8c81629b6d37e7
parent 424475 f909f0bf815fa44aa80c0f9bdfaa358317ac7953
child 424497 b9658b2c0044cdfe813ef226882584273f65a063
push id65755
push useraswan@mozilla.com
push dateFri, 29 Jun 2018 21:34:31 +0000
treeherderautoland@c1335d07ea34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1451519
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1451519 Convert specialpowers to a webextension r=kmag This is a quick-and-dirty port. It might be nice to replace SpecialPowersObserver with the webextensions content script injection system at some point, but that isn't practical right now (since WE experiments cannot implement new APIs visible to content scripts). MozReview-Commit-ID: GinCu3VcbWK
browser/base/content/test/performance/browser_startup_content.js
dom/ipc/tests/test_bug1086684.html
js/xpconnect/loader/mozJSComponentLoader.cpp
testing/specialpowers/api.js
testing/specialpowers/bootstrap.js
testing/specialpowers/content/SpecialPowersObserver.jsm
testing/specialpowers/content/SpecialPowersObserverAPI.js
testing/specialpowers/content/specialpowers.js
testing/specialpowers/content/specialpowersAPI.js
testing/specialpowers/install.rdf
testing/specialpowers/jar.mn
testing/specialpowers/manifest.json
testing/specialpowers/moz.build
testing/specialpowers/schema.json
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -21,19 +21,19 @@ const whitelist = {
   components: new Set([
     "ContentProcessSingleton.js",
     "EnterprisePoliciesContent.js", // bug 1470324
     "extension-process-script.js",
   ]),
   modules: new Set([
     // From the test harness
     "chrome://mochikit/content/ShutdownLeaksCollector.jsm",
-    "chrome://specialpowers/content/MockColorPicker.jsm",
-    "chrome://specialpowers/content/MockFilePicker.jsm",
-    "chrome://specialpowers/content/MockPermissionPrompt.jsm",
+    "resource://specialpowers/MockColorPicker.jsm",
+    "resource://specialpowers/MockFilePicker.jsm",
+    "resource://specialpowers/MockPermissionPrompt.jsm",
 
     // General utilities
     "resource://gre/modules/AppConstants.jsm",
     "resource://gre/modules/AsyncShutdown.jsm",
     "resource://gre/modules/DeferredTask.jsm",
     "resource://gre/modules/FileUtils.jsm",
     "resource://gre/modules/NetUtil.jsm",
     "resource://gre/modules/PromiseUtils.jsm",
--- a/dom/ipc/tests/test_bug1086684.html
+++ b/dom/ipc/tests/test_bug1086684.html
@@ -16,17 +16,17 @@
 
     const childFrameURL =
       "http://mochi.test:8888/tests/dom/ipc/tests/file_bug1086684.html";
 
     function childFrameScript() {
       "use strict";
 
       let { MockFilePicker } =
-        ChromeUtils.import("chrome://specialpowers/content/MockFilePicker.jsm", {});
+        ChromeUtils.import("resource://specialpowers/MockFilePicker.jsm", {});
 
       function parentReady(message) {
         MockFilePicker.init(content);
         MockFilePicker.setFiles([message.data.file]);
         MockFilePicker.returnValue = MockFilePicker.returnOK;
 
         let input = content.document.getElementById("f");
         input.addEventListener("change", () => {
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -630,17 +630,17 @@ mozJSComponentLoader::ReuseGlobal(nsIURI
     if (spec.EqualsASCII("resource://gre/modules/jsdebugger.jsm")) {
         return false;
     }
 
     // Some SpecialPowers jsms call Cu.forcePermissiveCOWs(),
     // which sets a per-compartment flag that disables certain
     // security wrappers, so don't use the shared global for them
     // to avoid breaking tests.
-    if (FindInReadable(NS_LITERAL_CSTRING("chrome://specialpowers/"), spec)) {
+    if (FindInReadable(NS_LITERAL_CSTRING("resource://specialpowers/"), spec)) {
         return false;
     }
 
     return true;
 }
 
 JSObject*
 mozJSComponentLoader::GetSharedGlobal(JSContext* aCx)
rename from testing/specialpowers/bootstrap.js
rename to testing/specialpowers/api.js
--- a/testing/specialpowers/bootstrap.js
+++ b/testing/specialpowers/api.js
@@ -1,39 +1,30 @@
 /* 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/. */
 
+/* globals ExtensionAPI */
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-var spObserver;
-
-function startup(data, reason) {
-  let observer = {};
-  ChromeUtils.import("chrome://specialpowers/content/SpecialPowersObserver.jsm", observer);
+XPCOMUtils.defineLazyServiceGetter(this, "resProto",
+                                   "@mozilla.org/network/protocol;1?name=resource",
+                                   "nsISubstitutingProtocolHandler");
 
-  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(
-    observer.SpecialPowersObserver.prototype.classID,
-    "SpecialPowersObserver",
-    observer.SpecialPowersObserver.prototype.contractID,
-    observer.SpecialPowersObserverFactory
-  );
+this.specialpowers = class extends ExtensionAPI {
+  onStartup() {
+    let uri = Services.io.newURI("content/", null, this.extension.rootURI);
+    resProto.setSubstitutionWithFlags("specialpowers", uri,
+                                      resProto.ALLOW_CONTENT_ACCESS);
 
-  spObserver = new observer.SpecialPowersObserver();
-  spObserver.init();
-}
-
-function shutdown(data, reason) {
-  let observer = {};
-  ChromeUtils.import("chrome://specialpowers/content/SpecialPowersObserver.jsm", observer);
+    ChromeUtils.import("resource://specialpowers/SpecialPowersObserver.jsm");
+    this.observer = new SpecialPowersObserver();
+    this.observer.init();
+  }
 
-  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.unregisterFactory(
-    observer.SpecialPowersObserver.prototype.classID,
-    observer.SpecialPowersObserverFactory
-  );
-
-  spObserver.uninit();
-}
-
-function install(data, reason) {}
-function uninstall(data, reason) {}
+  onShutdown() {
+    this.observer.uninit();
+    this.observer = null;
+    resProto.setSubstitution("specialpowers", null);
+  }
+};
--- a/testing/specialpowers/content/SpecialPowersObserver.jsm
+++ b/testing/specialpowers/content/SpecialPowersObserver.jsm
@@ -6,42 +6,39 @@
 // Based on:
 // https://bugzilla.mozilla.org/show_bug.cgi?id=549539
 // https://bug549539.bugzilla.mozilla.org/attachment.cgi?id=429661
 // https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_1.9.3
 // https://developer.mozilla.org/en/how_to_build_an_xpcom_component_in_javascript
 
 /* import-globals-from SpecialPowersObserverAPI.js */
 
-var EXPORTED_SYMBOLS = ["SpecialPowersObserver", "SpecialPowersObserverFactory"];
+var EXPORTED_SYMBOLS = ["SpecialPowersObserver"];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 Cu.importGlobalProperties(["File"]);
 
-const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js";
-const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js";
-const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js";
+const CHILD_SCRIPT = "resource://specialpowers/specialpowers.js";
+const CHILD_SCRIPT_API = "resource://specialpowers/specialpowersAPI.js";
+const CHILD_LOGGER_SCRIPT = "resource://specialpowers/MozillaLogger.js";
 
 
 // Glue to add in the observer API to this object.  This allows us to share code with chrome tests
-Services.scriptloader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js");
+Services.scriptloader.loadSubScript("resource://specialpowers/SpecialPowersObserverAPI.js");
 
 /* XPCOM gunk */
 function SpecialPowersObserver() {
   this._isFrameScriptLoaded = false;
   this._messageManager = Services.mm;
 }
 
 
 SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
 
-SpecialPowersObserver.prototype.classDescription = "Special powers Observer for use in testing.";
-SpecialPowersObserver.prototype.classID = Components.ID("{59a52458-13e0-4d93-9d85-a637344f29a1}");
-SpecialPowersObserver.prototype.contractID = "@mozilla.org/special-powers-observer;1";
 SpecialPowersObserver.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIObserver]);
 
 SpecialPowersObserver.prototype.observe = function(aSubject, aTopic, aData) {
   switch (aTopic) {
     case "chrome-document-global-created":
       this._loadFrameScript();
       break;
 
@@ -284,17 +281,8 @@ SpecialPowersObserver.prototype.receiveM
         this._createdFiles = null;
       }
       break;
     default:
       return this._receiveMessage(aMessage);
   }
   return undefined;
 };
-
-var SpecialPowersObserverFactory = Object.freeze({
-  createInstance(outer, id) {
-    if (outer) { throw Cr.NS_ERROR_NO_AGGREGATION; }
-    return new SpecialPowersObserver();
-  },
-  loadFactory(lock) {},
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
-});
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -496,17 +496,17 @@ SpecialPowersObserverAPI.prototype = {
           // Pipe assertions back to parent process
           mm.sendAsyncMessage("SPChromeScriptAssert",
                               { id, name: scriptName, err, message,
                                 stack });
         };
         Object.defineProperty(sb, "assert", {
           get() {
             let scope = Cu.createObjectIn(sb);
-            Services.scriptloader.loadSubScript("chrome://specialpowers/content/Assert.jsm",
+            Services.scriptloader.loadSubScript("resource://specialpowers/Assert.jsm",
                                                 scope);
 
             let assert = new scope.Assert(reporter);
             delete sb.assert;
             return sb.assert = assert;
           },
           configurable: true
         });
--- a/testing/specialpowers/content/specialpowers.js
+++ b/testing/specialpowers/content/specialpowers.js
@@ -212,19 +212,19 @@ SpecialPowers.prototype.nestedFrameSetup
         });
       });
       mm.addMessageListener("SPPAddNestedMessageListener", function(msg) {
         self._addMessageListener(msg.json.name, function(aMsg) {
           mm.sendAsyncMessage(aMsg.name, aMsg.data);
           });
       });
 
-      mm.loadFrameScript("chrome://specialpowers/content/MozillaLogger.js", false);
-      mm.loadFrameScript("chrome://specialpowers/content/specialpowersAPI.js", false);
-      mm.loadFrameScript("chrome://specialpowers/content/specialpowers.js", false);
+      mm.loadFrameScript("resource://specialpowers/MozillaLogger.js", false);
+      mm.loadFrameScript("resource://specialpowers/specialpowersAPI.js", false);
+      mm.loadFrameScript("resource://specialpowers/specialpowers.js", false);
 
       let frameScript = "SpecialPowers.prototype.IsInNestedFrame=true;";
       mm.loadFrameScript("data:," + frameScript, false);
     }
   }, "remote-browser-shown");
 };
 
 SpecialPowers.prototype.isServiceWorkerRegistered = function() {
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -7,19 +7,19 @@
 
 "use strict";
 
 /* import-globals-from MozillaLogger.js */
 /* globals XPCNativeWrapper, content */
 
 var global = this;
 
-ChromeUtils.import("chrome://specialpowers/content/MockFilePicker.jsm");
-ChromeUtils.import("chrome://specialpowers/content/MockColorPicker.jsm");
-ChromeUtils.import("chrome://specialpowers/content/MockPermissionPrompt.jsm");
+ChromeUtils.import("resource://specialpowers/MockFilePicker.jsm");
+ChromeUtils.import("resource://specialpowers/MockColorPicker.jsm");
+ChromeUtils.import("resource://specialpowers/MockPermissionPrompt.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/ServiceWorkerCleanUp.jsm");
 
 // We're loaded with "this" not set to the global in some cases, so we
deleted file mode 100644
--- a/testing/specialpowers/install.rdf
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0"?>
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>special-powers@mozilla.org</em:id>
-    <em:version>2015.11.16</em:version>
-    <em:type>2</em:type>
-    <em:bootstrap>true</em:bootstrap>
-
-    <!-- Target Application this extension can install into, 
-         with minimum and maximum supported versions. -->
-    <em:targetApplication>
-      <Description>
-        <em:id>toolkit@mozilla.org</em:id>
-#expand        <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
-               <!-- Set to * so toolkit/mozapps/update/chrome tests pass. -->
-               <em:maxVersion>*</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-
-    <!-- Front End MetaData -->
-    <em:name>Special Powers</em:name>
-    <em:description>Special powers for use in testing.</em:description>
-    <em:creator>Mozilla</em:creator>
-  </Description>      
-</RDF>
deleted file mode 100644
--- a/testing/specialpowers/jar.mn
+++ /dev/null
@@ -1,11 +0,0 @@
-specialpowers.jar:
-% content specialpowers %content/ contentaccessible=true
-  content/specialpowers.js (content/specialpowers.js)
-  content/specialpowersAPI.js (content/specialpowersAPI.js)
-  content/SpecialPowersObserverAPI.js (content/SpecialPowersObserverAPI.js)
-  content/SpecialPowersObserver.jsm (content/SpecialPowersObserver.jsm)
-  content/MozillaLogger.js (content/MozillaLogger.js)
-  content/MockFilePicker.jsm (content/MockFilePicker.jsm)
-  content/MockColorPicker.jsm (content/MockColorPicker.jsm)
-  content/MockPermissionPrompt.jsm (content/MockPermissionPrompt.jsm)
-  content/Assert.jsm (../modules/Assert.jsm)
new file mode 100644
--- /dev/null
+++ b/testing/specialpowers/manifest.json
@@ -0,0 +1,23 @@
+{
+  "manifest_version": 2,
+  "name": "Special Powers",
+  "version": "2018.06.27",
+
+  "applications": {
+    "gecko": {
+      "id": "special-powers@mozilla.org"
+    }
+  },
+  "permissions": [],
+
+  "experiment_apis": {
+    "specialpowers": {
+      "schema": "schema.json",
+      "parent": {
+        "scopes": ["addon_parent"],
+        "script": "api.js",
+        "events": ["startup"]
+      }
+    }
+  }
+}
--- a/testing/specialpowers/moz.build
+++ b/testing/specialpowers/moz.build
@@ -1,23 +1,31 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 XPI_NAME = 'specialpowers'
 
-JAR_MANIFESTS += ['jar.mn']
-
 USE_EXTENSION_MANIFEST = True
 NO_JS_MANIFEST = True
 
-FINAL_TARGET_PP_FILES += [
-    'install.rdf',
+FINAL_TARGET_FILES += [
+    'api.js',
+    'manifest.json',
+    'schema.json',
 ]
 
-FINAL_TARGET_FILES += [
-    'bootstrap.js',
+FINAL_TARGET_FILES.content += [
+    '../modules/Assert.jsm',
+    'content/MockColorPicker.jsm',
+    'content/MockFilePicker.jsm',
+    'content/MockPermissionPrompt.jsm',
+    'content/MozillaLogger.js',
+    'content/specialpowers.js',
+    'content/specialpowersAPI.js',
+    'content/SpecialPowersObserver.jsm',
+    'content/SpecialPowersObserverAPI.js',
 ]
 
 with Files("**"):
     BUG_COMPONENT = ("Testing", "Mochitest")
new file mode 100644
--- /dev/null
+++ b/testing/specialpowers/schema.json
@@ -0,0 +1,1 @@
+[]