Backed out changeset 641430a49682 (bug 1402066)
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 26 Sep 2017 11:37:44 +0200
changeset 670378 998dd0100a61ba5ceafe8fe27b13753b3537a8bd
parent 670377 f9df54bc39999524555f6d24ff609627fdc7553c
child 670379 6a9d008002efc9044416d5fff5713f899c954ebb
push id81612
push userbmo:dharvey@mozilla.com
push dateTue, 26 Sep 2017 10:16:26 +0000
bugs1402066
milestone58.0a1
backs out641430a496824e34170786f6f3bc5e587f2056eb
Backed out changeset 641430a49682 (bug 1402066)
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
toolkit/components/extensions/test/xpcshell/test_ext_redirects.js
toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
toolkit/components/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -90,19 +90,18 @@ function promiseBrowserLoaded(browser, u
     // use one. But we also need to make sure it stays alive until we're
     // done with it, so thunk away a strong reference to keep it alive.
     kungFuDeathGrip.add(listener);
     browser.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
   });
 }
 
 class ContentPage {
-  constructor(remote = REMOTE_CONTENT_SCRIPTS, extension = null) {
+  constructor(remote = REMOTE_CONTENT_SCRIPTS) {
     this.remote = remote;
-    this.extension = extension;
 
     this.browserReady = this._initBrowser();
   }
 
   async _initBrowser() {
     this.windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
 
     let system = Services.scriptSecurityManager.getSystemPrincipal();
@@ -119,22 +118,16 @@ class ContentPage {
                           win => win.document == chromeShell.document);
 
     let chromeDoc = await promiseDocumentLoaded(chromeShell.document);
 
     let browser = chromeDoc.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
 
-    if (this.extension && this.extension.remote) {
-      browser.setAttribute("remote", "true");
-      browser.setAttribute("remoteType", "extension");
-      browser.sameProcessAsFrameLoader = this.extension.groupFrameLoader;
-    }
-
     let awaitFrameLoader = Promise.resolve();
     if (this.remote) {
       awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
       browser.setAttribute("remote", "true");
     }
 
     chromeDoc.documentElement.appendChild(browser);
 
@@ -690,34 +683,16 @@ var ExtensionTestUtils = {
   get remoteContentScripts() {
     return REMOTE_CONTENT_SCRIPTS;
   },
 
   set remoteContentScripts(val) {
     REMOTE_CONTENT_SCRIPTS = !!val;
   },
 
-  /**
-   * Loads a content page into a hidden docShell.
-   *
-   * @param {string} url
-   *        The URL to load.
-   * @param {object} [options = {}]
-   * @param {ExtensionWrapper} [options.extension]
-   *        If passed, load the URL as an extension page for the given
-   *        extension.
-   * @param {boolean} [options.remote]
-   *        If true, load the URL in a content process. If false, load
-   *        it in the parent process.
-   * @param {string} [options.redirectUrl]
-   *        An optional URL that the initial page is expected to
-   *        redirect to.
-   *
-   * @returns {ContentPage}
-   */
-  loadContentPage(url, {extension = undefined, remote = undefined, redirectUrl = undefined} = {}) {
-    let contentPage = new ContentPage(remote, extension && extension.extension);
+  loadContentPage(url, remote = undefined, redirectUrl = undefined) {
+    let contentPage = new ContentPage(remote);
 
     return contentPage.loadURL(url, redirectUrl).then(() => {
       return contentPage;
     });
   },
 };
--- a/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
@@ -1,52 +1,36 @@
 "use strict";
 
+XPCOMUtils.defineLazyGetter(this, "ExtensionManager", () => {
+  const {ExtensionManager}
+    = Cu.import("resource://gre/modules/ExtensionChild.jsm", {});
+  return ExtensionManager;
+});
 Cu.import("resource://gre/modules/ExtensionPermissions.jsm");
-Cu.import("resource://gre/modules/MessageChannel.jsm");
 
 const BROWSER_PROPERTIES = "chrome://browser/locale/browser.properties";
 
 AddonTestUtils.init(this);
 AddonTestUtils.overrideCertDB();
 AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 
-let extensionHandlers = new WeakSet();
-
-function frameScript() {
-  /* globals content */
-  const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-  Cu.import("resource://gre/modules/MessageChannel.jsm");
-
-  let handle;
-  MessageChannel.addListener(this, "ExtensionTest:HandleUserInput", {
-    receiveMessage({name, data}) {
-      if (data) {
-        handle = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIDOMWindowUtils)
-                        .setHandlingUserInput(true);
-      } else if (handle) {
-        handle.destruct();
-        handle = null;
-      }
-    },
-  });
-}
-
-async function withHandlingUserInput(extension, fn) {
-  let {messageManager} = extension.extension.groupFrameLoader;
-
-  if (!extensionHandlers.has(extension)) {
-    messageManager.loadFrameScript(`data:,(${frameScript})(this)`, false);
-    extensionHandlers.add(extension);
+// Find the DOMWindowUtils for the background page for the given
+// extension (wrapper)
+function findWinUtils(extension) {
+  let extensionChild = ExtensionManager.extensions.get(extension.extension.id);
+  let bgwin = null;
+  for (let view of extensionChild.views) {
+    if (view.viewType == "background") {
+      bgwin = view.contentWindow;
+    }
   }
-
-  await MessageChannel.sendMessage(messageManager, "ExtensionTest:HandleUserInput", true);
-  await fn();
-  await MessageChannel.sendMessage(messageManager, "ExtensionTest:HandleUserInput", false);
+  notEqual(bgwin, null, "Found background window for the test extension");
+  return bgwin.QueryInterface(Ci.nsIInterfaceRequestor)
+              .getInterface(Ci.nsIDOMWindowUtils);
 }
 
 let sawPrompt = false;
 let acceptPrompt = false;
 const observer = {
   observe(subject, topic, data) {
     if (topic == "webextension-optional-permission-prompt") {
       sawPrompt = true;
@@ -105,16 +89,17 @@ add_task(async function test_permissions
     manifest: {
       permissions: [...REQUIRED_PERMISSIONS, ...REQUIRED_ORIGINS],
       optional_permissions: [...OPTIONAL_PERMISSIONS, ...OPTIONAL_ORIGINS],
     },
     useAddonManager: "permanent",
   });
 
   await extension.startup();
+  let winUtils = findWinUtils(extension);
 
   function call(method, arg) {
     extension.sendMessage(method, arg);
     return extension.awaitMessage(`${method}.result`);
   }
 
   let result = await call("getAll");
   deepEqual(result.permissions, REQUIRED_PERMISSIONS);
@@ -147,41 +132,42 @@ add_task(async function test_permissions
   let perm = OPTIONAL_PERMISSIONS[0];
   result = await call("request", {permissions: [perm]});
   equal(result.status, "error", "request() fails if not called from an event handler");
   ok(/request may only be called from a user input handler/.test(result.message),
      "error message for calling request() outside an event handler is reasonable");
   result = await call("contains", {permissions: [perm]});
   equal(result, false, "Permission requested outside an event handler was not granted");
 
-  await withHandlingUserInput(extension, async () => {
-    result = await call("request", {permissions: ["notifications"]});
-    equal(result.status, "error", "request() for permission not in optional_permissions should fail");
-    ok(/since it was not declared in optional_permissions/.test(result.message),
-       "error message for undeclared optional_permission is reasonable");
+  let userInputHandle = winUtils.setHandlingUserInput(true);
 
-    // Check request() when the prompt is canceled.
-    acceptPrompt = false;
-    result = await call("request", {permissions: [perm]});
-    equal(result.status, "success", "request() returned cleanly");
-    equal(result.result, false, "request() returned false for rejected permission");
+  result = await call("request", {permissions: ["notifications"]});
+  equal(result.status, "error", "request() for permission not in optional_permissions should fail");
+  ok(/since it was not declared in optional_permissions/.test(result.message),
+     "error message for undeclared optional_permission is reasonable");
+
+  // Check request() when the prompt is canceled.
+  acceptPrompt = false;
+  result = await call("request", {permissions: [perm]});
+  equal(result.status, "success", "request() returned cleanly");
+  equal(result.result, false, "request() returned false for rejected permission");
 
-    result = await call("contains", {permissions: [perm]});
-    equal(result, false, "Rejected permission was not granted");
+  result = await call("contains", {permissions: [perm]});
+  equal(result, false, "Rejected permission was not granted");
 
-    // Call request() and accept the prompt
-    acceptPrompt = true;
-    let allOptional = {
-      permissions: OPTIONAL_PERMISSIONS,
-      origins: OPTIONAL_ORIGINS,
-    };
-    result = await call("request", allOptional);
-    equal(result.status, "success", "request() returned cleanly");
-    equal(result.result, true, "request() returned true for accepted permissions");
-  });
+  // Call request() and accept the prompt
+  acceptPrompt = true;
+  let allOptional = {
+    permissions: OPTIONAL_PERMISSIONS,
+    origins: OPTIONAL_ORIGINS,
+  };
+  result = await call("request", allOptional);
+  equal(result.status, "success", "request() returned cleanly");
+  equal(result.result, true, "request() returned true for accepted permissions");
+  userInputHandle.destruct();
 
   let allPermissions = {
     permissions: [...REQUIRED_PERMISSIONS, ...OPTIONAL_PERMISSIONS],
     origins: [...REQUIRED_ORIGINS_NORMALIZED, ...OPTIONAL_ORIGINS_NORMALIZED],
   };
 
   result = await call("getAll");
   deepEqual(result, allPermissions, "getAll() returns required and runtime requested permissions");
@@ -249,25 +235,27 @@ add_task(async function test_startup() {
   });
 
   await extension1.startup();
   await extension2.startup();
 
   let perms = await extension1.awaitMessage("perms");
   perms = await extension2.awaitMessage("perms");
 
-  await withHandlingUserInput(extension1, async () => {
-    extension1.sendMessage(PERMS1);
-    await extension1.awaitMessage("requested");
-  });
+  let winUtils = findWinUtils(extension1);
+  let handle = winUtils.setHandlingUserInput(true);
+  extension1.sendMessage(PERMS1);
+  await extension1.awaitMessage("requested");
+  handle.destruct();
 
-  await withHandlingUserInput(extension2, async () => {
-    extension2.sendMessage(PERMS2);
-    await extension2.awaitMessage("requested");
-  });
+  winUtils = findWinUtils(extension2);
+  handle = winUtils.setHandlingUserInput(true);
+  extension2.sendMessage(PERMS2);
+  await extension2.awaitMessage("requested");
+  handle.destruct();
 
   // Restart everything, and force the permissions store to be
   // re-read on startup
   ExtensionPermissions._uninit();
   await AddonTestUtils.promiseRestartManager();
   await extension1.awaitStartup();
   await extension2.awaitStartup();
 
@@ -330,55 +318,57 @@ add_task(async function test_alreadyGran
         </head></html>`,
 
       "page.js": pageScript,
     },
   });
 
   await extension.startup();
 
-  await withHandlingUserInput(extension, async () => {
-    let url = await extension.awaitMessage("ready");
-    await ExtensionTestUtils.loadContentPage(url, {extension});
-    await extension.awaitMessage("page-ready");
+  let winUtils = findWinUtils(extension);
+  let handle = winUtils.setHandlingUserInput(true);
+
+  let url = await extension.awaitMessage("ready");
+  await ExtensionTestUtils.loadContentPage(url);
+  await extension.awaitMessage("page-ready");
 
-    async function checkRequest(arg, expectPrompt, msg) {
-      sawPrompt = false;
-      extension.sendMessage("request", arg);
-      let result = await extension.awaitMessage("request.result");
-      ok(result, "request() call succeeded");
-      equal(sawPrompt, expectPrompt,
-            `Got ${expectPrompt ? "" : "no "}permission prompt for ${msg}`);
-    }
+  async function checkRequest(arg, expectPrompt, msg) {
+    sawPrompt = false;
+    extension.sendMessage("request", arg);
+    let result = await extension.awaitMessage("request.result");
+    ok(result, "request() call succeeded");
+    equal(sawPrompt, expectPrompt,
+          `Got ${expectPrompt ? "" : "no "}permission prompt for ${msg}`);
+  }
 
-    await checkRequest({permissions: ["geolocation"]}, false,
-                       "required permission from manifest");
-    await checkRequest({origins: ["http://required-host.com/"]}, false,
-                       "origin permission from manifest");
-    await checkRequest({origins: ["http://host.required-domain.com/"]}, false,
-                       "wildcard origin permission from manifest");
+  await checkRequest({permissions: ["geolocation"]}, false,
+                     "required permission from manifest");
+  await checkRequest({origins: ["http://required-host.com/"]}, false,
+                     "origin permission from manifest");
+  await checkRequest({origins: ["http://host.required-domain.com/"]}, false,
+                     "wildcard origin permission from manifest");
 
-    await checkRequest({permissions: ["clipboardRead"]}, true,
-                       "optional permission");
-    await checkRequest({permissions: ["clipboardRead"]}, false,
-                       "already granted optional permission");
+  await checkRequest({permissions: ["clipboardRead"]}, true,
+                     "optional permission");
+  await checkRequest({permissions: ["clipboardRead"]}, false,
+                     "already granted optional permission");
 
-    await checkRequest({origins: ["http://optional-host.com/"]}, true,
-                       "optional origin");
-    await checkRequest({origins: ["http://optional-host.com/"]}, false,
-                       "already granted origin permission");
+  await checkRequest({origins: ["http://optional-host.com/"]}, true,
+                     "optional origin");
+  await checkRequest({origins: ["http://optional-host.com/"]}, false,
+                     "already granted origin permission");
 
-    await checkRequest({origins: ["http://*.optional-domain.com/"]}, true,
-                       "optional wildcard origin");
-    await checkRequest({origins: ["http://*.optional-domain.com/"]}, false,
-                       "already granted optional wildcard origin");
-    await checkRequest({origins: ["http://host.optional-domain.com/"]}, false,
-                       "host matching optional wildcard origin");
-  });
+  await checkRequest({origins: ["http://*.optional-domain.com/"]}, true,
+                     "optional wildcard origin");
+  await checkRequest({origins: ["http://*.optional-domain.com/"]}, false,
+                     "already granted optional wildcard origin");
+  await checkRequest({origins: ["http://host.optional-domain.com/"]}, false,
+                     "host matching optional wildcard origin");
 
+  handle.destruct();
   await extension.unload();
 });
 
 // IMPORTANT: Do not change this list without review from a Web Extensions peer!
 
 const GRANTED_WITHOUT_USER_PROMPT = [
   "activeTab",
   "alarms",
--- a/toolkit/components/extensions/test/xpcshell/test_ext_redirects.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_redirects.js
@@ -143,44 +143,44 @@ add_task(async function test_channel_red
 add_task(async function test_content_redirect_to_non_accessible_resource() {
   let extension = getExtension();
   await extension.startup();
   let redirectUrl = await extension.awaitMessage("redirectURI");
   let url = `${gServerUrl}/redirect?redirect_uri=${redirectUrl}`;
   let watcher = onModifyListener(url).then(channel => {
     return onStopListener(channel);
   });
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {redirectURL: "about:blank"});
+  let contentPage = await ExtensionTestUtils.loadContentPage(url, undefined, "about:blank");
   equal(contentPage.browser.documentURI.spec, "about:blank", `expected no redirect`);
   equal(await watcher, url, "expected no redirect");
   await contentPage.close();
   await extension.unload();
 });
 
 // This test makes a request against a server that redirects with a 302.
 add_task(async function test_content_302_redirect_to_extension() {
   let extension = getExtension(true);
   await extension.startup();
   let redirectUrl = await extension.awaitMessage("redirectURI");
   let url = `${gServerUrl}/redirect?redirect_uri=${redirectUrl}`;
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {redirectUrl});
+  let contentPage = await ExtensionTestUtils.loadContentPage(url, undefined, redirectUrl);
   equal(contentPage.browser.documentURI.spec, redirectUrl, `expected redirect`);
   await contentPage.close();
   await extension.unload();
 });
 
 // This test uses channel.redirectTo during http-on-modify to redirect to the
 // moz-extension url.
 add_task(async function test_content_channel_redirect_to_extension() {
   let extension = getExtension(true);
   await extension.startup();
   let redirectUrl = await extension.awaitMessage("redirectURI");
   let url = `${gServerUrl}/dummy?r=${Math.random()}`;
   onModifyListener(url, redirectUrl);
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {redirectUrl});
+  let contentPage = await ExtensionTestUtils.loadContentPage(url, undefined, redirectUrl);
   equal(contentPage.browser.documentURI.spec, redirectUrl, `expected redirect`);
   await contentPage.close();
   await extension.unload();
 });
 
 // This test makes a request against a server and tests webrequest.  Currently
 // disabled due to NS_BINDING_ABORTED happening.
 add_task(async function test_extension_302_redirect() {
@@ -200,17 +200,17 @@ add_task(async function test_extension_3
     }, {urls: ["<all_urls>", myuri]});
     // send the extensions public uri to the test.
     browser.test.sendMessage("redirectURI", exturi);
   });
   await extension.startup();
   let redirectUrl = await extension.awaitMessage("redirectURI");
   let completed = extension.awaitFinish("requestCompleted");
   let url = `${gServerUrl}/redirect?r=${Math.random()}&redirect_uri=${redirectUrl}`;
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {redirectUrl});
+  let contentPage = await ExtensionTestUtils.loadContentPage(url, undefined, redirectUrl);
   equal(contentPage.browser.documentURI.spec, redirectUrl, `expected content redirect`);
   await completed;
   await contentPage.close();
   await extension.unload();
 }).skip();
 
 // This test makes a request and uses onBeforeRequet to redirect to moz-ext.
 // Currently disabled due to NS_BINDING_ABORTED happening.
@@ -234,14 +234,14 @@ add_task(async function test_extension_r
     }, {urls: ["<all_urls>", myuri]});
     // send the extensions public uri to the test.
     browser.test.sendMessage("redirectURI", exturi);
   });
   await extension.startup();
   let redirectUrl = await extension.awaitMessage("redirectURI");
   let completed = extension.awaitFinish("requestCompleted");
   let url = `${gServerUrl}/dummy?r=${Math.random()}`;
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {redirectUrl});
+  let contentPage = await ExtensionTestUtils.loadContentPage(url, undefined, redirectUrl);
   equal(contentPage.browser.documentURI.spec, redirectUrl, `expected redirect`);
   await completed;
   await contentPage.close();
   await extension.unload();
 }).skip();
--- a/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini
@@ -69,13 +69,11 @@ skip-if = os == "android"
 [test_ext_storage_sync_crypto.js]
 skip-if = os == "android"
 [test_ext_storage_telemetry.js]
 skip-if = os == "android" # checking for telemetry needs to be updated: 1384923
 [test_ext_topSites.js]
 skip-if = os == "android"
 [test_native_manifests.js]
 skip-if = os == "android"
-[test_ext_permissions.js]
-skip-if = os == "android" # Bug 1350559
 [test_proxy_scripts.js]
 skip-if = os == "linux" # bug 1393940
 [test_proxy_scripts_results.js]
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -43,12 +43,14 @@ tags = webextensions in-process-webexten
 [test_ext_schemas_allowed_contexts.js]
 [test_ext_schemas_interactive.js]
 [test_ext_schemas_revoke.js]
 [test_ext_themes_supported_properties.js]
 [test_ext_unknown_permissions.js]
 [test_locale_converter.js]
 [test_locale_data.js]
 
+[test_ext_permissions.js]
+skip-if = os == "android" # Bug 1350559
 [test_ext_runtime_sendMessage_args.js]
 
 [include:xpcshell-common.ini]
 [include:xpcshell-content.ini]