Bug 1162088 - ServiceWorkerManager should use the principal+scope for the initialization of ServiceWorkers, r=nsm,ehsan

This commit is contained in:
Andrea Marchesini 2015-05-19 17:53:36 +01:00
Родитель 25e7d5ffdc
Коммит 1d31da42fd
9 изменённых файлов: 470 добавлений и 136 удалений

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

@ -13994,18 +13994,19 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate,
return NS_OK;
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIServiceWorkerManager> swm = services::GetServiceWorkerManager();
if (!swm) {
return NS_OK;
}
if (aIsNavigate) {
return swm->IsAvailableForURI(aURI, aShouldIntercept);
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
return swm->IsAvailableForURI(principal, aURI, aShouldIntercept);
}
return swm->IsControlled(doc, aShouldIntercept);
@ -14024,13 +14025,9 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
nsresult rv = aChannel->GetIsNavigation(&isNavigation);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc;
if (!isNavigation) {
doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIDocument> doc = GetDocument();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
bool isReload = mLoadType & LOAD_CMD_RELOAD;

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

@ -20,7 +20,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
void unregisterFailed();
};
[scriptable, builtinclass, uuid(8ce0d197-5740-4ddf-aa4a-e5a63e611d03)]
[scriptable, builtinclass, uuid(103763c8-53ba-42e4-8b26-e601d5bc4afe)]
interface nsIServiceWorkerInfo : nsISupports
{
readonly attribute nsIPrincipal principal;
@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
readonly attribute DOMString waitingCacheName;
};
[scriptable, builtinclass, uuid(384c9aec-29e5-4bdb-abc2-fba10da83e17)]
[scriptable, builtinclass, uuid(f9375a26-6f56-417a-b4f7-7ddffa4bd873)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -67,7 +67,7 @@ interface nsIServiceWorkerManager : nsISupports
void removeReadyPromise(in nsIDOMWindow aWindow);
// Returns true if a ServiceWorker is available for the scope of aURI.
bool isAvailableForURI(in nsIURI aURI);
bool isAvailableForURI(in nsIPrincipal aPrincipal, in nsIURI aURI);
// Returns true if a given document is currently controlled by a ServiceWorker
bool isControlled(in nsIDocument aDocument);
@ -109,7 +109,7 @@ interface nsIServiceWorkerManager : nsISupports
/*
* This implements the soft update algorithm.
*/
void softUpdate(in DOMString aScope);
void softUpdate(in nsIPrincipal aPrincipal, in DOMString aScope);
/*
* Clears ServiceWorker registrations from memory and disk for the specified
@ -128,14 +128,16 @@ interface nsIServiceWorkerManager : nsISupports
void removeAll();
// Testing
DOMString getScopeForUrl(in DOMString path);
DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);
// This is meant to be used only by about:serviceworkers. It returns an array
// of nsIServiceWorkerInfo.
nsIArray getAllRegistrations();
void sendPushEvent(in ACString scope, in DOMString data);
void sendPushSubscriptionChangeEvent(in ACString scope);
void sendPushEvent(in nsIPrincipal aPrincipal, in ACString aScope,
in DOMString aData);
void sendPushSubscriptionChangeEvent(in nsIPrincipal aPrincipal,
in ACString scope);
void updateAllRegistrations();
};

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

@ -10,9 +10,11 @@ XPCOMUtils.defineLazyServiceGetter(this,
"nsIServiceWorkerManager");
addMessageListener("push", function (aMessage) {
swm.sendPushEvent(aMessage.data.scope, aMessage.data.payload);
let principal = content.document.nodePrincipal;
swm.sendPushEvent(principal, aMessage.data.scope, aMessage.data.payload);
});
addMessageListener("pushsubscriptionchange", function (aMessage) {
swm.sendPushSubscriptionChangeEvent(aMessage.data);
let principal = content.document.nodePrincipal;
swm.sendPushSubscriptionChangeEvent(principal, aMessage.data);
});

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

@ -114,7 +114,7 @@ public:
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsTArray<ServiceWorkerClientInfo> result;
swm->GetAllClients(mScope, result);
swm->GetAllClients(mWorkerPrivate->GetPrincipal(), mScope, result);
nsRefPtr<ResolvePromiseWorkerRunnable> r =
new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseProxy, result);
@ -197,7 +197,9 @@ public:
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsresult rv = swm->ClaimClients(mScope, mServiceWorkerID);
nsresult rv =
swm->ClaimClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
mScope, mServiceWorkerID);
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
if (mPromiseProxy->IsClean()) {

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

@ -225,13 +225,19 @@ ServiceWorkerContainer::GetScopeForUrl(const nsAString& aUrl,
nsString& aScope,
ErrorResult& aRv)
{
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
MOZ_ASSERT(doc);
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
MOZ_ASSERT(principal);
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
aRv = swm->GetScopeForUrl(aUrl, aScope);
aRv = swm->GetScopeForUrl(principal, aUrl, aScope);
}
} // namespace dom

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

@ -51,6 +51,7 @@
#include "ServiceWorker.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerContainer.h"
#include "ServiceWorkerRegistrar.h"
#include "ServiceWorkerRegistration.h"
#include "ServiceWorkerScriptCache.h"
#include "ServiceWorkerEvents.h"
@ -81,6 +82,24 @@ static_assert(nsIHttpChannelInternal::CORS_MODE_CORS == static_cast<uint32_t>(Re
static_assert(nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT == static_cast<uint32_t>(RequestMode::Cors_with_forced_preflight),
"RequestMode enumeration value should match Necko CORS mode value.");
struct ServiceWorkerManager::RegistrationDataPerPrincipal
{
// Ordered list of scopes for glob matching.
// Each entry is an absolute URL representing the scope.
// Each value of the hash table is an array of an absolute URLs representing
// the scopes.
//
// An array is used for now since the number of controlled scopes per
// domain is expected to be relatively low. If that assumption was proved
// wrong this should be replaced with a better structure to avoid the
// memmoves associated with inserting stuff in the middle of the array.
nsTArray<nsCString> mOrderedScopes;
// Scope to registration.
// The scope should be a fully qualified valid URL.
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mInfos;
};
struct ServiceWorkerManager::PendingOperation
{
nsCOMPtr<nsIRunnable> mRunnable;
@ -258,7 +277,7 @@ ServiceWorkerManager::ServiceWorkerManager()
ServiceWorkerManager::~ServiceWorkerManager()
{
// The map will assert if it is not empty when destroyed.
mServiceWorkerRegistrationInfos.Clear();
mRegistrationInfos.Clear();
}
class ContinueLifecycleTask : public nsISupports
@ -642,7 +661,7 @@ public:
}
if (mJobType == REGISTER_JOB) {
mRegistration = swm->GetRegistration(mScope);
mRegistration = swm->GetRegistration(mPrincipal, mScope);
if (mRegistration) {
nsRefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
@ -1437,8 +1456,20 @@ public:
return NS_OK;
}
for (uint32_t i = 0; i < swm->mOrderedScopes.Length(); ++i) {
NS_ConvertUTF8toUTF16 scope(swm->mOrderedScopes[i]);
nsAutoCString principalKey;
rv = swm->PrincipalToScopeKey(principal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
if (!swm->mRegistrationInfos.Get(principalKey, &data)) {
mPromise->MaybeResolve(array);
return NS_OK;
}
for (uint32_t i = 0; i < data->mOrderedScopes.Length(); ++i) {
NS_ConvertUTF8toUTF16 scope(data->mOrderedScopes[i]);
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), scope, nullptr, nullptr);
@ -1548,7 +1579,7 @@ public:
}
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetServiceWorkerRegistrationInfo(uri);
swm->GetServiceWorkerRegistrationInfo(principal, uri);
if (!registration) {
mPromise->MaybeResolve(JS::UndefinedHandleValue);
@ -1724,12 +1755,15 @@ public:
#endif /* ! MOZ_SIMPLEPUSH */
NS_IMETHODIMP
ServiceWorkerManager::SendPushEvent(const nsACString& aScope, const nsAString& aData)
ServiceWorkerManager::SendPushEvent(nsIPrincipal* aPrincipal,
const nsACString& aScope,
const nsAString& aData)
{
#ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE;
#else
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(aScope);
nsRefPtr<ServiceWorker> serviceWorker =
CreateServiceWorkerForScope(aPrincipal, aScope);
if (!serviceWorker) {
return NS_ERROR_FAILURE;
}
@ -1738,7 +1772,8 @@ ServiceWorkerManager::SendPushEvent(const nsACString& aScope, const nsAString& a
new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
nsRefPtr<SendPushEventRunnable> r =
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData, serviceWorkerHandle);
new SendPushEventRunnable(serviceWorker->GetWorkerPrivate(), aData,
serviceWorkerHandle);
AutoJSAPI jsapi;
jsapi.Init();
@ -1751,12 +1786,14 @@ ServiceWorkerManager::SendPushEvent(const nsACString& aScope, const nsAString& a
}
NS_IMETHODIMP
ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aScope)
ServiceWorkerManager::SendPushSubscriptionChangeEvent(nsIPrincipal* aPrincipal,
const nsACString& aScope)
{
#ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE;
#else
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(aScope);
nsRefPtr<ServiceWorker> serviceWorker =
CreateServiceWorkerForScope(aPrincipal, aScope);
if (!serviceWorker) {
return NS_ERROR_FAILURE;
}
@ -1764,7 +1801,8 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aScope)
new nsMainThreadPtrHolder<ServiceWorker>(serviceWorker));
nsRefPtr<SendPushSubscriptionChangeEventRunnable> r =
new SendPushSubscriptionChangeEventRunnable(serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
new SendPushSubscriptionChangeEventRunnable(
serviceWorker->GetWorkerPrivate(), serviceWorkerHandle);
AutoJSAPI jsapi;
jsapi.Init();
@ -1863,8 +1901,17 @@ bool
ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
nsIURI* aURI, Promise* aPromise)
{
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aURI);
nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
MOZ_ASSERT(doc);
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
MOZ_ASSERT(principal);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(aURI);
GetServiceWorkerRegistrationInfo(principal, aURI);
if (registration && registration->mActiveWorker) {
NS_ConvertUTF8toUTF16 scope(registration->mScope);
@ -1878,7 +1925,8 @@ ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
}
already_AddRefed<ServiceWorker>
ServiceWorkerManager::CreateServiceWorkerForScope(const nsACString& aScope)
ServiceWorkerManager::CreateServiceWorkerForScope(nsIPrincipal* aPrincipal,
const nsACString& aScope)
{
AssertIsOnMainThread();
@ -1887,7 +1935,8 @@ ServiceWorkerManager::CreateServiceWorkerForScope(const nsACString& aScope)
if (NS_FAILED(rv)) {
return nullptr;
}
nsRefPtr<ServiceWorkerRegistrationInfo> registration = GetServiceWorkerRegistrationInfo(scopeURI);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(aPrincipal, scopeURI);
if (!registration) {
return nullptr;
}
@ -1913,7 +1962,7 @@ class ServiceWorkerUnregisterJob final : public ServiceWorkerJob
nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
const nsCString mScope;
nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
PrincipalInfo mPrincipalInfo;
nsCOMPtr<nsIPrincipal> mPrincipal;
~ServiceWorkerUnregisterJob()
{ }
@ -1922,11 +1971,11 @@ public:
ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue,
const nsACString& aScope,
nsIServiceWorkerUnregisterCallback* aCallback,
PrincipalInfo& aPrincipalInfo)
nsIPrincipal* aPrincipal)
: ServiceWorkerJob(aQueue)
, mScope(aScope)
, mCallback(aCallback)
, mPrincipalInfo(aPrincipalInfo)
, mPrincipal(aPrincipal)
{
AssertIsOnMainThread();
}
@ -1947,12 +1996,30 @@ private:
{
AssertIsOnMainThread();
PrincipalInfo principalInfo;
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(mPrincipal,
&principalInfo)))) {
return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsAutoCString principalKey;
nsresult rv = swm->PrincipalToScopeKey(mPrincipal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
}
// "Let registration be the result of running [[Get Registration]]
// algorithm passing scope as the argument."
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
if (!swm->mRegistrationInfos.Get(principalKey, &data)) {
// "If registration is null, then, resolve promise with false."
return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
}
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
if (!swm->mServiceWorkerRegistrationInfos.Get(mScope, getter_AddRefs(registration))) {
if (!data->mInfos.Get(mScope, getter_AddRefs(registration))) {
// "If registration is null, then, resolve promise with false."
return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
}
@ -1962,7 +2029,7 @@ private:
// "Set registration's uninstalling flag."
registration->mPendingUninstall = true;
// "Resolve promise with true"
nsresult rv = mCallback ? mCallback->UnregisterSucceeded(true) : NS_OK;
rv = mCallback ? mCallback->UnregisterSucceeded(true) : NS_OK;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1980,7 +2047,7 @@ private:
}
MOZ_ASSERT(swm->mActor);
swm->mActor->SendUnregisterServiceWorker(mPrincipalInfo,
swm->mActor->SendUnregisterServiceWorker(principalInfo,
NS_ConvertUTF8toUTF16(mScope));
return NS_OK;
@ -2021,14 +2088,8 @@ ServiceWorkerManager::Unregister(nsIPrincipal* aPrincipal,
ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scope);
MOZ_ASSERT(queue);
PrincipalInfo principalInfo;
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
&principalInfo)))) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsRefPtr<ServiceWorkerUnregisterJob> job =
new ServiceWorkerUnregisterJob(queue, scope, aCallback, principalInfo);
new ServiceWorkerUnregisterJob(queue, scope, aCallback, aPrincipal);
if (mActor) {
queue->Append(job);
@ -2246,6 +2307,7 @@ ServiceWorkerManager::StoreRegistration(
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow)
{
MOZ_ASSERT(aWindow);
nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc();
return GetServiceWorkerRegistrationInfo(document);
}
@ -2253,26 +2315,35 @@ ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow)
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIDocument* aDoc)
{
MOZ_ASSERT(aDoc);
nsCOMPtr<nsIURI> documentURI = aDoc->GetDocumentURI();
return GetServiceWorkerRegistrationInfo(documentURI);
nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
return GetServiceWorkerRegistrationInfo(principal, documentURI);
}
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIURI* aURI)
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal,
nsIURI* aURI)
{
nsCString spec;
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aURI);
nsAutoCString spec;
nsresult rv = aURI->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsCString scope = FindScopeForPath(mOrderedScopes, spec);
if (scope.IsEmpty()) {
nsAutoCString scope;
RegistrationDataPerPrincipal* data;
if (!FindScopeForPath(aPrincipal, spec, &data, scope)) {
return nullptr;
}
MOZ_ASSERT(data);
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
mServiceWorkerRegistrationInfos.Get(scope, getter_AddRefs(registration));
data->mInfos.Get(scope, getter_AddRefs(registration));
// ordered scopes and registrations better be in sync.
MOZ_ASSERT(registration);
@ -2282,14 +2353,84 @@ ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIURI* aURI)
return registration.forget();
}
/* static */ void
ServiceWorkerManager::AddScope(nsTArray<nsCString>& aList, const nsACString& aScope)
/* static */ nsresult
ServiceWorkerManager::PrincipalToScopeKey(nsIPrincipal* aPrincipal,
nsACString& aKey)
{
for (uint32_t i = 0; i < aList.Length(); ++i) {
const nsCString& current = aList[i];
MOZ_ASSERT(aPrincipal);
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
aKey.AssignLiteral(SERVICEWORKERREGISTRAR_SYSTEM_PRINCIPAL);
return NS_OK;
}
nsAutoCString key;
nsresult rv;
bool isNullPrincipal = true;
rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// No null principals.
if (isNullPrincipal) {
return NS_ERROR_FAILURE;
}
uint32_t appId;
rv = aPrincipal->GetAppId(&appId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
key.AppendInt(appId);
key.Append('-');
bool inBrowserElement;
rv = aPrincipal->GetIsInBrowserElement(&inBrowserElement);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (inBrowserElement) {
key.AppendLiteral(SERVICEWORKERREGISTRAR_TRUE);
} else {
key.AppendLiteral(SERVICEWORKERREGISTRAR_FALSE);
}
aKey = key;
return NS_OK;
}
/* static */ void
ServiceWorkerManager::AddScopeAndRegistration(nsIPrincipal* aPrincipal,
const nsACString& aScope,
ServiceWorkerRegistrationInfo* aInfo)
{
MOZ_ASSERT(aInfo);
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsAutoCString principalKey;
nsresult rv = swm->PrincipalToScopeKey(aPrincipal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
RegistrationDataPerPrincipal* data;
if (!swm->mRegistrationInfos.Get(principalKey, &data)) {
data = new RegistrationDataPerPrincipal();
swm->mRegistrationInfos.Put(principalKey, data);
}
for (uint32_t i = 0; i < data->mOrderedScopes.Length(); ++i) {
const nsCString& current = data->mOrderedScopes[i];
// Perfect match!
if (aScope.Equals(current)) {
data->mInfos.Put(aScope, aInfo);
return;
}
@ -2297,34 +2438,95 @@ ServiceWorkerManager::AddScope(nsTArray<nsCString>& aList, const nsACString& aSc
// /foo/bar should be before /foo/
// Similarly /foo/b is between the two.
if (StringBeginsWith(aScope, current)) {
aList.InsertElementAt(i, aScope);
data->mOrderedScopes.InsertElementAt(i, aScope);
data->mInfos.Put(aScope, aInfo);
return;
}
}
aList.AppendElement(aScope);
data->mOrderedScopes.AppendElement(aScope);
data->mInfos.Put(aScope, aInfo);
}
/* static */ nsCString
ServiceWorkerManager::FindScopeForPath(nsTArray<nsCString>& aList, const nsACString& aPath)
/* static */ bool
ServiceWorkerManager::FindScopeForPath(nsIPrincipal* aPrincipal,
const nsACString& aPath,
RegistrationDataPerPrincipal** aData,
nsACString& aMatch)
{
nsCString match;
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aData);
for (uint32_t i = 0; i < aList.Length(); ++i) {
const nsCString& current = aList[i];
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsAutoCString principalKey;
nsresult rv = swm->PrincipalToScopeKey(aPrincipal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (!swm->mRegistrationInfos.Get(principalKey, aData)) {
return false;
}
for (uint32_t i = 0; i < (*aData)->mOrderedScopes.Length(); ++i) {
const nsCString& current = (*aData)->mOrderedScopes[i];
if (StringBeginsWith(aPath, current)) {
match = current;
break;
aMatch = current;
return true;
}
}
return match;
return false;
}
/* static */ void
ServiceWorkerManager::RemoveScope(nsTArray<nsCString>& aList, const nsACString& aScope)
#ifdef DEBUG
/* static */ bool
ServiceWorkerManager::HasScope(nsIPrincipal* aPrincipal,
const nsACString& aScope)
{
aList.RemoveElement(aScope);
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsAutoCString principalKey;
nsresult rv = swm->PrincipalToScopeKey(aPrincipal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
RegistrationDataPerPrincipal* data;
if (!swm->mRegistrationInfos.Get(principalKey, &data)) {
return false;
}
return data->mOrderedScopes.Contains(aScope);
}
#endif
/* static */ void
ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration)
{
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsAutoCString principalKey;
nsresult rv = swm->PrincipalToScopeKey(aRegistration->mPrincipal, principalKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
RegistrationDataPerPrincipal* data;
if (!swm->mRegistrationInfos.Get(principalKey, &data)) {
return;
}
data->mInfos.Remove(aRegistration->mScope);
data->mOrderedScopes.RemoveElement(aRegistration->mScope);
if (data->mOrderedScopes.IsEmpty()) {
swm->mRegistrationInfos.Remove(principalKey);
}
}
void
@ -2389,15 +2591,19 @@ ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aR
}
NS_IMETHODIMP
ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
ServiceWorkerManager::GetScopeForUrl(nsIPrincipal* aPrincipal,
const nsAString& aUrl, nsAString& aScope)
{
MOZ_ASSERT(aPrincipal);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
nsRefPtr<ServiceWorkerRegistrationInfo> r = GetServiceWorkerRegistrationInfo(uri);
nsRefPtr<ServiceWorkerRegistrationInfo> r =
GetServiceWorkerRegistrationInfo(aPrincipal, uri);
if (!r) {
return NS_ERROR_FAILURE;
}
@ -2502,7 +2708,8 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
}
////////////////////////////////////////////
nsRefPtr<ServiceWorkerRegistrationInfo> registration = GetRegistration(scope);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(documentPrincipal, scope);
if (NS_WARN_IF(!registration)) {
return NS_ERROR_FAILURE;
}
@ -2780,7 +2987,7 @@ ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChanne
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(uri);
GetServiceWorkerRegistrationInfo(aDoc->NodePrincipal(), uri);
if (!registration) {
NS_WARNING("No registration found when dispatching the fetch event");
return NS_ERROR_FAILURE;
@ -2822,12 +3029,14 @@ ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChanne
}
NS_IMETHODIMP
ServiceWorkerManager::IsAvailableForURI(nsIURI* aURI, bool* aIsAvailable)
ServiceWorkerManager::IsAvailableForURI(nsIPrincipal* aPrincipal, nsIURI* aURI,
bool* aIsAvailable)
{
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aURI);
MOZ_ASSERT(aIsAvailable);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(aURI);
GetServiceWorkerRegistrationInfo(aPrincipal, aURI);
*aIsAvailable = registration && registration->mActiveWorker;
return NS_OK;
}
@ -3008,13 +3217,14 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
}
NS_IMETHODIMP
ServiceWorkerManager::SoftUpdate(const nsAString& aScope)
ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal,
const nsAString& aScope)
{
AssertIsOnMainThread();
NS_ConvertUTF16toUTF8 scope(aScope);
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
mServiceWorkerRegistrationInfos.Get(scope, getter_AddRefs(registration));
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aPrincipal, scope);
if (NS_WARN_IF(!registration)) {
return NS_OK;
}
@ -3156,10 +3366,14 @@ ClaimMatchingClients(nsISupportsHashKey* aKey, void* aData)
} // anonymous namespace
void
ServiceWorkerManager::GetAllClients(const nsCString& aScope,
ServiceWorkerManager::GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
nsTArray<ServiceWorkerClientInfo>& aControlledDocuments)
{
nsRefPtr<ServiceWorkerRegistrationInfo> registration = GetRegistration(aScope);
MOZ_ASSERT(aPrincipal);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aPrincipal, aScope);
if (!registration) {
// The registration was removed, leave the array empty.
@ -3205,10 +3419,11 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument,
}
nsresult
ServiceWorkerManager::ClaimClients(const nsCString& aScope, uint64_t aId)
ServiceWorkerManager::ClaimClients(nsIPrincipal* aPrincipal,
const nsCString& aScope, uint64_t aId)
{
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(aScope);
GetRegistration(aPrincipal, aScope);
if (!registration || !registration->mActiveWorker ||
!(registration->mActiveWorker->ID() == aId)) {
@ -3227,6 +3442,27 @@ ServiceWorkerManager::FireControllerChange(ServiceWorkerRegistrationInfo* aRegis
mControlledDocuments.EnumerateRead(FireControllerChangeOnMatchingDocument, aRegistration);
}
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal,
const nsCString& aScope) const
{
nsRefPtr<ServiceWorkerRegistrationInfo> reg;
nsAutoCString scopeKey;
nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return reg.forget();
}
RegistrationDataPerPrincipal* data;
if (!mRegistrationInfos.Get(scopeKey, &data)) {
return reg.forget();
}
data->mInfos.Get(aScope, getter_AddRefs(reg));
return reg.forget();
}
ServiceWorkerRegistrationInfo*
ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
nsIPrincipal* aPrincipal)
@ -3237,11 +3473,11 @@ ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
MOZ_ASSERT(NS_SUCCEEDED(rv));
#endif
ServiceWorkerRegistrationInfo* registration = new ServiceWorkerRegistrationInfo(aScope, aPrincipal);
// From now on ownership of registration is with
// mServiceWorkerRegistrationInfos.
mServiceWorkerRegistrationInfos.Put(aScope, registration);
AddScope(mOrderedScopes, aScope);
AddScopeAndRegistration(aPrincipal, aScope, registration);
return registration;
}
@ -3260,8 +3496,6 @@ ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo*
{
MOZ_ASSERT(aRegistration);
MOZ_ASSERT(!aRegistration->IsControllingDocuments());
MOZ_ASSERT(mServiceWorkerRegistrationInfos.Contains(aRegistration->mScope));
ServiceWorkerManager::RemoveScope(mOrderedScopes, aRegistration->mScope);
// All callers should be either from a job in which case the actor is
// available, or from MaybeStopControlling(), in which case, this will only be
@ -3279,7 +3513,9 @@ ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo*
NS_WARNING("Unable to unregister serviceworker due to possible OOM");
return;
}
mActor->SendUnregisterServiceWorker(principalInfo, NS_ConvertUTF8toUTF16(aRegistration->mScope));
mActor->SendUnregisterServiceWorker(principalInfo,
NS_ConvertUTF8toUTF16(aRegistration->mScope));
}
class ServiceWorkerDataInfo final : public nsIServiceWorkerInfo
@ -3309,8 +3545,8 @@ void
ServiceWorkerManager::RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration)
{
RemoveRegistrationInternal(aRegistration);
MOZ_ASSERT(mServiceWorkerRegistrationInfos.Contains(aRegistration->mScope));
mServiceWorkerRegistrationInfos.Remove(aRegistration->mScope);
MOZ_ASSERT(HasScope(aRegistration->mPrincipal, aRegistration->mScope));
RemoveScopeAndRegistration(aRegistration);
}
namespace {
@ -3384,6 +3620,17 @@ UnregisterIfMatchesHost(const nsACString& aScope,
return PL_DHASH_NEXT;
}
// If host/aData is null, unconditionally unregisters.
PLDHashOperator
UnregisterIfMatchesHostPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
aData->mInfos.EnumerateRead(UnregisterIfMatchesHost, aUserData);
return PL_DHASH_NEXT;
}
} // anonymous namespace
NS_IMPL_ISUPPORTS(ServiceWorkerDataInfo, nsIServiceWorkerInfo)
@ -3505,7 +3752,8 @@ NS_IMETHODIMP
ServiceWorkerManager::Remove(const nsACString& aHost)
{
AssertIsOnMainThread();
mServiceWorkerRegistrationInfos.EnumerateRead(UnregisterIfMatchesHost, &const_cast<nsACString&>(aHost));
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal,
&const_cast<nsACString&>(aHost));
return NS_OK;
}
@ -3513,7 +3761,7 @@ NS_IMETHODIMP
ServiceWorkerManager::RemoveAll()
{
AssertIsOnMainThread();
mServiceWorkerRegistrationInfos.EnumerateRead(UnregisterIfMatchesHost, nullptr);
mRegistrationInfos.EnumerateRead(UnregisterIfMatchesHostPerPrincipal, nullptr);
return NS_OK;
}
@ -3523,18 +3771,27 @@ UpdateEachRegistration(const nsACString& aKey,
void* aUserArg) {
auto This = static_cast<ServiceWorkerManager*>(aUserArg);
MOZ_ASSERT(!aInfo->mScope.IsEmpty());
nsresult res = This->SoftUpdate(NS_ConvertUTF8toUTF16(aInfo->mScope));
nsresult res = This->SoftUpdate(aInfo->mPrincipal,
NS_ConvertUTF8toUTF16(aInfo->mScope));
unused << NS_WARN_IF(NS_FAILED(res));
return PL_DHASH_NEXT;
}
static PLDHashOperator
UpdateEachRegistrationPerPrincipal(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserArg) {
aData->mInfos.EnumerateRead(UpdateEachRegistration, aUserArg);
return PL_DHASH_NEXT;
}
NS_IMETHODIMP
ServiceWorkerManager::UpdateAllRegistrations()
{
AssertIsOnMainThread();
mServiceWorkerRegistrationInfos.EnumerateRead(UpdateEachRegistration, this);
mRegistrationInfos.EnumerateRead(UpdateEachRegistrationPerPrincipal, this);
return NS_OK;
}

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

