Bug 1468503 - Implement nsIEffectiveTLDService.hasRootDomain, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 13 Jun 2018 12:29:39 -0700
changeset 479205 ca68fa3212d349d7edac9777b259039c22fae998
parent 479204 b75ad30847fe46f49fcd93975de49609bd820248
child 479206 73a994c463a0b1f6cab41b8c48f04cb99a1c0008
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1468503
milestone62.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 1468503 - Implement nsIEffectiveTLDService.hasRootDomain, r=smaug
netwerk/dns/nsEffectiveTLDService.cpp
netwerk/dns/nsIEffectiveTLDService.idl
toolkit/components/cleardata/ClearDataService.js
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -341,8 +341,40 @@ bool
 nsEffectiveTLDService::LookupForAdd(const nsACString& aHost, TLDCacheEntry** aEntry)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   const uint32_t hash = HashString(aHost.BeginReading(), aHost.Length());
   *aEntry = &mMruTable[hash % kTableSize];
   return (*aEntry)->mHost == aHost;
 }
+
+NS_IMETHODIMP
+nsEffectiveTLDService::HasRootDomain(const nsACString& aInput,
+                                     const nsACString& aHost,
+                                     bool* aResult)
+{
+  if (NS_WARN_IF(!aResult)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = false;
+
+  // If the strings are the same, we obviously have a match.
+  if (aInput == aHost) {
+    *aResult = true;
+    return NS_OK;
+  }
+
+  // If aHost is not found, we know we do not have it as a root domain.
+  int32_t index = nsAutoCString(aInput).Find(aHost.BeginReading());
+  if (index == kNotFound) {
+    return NS_OK;
+  }
+
+  // Otherwise, we have aHost as our root domain iff the index of aHost is
+  // aHost.length subtracted from our length and (since we do not have an
+  // exact match) the character before the index is a dot or slash.
+  *aResult = index > 0 &&
+             (uint32_t)index == aInput.Length() - aHost.Length() &&
+             (aInput[index - 1] == '.' || aInput[index - 1] == '/');
+  return NS_OK;
+}
--- a/netwerk/dns/nsIEffectiveTLDService.idl
+++ b/netwerk/dns/nsIEffectiveTLDService.idl
@@ -116,10 +116,21 @@ interface nsIEffectiveTLDService : nsISu
      *              "bbc.co.uk" would throw NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS.
      *
      * @param   aHost   The host to be analyzed. Any additional parts (e.g. scheme,
      *                  port, or path) will cause this method to throw. ASCII/ACE and
      *                  UTF8 encodings are acceptable as input; normalization will
      *                  be performed as specified in getBaseDomain().
      */
     ACString getNextSubDomain(in AUTF8String aHost);
+
+    /**
+     * Returns true if the |aInput| in is part of the root domain of |aHost|.
+     * For example, if |aInput| is "www.mozilla.org", and we pass in
+     * "mozilla.org" as |aHost|, this will return true.  It would return false
+     * the other way around.
+     *
+     * @param aInput The host to be analyzed.
+     * @param aHost  The host to compare to.
+     */
+    bool hasRootDomain(in AUTF8String aInput, in AUTF8String aHost);
 };
 
--- a/toolkit/components/cleardata/ClearDataService.js
+++ b/toolkit/components/cleardata/ClearDataService.js
@@ -13,16 +13,19 @@ XPCOMUtils.defineLazyModuleGetters(this,
   OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm",
   ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "sas",
                                    "@mozilla.org/storage/activity-service;1",
                                    "nsIStorageActivityService");
+XPCOMUtils.defineLazyServiceGetter(this, "eTLDService",
+                                   "@mozilla.org/network/effective-tld-service;1",
+                                   "nsIEffectiveTLDService");
 
 // A Cleaner is an object with 3 methods. These methods must return a Promise
 // object. Here a description of these methods:
 // * deleteAll() - this method _must_ exist. When called, it deletes all the
 //                 data owned by the cleaner.
 // * deleteByPrincipal() - this method is implemented only if the cleaner knows
 //                         how to delete data by nsIPrincipal. If not
 //                         implemented, deleteByHost will be used instead.
