--- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm
+++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm
@@ -39,188 +39,234 @@ function hasRootDomain(str, aDomain) {
(prevChar == "." || prevChar == "/");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
this.ForgetAboutSite = {
- removeDataFromDomain: function CRH_removeDataFromDomain(aDomain) {
+ removeDataFromDomain: Task.async(function* (aDomain) {
PlacesUtils.history.removePagesFromHost(aDomain, true);
+ let promises = [];
// Cache
- let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"].
- getService(Ci.nsICacheStorageService);
- // NOTE: there is no way to clear just that domain, so we clear out
- // everything)
- try {
- cs.clear();
- } catch (ex) {
- Cu.reportError("Exception thrown while clearing the cache: " +
- ex.toString());
- }
+ promises.push(new Promise((resolve, reject) => {
+ let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"].
+ getService(Ci.nsICacheStorageService);
+ // NOTE: there is no way to clear just that domain, so we clear out
+ // everything)
+ try {
+ cs.clear();
+ resolve();
+ } catch (ex) {
+ reject("Exception thrown while clearing the cache: " + ex);
+ }
+ }));
// Image Cache
- let imageCache = Cc["@mozilla.org/image/tools;1"].
- getService(Ci.imgITools).getImgCacheForDocument(null);
- try {
- imageCache.clearCache(false); // true=chrome, false=content
- } catch (ex) {
- Cu.reportError("Exception thrown while clearing the image cache: " +
- ex.toString());
- }
+ promises.push(new Promise((resolve, reject) => {
+ let imageCache = Cc["@mozilla.org/image/tools;1"].
+ getService(Ci.imgITools).getImgCacheForDocument(null);
+ try {
+ imageCache.clearCache(false); // true=chrome, false=content
+ resolve();
+ } catch (ex) {
+ reject("Exception thrown while clearing the image cache: " + ex);
+ }
+ }));
// Cookies
+ // Need to maximize the number of cookies cleaned here
let cm = Cc["@mozilla.org/cookiemanager;1"].
getService(Ci.nsICookieManager2);
let enumerator = cm.getCookiesWithOriginAttributes(JSON.stringify({}), aDomain);
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
- cm.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
+ promises.push(new Promise((resolve, reject) => {
+ try {
+ cm.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
+ resolve();
+ } catch (ex) {
+ reject("Exception thrown while clearning cookie " + cookie.name + ": " + ex);
+ }
+ }));
}
// EME
- let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
- getService(Ci.mozIGeckoMediaPluginChromeService);
- mps.forgetThisSite(aDomain, JSON.stringify({}));
+ promises.push(new Promise((resolve, reject) => {
+ let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
+ getService(Ci.mozIGeckoMediaPluginChromeService);
+ try {
+ mps.forgetThisSite(aDomain, JSON.stringify({}));
+ resolve();
+ } catch (ex) {
+ reject("Exception thrown while clearing Encrypted Media Extensions: " + ex);
+ }
+ }));
// Plugin data
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
let tags = ph.getPluginTags();
- let promises = [];
for (let i = 0; i < tags.length; i++) {
- let promise = new Promise(resolve => {
+ promises.push(new Promise((resolve, reject) => {
try {
ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1, function(rv) {
resolve();
});
- } catch (e) {
- // Ignore errors from the plugin, but resolve the promise
- resolve();
+ } catch (ex) {
+ reject("Exception thrown while clearing plugin with tag " + tags[i] + ": " + ex);
}
- });
- promises.push(promise);
+ }));
}
// Downloads
- Task.spawn(function*() {
+ promises.push(Task.spawn(function*() {
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(download => hasRootDomain(
- NetUtil.newURI(download.source.url).host, aDomain));
- }).then(null, Cu.reportError);
+ NetUtil.newURI(download.source.url).host, aDomain));
+ }));
// Passwords
- let lm = Cc["@mozilla.org/login-manager;1"].
- getService(Ci.nsILoginManager);
- // Clear all passwords for domain
- try {
- let logins = lm.getAllLogins();
- for (let i = 0; i < logins.length; i++)
- if (hasRootDomain(logins[i].hostname, aDomain))
- lm.removeLogin(logins[i]);
- } catch (ex) {
- // XXXehsan: is there a better way to do this rather than this
- // hacky comparison?
- if (ex.message.indexOf("User canceled Master Password entry") == -1) {
- throw ex;
+ promises.push(new Promise((resolve, reject) => {
+ let lm = Cc["@mozilla.org/login-manager;1"].
+ getService(Ci.nsILoginManager);
+ // Clear all passwords for domain
+ try {
+ let logins = lm.getAllLogins();
+ for (let i = 0; i < logins.length; i++)
+ if (hasRootDomain(logins[i].hostname, aDomain))
+ lm.removeLogin(logins[i]);
+ resolve();
+ } catch (ex) {
+ // XXXehsan: is there a better way to do this rather than this
+ // hacky comparison?
+ if (ex.message.indexOf("User canceled Master Password entry") == -1) {
+ reject("Exception occured in clearing passwords :" + ex);
+ } else {
+ resolve();
+ }
}
- }
+ }));
// Permissions
let pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager);
// Enumerate all of the permissions, and if one matches, remove it
enumerator = pm.enumerator;
while (enumerator.hasMoreElements()) {
let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
- try {
- if (hasRootDomain(perm.principal.URI.host, aDomain)) {
- pm.removePermission(perm);
+ promises.push(new Promise((resolve, reject) => {
+ try {
+ if (hasRootDomain(perm.principal.URI.host, aDomain)) {
+ pm.removePermission(perm);
+ }
+ resolve();
+ } catch (ex) {
+ reject("Exception occured while clearing a permission: " + ex);
}
- } catch (e) {
- /* Ignore entry */
- }
+ }));
}
// Offline Storages
- let qms = Cc["@mozilla.org/dom/quota-manager-service;1"].
- getService(Ci.nsIQuotaManagerService);
- // delete data from both HTTP and HTTPS sites
- let caUtils = {};
- let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
- getService(Ci.mozIJSSubScriptLoader);
- scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js",
- caUtils);
- let httpURI = caUtils.makeURI("http://" + aDomain);
- let httpsURI = caUtils.makeURI("https://" + aDomain);
- // Following code section has been reverted to the state before Bug 1238183,
- // but added a new argument to clearStoragesForPrincipal() for indicating
- // clear all storages under a given origin.
- let httpPrincipal = Services.scriptSecurityManager
- .createCodebasePrincipal(httpURI, {});
- let httpsPrincipal = Services.scriptSecurityManager
- .createCodebasePrincipal(httpsURI, {});
- qms.clearStoragesForPrincipal(httpPrincipal, null, true);
- qms.clearStoragesForPrincipal(httpsPrincipal, null, true);
-
-
- function onContentPrefsRemovalFinished() {
- // Everybody else (including extensions)
- Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain);
- }
+ promises.push(new Promise((resolve, reject) => {
+ try {
+ let qms = Cc["@mozilla.org/dom/quota-manager-service;1"].
+ getService(Ci.nsIQuotaManagerService);
+ // delete data from both HTTP and HTTPS sites
+ let httpURI = NetUtil.newURI("http://" + aDomain);
+ let httpsURI = NetUtil.newURI("https://" + aDomain);
+ // Following code section has been reverted to the state before Bug 1238183,
+ // but added a new argument to clearStoragesForPrincipal() for indicating
+ // clear all storages under a given origin.
+ let httpPrincipal = Services.scriptSecurityManager
+ .createCodebasePrincipal(httpURI, {});
+ let httpsPrincipal = Services.scriptSecurityManager
+ .createCodebasePrincipal(httpsURI, {});
+ qms.clearStoragesForPrincipal(httpPrincipal, null, true);
+ qms.clearStoragesForPrincipal(httpsPrincipal, null, true);
+ resolve();
+ } catch (ex) {
+ reject("Exception occured while clearing offline storages: " + ex);
+ }
+ }));
// Content Preferences
- let cps2 = Cc["@mozilla.org/content-pref/service;1"].
- getService(Ci.nsIContentPrefService2);
- cps2.removeBySubdomain(aDomain, null, {
- handleCompletion: () => onContentPrefsRemovalFinished(),
- handleError() {}
- });
+ promises.push(new Promise((resolve, reject) => {
+ let cps2 = Cc["@mozilla.org/content-pref/service;1"].
+ getService(Ci.nsIContentPrefService2);
+ cps2.removeBySubdomain(aDomain, null, {
+ handleCompletion: (reason) => {
+ // Notify other consumers, including extensions
+ Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain);
+ if (reason === cps2.COMPLETE_ERROR)
+ reject("Exception occured while clearing content preferences");
+ else
+ resolve();
+ },
+ handleError() {}
+ });
+ }));
// Predictive network data - like cache, no way to clear this per
// domain, so just trash it all
- let np = Cc["@mozilla.org/network/predictor;1"].
- getService(Ci.nsINetworkPredictor);
- np.reset();
+ promises.push(new Promise((resolve, reject) => {
+ try {
+ let np = Cc["@mozilla.org/network/predictor;1"].
+ getService(Ci.nsINetworkPredictor);
+ np.reset();
+ resolve();
+ } catch (ex) {
+ reject("Exception occured while clearing predictive network data: " + ex);
+ }
+ }));
// Push notifications.
promises.push(new Promise((resolve, reject) => {
- var push = Cc["@mozilla.org/push/Service;1"]
- .getService(Ci.nsIPushService);
+ var push = Cc["@mozilla.org/push/Service;1"].
+ getService(Ci.nsIPushService);
push.clearForDomain(aDomain, status => {
(Components.isSuccessCode(status) ? resolve : reject)(status);
});
- }).catch(e => {
- Cu.reportError("Exception thrown while clearing Push notifications: " +
- e.toString());
}));
// HSTS and HPKP
- try {
- let sss = Cc["@mozilla.org/ssservice;1"].
- getService(Ci.nsISiteSecurityService);
- for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
- Ci.nsISiteSecurityService.HEADER_HPKP]) {
- // Also remove HSTS/HPKP 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 the hostname is aDomain's subdomain, we remove its state.
- if (hostname == aDomain || hostname.endsWith("." + aDomain)) {
- // This uri is used as a key to remove the state.
- let uri = caUtils.makeURI("https://" + hostname);
- sss.removeState(type, uri, 0, entry.originAttributes);
+ promises.push(new Promise((resolve, reject) => {
+ try {
+ let sss = Cc["@mozilla.org/ssservice;1"].
+ getService(Ci.nsISiteSecurityService);
+ for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS,
+ Ci.nsISiteSecurityService.HEADER_HPKP]) {
+ // Also remove HSTS/HPKP 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 the hostname is aDomain's subdomain, we remove its state.
+ if (hostname == aDomain || hostname.endsWith("." + aDomain)) {
+ // This uri is used as a key to remove the state.
+ let uri = NetUtil.newURI("https://" + hostname);
+ sss.removeState(type, uri, 0, entry.originAttributes);
+ }
}
}
+ resolve();
+ } catch (e) {
+ reject("Exception thrown while clearing HSTS/HPKP: " + e);
}
- } catch (e) {
- Cu.reportError("Exception thrown while clearing HSTS/HPKP: " +
- e.toString());
+ }));
+
+ let ErrorCount = 0;
+ for (let promise in promises) {
+ try {
+ yield promise;
+ } catch (ex) {
+ Cu.reportError(ex);
+ ErrorCount++;
+ }
}
-
- return Promise.all(promises);
- }
-};
+ if (ErrorCount !== 0)
+ throw new Error(`There were a total of ${ErrorCount} errors during removal`);
+ })
+}