Bug 1298950 - Add support for overriding about:home to chrome_url_overrides r=mixedpuppy
authorMatthew Wein <mwein@mozilla.com>
Mon, 13 Feb 2017 11:36:38 +0000
changeset 391708 e88f2e7f0ee55d495772b6383935e82b5a69bd09
parent 391637 cb86d9e0867224ad5603cff705b09ed486b513ec
child 391709 e5b189f0363b3db64159e6629a25ce8109097e5f
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1298950
milestone54.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 1298950 - Add support for overriding about:home to chrome_url_overrides r=mixedpuppy MozReview-Commit-ID: 4Bc2F0W7WqV
browser/components/extensions/ext-url-overrides.js
browser/components/extensions/schemas/url_overrides.json
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_url_overrides.js
browser/components/extensions/test/browser/browser_ext_url_overrides_all.js
browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
--- a/browser/components/extensions/ext-url-overrides.js
+++ b/browser/components/extensions/ext-url-overrides.js
@@ -3,47 +3,102 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
 
 // Bug 1320736 tracks creating a generic precedence manager for handling
 // multiple addons modifying the same properties, and bug 1330494 has been filed
 // to track utilizing this manager for chrome_url_overrides. Until those land,
 // the edge cases surrounding multiple addons using chrome_url_overrides will
 // be ignored and precedence will be first come, first serve.
 let overrides = {
   // A queue of extensions in line to override the newtab page (sorted oldest to newest).
   newtab: [],
+  // A queue of extensions in line to override the home page (sorted oldest to newest).
+  home: [],
 };
 