@@ -183,17 +186,17 @@ const PluginDataCleaner = {
       new Promise(aResolve => setTimeout(aResolve, 10000 /* 10 seconds */))
     ]);
   },
 };
 
 const DownloadsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
     return Downloads.getList(Downloads.ALL).then(aList => {
-      aList.removeFinished(aDownload => hasRootDomain(
+      aList.removeFinished(aDownload => eTLDService.hasRootDomain(
         Services.io.newURI(aDownload.source.url).host, aHost));
     });
   },
 
   deleteByRange(aFrom, aTo) {
     // Convert microseconds back to milliseconds for date comparisons.
     let rangeBeginMs = aFrom / 1000;
     let rangeEndMs = aTo / 1000;
@@ -208,17 +211,17 @@ const DownloadsCleaner = {
     return Downloads.getList(Downloads.ALL).then(aList => {
       aList.removeFinished(null);
     });
   },
 };
 
 const PasswordsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
-    return this._deleteInternal(aLogin => hasRootDomain(aLogin.hostname, aHost));
+    return this._deleteInternal(aLogin => eTLDService.hasRootDomain(aLogin.hostname, aHost));
   },
 
   deleteAll() {
     return this._deleteInternal(() => true);
   },
 
   _deleteInternal(aCb) {
     return new Promise(aResolve => {
@@ -485,17 +488,17 @@ const AuthCacheCleaner = {
 
 const PermissionsCleaner = {
   deleteByHost(aHost, aOriginAttributes) {
     return new Promise(aResolve => {
       let enumerator = Services.perms.enumerator;
       while (enumerator.hasMoreElements()) {
         let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
         try {
-          if (hasRootDomain(perm.principal.URI.host, aHost)) {
+          if (eTLDService.hasRootDomain(perm.principal.URI.host, aHost)) {
             Services.perms.removePermission(perm);
           }
         } catch (ex) {
           // Ignore entry
         }
       }
 
       aResolve();
@@ -561,17 +564,17 @@ const SecuritySettingsCleaner = {
       for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
                         Ci.nsISiteSecurityService.HEADER_HPKP]) {
         // Also remove HSTS/HPKP/OMS information for subdomains by enumerating
         // the information in the site security service.
         let enumerator = sss.enumerate(type);
         while (enumerator.hasMoreElements()) {
           let entry = enumerator.getNext();
           let hostname = entry.QueryInterface(Ci.nsISiteSecurityState).hostname;
-          if (hasRootDomain(hostname, aHost)) {
+          if (eTLDService.hasRootDomain(hostname, aHost)) {
             // This uri is used as a key to remove the state.
             let uri = Services.io.newURI("https://" + hostname);
             sss.removeState(type, uri, 0, entry.originAttributes);
           }
         }
       }
 
       aResolve();
@@ -759,32 +762,8 @@ ClearDataService.prototype = Object.free
       return aHelper(c.cleaner).catch(() => { resultFlags |= c.flag; });
     });
     Promise.all(promises).then(() => { aCallback.onDataDeleted(resultFlags); });
     return Cr.NS_OK;
   },
 });
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ClearDataService]);
-
-/**
- * Returns true if the string passed in is part of the root domain of the
- * current string.  For example, if this is "www.mozilla.org", and we pass in
- * "mozilla.org", this will return true.  It would return false the other way
- * around.
- */
-function hasRootDomain(str, aDomain) {
-  let index = str.indexOf(aDomain);
-  // If aDomain is not found, we know we do not have it as a root domain.
-  if (index == -1)
-    return false;
-
-  // If the strings are the same, we obviously have a match.
-  if (str == aDomain)
-    return true;
-
-  // Otherwise, we have aDomain as our root domain iff the index of aDomain is
-  // aDomain.length subtracted from our length and (since we do not have an
-  // exact match) the character before the index is a dot or slash.
-  let prevChar = str[index - 1];
-  return (index == (str.length - aDomain.length)) &&
-         (prevChar == "." || prevChar == "/");
-}