Bug 1301315 - Add support for chrome_settings_overrides/search_provider. r?mixedpuppy draft
authorMichael Kaply <mozilla@kaply.com>
Tue, 14 Mar 2017 14:03:47 -0500
changeset 500150 50bb4480046bb6d62e1af82f1a6cf91b593a445b
parent 499354 f307a6f0809faa7cdf23b250b1acb6f4f77352be
child 500153 efb1be243e1c38cd6a6b167b81fa4a251c9bd331
push id49629
push usermozilla@kaply.com
push dateThu, 16 Mar 2017 18:36:23 +0000
reviewersmixedpuppy
bugs1301315
milestone55.0a1
Bug 1301315 - Add support for chrome_settings_overrides/search_provider. r?mixedpuppy MozReview-Commit-ID: E5848ih1q0Y
browser/components/extensions/ext-chrome-settings-overrides.js
browser/components/extensions/schemas/chrome_settings_overrides.json
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_settings_overrides_search.js
--- a/browser/components/extensions/ext-chrome-settings-overrides.js
+++ b/browser/components/extensions/ext-chrome-settings-overrides.js
@@ -5,22 +5,63 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
                                   "resource://gre/modules/ExtensionPreferencesManager.jsm");
 
+var searchEngineMap = new WeakMap();
+
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_chrome_settings_overrides", (type, directive, extension, manifest) => {
   if (manifest.chrome_settings_overrides.homepage) {
     ExtensionPreferencesManager.setSetting(extension, "homepage_override",
                                            manifest.chrome_settings_overrides.homepage);
   }
+  if (manifest.chrome_settings_overrides.search_provider) {
+    let searchProvider = manifest.chrome_settings_overrides.search_provider;
+    try {
+      Services.search.addEngineWithDetails(searchProvider.name.trim(), searchProvider.favicon_url,
+                                           searchProvider.keyword, null,
+                                           "GET", searchProvider.search_url);
+      let engine = Services.search.getEngineByName(searchProvider.name.trim());
+      searchEngineMap.set(extension, engine);
+    } catch (e) {
+      // It's possible we got restarted but we don't have a reference to our
+      // engine anymore. Attempt to find it.
+      let engine = Services.search.getEngineByName(searchProvider.name.trim());
+      if (engine) {
+        let submission = engine.getSubmission("searchTerms");
+        // This is a little hacky, but there's no way to get at
+        // the original search URL of the engine.
+        if (submission.uri.spec.replace("searchTerms", "") ==
+            searchProvider.search_url.replace("{searchTerms}", "")) {
+          searchEngineMap.set(extension, engine);
+          return;
+        }
+      }
+      Components.utils.reportError(e);
+    }
+  }
+});
+
+extensions.on("shutdown", (type, extension) => {
+  if (extension.manifest.chrome_settings_overrides.search_provider) {
+    let engine = searchEngineMap.get(extension);
+    searchEngineMap.delete(extension);
+    if (engine) {
+      try {
+        Services.search.removeEngine(engine);
+      } catch (e) {
+        Components.utils.reportError(e);
+      }
+    }
+  }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 ExtensionPreferencesManager.addSetting("homepage_override", {
   prefNames: [
     "browser.startup.homepage",
   ],
   setCallback(value) {
--- a/browser/components/extensions/schemas/chrome_settings_overrides.json
+++ b/browser/components/extensions/schemas/chrome_settings_overrides.json
@@ -10,16 +10,103 @@
             "optional": true,
             "additionalProperties": { "$ref": "UnrecognizedProperty" },
             "properties": {
               "homepage": {
                 "type": "string",
                 "format": "url",
                 "optional": true,
                 "preprocess": "localize"
+              },
+             "search_provider": {
+                "type": "object",
+                "optional": true,
+                "additionalProperties": { "$ref": "UnrecognizedProperty" },
+                "properties": {
+                  "name": {
+                    "type": "string",
+                    "preprocess": "localize"
+                  },
+                  "keyword": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize"
+                  },
+                  "search_url": {
+                    "type": "string",
+                    "format": "url",
+                    "pattern": "^https://.*$",
+                    "preprocess": "localize"
+                  },
+                  "favicon_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize"
+                  },
+                  "suggest_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "instant_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "image_url": {
+                    "type": "string",
+                    "optional": true,
+                    "format": "url",
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "search_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "instant_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "image_url_post_params": {
+                    "type": "string",
+                    "optional": true,
+                    "preprocess": "localize",
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "alternate_urls": {
+                    "type": "array",
+                    "items": {
+                      "type": "string",
+                      "format": "url",
+                      "preprocess": "localize"
+                    },
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox at this time."
+                  },
+                  "prepopulated_id": {
+                    "type": "integer",
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox."
+                  },
+                  "is_default": {
+                    "type": "boolean",
+                    "optional": true,
+                    "deprecated": "Unsupported on Firefox at this time."
+                  }
+                }
               }
             }
           }
         }
       }
     ]
   }
 ]
\ No newline at end of file
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -79,16 +79,17 @@ support-files =
 [browser_ext_popup_shutdown.js]
 [browser_ext_runtime_openOptionsPage.js]
 [browser_ext_runtime_openOptionsPage_uninstall.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_sessions_getRecentlyClosed.js]
 [browser_ext_sessions_getRecentlyClosed_private.js]
 [browser_ext_sessions_getRecentlyClosed_tabs.js]
 [browser_ext_sessions_restore.js]
+[browser_ext_settings_overrides_search.js]
 [browser_ext_sidebarAction.js]
 [browser_ext_sidebarAction_context.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 [browser_ext_tabs_create_invalid_url.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_settings_overrides_search.js
@@ -0,0 +1,52 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+add_task(function* test_extension_adding_engine() {
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}"
+         }
+      },
+    }
+  });
+
+  yield ext1.startup();
+
+  let engine = Services.search.getEngineByName("MozSearch");
+  ok(engine, "Engine should exist.");
+
+  yield ext1.unload();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  ok(!engine, "Engine should not exist");
+});
+
+add_task(function* test_extension_adding_engine_with_spaces() {
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_settings_overrides": {
+        "search_provider": {
+             "name": "MozSearch     ",
+             "keyword": "MozSearch",
+             "search_url": "https://example.com/?q={searchTerms}"
+         }
+      },
+    }
+  });
+
+  yield ext1.startup();
+
+  let engine = Services.search.getEngineByName("MozSearch");
+  ok(engine, "Engine should exist.");
+
+  yield ext1.unload();
+
+  engine = Services.search.getEngineByName("MozSearch");
+  ok(!engine, "Engine should not exist");
+});