Bug 1476088 - Additional search submission telemetry. r=florian
authorMichael Kaply <mozilla@kaply.com>
Mon, 06 Aug 2018 21:40:03 +0000
changeset 827162 fb85f9a81670722ca0de657cdad944b342585a79
parent 827161 308ac9e24b442b9a3d3a328a2213d3b02bf685b1
child 827163 5b36bf1368f66d3f028bf990c0e36362f875c579
push id118488
push userbmo:hsivonen@hsivonen.fi
push dateTue, 07 Aug 2018 12:28:14 +0000
reviewersflorian
bugs1476088
milestone63.0a1
Bug 1476088 - Additional search submission telemetry. r=florian Differential Revision: https://phabricator.services.mozilla.com/D2165
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js
toolkit/components/search/tests/xpcshell/xpcshell.ini
toolkit/components/telemetry/docs/data/environment.rst
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -984,19 +984,20 @@ function EngineURL(aType, aMethod, aTemp
     // case "file":
     // case "resource":
       this.template = aTemplate;
       break;
     default:
       FAIL("new EngineURL: template uses invalid scheme!", Cr.NS_ERROR_FAILURE);
   }
 
+  this.templateHost = templateURI.host;
   // If no resultDomain was specified in the engine definition file, use the
   // host from the template.
