Bug 1468503 - Implement nsIEffectiveTLDService.hasRootDomain, r=smaug
--- 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 == "/");
-}