Bug 1451519 Convert specialpowers to a webextension draft
authorAndrew Swan <aswan@mozilla.com>
Wed, 27 Jun 2018 13:10:51 -0700
changeset 812670 cef957b8c3f8a60806505de29dd852265e27c792
parent 812548 a009b5249a4b78a889fdc5ffcf55ad51715cc686
push id114631
push useraswan@mozilla.com
push dateFri, 29 Jun 2018 19:22:50 +0000
bugs1451519
milestone63.0a1
Bug 1451519 Convert specialpowers to a webextension 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 @@
+[]