Bug 984048 - Part 7 - Documents register themselves with corresponding ServiceWorkerInfo. r=bz

--HG--
extra : transplant_source : %FD%9BD%8C%E4a%A9%CB9%17L%EE%E38%11%A1t%8A%3Bs
This commit is contained in:
Nikhil Marathe 2014-07-20 23:25:44 -07:00
Родитель c9ae48f4e5
Коммит 4fad78d9c2
5 изменённых файлов: 171 добавлений и 69 удалений

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

@ -69,6 +69,7 @@
#include "mozilla/dom/TreeWalker.h"
#include "nsIServiceManager.h"
#include "nsIServiceWorkerManager.h"
#include "nsContentCID.h"
#include "nsError.h"
@ -4465,6 +4466,24 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
}
nsCOMPtr<nsIChannel> channel = GetChannel();
if (!mMaybeServiceWorkerControlled && channel) {
nsLoadFlags loadFlags = 0;
channel->GetLoadFlags(&loadFlags);
// If we are shift-reloaded, don't associate with a ServiceWorker.
// FIXME(nsm): Bug 1041339.
if (loadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
return;
}
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) {
swm->MaybeStartControlling(this);
mMaybeServiceWorkerControlled = true;
}
}
}
nsIScriptGlobalObject*
@ -8483,6 +8502,11 @@ nsDocument::Destroy()
mRegistry = nullptr;
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
if (swm) {
swm->MaybeStopControlling(this);
}
// XXX We really should let cycle collection do this, but that currently still
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
ReleaseWrapper(static_cast<nsINode*>(this));

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

@ -1742,6 +1742,10 @@ private:
nsCOMPtr<nsIDocument> mMasterDocument;
nsRefPtr<mozilla::dom::ImportManager> mImportManager;
// Set to true when the document is possibly controlled by the ServiceWorker.
// Used to prevent multiple requests to ServiceWorkerManager.
bool mMaybeServiceWorkerControlled;
#ifdef DEBUG
public:
bool mWillReparent;

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