@ -364,18 +364,8 @@ public:
return res;
}
// Ordered list of scopes for glob matching.
// Each entry is an absolute URL representing the scope.
//
// An array is used for now since the number of controlled scopes per
// domain is expected to be relatively low. If that assumption was proved
// wrong this should be replaced with a better structure to avoid the
// memmoves associated with inserting stuff in the middle of the array.
nsTArray<nsCString> mOrderedScopes;
// Scope to registration.
// The scope should be a fully qualified valid URL.
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mServiceWorkerRegistrationInfos;
struct RegistrationDataPerPrincipal;
nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal> mRegistrationInfos;
nsTObserverArray<ServiceWorkerRegistrationListener*> mServiceWorkerRegistrationListeners;
@ -390,12 +380,7 @@ public:
nsDataHashtable<nsCStringHashKey, bool> mSetOfScopesBeingUpdated;
already_AddRefed<ServiceWorkerRegistrationInfo>
GetRegistration(const nsCString& aScope) const
{
nsRefPtr<ServiceWorkerRegistrationInfo> reg;
mServiceWorkerRegistrationInfos.Get(aScope, getter_AddRefs(reg));
return reg.forget();
}
GetRegistration(nsIPrincipal* aPrincipal, const nsCString& aScope) const;
ServiceWorkerRegistrationInfo*
CreateNewRegistration(const nsCString& aScope, nsIPrincipal* aPrincipal);
@ -429,7 +414,8 @@ public:
uint32_t aFlags);
void
GetAllClients(const nsCString& aScope,
GetAllClients(nsIPrincipal* aPrincipal,
const nsCString& aScope,
nsTArray<ServiceWorkerClientInfo>& aControlledDocuments);
void
@ -437,7 +423,7 @@ public:
ServiceWorkerRegistrationInfo* aWorkerRegistration);
nsresult
ClaimClients(const nsCString& aScope, uint64_t aId);
ClaimClients(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aId);
static already_AddRefed<ServiceWorkerManager>
GetInstance();
@ -487,7 +473,8 @@ private:
nsISupports** aServiceWorker);
already_AddRefed<ServiceWorker>
CreateServiceWorkerForScope(const nsACString& aScope);
CreateServiceWorkerForScope(nsIPrincipal* aPrincipal,
const nsACString& aScope);
void
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
@ -507,16 +494,29 @@ private:
GetServiceWorkerRegistrationInfo(nsIDocument* aDoc);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetServiceWorkerRegistrationInfo(nsIURI* aURI);
GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal, nsIURI* aURI);
// This method generates a key using appId and isInElementBrowser from the
// principal. We don't use the origin because it can simple change during the
// loading.
static nsresult
PrincipalToScopeKey(nsIPrincipal* aPrincipal, nsACString& aPrincipalKey);
static void
AddScope(nsTArray<nsCString>& aList, const nsACString& aScope);
AddScopeAndRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope,
ServiceWorkerRegistrationInfo* aRegistation);
static nsCString
FindScopeForPath(nsTArray<nsCString>& aList, const nsACString& aPath);
static bool
FindScopeForPath(nsIPrincipal* aPrincipal, const nsACString& aPath,
RegistrationDataPerPrincipal** aData, nsACString& aMatch);
#ifdef DEBUG
static bool
HasScope(nsIPrincipal* aPrincipal, const nsACString& aScope);
#endif
static void
RemoveScope(nsTArray<nsCString>& aList, const nsACString& aScope);
RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration);
void
QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,

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

