--- a/browser/components/preferences/SiteDataManager.jsm
+++ b/browser/components/preferences/SiteDataManager.jsm
@@ -1,11 +1,11 @@
"use strict";
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OfflineAppCacheHelper",
"resource:///modules/offlineAppCache.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
"resource://gre/modules/ContextualIdentityService.jsm");
@@ -44,47 +44,49 @@ this.SiteDataManager = {
},
_getQuotaUsage() {
// Clear old data and requests first
this._sites.clear();
this._cancelGetQuotaUsage();
this._getQuotaUsagePromise = new Promise(resolve => {
let onUsageResult = request => {
- let items = request.result;
- for (let item of items) {
- if (!item.persisted && item.usage <= 0) {
- // An non-persistent-storage site with 0 byte quota usage is redundant for us so skip it.
- continue;
- }
- let principal =
- Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
- let uri = principal.URI;
- if (uri.scheme == "http" || uri.scheme == "https") {
- let site = this._sites.get(uri.host);
- if (!site) {
- site = {
- persisted: false,
- quotaUsage: 0,
- principals: [],
- appCacheList: [],
- };
+ if (request.resultCode == Cr.NS_OK) {
+ let items = request.result;
+ for (let item of items) {
+ if (!item.persisted && item.usage <= 0) {
+ // An non-persistent-storage site with 0 byte quota usage is redundant for us so skip it.
+ continue;
}
- // Assume 3 sites:
- // - Site A (not persisted): https://www.foo.com
- // - Site B (not persisted): https://www.foo.com^userContextId=2
- // - Site C (persisted): https://www.foo.com:1234
- // Although only C is persisted, grouping by host, as a result,
- // we still mark as persisted here under this host group.
- if (item.persisted) {
- site.persisted = true;
+ let principal =
+ Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
+ let uri = principal.URI;
+ if (uri.scheme == "http" || uri.scheme == "https") {
+ let site = this._sites.get(uri.host);
+ if (!site) {
+ site = {
+ persisted: false,
+ quotaUsage: 0,
+ principals: [],
+ appCacheList: [],
+ };
+ }
+ // Assume 3 sites:
+ // - Site A (not persisted): https://www.foo.com
+ // - Site B (not persisted): https://www.foo.com^userContextId=2
+ // - Site C (persisted): https://www.foo.com:1234
+ // Although only C is persisted, grouping by host, as a result,
+ // we still mark as persisted here under this host group.
+ if (item.persisted) {
+ site.persisted = true;
+ }
+ site.principals.push(principal);
+ site.quotaUsage += item.usage;
+ this._sites.set(uri.host, site);
}
- site.principals.push(principal);
- site.quotaUsage += item.usage;
- this._sites.set(uri.host, site);
}
}
resolve();
};
// XXX: The work of integrating localStorage into Quota Manager is in progress.
// After the bug 742822 and 1286798 landed, localStorage usage will be included.
// So currently only get indexedDB usage.
this._quotaUsageRequest = this._qms.getUsage(onUsageResult);
@@ -217,78 +219,96 @@ this.SiteDataManager = {
cookie.host, cookie.name, cookie.path, false, cookie.originAttributes);
}
}
Services.obs.notifyObservers(null, "browser:purge-domain-data", principal.URI.host);
}
},
- _removeServiceWorkers(site) {
+ _unregisterServiceWorker(serviceWorker) {
+ return new Promise(resolve => {
+ let unregisterCallback = {
+ unregisterSucceeded: resolve,
+ unregisterFailed: resolve, // We don't care about failures.
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIServiceWorkerUnregisterCallback])
+ };
+ serviceWorkerManager.propagateUnregister(serviceWorker.principal, unregisterCallback, serviceWorker.scope);
+ });
+ },
+
+ _removeServiceWorkersForSites(sites) {
+ let promises = [];
+ let targetHosts = sites.map(s => s.principals[0].URI.host);
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
- for (let principal of site.principals) {
- if (sw.principal.equals(principal)) {
- serviceWorkerManager.removeAndPropagate(sw.principal.URI.host);
- break;
- }
+ // Sites are grouped and removed by host so we unregister service workers by the same host as well
+ if (targetHosts.includes(sw.principal.URI.host)) {
+ promises.push(this._unregisterServiceWorker(sw));
}
}
+ return Promise.all(promises);
},
remove(hosts) {
- let promises = [];
let unknownHost = "";
+ let targetSites = [];
for (let host of hosts) {
let site = this._sites.get(host);
if (site) {
this._removePermission(site);
this._removeAppCache(site);
this._removeCookie(site);
- this._removeServiceWorkers(site);
- promises.push(this._removeQuotaUsage(site));
+ targetSites.push(site);
} else {
unknownHost = host;
break;
}
}
- if (promises.length > 0) {
- Promise.all(promises).then(() => this.updateSites());
+
+ if (targetSites.length > 0) {
+ this._removeServiceWorkersForSites(targetSites)
+ .then(() => {
+ let promises = targetSites.map(s => this._removeQuotaUsage(s));
+ return Promise.all(promises);
+ })
+ .then(() => this.updateSites());
}
if (unknownHost) {
throw `SiteDataManager: removing unknown site of ${unknownHost}`;
}
},
async removeAll() {
Services.cache2.clear();
Services.cookies.removeAll();
OfflineAppCacheHelper.clear();
// Iterate through the service workers and remove them.
+ let promises = [];
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
- let host = sw.principal.URI.host;
- serviceWorkerManager.removeAndPropagate(host);
+ promises.push(this._unregisterServiceWorker(sw));
}
+ await Promise.all(promises);
// Refresh sites using quota usage again.
// This is for the case:
// 1. User goes to the about:preferences Site Data section.
// 2. With the about:preferences opened, user visits another website.
// 3. The website saves to quota usage, like indexedDB.
// 4. User goes back to the Site Data section and commands to clear all site data.
// For this case, we should refresh the site list so not to miss the website in the step 3.
// We don't do "Clear All" on the quota manager like the cookie, appcache, http cache above
// because that would clear browser data as well too,
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1312361#c9
await this._getQuotaUsage();
- let promises = [];
+ promises = [];
for (let site of this._sites.values()) {
this._removePermission(site);
promises.push(this._removeQuotaUsage(site));
}
return Promise.all(promises).then(() => this.updateSites());
},
isPrivateCookie(cookie) {