Bug 1664708 - Extend windows API to open webpages in default system browser. r=darktrojan
authorJohn Bieling <john@thunderbird.net>
Fri, 20 Nov 2020 11:59:19 +0100
changeset 95740 3d2772720a88b253d7318b53d869411490a7e1ea
parent 95739 3c8996f7d3ae715359f5eb7f08f26a4418150719
child 95741 4158e4c8d8f490490f7233f960daa6d241a8b00c
push id12262
push userbenc@thunderbird.net
push dateThu, 26 Nov 2020 23:29:19 +0000
treeherdertry-comm-central@f45e1cddeaf1 [default view] [failures only]
reviewersdarktrojan
bugs1664708
Bug 1664708 - Extend windows API to open webpages in default system browser. r=darktrojan
mail/components/extensions/parent/ext-windows.js
mail/components/extensions/schemas/windows.json
mail/components/extensions/test/browser/browser_ext_windows.js
--- a/mail/components/extensions/parent/ext-windows.js
+++ b/mail/components/extensions/parent/ext-windows.js
@@ -333,12 +333,28 @@ this.windows = class extends ExtensionAP
           return new Promise(resolve => {
             let listener = () => {
               windowTracker.removeListener("domwindowclosed", listener);
               resolve();
             };
             windowTracker.addListener("domwindowclosed", listener);
           });
         },
+        openDefaultBrowser(url) {
+          let uri = null;
+          try {
+            uri = Services.io.newURI(url);
+          } catch (e) {
+            throw new ExtensionError(`Url "${url}" seems to be malformed.`);
+          }
+          if (!uri.schemeIs("http") && !uri.schemeIs("https")) {
+            throw new ExtensionError(
+              `Url scheme "${uri.scheme}" is not supported.`
+            );
+          }
+          Cc["@mozilla.org/uriloader/external-protocol-service;1"]
+            .getService(Ci.nsIExternalProtocolService)
+            .loadURI(uri);
+        },
       },
     };
   }
 };
--- a/mail/components/extensions/schemas/windows.json
+++ b/mail/components/extensions/schemas/windows.json
@@ -429,16 +429,28 @@
           },
           {
             "type": "function",
             "name": "callback",
             "optional": true,
             "parameters": []
           }
         ]
+      },
+      {
+        "name": "openDefaultBrowser",
+        "type": "function",
+        "description": "Opens the provided URL in the default system browser.",
+        "async": true,
+        "parameters": [
+          {
+            "type": "string",
+            "name": "url"
+          }
+        ]
       }
     ],
     "events": [
       {
         "name": "onCreated",
         "type": "function",
         "description": "Fired when a window is created.",
         "filters": [
--- a/mail/components/extensions/test/browser/browser_ext_windows.js
+++ b/mail/components/extensions/test/browser/browser_ext_windows.js
@@ -2,16 +2,86 @@
  * 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 MsgOpenNewWindowForFolder */
 
 let { BrowserTestUtils } = ChromeUtils.import(
   "resource://testing-common/BrowserTestUtils.jsm"
 );
+let { MockRegistrar } = ChromeUtils.import(
+  "resource://testing-common/MockRegistrar.jsm"
+);
+
+/** @implements {nsIExternalProtocolService} */
+let mockExternalProtocolService = {
+  _loadedURLs: [],
+  externalProtocolHandlerExists(aProtocolScheme) {},
+  getApplicationDescription(aScheme) {},
+  getProtocolHandlerInfo(aProtocolScheme) {},
+  getProtocolHandlerInfoFromOS(aProtocolScheme, aFound) {},
+  isExposedProtocol(aProtocolScheme) {},
+  loadURI(aURI, aWindowContext) {
+    this._loadedURLs.push(aURI.spec);
+  },
+  setProtocolHandlerDefaults(aHandlerInfo, aOSHandlerExists) {},
+  urlLoaded(aURL) {
+    return this._loadedURLs.includes(aURL);
+  },
+  QueryInterface: ChromeUtils.generateQI(["nsIExternalProtocolService"]),
+};
+
+let mockExternalProtocolServiceCID = MockRegistrar.register(
+  "@mozilla.org/uriloader/external-protocol-service;1",
+  mockExternalProtocolService
+);
+
+registerCleanupFunction(() => {
+  MockRegistrar.unregister(mockExternalProtocolServiceCID);
+});
+
+add_task(async () => {
+  let extension = ExtensionTestUtils.loadExtension({
+    async background() {
+      const urls = {
+        "http://www.google.de/": true,
+        "https://www.google.de/": true,
+        "ftp://www.google.de/": false,
+      };
+
+      for (let [url, expected] of Object.entries(urls)) {
+        let rv = null;
+        try {
+          await browser.windows.openDefaultBrowser(url);
+          rv = true;
+        } catch (e) {
+          rv = false;
+        }
+        browser.test.assertEq(
+          rv,
+          expected,
+          `Checking result for browser.windows.openDefaultBrowser(${url})`
+        );
+      }
+      browser.test.sendMessage("ready", urls);
+    },
+  });
+
+  await extension.startup();
+  let urls = await extension.awaitMessage("ready");
+  for (let [url, expected] of Object.entries(urls)) {
+    Assert.equal(
+      mockExternalProtocolService.urlLoaded(url),
+      expected,
+      `Double check result for browser.windows.openDefaultBrowser(${url})`
+    );
+  }
+
+  await extension.unload();
+});
 
 add_task(async () => {
   let extension = ExtensionTestUtils.loadExtension({
     async background() {
       let listener = {
         waitingPromises: [],
         waitForEvent() {
           return new Promise(resolve => {