+/**
+ * Resets the specified page to its default value.
+ *
+ * @param {string} page The page to override. Accepted values are "newtab" and "home".
+ */
+function resetPage(page) {
+  switch (page) {
+    case "newtab":
+      aboutNewTabService.resetNewTabURL();
+      break;
+    case "home":
+      Preferences.reset("browser.startup.homepage");
+      break;
+    default:
+      throw new Error("Unrecognized override type");
+  }
+}
+
+/**
+ * Overrides the specified page to the specified URL.
+ *
+ * @param {string} page The page to override. Accepted values are "newtab" and "home".
+ * @param {string} url The resolved URL to use for the page override.
+ */
+function overridePage(page, url) {
+  switch (page) {
+    case "newtab":
+      aboutNewTabService.newTabURL = url;
+      break;
+    case "home":
+      Preferences.set("browser.startup.homepage", url);
+      break;
+    default:
+      throw new Error("Unrecognized override type");
+  }
+}
+
+/**
+ * Updates the page to the URL specified by the extension next in line. If no extensions
+ * are in line, the page is reset to its default value.
+ *
+ * @param {string} page The page to override.
+ */
+function updatePage(page) {
+  if (overrides[page].length) {
+    overridePage(page, overrides[page][0].url);
+  } else {
+    resetPage(page);
+  }
+}
+
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_chrome_url_overrides", (type, directive, extension, manifest) => {
-  if (manifest.chrome_url_overrides.newtab) {
-    let newtab = manifest.chrome_url_overrides.newtab;
-    let url = extension.baseURI.resolve(newtab);
+  if (Object.keys(overrides).length > 1) {
+    extension.manifestError("Extensions can override only one page.");
+  }
 
-    // Only set the newtab URL if no other extension is overriding it.
-    if (!overrides.newtab.length) {
-      aboutNewTabService.newTabURL = url;
+  for (let page of Object.keys(overrides)) {
+    if (manifest.chrome_url_overrides[page]) {
+      let relativeURL = manifest.chrome_url_overrides[page];
+      let url = extension.baseURI.resolve(relativeURL);
+      // Store the extension ID instead of a hard reference to the extension.
+      overrides[page].push({id: extension.id, url});
+      updatePage(page);
+      break;
     }
-
-    overrides.newtab.push({extension, url});
   }
 });
 
 extensions.on("shutdown", (type, extension) => {
-  let i = overrides.newtab.findIndex(o => o.extension === extension);
-  if (i !== -1) {
-    overrides.newtab.splice(i, 1);
-
-    if (overrides.newtab.length) {
-      aboutNewTabService.newTabURL = overrides.newtab[0].url;
-    } else {
-      aboutNewTabService.resetNewTabURL();
+  for (let page of Object.keys(overrides)) {
+    let i = overrides[page].findIndex(o => o.id === extension.id);
+    if (i !== -1) {
+      overrides[page].splice(i, 1);
+      updatePage(page);
     }
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
--- a/browser/components/extensions/schemas/url_overrides.json
+++ b/browser/components/extensions/schemas/url_overrides.json
@@ -9,16 +9,21 @@
             "type": "object",
             "optional": true,
             "properties": {
               "newtab": {
                 "$ref": "ExtensionURL",
                 "optional": true,
                 "preprocess": "localize"
               },
+              "home": {
+                "$ref": "ExtensionURL",
+                "optional": true,
+                "preprocess": "localize"
+              },
               "bookmarks": {
                 "unsupported": true,
                 "$ref": "ExtensionURL",
                 "optional": true,
                 "preprocess": "localize"
               },
               "history": {
                 "unsupported": true,
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -109,17 +109,19 @@ support-files =
 [browser_ext_tabs_cookieStoreId.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_zoom.js]
 [browser_ext_tabs_update_url.js]
 [browser_ext_themes_chromeparity.js]
 [browser_ext_themes_dynamic_updates.js]
 [browser_ext_themes_lwtsupport.js]
 [browser_ext_topwindowid.js]
-[browser_ext_url_overrides.js]
+[browser_ext_url_overrides_all.js]
+[browser_ext_url_overrides_home.js]
+[browser_ext_url_overrides_newtab.js]
 [browser_ext_webRequest.js]
 [browser_ext_webNavigation_frameId0.js]
 [browser_ext_webNavigation_getFrames.js]
 [browser_ext_webNavigation_urlbar_transitions.js]
 [browser_ext_windows.js]
 [browser_ext_windows_create.js]
 tags = fullscreen
 [browser_ext_windows_create_params.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_all.js
@@ -0,0 +1,97 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+                                   "@mozilla.org/browser/aboutnewtab-service;1",
+                                   "nsIAboutNewTabService");
+
+const NEWTAB_URI = "webext-newtab.html";
+const HOME_URI = "webext-home.html";
+
+add_task(function* test_extensions_overriding_different_pages() {
+  let defaultHomePage = Preferences.get("browser.startup.homepage");
+  let defaultNewtabPage = aboutNewTabService.newTabURL;
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+    `Default home url should be ${defaultHomePage}`);
+  is(aboutNewTabService.newTabURL, defaultNewtabPage,
+    `Default newtab url should be ${defaultNewtabPage}`);
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {}},
+  });
+
+  let ext2 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI}},
+  });
+
+  let ext3 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {home: HOME_URI}},
+  });
+
+  yield ext1.startup();
+
+  is(aboutNewTabService.newTabURL, defaultNewtabPage,
+    `Default newtab url should still be ${defaultNewtabPage}`);
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+    `Default home url should be ${defaultHomePage}`);
+
+  yield ext2.startup();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
+    "Newtab url should be overriden by the second extension.");
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+    `Default home url should be ${defaultHomePage}`);
+
+  yield ext1.unload();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
+    "Newtab url should still be overriden by the second extension.");
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+    `Default home url should be ${defaultHomePage}`);
+
+  yield ext3.startup();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
+    "Newtab url should still be overriden by the second extension.");
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
+    "Home url should be overriden by the third extension.");
+
+  yield ext2.unload();
+
+  is(aboutNewTabService.newTabURL, defaultNewtabPage,
+    `Newtab url should be reset to ${defaultNewtabPage}`);
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
+    "Home url should still be overriden by the third extension.");
+
+  yield ext3.unload();
+
+  is(aboutNewTabService.newTabURL, defaultNewtabPage,
+    `Newtab url should be reset to ${defaultNewtabPage}`);
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+    `Home url should be reset to ${defaultHomePage}`);
+});
+
+add_task(function* test_extensions_with_multiple_overrides() {
+  let ext = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {
+      newtab: NEWTAB_URI,
+      home: HOME_URI,
+    }},
+  });
+
+  SimpleTest.waitForExplicitFinish();
+  let waitForConsole = new Promise(resolve => {
+    SimpleTest.monitorConsole(resolve, [{
+      message: /Extensions can override only one page./,
+    }]);
+  });
+
+  yield ext.startup();
+  yield ext.unload();
+
+  SimpleTest.endMonitorConsole();
+  yield waitForConsole;
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
@@ -0,0 +1,74 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
+
+const HOME_URI_1 = "webext-home-1.html";
+const HOME_URI_2 = "webext-home-2.html";
+const HOME_URI_3 = "webext-home-3.html";
+
+add_task(function* test_multiple_extensions_overriding_newtab_page() {
+  let defaultHomePage = Preferences.get("browser.startup.homepage");
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     `Default home url should be ${defaultHomePage}`);
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {}},
+  });
+
+  let ext2 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {home: HOME_URI_1}},
+  });
+
+  let ext3 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {home: HOME_URI_2}},
+  });
+
+  let ext4 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {home: HOME_URI_3}},
+  });
+
+  yield ext1.startup();
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+       `Default home url should still be ${defaultHomePage}`);
+
+  yield ext2.startup();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should be overriden by the second extension.");
+
+  yield ext1.unload();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should still be overriden by the second extension.");
+
+  yield ext3.startup();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
+     "Home url should still be overriden by the second extension.");
+
+  yield ext2.unload();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
+     "Home url should be overriden by the third extension.");
+
+  yield ext4.startup();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
+     "Home url should be overriden by the third extension.");
+
+  yield ext4.unload();
+
+  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
+     "Home url should be overriden by the third extension.");
+
+  yield ext3.unload();
+
+  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
+     `Home url should be reset to ${defaultHomePage}`);
+});
rename from browser/components/extensions/test/browser/browser_ext_url_overrides.js
rename to browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides.js
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
@@ -71,21 +71,21 @@ add_task(function* test_multiple_extensi
   is(aboutNewTabService.newTabURL, "about:newtab",
      "Newtab url should be reset to about:newtab");
 });
 
 add_task(function* test_sending_message_from_newtab_page() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "chrome_url_overrides": {
-        newtab: NEWTAB_URI_2,
+        newtab: NEWTAB_URI_1,
       },
     },
     files: {
-      [NEWTAB_URI_2]: `
+      [NEWTAB_URI_1]: `
         <!DOCTYPE html>
         <head>
           <meta charset="utf-8"/></head>
         <html>
           <body>
             <script src="newtab.js"></script>
           </body>
         </html>