Bug 1364852 - Handle error from Services.eTLD.getBaseDomainFromHost, r?Gijs draft
authorFischer.json <fischer.json@gmail.com>
Thu, 18 May 2017 00:29:31 +0800
changeset 584217 1c74f41e32fdb7dbc3ab9ff937c12fda4df1620e
parent 584216 f81bcc23d37d7bec48f08b19a9327e93c54d37b5
child 630301 0646dffd01954bafac5cd8b08ece17f43d662c2b
push id60652
push userbmo:fliu@mozilla.com
push dateThu, 25 May 2017 01:51:10 +0000
reviewersGijs
bugs1364852, 1365892
milestone55.0a1
Bug 1364852 - Handle error from Services.eTLD.getBaseDomainFromHost, r?Gijs Quota Manager could return origin which being set to eTLD (see bug 1365892 for more details) or in ipv4/ipv6. That could cause error while calling Services.eTLD.getBaseDomainFromHost. This patch handles these expected errors. MozReview-Commit-ID: qlfb8nh8cV
browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
browser/components/preferences/in-content/tests/browser_siteData2.js
browser/components/preferences/siteDataSettings.js
--- a/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
@@ -711,16 +711,34 @@ add_task(async function() {
       persisted: true
     },
     {
       usage: 1024,
       principal: Services.scriptSecurityManager
                          .createCodebasePrincipalFromOrigin("http://email.bar.com"),
       persisted: false
     },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://s3-us-west-2.amazonaws.com"),
+      persisted: true
+    },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://127.0.0.1"),
+      persisted: false
+    },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://[0:0:0:0:0:0:0:1]"),
+      persisted: true
+    },
   ];
   let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
 
   let updatePromise = promiseSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
   await updatePromise;
   await openSettingsDialog();
 
--- a/browser/components/preferences/in-content/tests/browser_siteData2.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData2.js
@@ -153,16 +153,34 @@ add_task(async function() {
       persisted: true
     },
     {
       usage: 1024,
       principal: Services.scriptSecurityManager
                          .createCodebasePrincipalFromOrigin("http://email.bar.com"),
       persisted: false
     },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://s3-us-west-2.amazonaws.com"),
+      persisted: true
+    },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://127.0.0.1"),
+      persisted: false
+    },
+    {
+      usage: 1024,
+      principal: Services.scriptSecurityManager
+                         .createCodebasePrincipalFromOrigin("https://[0:0:0:0:0:0:0:1]"),
+      persisted: true
+    },
   ];
   let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
 
   let updatePromise = promiseSiteDataManagerSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   await updatePromise;
   await openSiteDataSettingsDialog();
 
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -1,13 +1,13 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
-const { interfaces: Ci, utils: Cu } = Components;
+const { interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
                                   "resource:///modules/SiteDataManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
                                   "resource://gre/modules/DownloadUtils.jsm");
@@ -170,30 +170,48 @@ let gSiteDataSettings = {
       if (siteForHost) {
         siteForHost.userAction = "remove";
       }
       item.remove();
     }
     this._updateButtonsState();
   },
 
+  _getBaseDomainFromHost(host) {
+    let result = host;
+    try {
+      result = Services.eTLD.getBaseDomainFromHost(host);
+    } catch (e) {
+      if (e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS ||
+          e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
+        // For this 2 expected errors, just take the host as the result.
+        // - NS_ERROR_HOST_IS_IP_ADDRESS: the host is in ipv4/ipv6.
+        // - NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS: not enough domain part to extract.
+        result = host;
+      } else {
+        throw e;
+      }
+    }
+    return result;
+  },
+
   saveChanges() {
     let allowed = true;
 
     // Confirm user really wants to remove site data starts
-    let removals = [];
+    let removals = new Set();
     this._sites = this._sites.filter(site => {
       if (site.userAction === "remove") {
-        removals.push(site.host);
+        removals.add(site.host);
         return false;
       }
       return true;
     });
 
-    if (removals.length > 0) {
+    if (removals.size > 0) {
       if (this._sites.length == 0) {
         // User selects all sites so equivalent to clearing all data
         let flags =
           Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
           Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
           Services.prompt.BUTTON_POS_0_DEFAULT;
         let prefStrBundle = document.getElementById("bundlePreferences");
         let title = prefStrBundle.getString("clearSiteDataPromptTitle");
@@ -207,27 +225,28 @@ let gSiteDataSettings = {
       } else {
         // User only removes partial sites.
         // We will remove cookies based on base domain, say, user selects "news.foo.com" to remove.
         // The cookies under "music.foo.com" will be removed together.
         // We have to prompt user about this action.
         let hostsTable = new Map();
         // Group removed sites by base domain
         for (let host of removals) {
-          let baseDomain = Services.eTLD.getBaseDomainFromHost(host);
+          let baseDomain = this._getBaseDomainFromHost(host);
           let hosts = hostsTable.get(baseDomain);
           if (!hosts) {
             hosts = [];
             hostsTable.set(baseDomain, hosts);
           }
           hosts.push(host);
         }
+
         // Pick out sites with the same base domain as removed sites
         for (let site of this._sites) {
-          let baseDomain = Services.eTLD.getBaseDomainFromHost(site.host);
+          let baseDomain = this._getBaseDomainFromHost(site.host);
           let hosts = hostsTable.get(baseDomain);
           if (hosts) {
             hosts.push(site.host);
           }
         }
 
         let args = {
           hostsTable,