-  this.resultDomain = aResultDomain || templateURI.host;
+  this.resultDomain = aResultDomain || this.templateHost;
 }
 EngineURL.prototype = {
 
   addParam: function SRCH_EURL_addParam(aName, aValue, aPurpose) {
     this.params.push(new QueryParameter(aName, aValue, aPurpose));
   },
 
   // Note: This method requires that aObj has a unique name or the previous MozParams entry with
@@ -4149,16 +4150,43 @@ SearchService.prototype = {
         for (let engineName of this._searchOrder) {
           if (result.name == engineName) {
             sendSubmissionURL = true;
             break;
           }
         }
       }
 
+      if (!sendSubmissionURL) {
+        // ... or engines that are the same domain as a default engine.
+        let engineHost = engine._getURLOfType(URLTYPE_SEARCH_HTML).templateHost;
+        for (let name in this._engines) {
+          let innerEngine = this._engines[name];
+          if (!innerEngine._isDefault) {
+            continue;
+          }
+
+          let innerEngineURL = innerEngine._getURLOfType(URLTYPE_SEARCH_HTML);
+          if (innerEngineURL.templateHost == engineHost) {
+            sendSubmissionURL = true;
+            break;
+          }
+        }
+
+        if (!sendSubmissionURL) {
+          // ... or well known search domains.
+          //
+          // Starts with: www.google., search.aol., yandex.
+          // or
+          // Ends with: search.yahoo.com, .ask.com, .bing.com, .startpage.com, baidu.com, duckduckgo.com
+          const urlTest = /^(?:www\.google\.|search\.aol\.|yandex\.)|(?:search\.yahoo|\.ask|\.bing|\.startpage|\.baidu|\.duckduckgo)\.com$/;
+          sendSubmissionURL = urlTest.test(engineHost);
+        }
+      }
+
       if (sendSubmissionURL) {
         let uri = engine._getURLOfType("text/html")
                         .getSubmission("", engine, "searchbar").uri;
         uri = uri.mutate()
                  .setUserPass("") // Avoid reporting a username or password.
                  .finalize();
         result.submissionURL = uri.spec;
       }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ *    http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/*
+ * Tests covering sending submission URLs for major engines
+ */
+
+const SUBMISSION_YES = new Map([
+  ["Google1 Test", "https://www.google.com/search?q={searchTerms}"],
+  ["Google2 Test", "https://www.google.co.uk/search?q={searchTerms}"],
+  ["Yahoo1 Test", "https://search.yahoo.com/search?p={searchTerms}"],
+  ["Yahoo2 Test", "https://uk.search.yahoo.com/search?p={searchTerms}"],
+  ["AOL1 Test", "https://search.aol.com/aol/search?q={searchTerms}"],
+  ["AOL2 Test", "https://search.aol.co.uk/aol/search?q={searchTerms}"],
+  ["Yandex1 Test", "https://yandex.ru/search/?text={searchTerms}"],
+  ["Yandex2 Test", "https://yandex.com/search/?text{searchTerms}"],
+  ["Ask1 Test", "https://www.ask.com/web?q={searchTerms}"],
+  ["Ask2 Test", "https://fr.ask.com/web?q={searchTerms}"],
+  ["Bing Test", "https://www.bing.com/search?q={searchTerms}"],
+  ["Startpage Test", "https://www.startpage.com/do/search?query={searchTerms}"],
+  ["DuckDuckGo Test", "https://duckduckgo.com/?q={searchTerms}"],
+  ["Baidu Test", "https://www.baidu.com/s?wd={searchTerms}"],
+]);
+
+const SUBMISSION_NO = new Map([
+  ["Other1 Test", "https://example.com?q={searchTerms}"],
+  ["Other2 Test", "https://googlebutnotgoogle.com?q={searchTerms}"],
+]);
+
+function addAndMakeDefault(name, searchURL) {
+   Services.search.addEngineWithDetails(name, null, null, null, "GET", searchURL);
+   let engine = Services.search.getEngineByName(name);
+   Services.search.currentEngine = engine;
+   return engine;
+}
+
+add_task(async function test() {
+  Assert.ok(!Services.search.isInitialized);
+
+  await asyncInit();
+
+  let engineInfo;
+  let engine;
+
+  for (let [name, searchURL] of SUBMISSION_YES) {
+    engine = addAndMakeDefault(name, searchURL);
+    engineInfo = Services.search.getDefaultEngineInfo();
+    Assert.equal(engineInfo.submissionURL, searchURL.replace("{searchTerms}", ""));
+    Services.search.removeEngine(engine);
+  }
+
+ for (let [name, searchURL] of SUBMISSION_NO) {
+   engine = addAndMakeDefault(name, searchURL);
+   engineInfo = Services.search.getDefaultEngineInfo();
+   Assert.equal(engineInfo.submissionURL, null);
+   Services.search.removeEngine(engine);
+ }
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -96,8 +96,9 @@ skip-if = (verify && !debug && (os == 'l
 [test_addEngineWithDetails.js]
 [test_addEngineWithDetailsObject.js]
 [test_addEngineWithExtensionID.js]
 [test_chromeresource_icon1.js]
 [test_chromeresource_icon2.js]
 [test_engineUpdate.js]
 [test_paramSubstitution.js]
 [test_migrateWebExtensionEngine.js]
+[test_sendSubmissionURL.js]
--- a/toolkit/components/telemetry/docs/data/environment.rst
+++ b/toolkit/components/telemetry/docs/data/environment.rst
@@ -37,17 +37,17 @@ Structure:
         addonCompatibilityCheckEnabled: <bool>, // Whether application compatibility is respected for add-ons
         blocklistEnabled: <bool>, // true on failure
         isDefaultBrowser: <bool>, // null on failure and until session restore completes, not available on Android
         defaultSearchEngine: <string>, // e.g. "yahoo"
         defaultSearchEngineData: {, // data about the current default engine
           name: <string>, // engine name, e.g. "Yahoo"; or "NONE" if no default
           loadPath: <string>, // where the engine line is located; missing if no default
           origin: <string>, // 'default', 'verified', 'unverified', or 'invalid'; based on the presence and validity of the engine's loadPath verification hash.
-          submissionURL: <string> // missing if no default or for user-installed engines
+          submissionURL: <string> // set for default engines or well known search domains
         },
         searchCohort: <string>, // optional, contains an identifier for any active search A/B experiments
         e10sEnabled: <bool>, // whether e10s is on, i.e. browser tabs open by default in a different process
         telemetryEnabled: <bool>, // false on failure
         locale: <string>, // e.g. "it", null on failure
         update: {
           channel: <string>, // e.g. "release", null on failure
           enabled: <bool>, // true on failure