@ -236,35 +236,98 @@ ServiceWorkerRegistrationMainThread::InvalidateWorkers(WhichServiceWorker aWhich
namespace {
void
UpdateInternal(const nsAString& aScope)
UpdateInternal(nsIPrincipal* aPrincipal, const nsAString& aScope)
{
AssertIsOnMainThread();
nsCOMPtr<nsIServiceWorkerManager> swm =
mozilla::services::GetServiceWorkerManager();
MOZ_ASSERT(swm);
// The spec defines ServiceWorkerRegistration.update() exactly as Soft Update.
swm->SoftUpdate(aScope);
swm->SoftUpdate(aPrincipal, aScope);
}
// This Runnable needs to have a valid WorkerPrivate. For this reason it is also
// a WorkerFeature that is registered before dispatching itself to the
// main-thread and it's removed with ReleaseRunnable when the operation is
// completed. This will keep the worker alive as long as necessary.
class UpdateRunnable final : public nsRunnable
, public WorkerFeature
{
public:
explicit UpdateRunnable(const nsAString& aScope)
: mScope(aScope)
UpdateRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aScope)
: mWorkerPrivate(aWorkerPrivate)
, mScope(aScope)
{}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
UpdateInternal(mScope);
UpdateInternal(mWorkerPrivate->GetPrincipal(), mScope);
class ReleaseRunnable final : public MainThreadWorkerControlRunnable
{
nsRefPtr<UpdateRunnable> mRunnable;
public:
ReleaseRunnable(WorkerPrivate* aWorkerPrivate,
UpdateRunnable* aRunnable)
: MainThreadWorkerControlRunnable(aWorkerPrivate)
, mRunnable(aRunnable)
{
MOZ_ASSERT(aRunnable);
}
virtual bool
WorkerRun(JSContext* aCx,
workers::WorkerPrivate* aWorkerPrivate) override
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
aWorkerPrivate->RemoveFeature(aCx, mRunnable);
return true;
}
private:
~ReleaseRunnable()
{}
};
nsRefPtr<WorkerControlRunnable> runnable =
new ReleaseRunnable(mWorkerPrivate, this);
runnable->Dispatch(nullptr);
return NS_OK;
}
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override
{
// We don't care about the notification. We just want to keep the
// mWorkerPrivate alive.
return true;
}
bool
Dispatch()
{
mWorkerPrivate->AssertIsOnWorkerThread();
JSContext* cx = mWorkerPrivate->GetJSContext();
if (NS_WARN_IF(!mWorkerPrivate->AddFeature(cx, this))) {
return false;
}
NS_SUCCEEDED(NS_DispatchToMainThread(this));
return true;
}
private:
~UpdateRunnable()
{}
WorkerPrivate* mWorkerPrivate;
const nsString mScope;
};
@ -457,7 +520,13 @@ public:
void
ServiceWorkerRegistrationMainThread::Update()
{
UpdateInternal(mScope);
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
MOZ_ASSERT(doc);
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
MOZ_ASSERT(principal);
UpdateInternal(principal, mScope);
}
already_AddRefed<Promise>
@ -739,13 +808,12 @@ ServiceWorkerRegistrationWorkerThread::GetActive()
void
ServiceWorkerRegistrationWorkerThread::Update()
{
#ifdef DEBUG
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
#endif
nsCOMPtr<nsIRunnable> r = new UpdateRunnable(mScope);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
nsRefPtr<UpdateRunnable> r = new UpdateRunnable(worker, mScope);
r->Dispatch();
}
already_AddRefed<Promise>

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

@ -132,7 +132,7 @@ function display(info) {
let updateButton = document.createElement("button");
updateButton.appendChild(document.createTextNode(bundle.GetStringFromName('update')));
updateButton.onclick = function() {
gSWM.softUpdate(info.scope);
gSWM.softUpdate(info.principal, info.scope);
};
div.appendChild(updateButton);