@ -5,9 +5,10 @@
#include "domstubs.idl"
interface nsIDocument;
interface nsIURI;
[uuid(6117cdf1-cb10-42a3-9901-4f1bab7ffa4d)]
[uuid(6e1382f4-3cbc-435f-8ce0-70175f6eb400)]
interface nsIServiceWorkerManager : nsISupports
{
// Returns a Promise
@ -20,6 +21,21 @@ interface nsIServiceWorkerManager : nsISupports
[noscript] void AddContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void RemoveContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
/**
* Call this to request that document `aDoc` be controlled by a ServiceWorker
* if a registration exists for it's scope.
*
* This MUST only be called once per document!
*/
[notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
/**
* Documents that have called MaybeStartControlling() should call this when
* they are destroyed. This function may be called multiple times, and is
* idempotent.
*/
[notxpcom,nostdcall] void MaybeStopControlling(in nsIDocument aDoc);
// Testing
DOMString getScopeForUrl(in DOMString path);
};

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

@ -11,7 +11,6 @@
#include "jsapi.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DOMError.h"
#include "mozilla/dom/ErrorEvent.h"
@ -299,12 +298,15 @@ FinishFetchOnMainThreadRunnable::Run()
}
ServiceWorkerRegistration::ServiceWorkerRegistration(const nsACString& aScope)
: mScope(aScope),
: mControlledDocumentsCounter(0),
mScope(aScope),
mPendingUninstall(false)
{ }
ServiceWorkerRegistration::~ServiceWorkerRegistration()
{ }
{
MOZ_ASSERT(!IsControllingDocuments());
}
//////////////////////////
// ServiceWorkerManager //
@ -360,18 +362,16 @@ public:
NS_IMETHODIMP
Run()
{
nsCString domain;
nsresult rv = mScriptURI->GetHost(domain);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
return NS_OK;
}
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo;
// XXXnsm: This pattern can be refactored if we end up using it
// often enough.
if (!swm->mDomainMap.Get(domain, getter_AddRefs(domainInfo))) {
nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo = swm->GetDomainInfo(mScriptURI);
if (!domainInfo) {
nsCString domain;
nsresult rv = mScriptURI->GetHost(domain);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
return NS_OK;
}
domainInfo = new ServiceWorkerManager::ServiceWorkerDomainInfo;
swm->mDomainMap.Put(domain, domainInfo);
}
@ -380,7 +380,7 @@ public:
domainInfo->GetRegistration(mScope);
nsCString spec;
rv = mScriptURI->GetSpec(spec);
nsresult rv = mScriptURI->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(rv);
return NS_OK;
@ -399,12 +399,12 @@ public:
// There is no update in progress and since SW updating is upto the UA,
// we will not update right now. Simply resolve with whatever worker we
// have.
ServiceWorkerInfo info = registration->Newest();
if (info.IsValid()) {
nsRefPtr<ServiceWorkerInfo> info = registration->Newest();
if (info) {
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
swm->CreateServiceWorkerForWindow(mWindow,
info.GetScriptSpec(),
info->GetScriptSpec(),
registration->mScope,
getter_AddRefs(serviceWorker));
@ -563,14 +563,14 @@ ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
aRegistration->mUpdateInstance = nullptr;
}
if (aRegistration->mInstallingWorker.IsValid()) {
if (aRegistration->mInstallingWorker) {
// FIXME(nsm): Terminate the worker. We still haven't figured out worker
// instance ownership when not associated with a window, so let's wait on
// this.
// FIXME(nsm): We should be setting the state on the actual worker
// instance.
// FIXME(nsm): Fire "statechange" on installing worker instance.
aRegistration->mInstallingWorker.Invalidate();
aRegistration->mInstallingWorker = nullptr;
}
aRegistration->mUpdatePromise = new UpdatePromise();
@ -657,7 +657,7 @@ ServiceWorkerManager::FinishFetch(ServiceWorkerRegistration* aRegistration,
ResolveRegisterPromises(aRegistration, aRegistration->mScriptSpec);
ServiceWorkerInfo info(aRegistration->mScriptSpec);
nsRefPtr<ServiceWorkerInfo> info = new ServiceWorkerInfo(aRegistration->mScriptSpec);
Install(aRegistration, info);
}
@ -680,14 +680,8 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
return;
}
nsCString domain;
rv = uri->GetHost(domain);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsRefPtr<ServiceWorkerDomainInfo> domainInfo;
if (!mDomainMap.Get(domain, getter_AddRefs(domainInfo))) {
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(uri);
if (!domainInfo) {
return;
}
@ -760,7 +754,7 @@ public:
AssertIsOnMainThread();
// FIXME(nsm): Change installing worker state to redundant.
// FIXME(nsm): Fire statechange.
mRegistration->mInstallingWorker.Invalidate();
mRegistration->mInstallingWorker = nullptr;
return NS_OK;
}
};
@ -881,7 +875,7 @@ private:
void
ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
ServiceWorkerInfo aServiceWorkerInfo)
ServiceWorkerInfo* aServiceWorkerInfo)
{
AssertIsOnMainThread();
aRegistration->mInstallingWorker = aServiceWorkerInfo;
@ -891,12 +885,12 @@ ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
CreateServiceWorker(aServiceWorkerInfo.GetScriptSpec(),
CreateServiceWorker(aServiceWorkerInfo->GetScriptSpec(),
aRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
aRegistration->mInstallingWorker.Invalidate();
aRegistration->mInstallingWorker = nullptr;
return;
}
@ -936,12 +930,11 @@ ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
{
AssertIsOnMainThread();
if (aRegistration->mWaitingWorker.IsValid()) {
if (aRegistration->mWaitingWorker) {
// FIXME(nsm): Actually update the state of active ServiceWorker instances.
}
aRegistration->mWaitingWorker = aRegistration->mInstallingWorker;
aRegistration->mInstallingWorker.Invalidate();
aRegistration->mWaitingWorker = aRegistration->mInstallingWorker.forget();
// FIXME(nsm): Actually update state of active ServiceWorker instances to
// installed.
@ -995,8 +988,8 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
already_AddRefed<ServiceWorkerRegistration>
ServiceWorkerManager::GetServiceWorkerRegistration(nsPIDOMWindow* aWindow)
{
nsCOMPtr<nsIURI> documentURI = aWindow->GetDocumentURI();
return GetServiceWorkerRegistration(documentURI);
nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc();
return GetServiceWorkerRegistration(document);
}
already_AddRefed<ServiceWorkerRegistration>
@ -1158,6 +1151,53 @@ ServiceWorkerManager::GetDomainInfo(const nsCString& aURL)
return GetDomainInfo(uri);
}
void
ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
{
AssertIsOnMainThread();
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
return;
}
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDoc);
if (!domainInfo) {
return;
}
nsRefPtr<ServiceWorkerRegistration> registration =
GetServiceWorkerRegistration(aDoc);
if (registration) {
MOZ_ASSERT(!domainInfo->mControlledDocuments.Contains(aDoc));
registration->StartControllingADocument();
// Use the already_AddRefed<> form of Put to avoid the addref-deref since
// we don't need the registration pointer in this function anymore.
domainInfo->mControlledDocuments.Put(aDoc, registration.forget());
}
}
void
ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
{
MOZ_ASSERT(aDoc);
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
return;
}
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDoc);
if (!domainInfo) {
return;
}
nsRefPtr<ServiceWorkerRegistration> registration;
domainInfo->mControlledDocuments.Remove(aDoc, getter_AddRefs(registration));
// A document which was uncontrolled does not maintain that state itself, so
// it will always call MaybeStopControlling() even if there isn't an
// associated registration. So this check is required.
if (registration) {
registration->StopControllingADocument();
}
}
NS_IMETHODIMP
ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
{

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

@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
@ -72,35 +73,22 @@ private:
* _GetNewestWorker(serviceWorkerRegistration)", we represent the description
* by this class and spawn a ServiceWorker in the right global when required.
*/
class ServiceWorkerInfo
class ServiceWorkerInfo MOZ_FINAL
{
nsCString mScriptSpec;
~ServiceWorkerInfo()
{ }
public:
bool
IsValid() const
{
return !mScriptSpec.IsVoid();
}
void
Invalidate()
{
mScriptSpec.SetIsVoid(true);
}
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerInfo)
const nsCString&
GetScriptSpec() const
{
MOZ_ASSERT(IsValid());
return mScriptSpec;
}
ServiceWorkerInfo()
{
Invalidate();
}
explicit ServiceWorkerInfo(const nsACString& aScriptSpec)
: mScriptSpec(aScriptSpec)
{ }
@ -110,6 +98,8 @@ public:
// non-ISupports classes.
class ServiceWorkerRegistration MOZ_FINAL : public nsISupports
{
uint32_t mControlledDocumentsCounter;
virtual ~ServiceWorkerRegistration();
public:
@ -120,9 +110,9 @@ public:
// the URLs of the following three workers.
nsCString mScriptSpec;
ServiceWorkerInfo mCurrentWorker;
ServiceWorkerInfo mWaitingWorker;
ServiceWorkerInfo mInstallingWorker;
nsRefPtr<ServiceWorkerInfo> mCurrentWorker;
nsRefPtr<ServiceWorkerInfo> mWaitingWorker;
nsRefPtr<ServiceWorkerInfo> mInstallingWorker;
nsAutoPtr<UpdatePromise> mUpdatePromise;
nsRefPtr<ServiceWorkerUpdateInstance> mUpdateInstance;
@ -147,16 +137,37 @@ public:
explicit ServiceWorkerRegistration(const nsACString& aScope);
ServiceWorkerInfo
Newest() const
already_AddRefed<ServiceWorkerInfo>
Newest()
{
if (mInstallingWorker.IsValid()) {
return mInstallingWorker;
} else if (mWaitingWorker.IsValid()) {
return mWaitingWorker;
nsRefPtr<ServiceWorkerInfo> newest;
if (mInstallingWorker) {
newest = mInstallingWorker;
} else if (mWaitingWorker) {
newest = mWaitingWorker;
} else {
return mCurrentWorker;
newest = mCurrentWorker;
}
return newest.forget();
}
void
StartControllingADocument()
{
++mControlledDocumentsCounter;
}
void
StopControllingADocument()
{
--mControlledDocumentsCounter;
}
bool
IsControllingDocuments() const
{
return mControlledDocumentsCounter > 0;
}
};
@ -186,6 +197,11 @@ public:
static ServiceWorkerManager* FactoryCreate()
{
AssertIsOnMainThread();
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
return nullptr;
}
ServiceWorkerManager* res = new ServiceWorkerManager;
NS_ADDREF(res);
return res;
@ -216,6 +232,8 @@ public:
// The containers inform the SWM on creation and destruction.
nsTObserverArray<ServiceWorkerContainer*> mServiceWorkerContainers;
nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistration> mControlledDocuments;
ServiceWorkerDomainInfo()
{ }
@ -290,7 +308,7 @@ private:
void
Install(ServiceWorkerRegistration* aRegistration,
ServiceWorkerInfo aServiceWorkerInfo);
ServiceWorkerInfo* aServiceWorkerInfo);
NS_IMETHOD
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,