Bug 1252998 - StorageActivityService - part 4 - Introduce ServiceWorkerCleanUp.jsm to clean up ServiceWorker data, r=asuth

This commit is contained in:
Andrea Marchesini 2018-04-18 18:19:12 +02:00
Родитель 770b7bb21e
Коммит c3b61ca1bf
10 изменённых файлов: 73 добавлений и 105 удалений

Просмотреть файл

@ -13,6 +13,8 @@ ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "setTimeout",
"resource://gre/modules/Timer.jsm");
ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp",
"resource://gre/modules/ServiceWorkerCleanUp.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
"@mozilla.org/serviceworkers/manager;1",
@ -145,22 +147,6 @@ const clearPluginData = options => {
return Sanitizer.items.pluginData.clear(makeRange(options));
};
const clearServiceWorkers = async function() {
// Clearing service workers does not support timestamps.
let yieldCounter = 0;
// Iterate through the service workers and remove them.
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);
if (++yieldCounter % YIELD_PERIOD == 0) {
await new Promise(resolve => setTimeout(resolve, 0)); // Don't block the main thread too long.
}
}
};
const doRemoval = (options, dataToRemove, extension) => {
if (options.originTypes &&
(options.originTypes.protectedWeb || options.originTypes.extension)) {
@ -201,7 +187,7 @@ const doRemoval = (options, dataToRemove, extension) => {
removalPromises.push(clearPluginData(options));
break;
case "serviceWorkers":
removalPromises.push(clearServiceWorkers());
removalPromises.push(ServiceWorkerCleanUp.removeAll());
break;
default:
invalidDataTypes.push(dataType);

Просмотреть файл

@ -16,11 +16,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
DownloadsCommon: "resource:///modules/DownloadsCommon.jsm",
TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
setTimeout: "resource://gre/modules/Timer.jsm",
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager");
XPCOMUtils.defineLazyServiceGetter(this, "quotaManagerService",
"@mozilla.org/dom/quota-manager-service;1",
"nsIQuotaManagerService");
@ -373,28 +371,10 @@ var Sanitizer = {
Services.obs.notifyObservers(null, "extension:purge-localStorage");
// ServiceWorkers
let promises = [];
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
promises.push(new Promise(resolve => {
let unregisterCallback = {
unregisterSucceeded: () => { resolve(true); },
// We don't care about failures.
unregisterFailed: () => { resolve(true); },
QueryInterface: XPCOMUtils.generateQI(
[Ci.nsIServiceWorkerUnregisterCallback])
};
serviceWorkerManager.propagateUnregister(sw.principal, unregisterCallback, sw.scope);
}));
}
await Promise.all(promises);
await ServiceWorkerCleanUp.removeAll();
// QuotaManager
promises = [];
let promises = [];
await new Promise(resolve => {
quotaManagerService.getUsage(request => {
if (request.resultCode != Cr.NS_OK) {

Просмотреть файл

@ -5,9 +5,8 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "OfflineAppCacheHelper",
"resource:///modules/offlineAppCache.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager");
ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp",
"resource://gre/modules/ServiceWorkerCleanUp.jsm");
var EXPORTED_SYMBOLS = [
"SiteDataManager"
@ -315,27 +314,11 @@ var SiteDataManager = {
site.cookies = [];
},
_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 serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
// Sites are grouped and removed by host so we unregister service workers by the same host as well
if (sites.has(sw.principal.URI.host)) {
promises.push(this._unregisterServiceWorker(sw));
}
}
sites.forEach(s => {
promises.push(ServiceWorkerCleanUp.removeFromHost(s.principals[0].URI.host));
});
return Promise.all(promises);
},
@ -448,14 +431,7 @@ var SiteDataManager = {
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);
promises.push(this._unregisterServiceWorker(sw));
}
await Promise.all(promises);
await ServiceWorkerCleanUp.removeAll();
// Refresh sites using quota usage again.
// This is for the case:
@ -469,7 +445,7 @@ var SiteDataManager = {
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1312361#c9
this._sites.clear();
await this._getQuotaUsage();
promises = [];
let promises = [];
for (let site of this._sites.values()) {
this._removePermission(site);
promises.push(this._removeQuotaUsage(site));

Просмотреть файл

@ -144,17 +144,6 @@ interface nsIServiceWorkerManager : nsISupports
[notxpcom, nostdcall] bool StartControlling(in const_ClientInfoRef aClientInfo,
in const_ServiceWorkerDescriptorRef aServiceWorker);
/*
* Clears ServiceWorker registrations from memory and disk for the specified
* host.
* - All ServiceWorker instances change their state to redundant.
* - Existing ServiceWorker instances handling fetches will keep running.
* - All documents will immediately stop being controlled.
* - Unregister jobs will be queued for all registrations.
* This eventually results in the registration being deleted from disk too.
*/
void removeAndPropagate(in AUTF8String aHost);
// Testing
DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);

Просмотреть файл

@ -100,7 +100,6 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace dom {
#define PURGE_DOMAIN_DATA "browser:purge-domain-data"
#define CLEAR_ORIGIN_DATA "clear-origin-attributes-data"
static_assert(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN == static_cast<uint32_t>(RequestMode::Same_origin),
@ -291,8 +290,6 @@ ServiceWorkerManager::Init(ServiceWorkerRegistrar* aRegistrar)
if (obs) {
DebugOnly<nsresult> rv;
rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = obs->AddObserver(this, CLEAR_ORIGIN_DATA, false /* ownsWeak */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
@ -413,7 +410,6 @@ ServiceWorkerManager::MaybeStartShutdown()
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
if (XRE_IsParentProcess()) {
obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
obs->RemoveObserver(this, CLEAR_ORIGIN_DATA);
}
}
@ -3059,14 +3055,6 @@ ServiceWorkerManager::ForceUnregister(RegistrationDataPerPrincipal* aRegistratio
Unregister(aRegistration->Principal(), nullptr, NS_ConvertUTF8toUTF16(aRegistration->Scope()));
}
NS_IMETHODIMP
ServiceWorkerManager::RemoveAndPropagate(const nsACString& aHost)
{
Remove(aHost);
PropagateRemove(aHost);
return NS_OK;
}
void
ServiceWorkerManager::Remove(const nsACString& aHost)
{
@ -3179,13 +3167,6 @@ ServiceWorkerManager::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (strcmp(aTopic, PURGE_DOMAIN_DATA) == 0) {
MOZ_ASSERT(XRE_IsParentProcess());
nsAutoString domain(aData);
RemoveAndPropagate(NS_ConvertUTF16toUTF8(domain));
return NS_OK;
}
if (strcmp(aTopic, CLEAR_ORIGIN_DATA) == 0) {
MOZ_ASSERT(XRE_IsParentProcess());
OriginAttributesPattern pattern;

Просмотреть файл

@ -38,7 +38,7 @@
is(body, "intercepted", "Expected serviceworker to intercept request");
});
}).then(function() {
SpecialPowers.removeServiceWorkerDataForExampleDomain();
return SpecialPowers.removeServiceWorkerDataForExampleDomain();
}).then(function() {
return checkDomainRegistration("prefixexample.com", true /* exists */)
.then(function(e) {

Просмотреть файл

@ -20,6 +20,7 @@ ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.import("resource://gre/modules/ServiceWorkerCleanUp.jsm");
// We're loaded with "this" not set to the global in some cases, so we
// have to play some games to get at the global object here. Normally
@ -1961,11 +1962,11 @@ SpecialPowersAPI.prototype = {
},
removeAllServiceWorkerData() {
this.notifyObserversInParentProcess(null, "browser:purge-session-history", "");
return wrapIfUnwrapped(ServiceWorkerCleanUp.removeAll());
},
removeServiceWorkerDataForExampleDomain() {
this.notifyObserversInParentProcess(null, "browser:purge-domain-data", "example.com");
return wrapIfUnwrapped(ServiceWorkerCleanUp.removeFromHost("example.com"));
},
cleanUpSTSData(origin, flags) {

Просмотреть файл

@ -11,6 +11,8 @@ ChromeUtils.defineModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
ChromeUtils.defineModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp",
"resource://gre/modules/ServiceWorkerCleanUp.jsm");
var EXPORTED_SYMBOLS = ["ForgetAboutSite"];
@ -142,7 +144,11 @@ var ForgetAboutSite = {
}));
}
// Offline Storages
// ServiceWorkers
await ServiceWorkerCleanUp.removeFromHost("http://" + aDomain);
await ServiceWorkerCleanUp.removeFromHost("https://" + aDomain);
// Offline Storages. This must run after the ServiceWorkers promises.
promises.push((async function() {
// delete data from both HTTP and HTTPS sites
let httpURI = NetUtil.newURI("http://" + aDomain);

Просмотреть файл

@ -0,0 +1,48 @@
/* 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/. */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager");
this.EXPORTED_SYMBOLS = ["ServiceWorkerCleanUp"];
function unregisterServiceWorker(aSW) {
return new Promise(resolve => {
let unregisterCallback = {
unregisterSucceeded: resolve,
unregisterFailed: resolve, // We don't care about failures.
QueryInterface: XPCOMUtils.generateQI([Ci.nsIServiceWorkerUnregisterCallback])
};
serviceWorkerManager.propagateUnregister(aSW.principal, unregisterCallback, aSW.scope);
});
}
this.ServiceWorkerCleanUp = {
removeFromHost(aHost) {
let promises = [];
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
if (sw.principal.URI.host == aHost) {
promises.push(unregisterServiceWorker(sw));
}
}
return Promise.all(promises);
},
removeAll() {
let promises = [];
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
for (let i = 0; i < serviceWorkers.length; i++) {
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
promises.push(unregisterServiceWorker(sw));
}
return Promise.all(promises);
},
};

Просмотреть файл

@ -9,6 +9,7 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
EXTRA_JS_MODULES += [
'ForgetAboutSite.jsm',
'ServiceWorkerCleanUp.jsm',
]
with Files('**'):