Bug 1434342 P4 Make ServiceWorker operate on an abstract Inner interface that ServiceWorkerInfo implements. r=asuth

This commit is contained in:
Ben Kelly 2018-01-31 09:10:26 -08:00
parent 2508c997c6
commit 00f7b788b7
4 changed files with 126 additions and 79 deletions

View File

@ -66,22 +66,23 @@ ServiceWorker::Create(nsIGlobalObject* aOwner,
}
ServiceWorker::ServiceWorker(nsIGlobalObject* aGlobal,
ServiceWorkerInfo* aInfo)
const ServiceWorkerDescriptor& aDescriptor,
ServiceWorker::Inner* aInner)
: DOMEventTargetHelper(aGlobal)
, mDescriptor(aDescriptor)
, mInfo(aInfo)
, mInner(aInner)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aInfo);
MOZ_DIAGNOSTIC_ASSERT(mInner);
// This will update our state too.
mInfo->AppendWorker(this);
mInner->AddServiceWorker(this);
}
ServiceWorker::~ServiceWorker()
{
MOZ_ASSERT(NS_IsMainThread());
mInfo->RemoveWorker(this);
mInner->RemoveServiceWorker(this);
}
NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
@ -130,33 +131,7 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
if (!window || !window->GetExtantDoc()) {
NS_WARNING("Trying to call post message from an invalid dom object.");
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
ServiceWorkerManager::LocalizeAndReportToAllClients(
mInfo->Scope(), "ServiceWorkerPostMessageStorageError",
nsTArray<nsString> { NS_ConvertUTF8toUTF16(mInfo->Scope()) });
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
Maybe<ClientState> clientState = window->GetClientState();
if (clientInfo.isNothing() || clientState.isNothing()) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable,
ClientInfoAndState(clientInfo.ref().ToIPC(),
clientState.ref().ToIPC()));
mInner->PostMessage(GetParentObject(), aCx, aMessage, aTransferable, aRv);
}
} // namespace dom

View File

@ -9,24 +9,56 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState.
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#ifdef XP_WIN
#undef PostMessage
#endif
class nsIGlobalObject;
namespace mozilla {
namespace dom {
class ServiceWorkerInfo;
class ServiceWorkerManager;
class SharedWorker;
bool
ServiceWorkerVisible(JSContext* aCx, JSObject* aObj);
class ServiceWorker final : public DOMEventTargetHelper
{
public:
// Abstract interface for the internal representation of the
// ServiceWorker object.
class Inner
{
public:
// This will be called when a DOM ServiceWorker object is
// created and takes a strong ref to the Inner object.
// RemoveServiceWorker() is guaranteed to be called on the
// current thread before the ServiceWorker is destroyed.
//
// In addition, the Inner object should check to see if
// the ServiceWorker's state is correct. If not, it should
// be updated automatically by calling SetState(). This is
// necessary to handle race conditions where the DOM
// ServiceWorker object is created while the state is being
// updated in another process.
virtual void
AddServiceWorker(ServiceWorker* aWorker) = 0;
// This is called when the DOM ServiceWorker object is
// destroyed and drops its ref to the Inner object.
virtual void
RemoveServiceWorker(ServiceWorker* aWorker) = 0;
virtual void
PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) = 0;
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
};
NS_DECL_ISUPPORTS_INHERITED
IMPL_EVENT_HANDLER(statechange)
@ -47,10 +79,6 @@ public:
void
GetScriptURL(nsString& aURL) const;
#ifdef XP_WIN
#undef PostMessage
#endif
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable, ErrorResult& aRv);
@ -58,13 +86,13 @@ public:
private:
ServiceWorker(nsIGlobalObject* aWindow,
const ServiceWorkerDescriptor& aDescriptor,
ServiceWorkerInfo* aInfo);
Inner* aInner);
// This class is reference-counted and will be destroyed from Release().
~ServiceWorker();
ServiceWorkerDescriptor mDescriptor;
const RefPtr<ServiceWorkerInfo> mInfo;
const RefPtr<Inner> mInner;
};
} // namespace dom

View File

@ -113,35 +113,6 @@ ServiceWorkerInfo::DetachDebugger()
return mServiceWorkerPrivate->DetachDebugger();
}
void
ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
{
MOZ_ASSERT(aWorker);
#ifdef DEBUG
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
#endif
MOZ_ASSERT(!mInstances.Contains(aWorker));
mInstances.AppendElement(aWorker);
aWorker->SetState(State());
}
void
ServiceWorkerInfo::RemoveWorker(ServiceWorker* aWorker)
{
MOZ_ASSERT(aWorker);
#ifdef DEBUG
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_ASSERT(workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
#endif
MOZ_ASSERT(mInstances.Contains(aWorker));
mInstances.RemoveElement(aWorker);
}
namespace {
class ChangeStateUpdater final : public Runnable
@ -253,6 +224,72 @@ ServiceWorkerInfo::GetNextID() const
return ++gServiceWorkerInfoCurrentID;
}
void
ServiceWorkerInfo::AddServiceWorker(ServiceWorker* aWorker)
{
MOZ_DIAGNOSTIC_ASSERT(aWorker);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_DIAGNOSTIC_ASSERT(
workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
#endif
MOZ_ASSERT(!mInstances.Contains(aWorker));
mInstances.AppendElement(aWorker);
aWorker->SetState(State());
}
void
ServiceWorkerInfo::RemoveServiceWorker(ServiceWorker* aWorker)
{
MOZ_DIAGNOSTIC_ASSERT(aWorker);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
nsAutoString workerURL;
aWorker->GetScriptURL(workerURL);
MOZ_DIAGNOSTIC_ASSERT(
workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
#endif
MOZ_ASSERT(mInstances.Contains(aWorker));
mInstances.RemoveElement(aWorker);
}
void
ServiceWorkerInfo::PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
if (NS_WARN_IF(!window || !window->GetExtantDoc())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
ServiceWorkerManager::LocalizeAndReportToAllClients(
Scope(), "ServiceWorkerPostMessageStorageError",
nsTArray<nsString> { NS_ConvertUTF8toUTF16(Scope()) });
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
Maybe<ClientState> clientState = window->GetClientState();
if (NS_WARN_IF(clientInfo.isNothing() || clientState.isNothing())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
aRv = mServiceWorkerPrivate->SendMessageEvent(aCx, aMessage, aTransferable,
ClientInfoAndState(clientInfo.ref().ToIPC(),
clientState.ref().ToIPC()));
}
already_AddRefed<ServiceWorker>
ServiceWorkerInfo::GetOrCreateInstance(nsPIDOMWindowInner* aWindow)
{

View File

@ -12,11 +12,11 @@
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/OriginAttributes.h"
#include "nsIServiceWorkerManager.h"
#include "ServiceWorker.h"
namespace mozilla {
namespace dom {
class ServiceWorker;
class ServiceWorkerPrivate;
/*
@ -75,6 +75,19 @@ private:
uint64_t
GetNextID() const;
// ServiceWorker::Inner implementation
virtual void
AddServiceWorker(ServiceWorker* aWorker) override;
virtual void
RemoveServiceWorker(ServiceWorker* aWorker) override;
virtual void
PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) override;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEWORKERINFO
@ -185,12 +198,6 @@ public:
return mHandlesFetch != Disabled;
}
void
AppendWorker(ServiceWorker* aWorker);
void
RemoveWorker(ServiceWorker* aWorker);
already_AddRefed<ServiceWorker>
GetOrCreateInstance(nsPIDOMWindowInner* aWindow);