Bug 1169249 - Unregister service worker registration when uninstalling a service-worker-enabled application. r=baku

This commit is contained in:
Fernando Jimenez 2015-06-11 19:42:38 +02:00
Родитель ebf8adc0a6
Коммит 86b73d268c
2 изменённых файлов: 92 добавлений и 5 удалений

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

@ -6,6 +6,8 @@
#include "ServiceWorkerManager.h"
#include "mozIApplication.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIAppsService.h"
#include "nsIDOMEventTarget.h"
#include "nsIDocument.h"
@ -78,6 +80,7 @@ BEGIN_WORKERS_NAMESPACE
#define PURGE_DOMAIN_DATA "browser:purge-domain-data"
#define PURGE_SESSION_HISTORY "browser:purge-session-history"
#define WEBAPPS_CLEAR_DATA "webapps-clear-data"
static_assert(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN == static_cast<uint32_t>(RequestMode::Same_origin),
"RequestMode enumeration value should match Necko CORS mode value.");
@ -415,6 +418,8 @@ ServiceWorkerManager::Init()
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = obs->AddObserver(this, WEBAPPS_CLEAR_DATA, false /* ownsWeak */);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
}
@ -4032,9 +4037,9 @@ HasRootDomain(nsIURI* aURI, const nsACString& aDomain)
return prevChar == '.';
}
struct UnregisterIfMatchesHostData
struct UnregisterIfMatchesHostOrPrincipalData
{
UnregisterIfMatchesHostData(
UnregisterIfMatchesHostOrPrincipalData(
ServiceWorkerManager::RegistrationDataPerPrincipal* aRegistrationData,
void* aUserData)
: mRegistrationData(aRegistrationData)
@ -4051,8 +4056,8 @@ UnregisterIfMatchesHost(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aPtr)
{
UnregisterIfMatchesHostData* data =
static_cast<UnregisterIfMatchesHostData*>(aPtr);
UnregisterIfMatchesHostOrPrincipalData* data =
static_cast<UnregisterIfMatchesHostOrPrincipalData*>(aPtr);
// We avoid setting toRemove = aReg by default since there is a possibility
// of failure when data->mUserData is passed, in which case we don't want to
@ -4084,11 +4089,47 @@ UnregisterIfMatchesHostPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
UnregisterIfMatchesHostData data(aData, aUserData);
UnregisterIfMatchesHostOrPrincipalData data(aData, aUserData);
aData->mInfos.EnumerateRead(UnregisterIfMatchesHost, &data);
return PL_DHASH_NEXT;
}
PLDHashOperator
UnregisterIfMatchesPrincipal(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aPtr)
{
UnregisterIfMatchesHostOrPrincipalData* data =
static_cast<UnregisterIfMatchesHostOrPrincipalData*>(aPtr);
if (data->mUserData) {
nsIPrincipal *principal = static_cast<nsIPrincipal*>(data->mUserData);
MOZ_ASSERT(principal);
MOZ_ASSERT(aReg->mPrincipal);
bool equals;
aReg->mPrincipal->Equals(principal, &equals);
if (equals) {
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->ForceUnregister(data->mRegistrationData, aReg);
}
}
return PL_DHASH_NEXT;
}
PLDHashOperator
UnregisterIfMatchesPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
UnregisterIfMatchesHostOrPrincipalData data(aData, aUserData);
// We can use EnumerateRead because ForceUnregister (and Unregister) are async.
// Otherwise doing some R/W operations on an hashtable during an EnumerateRead
// will crash.
aData->mInfos.EnumerateRead(UnregisterIfMatchesPrincipal, &data);
return PL_DHASH_NEXT;
}
PLDHashOperator
GetAllRegistrationsEnumerator(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
@ -4257,6 +4298,17 @@ UpdateEachRegistration(const nsACString& aKey,
return PL_DHASH_NEXT;
}
void
ServiceWorkerManager::RemoveAllRegistrations(nsIPrincipal* aPrincipal)
{
AssertIsOnMainThread();
MOZ_ASSERT(aPrincipal);
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesPrincipal,
aPrincipal);
}
static PLDHashOperator
UpdateEachRegistrationPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
@ -4298,12 +4350,43 @@ ServiceWorkerManager::Observe(nsISupports* aSubject,
}
Remove(NS_ConvertUTF16toUTF8(domain));
} else if (strcmp(aTopic, WEBAPPS_CLEAR_DATA) == 0) {
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(aSubject);
if (NS_WARN_IF(!params)) {
return NS_OK;
}
uint32_t appId;
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAppsService> appsService =
do_GetService(APPS_SERVICE_CONTRACTID);
if (NS_WARN_IF(!appsService)) {
return NS_OK;
}
nsCOMPtr<mozIApplication> app;
appsService->GetAppByLocalId(appId, getter_AddRefs(app));
if (NS_WARN_IF(!app)) {
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal;
app->GetPrincipal(getter_AddRefs(principal));
if (NS_WARN_IF(!principal)) {
return NS_OK;
}
RemoveAllRegistrations(principal);
} else if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
obs->RemoveObserver(this, PURGE_SESSION_HISTORY);
obs->RemoveObserver(this, PURGE_DOMAIN_DATA);
obs->RemoveObserver(this, WEBAPPS_CLEAR_DATA);
}
} else {
MOZ_CRASH("Received message we aren't supposed to be registered for!");

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

@ -532,6 +532,10 @@ private:
void
RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration);
// Removes all service worker registrations for a given principal.
void
RemoveAllRegistrations(nsIPrincipal* aPrincipal);
nsRefPtr<ServiceWorkerManagerChild> mActor;
struct PendingOperation;