зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c9ae48f4e5
Коммит
4fad78d9c2
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче