Bug 1155153 - about:serviceworkers should work in e10s mode, r=nsm, r=bholley

This commit is contained in:
Andrea Marchesini 2015-06-04 19:51:57 +01:00
parent 1b896120e7
commit 24ae5c2715
28 changed files with 1425 additions and 325 deletions

View File

@ -17,44 +17,109 @@
#include "mozilla/dom/CSPDictionariesBinding.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/URLSearchParams.h"
namespace mozilla {
using dom::URLSearchParams;
void
OriginAttributes::CreateSuffix(nsACString& aStr) const
{
aStr.Truncate();
MOZ_RELEASE_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
int attrCount = 0;
nsRefPtr<URLSearchParams> usp = new URLSearchParams();
nsAutoString value;
if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
aStr.Append(attrCount++ ? "&appId=" : "!appId=");
aStr.AppendInt(mAppId);
value.AppendInt(mAppId);
usp->Set(NS_LITERAL_STRING("appId"), value);
}
if (mInBrowser) {
aStr.Append(attrCount++ ? "&inBrowser=1" : "!inBrowser=1");
usp->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
}
aStr.Truncate();
usp->Serialize(value);
if (!value.IsEmpty()) {
aStr.AppendLiteral("!");
aStr.Append(NS_ConvertUTF16toUTF8(value));
}
}
void
OriginAttributes::Serialize(nsIObjectOutputStream* aStream) const
namespace {
class MOZ_STACK_CLASS PopulateFromSuffixIterator final
: public URLSearchParams::ForEachIterator
{
aStream->Write32(mAppId);
aStream->WriteBoolean(mInBrowser);
public:
explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
: mOriginAttributes(aOriginAttributes)
{
MOZ_ASSERT(aOriginAttributes);
}
bool URLSearchParamsIterator(const nsString& aName,
const nsString& aValue) override
{
if (aName.EqualsLiteral("appId")) {
nsresult rv;
mOriginAttributes->mAppId = aValue.ToInteger(&rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (mOriginAttributes->mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
return false;
}
return true;
}
if (aName.EqualsLiteral("inBrowser")) {
if (!aValue.EqualsLiteral("1")) {
return false;
}
mOriginAttributes->mInBrowser = true;
return true;
}
// No other attributes are supported.
return false;
}
private:
OriginAttributes* mOriginAttributes;
};
} // anonymous namespace
bool
OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
{
if (aStr.IsEmpty()) {
return true;
}
if (aStr[0] != '!') {
return false;
}
nsRefPtr<URLSearchParams> usp = new URLSearchParams();
usp->ParseInput(Substring(aStr, 1, aStr.Length() - 1), nullptr);
PopulateFromSuffixIterator iterator(this);
return usp->ForEach(iterator);
}
nsresult
OriginAttributes::Deserialize(nsIObjectInputStream* aStream)
{
nsresult rv = aStream->Read32(&mAppId);
NS_ENSURE_SUCCESS(rv, rv);
BasePrincipal::BasePrincipal()
{}
rv = aStream->ReadBoolean(&mInBrowser);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
BasePrincipal::~BasePrincipal()
{}
NS_IMETHODIMP
BasePrincipal::GetOrigin(nsACString& aOrigin)

View File

@ -13,6 +13,7 @@
#include "mozilla/dom/SystemDictionariesBinding.h"
class nsIContentSecurityPolicy;
class nsIObjectOutputStream;
class nsIObjectInputStream;
@ -38,13 +39,11 @@ public:
return !(*this == aOther);
}
// Serializes non-default values into the suffix format, i.e.
// Serializes/Deserializes non-default values into the suffix format, i.e.
// |!key1=value1&key2=value2|. If there are no non-default attributes, this
// returns an empty string.
void CreateSuffix(nsACString& aStr) const;
void Serialize(nsIObjectOutputStream* aStream) const;
nsresult Deserialize(nsIObjectInputStream* aStream);
bool PopulateFromSuffix(const nsACString& aStr);
};
/*
@ -57,7 +56,7 @@ public:
class BasePrincipal : public nsJSPrincipals
{
public:
BasePrincipal() {}
BasePrincipal();
enum DocumentDomainConsideration { DontConsiderDocumentDomain, ConsiderDocumentDomain};
bool Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
@ -93,7 +92,7 @@ public:
bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; }
protected:
virtual ~BasePrincipal() {}
virtual ~BasePrincipal();
virtual nsresult GetOriginInternal(nsACString& aOrigin) = 0;
virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;

View File

@ -82,7 +82,7 @@ nsNullPrincipal::GetHashValue(uint32_t *aResult)
return NS_OK;
}
NS_IMETHODIMP
NS_IMETHODIMP
nsNullPrincipal::GetURI(nsIURI** aURI)
{
return NS_EnsureSafeToReturn(mURI, aURI);
@ -160,13 +160,25 @@ nsNullPrincipal::Read(nsIObjectInputStream* aStream)
// that the Init() method has already been invoked by the time we deserialize.
// This is in contrast to nsPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR,
// in which case ::Read needs to invoke Init().
return mOriginAttributes.Deserialize(aStream);
nsAutoCString suffix;
nsresult rv = aStream->ReadCString(suffix);
NS_ENSURE_SUCCESS(rv, rv);
bool ok = mOriginAttributes.PopulateFromSuffix(suffix);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::Write(nsIObjectOutputStream* aStream)
{
OriginAttributesRef().Serialize(aStream);
nsAutoCString suffix;
OriginAttributesRef().CreateSuffix(suffix);
nsresult rv = aStream->WriteStringZ(suffix.get());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

View File

@ -23,8 +23,8 @@
class nsIURI;
#define NS_NULLPRINCIPAL_CID \
{ 0xa0bd8b42, 0xf6bf, 0x4fb9, \
{ 0x93, 0x42, 0x90, 0xbf, 0xc9, 0xb7, 0xa1, 0xab } }
{ 0xe502ffb8, 0x5d95, 0x48e8, \
{ 0x82, 0x3c, 0x0d, 0x29, 0xd8, 0x3a, 0x59, 0x33 } }
#define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
#define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"

View File

@ -360,10 +360,14 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
domain = do_QueryInterface(supports);
OriginAttributes attrs;
rv = attrs.Deserialize(aStream);
nsAutoCString suffix;
rv = aStream->ReadCString(suffix);
NS_ENSURE_SUCCESS(rv, rv);
OriginAttributes attrs;
bool ok = attrs.PopulateFromSuffix(suffix);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
NS_ENSURE_SUCCESS(rv, rv);
@ -404,7 +408,11 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
return rv;
}
OriginAttributesRef().Serialize(aStream);
nsAutoCString suffix;
OriginAttributesRef().CreateSuffix(suffix);
rv = aStream->WriteStringZ(suffix.get());
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_WriteOptionalCompoundObject(aStream, mCSP,
NS_GET_IID(nsIContentSecurityPolicy),

View File

@ -112,12 +112,12 @@ private:
#define NS_PRINCIPAL_CONTRACTID "@mozilla.org/principal;1"
#define NS_PRINCIPAL_CID \
{ 0x09b7e598, 0x490d, 0x423f, \
{ 0xa8, 0xa6, 0x2e, 0x6c, 0x4e, 0xc8, 0x77, 0x50 }}
{ 0xb7c8505e, 0xc56d, 0x4191, \
{ 0xa1, 0x5e, 0x5d, 0xcb, 0x88, 0x9b, 0xa0, 0x94 }}
#define NS_EXPANDEDPRINCIPAL_CONTRACTID "@mozilla.org/expandedprincipal;1"
#define NS_EXPANDEDPRINCIPAL_CID \
{ 0xb33a3807, 0xb76c, 0x44e5, \
{ 0xb9, 0x9d, 0x95, 0x7e, 0xe9, 0xba, 0x6e, 0x39 }}
{ 0x38539471, 0x68cc, 0x4a6f, \
{ 0x81, 0x20, 0xdb, 0xd5, 0x4a, 0x22, 0x0a, 0x13 }}
#endif // nsPrincipal_h__

View File

@ -105,6 +105,7 @@ static RedirEntry kRedirMap[] = {
},
{
"serviceworkers", "chrome://global/content/aboutServiceWorkers.xhtml",
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
nsIAboutModule::ALLOW_SCRIPT
},
// about:srcdoc is unresolvable by specification. It is included here

View File

@ -27,6 +27,10 @@ public:
virtual void URLSearchParamsUpdated(URLSearchParams* aFromThis) = 0;
};
// This class is used in BasePrincipal and it's _extremely_ important that the
// attributes are kept in the correct order. If this changes, please, update
// BasePrincipal code.
class URLSearchParams final : public nsISupports,
public nsWrapperCache
{
@ -81,15 +85,24 @@ public:
Serialize(aRetval);
}
typedef void (*ParamFunc)(const nsString& aName, const nsString& aValue,
void* aClosure);
class ForEachIterator
{
public:
virtual bool
URLSearchParamsIterator(const nsString& aName, const nsString& aValue) = 0;
};
void
ForEach(ParamFunc aFunc, void* aClosure)
bool
ForEach(ForEachIterator& aIterator)
{
for (uint32_t i = 0; i < mSearchParams.Length(); ++i) {
aFunc(mSearchParams[i].mKey, mSearchParams[i].mValue, aClosure);
if (!aIterator.URLSearchParamsIterator(mSearchParams[i].mKey,
mSearchParams[i].mValue)) {
return false;
}
}
return true;
}
private:

View File

@ -548,13 +548,26 @@ ExtractFromURLSearchParams(const URLSearchParams& aParams,
return NS_NewStringInputStream(aStream, serialized);
}
void
FillFormData(const nsString& aName, const nsString& aValue, void* aFormData)
class MOZ_STACK_CLASS FillFormIterator final
: public URLSearchParams::ForEachIterator
{
MOZ_ASSERT(aFormData);
nsFormData* fd = static_cast<nsFormData*>(aFormData);
fd->Append(aName, aValue);
}
public:
explicit FillFormIterator(nsFormData* aFormData)
: mFormData(aFormData)
{
MOZ_ASSERT(aFormData);
}
bool URLSearchParamsIterator(const nsString& aName,
const nsString& aValue) override
{
mFormData->Append(aName, aValue);
return true;
}
private:
nsFormData* mFormData;
};
/**
* A simple multipart/form-data parser as defined in RFC 2388 and RFC 2046.
@ -1591,7 +1604,10 @@ FetchBody<Derived>::ContinueConsumeBody(nsresult aStatus, uint32_t aResultLength
params->ParseInput(data, /* aObserver */ nullptr);
nsRefPtr<nsFormData> fd = new nsFormData(DerivedClass()->GetParentObject());
params->ForEach(FillFormData, static_cast<void*>(fd));
FillFormIterator iterator(fd);
DebugOnly<bool> status = params->ForEach(iterator);
MOZ_ASSERT(status);
localPromise->MaybeResolve(fd);
} else {
ErrorResult result;

View File

@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
readonly attribute DOMString waitingCacheName;
};
[scriptable, builtinclass, uuid(d130fcbd-1afe-4dd9-b70d-08a4b2373af5)]
[scriptable, builtinclass, uuid(5e112a42-df4c-4ae9-bc71-e6e681ab5f38)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -96,13 +96,6 @@ interface nsIServiceWorkerManager : nsISupports
*/
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
/*
* This implements the soft update algorithm.
* XXXbaku this can be removed when bug 1155153 lands.
*/
[implicit_jscontext] void softUpdate(in jsval aOriginAttributes,
in DOMString aScope);
/*
* Clears ServiceWorker registrations from memory and disk for the specified
* host.
@ -122,10 +115,22 @@ interface nsIServiceWorkerManager : nsISupports
// Testing
DOMString getScopeForUrl(in nsIPrincipal aPrincipal, in DOMString aPath);
// This is meant to be used only by about:serviceworkers. It returns an array
// of nsIServiceWorkerInfo.
// Note: This is meant to be used only by about:serviceworkers.
//It returns an array of nsIServiceWorkerInfo.
nsIArray getAllRegistrations();
// Note: This is meant to be used only by about:serviceworkers.
// It calls softUpdate() for each child process.
[implicit_jscontext] void propagateSoftUpdate(in jsval aOriginAttributes,
in DOMString aScope);
// Note: This is meant to be used only by about:serviceworkers.
// It calls unregister() in each child process. The callback is used to
// inform when unregister() is completed on the current process.
void propagateUnregister(in nsIPrincipal aPrincipal,
in nsIServiceWorkerUnregisterCallback aCallback,
in DOMString aScope);
[implicit_jscontext] void sendPushEvent(in jsval aOriginAttributes,
in ACString aScope,
in DOMString aData);

View File

@ -0,0 +1,39 @@
/* 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/. */
include protocol PBackground;
include PBackgroundSharedTypes;
include ServiceWorkerRegistrarTypes;
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
namespace mozilla {
namespace dom {
protocol PServiceWorkerManager
{
manager PBackground;
parent:
Register(ServiceWorkerRegistrationData data);
Unregister(PrincipalInfo principalInfo, nsString scope);
PropagateSoftUpdate(OriginAttributes originAttributes,
nsString scope);
PropagateUnregister(PrincipalInfo principalInfo, nsString scope);
Shutdown();
child:
NotifyRegister(ServiceWorkerRegistrationData data);
NotifySoftUpdate(OriginAttributes originAttributes, nsString scope);
NotifyUnregister(PrincipalInfo principalInfo, nsString scope);
__delete__();
};
} // namespace dom
} // namespace mozilla

View File

@ -55,6 +55,7 @@
#include "ServiceWorker.h"
#include "ServiceWorkerClient.h"
#include "ServiceWorkerContainer.h"
#include "ServiceWorkerManagerChild.h"
#include "ServiceWorkerRegistrar.h"
#include "ServiceWorkerRegistration.h"
#include "ServiceWorkerScriptCache.h"
@ -257,6 +258,28 @@ PopulateRegistrationData(nsIPrincipal* aPrincipal,
return NS_OK;
}
class TeardownRunnable final : public nsRunnable
{
public:
explicit TeardownRunnable(ServiceWorkerManagerChild* aActor)
: mActor(aActor)
{
MOZ_ASSERT(mActor);
}
NS_IMETHODIMP Run() override
{
MOZ_ASSERT(mActor);
mActor->SendShutdown();
return NS_OK;
}
private:
~TeardownRunnable() {}
nsRefPtr<ServiceWorkerManagerChild> mActor;
};
} // Anonymous namespace
NS_IMPL_ISUPPORTS0(ServiceWorkerJob)
@ -361,6 +384,14 @@ ServiceWorkerManager::~ServiceWorkerManager()
{
// The map will assert if it is not empty when destroyed.
mRegistrationInfos.Clear();
if (mActor) {
mActor->ManagerShuttingDown();
nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
nsresult rv = NS_DispatchToMainThread(runnable);
unused << NS_WARN_IF(NS_FAILED(rv));
}
}
void
@ -686,6 +717,72 @@ GetRequiredScopeStringPrefix(nsIURI* aScriptURI, nsACString& aPrefix,
}
return NS_OK;
}
class PropagateSoftUpdateRunnable final : public nsRunnable
{
public:
PropagateSoftUpdateRunnable(const OriginAttributes& aOriginAttributes,
const nsAString& aScope)
: mOriginAttributes(aOriginAttributes)
, mScope(aScope)
{}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
swm->PropagateSoftUpdate(mOriginAttributes,mScope);
return NS_OK;
}
private:
~PropagateSoftUpdateRunnable()
{}
const OriginAttributes mOriginAttributes;
const nsString mScope;
};
class PropagateUnregisterRunnable final : public nsRunnable
{
public:
PropagateUnregisterRunnable(nsIPrincipal* aPrincipal,
nsIServiceWorkerUnregisterCallback* aCallback,
const nsAString& aScope)
: mPrincipal(aPrincipal)
, mCallback(aCallback)
, mScope(aScope)
{
MOZ_ASSERT(aPrincipal);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsresult rv = swm->PropagateUnregister(mPrincipal, mCallback, mScope);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
private:
~PropagateUnregisterRunnable()
{}
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
const nsString mScope;
};
} // anonymous namespace
class ServiceWorkerRegisterJob final : public ServiceWorkerJob,
@ -2214,8 +2311,7 @@ private:
}
MOZ_ASSERT(swm->mActor);
swm->mActor->SendUnregisterServiceWorker(principalInfo,
NS_ConvertUTF8toUTF16(mScope));
swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
return NS_OK;
}
@ -2439,6 +2535,39 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
return rv;
}
void
ServiceWorkerManager::LoadRegistration(
const ServiceWorkerRegistrationData& aRegistration)
{
AssertIsOnMainThread();
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aRegistration.principal());
if (!principal) {
return;
}
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetRegistration(principal, aRegistration.scope());
if (!registration) {
registration = CreateNewRegistration(aRegistration.scope(), principal);
} else if (registration->mScriptSpec == aRegistration.scriptSpec() &&
!!registration->mActiveWorker == aRegistration.currentWorkerURL().IsEmpty()) {
// No needs for updates.
return;
}
registration->mScriptSpec = aRegistration.scriptSpec();
const nsCString& currentWorkerURL = aRegistration.currentWorkerURL();
if (!currentWorkerURL.IsEmpty()) {
registration->mActiveWorker =
new ServiceWorkerInfo(registration, currentWorkerURL,
aRegistration.activeCacheName());
registration->mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
}
}
void
ServiceWorkerManager::LoadRegistrations(
const nsTArray<ServiceWorkerRegistrationData>& aRegistrations)
@ -2446,23 +2575,7 @@ ServiceWorkerManager::LoadRegistrations(
AssertIsOnMainThread();
for (uint32_t i = 0, len = aRegistrations.Length(); i < len; ++i) {
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aRegistrations[i].principal());
if (!principal) {
continue;
}
ServiceWorkerRegistrationInfo* registration =
CreateNewRegistration(aRegistrations[i].scope(), principal);
registration->mScriptSpec = aRegistrations[i].scriptSpec();
const nsCString& currentWorkerURL = aRegistrations[i].currentWorkerURL();
if (!currentWorkerURL.IsEmpty()) {
registration->mActiveWorker =
new ServiceWorkerInfo(registration, currentWorkerURL, aRegistrations[i].activeCacheName());
registration->mActiveWorker->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
}
LoadRegistration(aRegistrations[i]);
}
}
@ -2477,7 +2590,11 @@ ServiceWorkerManager::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
{
MOZ_ASSERT(aActor);
MOZ_ASSERT(!mActor);
mActor = aActor;
PServiceWorkerManagerChild* actor =
aActor->SendPServiceWorkerManagerConstructor();
mActor = static_cast<ServiceWorkerManagerChild*>(actor);
// Flush the pending requests.
for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
@ -2519,7 +2636,7 @@ ServiceWorkerManager::StoreRegistration(
return;
}
mActor->SendRegisterServiceWorker(data);
mActor->SendRegister(data);
}
already_AddRefed<ServiceWorkerRegistrationInfo>
@ -3467,24 +3584,6 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
}
}
NS_IMETHODIMP
ServiceWorkerManager::SoftUpdate(JS::Handle<JS::Value> aOriginAttributes,
const nsAString& aScope, JSContext* aCx)
{
AssertIsOnMainThread();
OriginAttributes attrs;
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
nsAutoCString scopeKey;
attrs.CreateSuffix(scopeKey);
SoftUpdate(scopeKey, NS_ConvertUTF16toUTF8(aScope));
return NS_OK;
}
void
ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal,
const nsACString& aScope)
@ -3500,6 +3599,15 @@ ServiceWorkerManager::SoftUpdate(nsIPrincipal* aPrincipal,
SoftUpdate(scopeKey, aScope);
}
void
ServiceWorkerManager::SoftUpdate(const OriginAttributes& aOriginAttributes,
const nsACString& aScope)
{
nsAutoCString scopeKey;
aOriginAttributes.CreateSuffix(scopeKey);
SoftUpdate(scopeKey, aScope);
}
void
ServiceWorkerManager::SoftUpdate(const nsACString& aScopeKey,
const nsACString& aScope)
@ -3789,6 +3897,10 @@ ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
MOZ_ASSERT(NS_SUCCEEDED(rv));
nsRefPtr<ServiceWorkerRegistrationInfo> tmp =
GetRegistration(aPrincipal, aScope);
MOZ_ASSERT(!tmp);
#endif
ServiceWorkerRegistrationInfo* registration = new ServiceWorkerRegistrationInfo(aScope, aPrincipal);
@ -3831,8 +3943,7 @@ ServiceWorkerManager::RemoveRegistrationInternal(ServiceWorkerRegistrationInfo*
return;
}
mActor->SendUnregisterServiceWorker(principalInfo,
NS_ConvertUTF8toUTF16(aRegistration->mScope));
mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(aRegistration->mScope));
}
class ServiceWorkerDataInfo final : public nsIServiceWorkerInfo
@ -3842,7 +3953,7 @@ public:
NS_DECL_NSISERVICEWORKERINFO
static already_AddRefed<ServiceWorkerDataInfo>
Create(const ServiceWorkerRegistrationData& aData);
Create(const ServiceWorkerRegistrationInfo* aData);
private:
ServiceWorkerDataInfo()
@ -3858,6 +3969,7 @@ private:
nsString mActiveCacheName;
nsString mWaitingCacheName;
};
void
ServiceWorkerManager::RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration)
{
@ -3965,26 +4077,61 @@ UnregisterIfMatchesHostPerPrincipal(const nsACString& aKey,
return PL_DHASH_NEXT;
}
PLDHashOperator
GetAllRegistrationsEnumerator(const nsACString& aScope,
ServiceWorkerRegistrationInfo* aReg,
void* aData)
{
nsIMutableArray* array = static_cast<nsIMutableArray*>(aData);
MOZ_ASSERT(aReg);
if (aReg->mPendingUninstall) {
return PL_DHASH_NEXT;
}
nsCOMPtr<nsIServiceWorkerInfo> info = ServiceWorkerDataInfo::Create(aReg);
if (NS_WARN_IF(!info)) {
return PL_DHASH_NEXT;
}
array->AppendElement(info, false);
return PL_DHASH_NEXT;
}
PLDHashOperator
GetAllRegistrationsPerPrincipalEnumerator(const nsACString& aKey,
ServiceWorkerManager::RegistrationDataPerPrincipal* aData,
void* aUserData)
{
aData->mInfos.EnumerateRead(GetAllRegistrationsEnumerator, aUserData);
return PL_DHASH_NEXT;
}
} // anonymous namespace
NS_IMPL_ISUPPORTS(ServiceWorkerDataInfo, nsIServiceWorkerInfo)
/* static */ already_AddRefed<ServiceWorkerDataInfo>
ServiceWorkerDataInfo::Create(const ServiceWorkerRegistrationData& aData)
ServiceWorkerDataInfo::Create(const ServiceWorkerRegistrationInfo* aData)
{
AssertIsOnMainThread();
MOZ_ASSERT(aData);
nsRefPtr<ServiceWorkerDataInfo> info = new ServiceWorkerDataInfo();
info->mPrincipal = PrincipalInfoToPrincipal(aData.principal());
if (!info->mPrincipal) {
return nullptr;
info->mPrincipal = aData->mPrincipal;
CopyUTF8toUTF16(aData->mScope, info->mScope);
CopyUTF8toUTF16(aData->mScriptSpec, info->mScriptSpec);
if (aData->mActiveWorker) {
CopyUTF8toUTF16(aData->mActiveWorker->ScriptSpec(),
info->mCurrentWorkerURL);
info->mActiveCacheName = aData->mActiveWorker->CacheName();
}
CopyUTF8toUTF16(aData.scope(), info->mScope);
CopyUTF8toUTF16(aData.scriptSpec(), info->mScriptSpec);
CopyUTF8toUTF16(aData.currentWorkerURL(), info->mCurrentWorkerURL);
info->mActiveCacheName = aData.activeCacheName();
info->mWaitingCacheName = aData.waitingCacheName();
if (aData->mWaitingWorker) {
info->mWaitingCacheName = aData->mWaitingWorker->CacheName();
}
return info.forget();
}
@ -4042,26 +4189,12 @@ ServiceWorkerManager::GetAllRegistrations(nsIArray** aResult)
{
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
MOZ_ASSERT(swr);
nsTArray<ServiceWorkerRegistrationData> data;
swr->GetRegistrations(data);
nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID));
if (!array) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0, len = data.Length(); i < len; ++i) {
nsCOMPtr<nsIServiceWorkerInfo> info = ServiceWorkerDataInfo::Create(data[i]);
if (!info) {
return NS_ERROR_FAILURE;
}
array->AppendElement(info, false);
}
mRegistrationInfos.EnumerateRead(GetAllRegistrationsPerPrincipalEnumerator, array);
array.forget(aResult);
return NS_OK;
}
@ -4167,6 +4300,69 @@ ServiceWorkerManager::Observe(nsISupports* aSubject,
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerManager::PropagateSoftUpdate(JS::Handle<JS::Value> aOriginAttributes,
const nsAString& aScope,
JSContext* aCx)
{
MOZ_ASSERT(NS_IsMainThread());
OriginAttributes attrs;
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
PropagateSoftUpdate(attrs, aScope);
return NS_OK;
}
void
ServiceWorkerManager::PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
const nsAString& aScope)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mActor) {
nsRefPtr<nsIRunnable> runnable =
new PropagateSoftUpdateRunnable(aOriginAttributes, aScope);
AppendPendingOperation(runnable);
return;
}
mActor->SendPropagateSoftUpdate(aOriginAttributes, nsString(aScope));
}
NS_IMETHODIMP
ServiceWorkerManager::PropagateUnregister(nsIPrincipal* aPrincipal,
nsIServiceWorkerUnregisterCallback* aCallback,
const nsAString& aScope)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
if (!mActor) {
nsRefPtr<nsIRunnable> runnable =
new PropagateUnregisterRunnable(aPrincipal, aCallback, aScope);
AppendPendingOperation(runnable);
return NS_OK;
}
PrincipalInfo principalInfo;
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
&principalInfo)))) {
return NS_ERROR_FAILURE;
}
mActor->SendPropagateUnregister(principalInfo, nsString(aScope));
nsresult rv = Unregister(aPrincipal, aCallback, aScope);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
{

View File

@ -35,10 +35,6 @@ namespace mozilla {
class OriginAttributes;
namespace ipc {
class BackgroundChild;
}
namespace dom {
class ServiceWorkerRegistrationListener;
@ -50,6 +46,7 @@ class ServiceWorkerClientInfo;
class ServiceWorkerInfo;
class ServiceWorkerJob;
class ServiceWorkerJobQueue;
class ServiceWorkerManagerChild;
// Needs to inherit from nsISupports because NS_ProxyRelease() does not support
// non-ISupports classes.
@ -304,6 +301,13 @@ public:
void
SoftUpdate(nsIPrincipal* aPrincipal, const nsACString& aScope);
void
SoftUpdate(const OriginAttributes& aOriginAttributes, const nsACString& aScope);
void
PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
const nsAString& aScope);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const;
@ -352,6 +356,9 @@ public:
static already_AddRefed<ServiceWorkerManager>
GetInstance();
void
LoadRegistration(const ServiceWorkerRegistrationData& aRegistration);
void
LoadRegistrations(const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
@ -525,7 +532,7 @@ private:
void
RemoveRegistrationInternal(ServiceWorkerRegistrationInfo* aRegistration);
mozilla::ipc::PBackgroundChild* mActor;
nsRefPtr<ServiceWorkerManagerChild> mActor;
struct PendingOperation;
nsTArray<PendingOperation> mPendingOperations;

View File

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ServiceWorkerManagerChild.h"
#include "ServiceWorkerManager.h"
#include "mozilla/unused.h"
namespace mozilla {
using namespace ipc;
namespace dom {
namespace workers {
bool
ServiceWorkerManagerChild::RecvNotifyRegister(
const ServiceWorkerRegistrationData& aData)
{
if (mShuttingDown) {
return true;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
swm->LoadRegistration(aData);
return true;
}
bool
ServiceWorkerManagerChild::RecvNotifySoftUpdate(
const OriginAttributes& aOriginAttributes,
const nsString& aScope)
{
if (mShuttingDown) {
return true;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope));
return true;
}
bool
ServiceWorkerManagerChild::RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
{
if (mShuttingDown) {
return true;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(aPrincipalInfo);
if (NS_WARN_IF(!principal)) {
return true;
}
nsresult rv = swm->Unregister(principal, nullptr, aScope);
unused << NS_WARN_IF(NS_FAILED(rv));
return true;
}
} // workers namespace
} // dom namespace
} // mozilla namespace

View File

@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ServiceWorkerManagerChild_h
#define mozilla_dom_ServiceWorkerManagerChild_h
#include "mozilla/dom/PServiceWorkerManagerChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
namespace mozilla {
class OriginAttributes;
namespace ipc {
class BackgroundChildImpl;
}
namespace dom {
namespace workers {
class ServiceWorkerManagerChild final : public PServiceWorkerManagerChild
{
friend class mozilla::ipc::BackgroundChildImpl;
public:
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerManagerChild)
void ManagerShuttingDown()
{
mShuttingDown = true;
}
virtual bool RecvNotifyRegister(const ServiceWorkerRegistrationData& aData)
override;
virtual bool RecvNotifySoftUpdate(const OriginAttributes& aOriginAttributes,
const nsString& aScope) override;
virtual bool RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope) override;
private:
ServiceWorkerManagerChild()
: mShuttingDown(false)
{}
~ServiceWorkerManagerChild() {}
bool mShuttingDown;
};
} // workers namespace
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ServiceWorkerManagerChild_h

View File

@ -0,0 +1,289 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ServiceWorkerManagerParent.h"
#include "ServiceWorkerManagerService.h"
#include "mozilla/AppProcessChecker.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/unused.h"
namespace mozilla {
using namespace ipc;
namespace dom {
namespace workers {
namespace {
uint64_t sServiceWorkerManagerParentID = 0;
void
AssertIsInMainProcess()
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
}
class RegisterServiceWorkerCallback final : public nsRunnable
{
public:
RegisterServiceWorkerCallback(const ServiceWorkerRegistrationData& aData,
uint64_t aParentID)
: mData(aData)
, mParentID(aParentID)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
NS_IMETHODIMP
Run()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
nsRefPtr<dom::ServiceWorkerRegistrar> service =
dom::ServiceWorkerRegistrar::Get();
MOZ_ASSERT(service);
service->RegisterServiceWorker(mData);
nsRefPtr<ServiceWorkerManagerService> managerService =
ServiceWorkerManagerService::Get();
if (managerService) {
managerService->PropagateRegistration(mParentID, mData);
}
return NS_OK;
}
private:
ServiceWorkerRegistrationData mData;
const uint64_t mParentID;
};
class UnregisterServiceWorkerCallback final : public nsRunnable
{
public:
UnregisterServiceWorkerCallback(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
: mPrincipalInfo(aPrincipalInfo)
, mScope(aScope)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
NS_IMETHODIMP
Run()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
nsRefPtr<dom::ServiceWorkerRegistrar> service =
dom::ServiceWorkerRegistrar::Get();
MOZ_ASSERT(service);
service->UnregisterServiceWorker(mPrincipalInfo,
NS_ConvertUTF16toUTF8(mScope));
return NS_OK;
}
private:
const PrincipalInfo mPrincipalInfo;
nsString mScope;
};
class CheckPrincipalWithCallbackRunnable final : public nsRunnable
{
public:
CheckPrincipalWithCallbackRunnable(already_AddRefed<ContentParent> aParent,
const PrincipalInfo& aPrincipalInfo,
nsRunnable* aCallback)
: mContentParent(aParent)
, mPrincipalInfo(aPrincipalInfo)
, mCallback(aCallback)
, mBackgroundThread(NS_GetCurrentThread())
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(mContentParent);
MOZ_ASSERT(mCallback);
MOZ_ASSERT(mBackgroundThread);
}
NS_IMETHODIMP Run()
{
if (NS_IsMainThread()) {
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(mPrincipalInfo);
AssertAppPrincipal(mContentParent, principal);
mContentParent = nullptr;
mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL);
return NS_OK;
}
AssertIsOnBackgroundThread();
mCallback->Run();
mCallback = nullptr;
return NS_OK;
}
private:
nsRefPtr<ContentParent> mContentParent;
PrincipalInfo mPrincipalInfo;
nsRefPtr<nsRunnable> mCallback;
nsCOMPtr<nsIThread> mBackgroundThread;
};
} // anonymous namespace
ServiceWorkerManagerParent::ServiceWorkerManagerParent()
: mService(ServiceWorkerManagerService::GetOrCreate())
, mID(++sServiceWorkerManagerParentID)
{
AssertIsOnBackgroundThread();
mService->RegisterActor(this);
}
ServiceWorkerManagerParent::~ServiceWorkerManagerParent()
{
AssertIsOnBackgroundThread();
}
bool
ServiceWorkerManagerParent::RecvRegister(
const ServiceWorkerRegistrationData& aData)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
// Basic validation.
if (aData.scope().IsEmpty() ||
aData.scriptSpec().IsEmpty() ||
aData.principal().type() == PrincipalInfo::TNullPrincipalInfo ||
aData.principal().type() == PrincipalInfo::TSystemPrincipalInfo) {
return false;
}
nsRefPtr<RegisterServiceWorkerCallback> callback =
new RegisterServiceWorkerCallback(aData, mID);
nsRefPtr<ContentParent> parent =
BackgroundParent::GetContentParent(Manager());
// If the ContentParent is null we are dealing with a same-process actor.
if (!parent) {
callback->Run();
return true;
}
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
new CheckPrincipalWithCallbackRunnable(parent.forget(), aData.principal(),
callback);
nsresult rv = NS_DispatchToMainThread(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
return true;
}
bool
ServiceWorkerManagerParent::RecvUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
// Basic validation.
if (aScope.IsEmpty() ||
aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo ||
aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
return false;
}
nsRefPtr<UnregisterServiceWorkerCallback> callback =
new UnregisterServiceWorkerCallback(aPrincipalInfo, aScope);
nsRefPtr<ContentParent> parent =
BackgroundParent::GetContentParent(Manager());
// If the ContentParent is null we are dealing with a same-process actor.
if (!parent) {
callback->Run();
return true;
}
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
new CheckPrincipalWithCallbackRunnable(parent.forget(), aPrincipalInfo,
callback);
nsresult rv = NS_DispatchToMainThread(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
return true;
}
bool
ServiceWorkerManagerParent::RecvPropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
const nsString& aScope)
{
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!mService)) {
return false;
}
mService->PropagateSoftUpdate(mID, aOriginAttributes, aScope);
return true;
}
bool
ServiceWorkerManagerParent::RecvPropagateUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
{
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!mService)) {
return false;
}
mService->PropagateUnregister(mID, aPrincipalInfo, aScope);
return true;
}
bool
ServiceWorkerManagerParent::RecvShutdown()
{
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!mService)) {
return false;
}
mService->UnregisterActor(this);
mService = nullptr;
unused << Send__delete__(this);
return true;
}
void
ServiceWorkerManagerParent::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBackgroundThread();
if (mService) {
// This object is about to be released and with it, also mService will be
// released too.
mService->UnregisterActor(this);
}
}
} // workers namespace
} // dom namespace
} // mozilla namespace

View File

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ServiceWorkerManagerParent_h
#define mozilla_dom_ServiceWorkerManagerParent_h
#include "mozilla/dom/PServiceWorkerManagerParent.h"
namespace mozilla {
class OriginAttributes;
namespace ipc {
class BackgroundParentImpl;
}
namespace dom {
namespace workers {
class ServiceWorkerManagerService;
class ServiceWorkerManagerParent final : public PServiceWorkerManagerParent
{
friend class mozilla::ipc::BackgroundParentImpl;
public:
uint64_t ID() const
{
return mID;
}
private:
ServiceWorkerManagerParent();
~ServiceWorkerManagerParent();
virtual bool RecvRegister(
const ServiceWorkerRegistrationData& aData) override;
virtual bool RecvUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope) override;
virtual bool RecvPropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
const nsString& aScope) override;
virtual bool RecvPropagateUnregister(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope) override;
virtual bool RecvShutdown() override;
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
nsRefPtr<ServiceWorkerManagerService> mService;
// We use this ID in the Service in order to avoid the sending of messages to
// ourself.
uint64_t mID;
};
} // workers namespace
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ServiceWorkerManagerParent_h

View File

@ -0,0 +1,290 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ServiceWorkerManagerService.h"
#include "ServiceWorkerManagerParent.h"
#include "ServiceWorkerRegistrar.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/unused.h"
namespace mozilla {
using namespace ipc;
namespace dom {
namespace workers {
namespace {
ServiceWorkerManagerService* sInstance = nullptr;
} // anonymous namespace
ServiceWorkerManagerService::ServiceWorkerManagerService()
{
AssertIsOnBackgroundThread();
// sInstance is a raw ServiceWorkerManagerService*.
MOZ_ASSERT(!sInstance);
sInstance = this;
}
ServiceWorkerManagerService::~ServiceWorkerManagerService()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(sInstance == this);
MOZ_ASSERT(mAgents.Count() == 0);
sInstance = nullptr;
}
/* static */ already_AddRefed<ServiceWorkerManagerService>
ServiceWorkerManagerService::Get()
{
AssertIsOnBackgroundThread();
nsRefPtr<ServiceWorkerManagerService> instance = sInstance;
return instance.forget();
}
/* static */ already_AddRefed<ServiceWorkerManagerService>
ServiceWorkerManagerService::GetOrCreate()
{
AssertIsOnBackgroundThread();
nsRefPtr<ServiceWorkerManagerService> instance = sInstance;
if (!instance) {
instance = new ServiceWorkerManagerService();
}
return instance.forget();
}
void
ServiceWorkerManagerService::RegisterActor(ServiceWorkerManagerParent* aParent)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParent);
MOZ_ASSERT(!mAgents.Contains(aParent));
mAgents.PutEntry(aParent);
}
void
ServiceWorkerManagerService::UnregisterActor(ServiceWorkerManagerParent* aParent)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParent);
MOZ_ASSERT(mAgents.Contains(aParent));
mAgents.RemoveEntry(aParent);
}
namespace {
struct MOZ_STACK_CLASS RegistrationData final
{
RegistrationData(ServiceWorkerRegistrationData& aData,
uint64_t aParentID)
: mData(aData)
, mParentID(aParentID)
#ifdef DEBUG
, mParentFound(false)
#endif
{
MOZ_COUNT_CTOR(RegistrationData);
}
~RegistrationData()
{
MOZ_COUNT_DTOR(RegistrationData);
}
const ServiceWorkerRegistrationData& mData;
const uint64_t mParentID;
#ifdef DEBUG
bool mParentFound;
#endif
};
PLDHashOperator
RegistrationEnumerator(nsPtrHashKey<ServiceWorkerManagerParent>* aKey, void* aPtr)
{
AssertIsOnBackgroundThread();
auto* data = static_cast<RegistrationData*>(aPtr);
ServiceWorkerManagerParent* parent = aKey->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != data->mParentID) {
unused << parent->SendNotifyRegister(data->mData);
#ifdef DEBUG
} else {
data->mParentFound = true;
#endif
}
return PL_DHASH_NEXT;
}
struct MOZ_STACK_CLASS SoftUpdateData final
{
SoftUpdateData(const OriginAttributes& aOriginAttributes,
const nsAString& aScope,
uint64_t aParentID)
: mOriginAttributes(aOriginAttributes)
, mScope(aScope)
, mParentID(aParentID)
#ifdef DEBUG
, mParentFound(false)
#endif
{
MOZ_COUNT_CTOR(SoftUpdateData);
}
~SoftUpdateData()
{
MOZ_COUNT_DTOR(SoftUpdateData);
}
const OriginAttributes& mOriginAttributes;
const nsString mScope;
const uint64_t mParentID;
#ifdef DEBUG
bool mParentFound;
#endif
};
PLDHashOperator
SoftUpdateEnumerator(nsPtrHashKey<ServiceWorkerManagerParent>* aKey, void* aPtr)
{
AssertIsOnBackgroundThread();
auto* data = static_cast<SoftUpdateData*>(aPtr);
ServiceWorkerManagerParent* parent = aKey->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != data->mParentID) {
unused <<parent->SendNotifySoftUpdate(data->mOriginAttributes,
data->mScope);
#ifdef DEBUG
} else {
data->mParentFound = true;
#endif
}
return PL_DHASH_NEXT;
}
struct MOZ_STACK_CLASS UnregisterData final
{
UnregisterData(const PrincipalInfo& aPrincipalInfo,
const nsAString& aScope,
uint64_t aParentID)
: mPrincipalInfo(aPrincipalInfo)
, mScope(aScope)
, mParentID(aParentID)
#ifdef DEBUG
, mParentFound(false)
#endif
{
MOZ_COUNT_CTOR(UnregisterData);
}
~UnregisterData()
{
MOZ_COUNT_DTOR(UnregisterData);
}
const PrincipalInfo mPrincipalInfo;
const nsString mScope;
const uint64_t mParentID;
#ifdef DEBUG
bool mParentFound;
#endif
};
PLDHashOperator
UnregisterEnumerator(nsPtrHashKey<ServiceWorkerManagerParent>* aKey, void* aPtr)
{
AssertIsOnBackgroundThread();
auto* data = static_cast<UnregisterData*>(aPtr);
ServiceWorkerManagerParent* parent = aKey->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != data->mParentID) {
unused << parent->SendNotifyUnregister(data->mPrincipalInfo, data->mScope);
#ifdef DEBUG
} else {
data->mParentFound = true;
#endif
}
return PL_DHASH_NEXT;
}
} // anonymous namespce
void
ServiceWorkerManagerService::PropagateRegistration(
uint64_t aParentID,
ServiceWorkerRegistrationData& aData)
{
AssertIsOnBackgroundThread();
RegistrationData data(aData, aParentID);
mAgents.EnumerateEntries(RegistrationEnumerator, &data);
#ifdef DEBUG
MOZ_ASSERT(data.mParentFound);
#endif
}
void
ServiceWorkerManagerService::PropagateSoftUpdate(
uint64_t aParentID,
const OriginAttributes& aOriginAttributes,
const nsAString& aScope)
{
AssertIsOnBackgroundThread();
SoftUpdateData data(aOriginAttributes, aScope, aParentID);
mAgents.EnumerateEntries(SoftUpdateEnumerator, &data);
#ifdef DEBUG
MOZ_ASSERT(data.mParentFound);
#endif
}
void
ServiceWorkerManagerService::PropagateUnregister(
uint64_t aParentID,
const PrincipalInfo& aPrincipalInfo,
const nsAString& aScope)
{
AssertIsOnBackgroundThread();
nsRefPtr<dom::ServiceWorkerRegistrar> service =
dom::ServiceWorkerRegistrar::Get();
MOZ_ASSERT(service);
// It's possible that we don't have any ServiceWorkerManager managing this
// scope but we still need to unregister it from the ServiceWorkerRegistrar.
service->UnregisterServiceWorker(aPrincipalInfo,
NS_ConvertUTF16toUTF8(aScope));
UnregisterData data(aPrincipalInfo, aScope, aParentID);
mAgents.EnumerateEntries(UnregisterEnumerator, &data);
#ifdef DEBUG
MOZ_ASSERT(data.mParentFound);
#endif
}
} // workers namespace
} // dom namespace
} // mozilla namespace

View File

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_ServiceWorkerManagerService_h
#define mozilla_dom_ServiceWorkerManagerService_h
#include "nsISupportsImpl.h"
#include "nsHashKeys.h"
#include "nsTHashtable.h"
namespace mozilla {
class OriginAttributes;
namespace ipc {
class PrincipalInfo;
}
namespace dom {
class ServiceWorkerRegistrationData;
namespace workers {
class ServiceWorkerManagerParent;
class ServiceWorkerManagerService final
{
public:
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerManagerService)
static already_AddRefed<ServiceWorkerManagerService> Get();
static already_AddRefed<ServiceWorkerManagerService> GetOrCreate();
void RegisterActor(ServiceWorkerManagerParent* aParent);
void UnregisterActor(ServiceWorkerManagerParent* aParent);
void PropagateRegistration(uint64_t aParentID,
ServiceWorkerRegistrationData& aData);
void PropagateSoftUpdate(uint64_t aParentID,
const OriginAttributes& aOriginAttributes,
const nsAString& aScope);
void PropagateUnregister(uint64_t aParentID,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsAString& aScope);
private:
ServiceWorkerManagerService();
~ServiceWorkerManagerService();
nsTHashtable<nsPtrHashKey<ServiceWorkerManagerParent>> mAgents;
};
} // workers namespace
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ServiceWorkerManagerService_h

View File

@ -69,6 +69,9 @@ UNIFIED_SOURCES += [
'ServiceWorkerContainer.cpp',
'ServiceWorkerEvents.cpp',
'ServiceWorkerManager.cpp',
'ServiceWorkerManagerChild.cpp',
'ServiceWorkerManagerParent.cpp',
'ServiceWorkerManagerService.cpp',
'ServiceWorkerPeriodicUpdater.cpp',
'ServiceWorkerRegistrar.cpp',
'ServiceWorkerRegistration.cpp',
@ -86,6 +89,7 @@ UNIFIED_SOURCES += [
]
IPDL_SOURCES += [
'PServiceWorkerManager.ipdl',
'ServiceWorkerRegistrarTypes.ipdlh',
]

View File

@ -6,6 +6,7 @@
#include "ActorsChild.h" // IndexedDB
#include "BroadcastChannelChild.h"
#include "ServiceWorkerManagerChild.h"
#include "FileDescriptorSetChild.h"
#include "mozilla/media/MediaChild.h"
#include "mozilla/Assertions.h"
@ -260,6 +261,28 @@ BackgroundChildImpl::DeallocPBroadcastChannelChild(
return true;
}
// -----------------------------------------------------------------------------
// ServiceWorkerManager
// -----------------------------------------------------------------------------
dom::PServiceWorkerManagerChild*
BackgroundChildImpl::AllocPServiceWorkerManagerChild()
{
nsRefPtr<dom::workers::ServiceWorkerManagerChild> agent =
new dom::workers::ServiceWorkerManagerChild();
return agent.forget().take();
}
bool
BackgroundChildImpl::DeallocPServiceWorkerManagerChild(
PServiceWorkerManagerChild* aActor)
{
nsRefPtr<dom::workers::ServiceWorkerManagerChild> child =
dont_AddRef(static_cast<dom::workers::ServiceWorkerManagerChild*>(aActor));
MOZ_ASSERT(child);
return true;
}
// -----------------------------------------------------------------------------
// Cache API
// -----------------------------------------------------------------------------

View File

@ -98,6 +98,12 @@ protected:
virtual bool
DeallocPBroadcastChannelChild(PBroadcastChannelChild* aActor) override;
virtual PServiceWorkerManagerChild*
AllocPServiceWorkerManagerChild() override;
virtual bool
DeallocPServiceWorkerManagerChild(PServiceWorkerManagerChild* aActor) override;
virtual dom::cache::PCacheStorageChild*
AllocPCacheStorageChild(const dom::cache::Namespace& aNamespace,
const PrincipalInfo& aPrincipalInfo) override;

View File

@ -27,6 +27,7 @@
#include "nsThreadUtils.h"
#include "nsTraceRefcnt.h"
#include "nsXULAppAPI.h"
#include "ServiceWorkerManagerParent.h"
#ifdef DISABLE_ASSERTS_FOR_FUZZING
#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
@ -82,6 +83,7 @@ namespace ipc {
using mozilla::dom::ContentParent;
using mozilla::dom::BroadcastChannelParent;
using mozilla::dom::ServiceWorkerRegistrationData;
using mozilla::dom::workers::ServiceWorkerManagerParent;
BackgroundParentImpl::BackgroundParentImpl()
{
@ -468,6 +470,27 @@ BackgroundParentImpl::DeallocPBroadcastChannelParent(
return true;
}
mozilla::dom::PServiceWorkerManagerParent*
BackgroundParentImpl::AllocPServiceWorkerManagerParent()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return new ServiceWorkerManagerParent();
}
bool
BackgroundParentImpl::DeallocPServiceWorkerManagerParent(
PServiceWorkerManagerParent* aActor)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
delete static_cast<ServiceWorkerManagerParent*>(aActor);
return true;
}
media::PMediaParent*
BackgroundParentImpl::AllocPMediaParent()
{
@ -480,187 +503,6 @@ BackgroundParentImpl::DeallocPMediaParent(media::PMediaParent *aActor)
return media::DeallocPMediaParent(aActor);
}
namespace {
class RegisterServiceWorkerCallback final : public nsRunnable
{
public:
explicit RegisterServiceWorkerCallback(
const ServiceWorkerRegistrationData& aData)
: mData(aData)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
NS_IMETHODIMP
Run()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
nsRefPtr<dom::ServiceWorkerRegistrar> service =
dom::ServiceWorkerRegistrar::Get();
MOZ_ASSERT(service);
service->RegisterServiceWorker(mData);
return NS_OK;
}
private:
ServiceWorkerRegistrationData mData;
};
class UnregisterServiceWorkerCallback final : public nsRunnable
{
public:
UnregisterServiceWorkerCallback(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
: mPrincipalInfo(aPrincipalInfo)
, mScope(aScope)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
NS_IMETHODIMP
Run()
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
nsRefPtr<dom::ServiceWorkerRegistrar> service =
dom::ServiceWorkerRegistrar::Get();
MOZ_ASSERT(service);
service->UnregisterServiceWorker(mPrincipalInfo,
NS_ConvertUTF16toUTF8(mScope));
return NS_OK;
}
private:
const PrincipalInfo mPrincipalInfo;
nsString mScope;
};
class CheckPrincipalWithCallbackRunnable final : public nsRunnable
{
public:
CheckPrincipalWithCallbackRunnable(already_AddRefed<ContentParent> aParent,
const PrincipalInfo& aPrincipalInfo,
nsRunnable* aCallback)
: mContentParent(aParent)
, mPrincipalInfo(aPrincipalInfo)
, mCallback(aCallback)
, mBackgroundThread(NS_GetCurrentThread())
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(mContentParent);
MOZ_ASSERT(mCallback);
MOZ_ASSERT(mBackgroundThread);
}
NS_IMETHODIMP Run()
{
if (NS_IsMainThread()) {
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(mPrincipalInfo);
AssertAppPrincipal(mContentParent, principal);
mContentParent = nullptr;
mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL);
return NS_OK;
}
AssertIsOnBackgroundThread();
if (mCallback) {
mCallback->Run();
mCallback = nullptr;
}
return NS_OK;
}
private:
nsRefPtr<ContentParent> mContentParent;
PrincipalInfo mPrincipalInfo;
nsRefPtr<nsRunnable> mCallback;
nsCOMPtr<nsIThread> mBackgroundThread;
};
} // anonymous namespace
bool
BackgroundParentImpl::RecvRegisterServiceWorker(
const ServiceWorkerRegistrationData& aData)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
// Basic validation.
if (aData.scope().IsEmpty() ||
aData.scriptSpec().IsEmpty() ||
aData.principal().type() == PrincipalInfo::TNullPrincipalInfo ||
aData.principal().type() == PrincipalInfo::TSystemPrincipalInfo) {
return false;
}
nsRefPtr<RegisterServiceWorkerCallback> callback =
new RegisterServiceWorkerCallback(aData);
nsRefPtr<ContentParent> parent = BackgroundParent::GetContentParent(this);
// If the ContentParent is null we are dealing with a same-process actor.
if (!parent) {
callback->Run();
return true;
}
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
new CheckPrincipalWithCallbackRunnable(parent.forget(), aData.principal(),
callback);
nsresult rv = NS_DispatchToMainThread(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
return true;
}
bool
BackgroundParentImpl::RecvUnregisterServiceWorker(
const PrincipalInfo& aPrincipalInfo,
const nsString& aScope)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
// Basic validation.
if (aScope.IsEmpty() ||
aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo ||
aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
return false;
}
nsRefPtr<UnregisterServiceWorkerCallback> callback =
new UnregisterServiceWorkerCallback(aPrincipalInfo, aScope);
nsRefPtr<ContentParent> parent = BackgroundParent::GetContentParent(this);
// If the ContentParent is null we are dealing with a same-process actor.
if (!parent) {
callback->Run();
return true;
}
nsRefPtr<CheckPrincipalWithCallbackRunnable> runnable =
new CheckPrincipalWithCallbackRunnable(parent.forget(), aPrincipalInfo,
callback);
nsresult rv = NS_DispatchToMainThread(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
return true;
}
bool
BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar()
{

View File

@ -86,20 +86,18 @@ protected:
virtual bool
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
virtual PServiceWorkerManagerParent*
AllocPServiceWorkerManagerParent() override;
virtual bool
DeallocPServiceWorkerManagerParent(PServiceWorkerManagerParent* aActor) override;
virtual PMediaParent*
AllocPMediaParent() override;
virtual bool
DeallocPMediaParent(PMediaParent* aActor) override;
virtual bool
RecvRegisterServiceWorker(const ServiceWorkerRegistrationData& aData)
override;
virtual bool
RecvUnregisterServiceWorker(const PrincipalInfo& aPrincipalInfo,
const nsString& aScope) override;
virtual bool
RecvShutdownServiceWorkerRegistrar() override;

View File

@ -5,12 +5,38 @@
#ifndef mozilla_ipc_backgroundutils_h__
#define mozilla_ipc_backgroundutils_h__
#include "ipc/IPCMessageUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/BasePrincipal.h"
#include "nsCOMPtr.h"
#include "nscore.h"
class nsIPrincipal;
namespace IPC {
template<>
struct ParamTraits<mozilla::OriginAttributes>
{
typedef mozilla::OriginAttributes paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
nsAutoCString suffix;
aParam.CreateSuffix(suffix);
WriteParam(aMsg, suffix);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
nsAutoCString suffix;
return ReadParam(aMsg, aIter, &suffix) &&
aResult->PopulateFromSuffix(suffix);
}
};
} // IPC namespace
namespace mozilla {
namespace ipc {

View File

@ -11,13 +11,13 @@ include protocol PCacheStorage;
include protocol PCacheStreamControl;
include protocol PFileDescriptorSet;
include protocol PMedia;
include protocol PServiceWorkerManager;
include protocol PUDPSocket;
include protocol PVsync;
include DOMTypes;
include PBackgroundSharedTypes;
include PBackgroundIDBSharedTypes;
include ServiceWorkerRegistrarTypes;
using mozilla::dom::cache::Namespace from "mozilla/dom/cache/Types.h";
include "mozilla/dom/cache/IPCUtils.h";
@ -36,6 +36,7 @@ sync protocol PBackground
manages PCacheStreamControl;
manages PFileDescriptorSet;
manages PMedia;
manages PServiceWorkerManager;
manages PUDPSocket;
manages PVsync;
@ -52,9 +53,8 @@ parent:
PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel,
bool privateBrowsing);
RegisterServiceWorker(ServiceWorkerRegistrationData data);
UnregisterServiceWorker(PrincipalInfo principalInfo,
nsString scope);
PServiceWorkerManager();
ShutdownServiceWorkerRegistrar();
PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo);

View File

@ -133,6 +133,7 @@ LOCAL_INCLUDES += [
'/caps',
'/dom/broadcastchannel',
'/dom/indexedDB',
'/dom/workers',
'/xpcom/build',
]

View File

@ -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.principal.originAttributes, info.scope);
gSWM.propagateSoftUpdate(info.principal.originAttributes, info.scope);
};
div.appendChild(updateButton);
@ -164,7 +164,7 @@ function display(info) {
};
loadingMessage.classList.remove('inactive');
gSWM.unregister(info.principal, cb, info.scope);
gSWM.propagateUnregister(info.principal, cb, info.scope);
};
let sep = document.createElement('hr');