diff options
Diffstat (limited to 'dom/serviceworkers/ServiceWorkerInfo.cpp')
-rw-r--r-- | dom/serviceworkers/ServiceWorkerInfo.cpp | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/dom/serviceworkers/ServiceWorkerInfo.cpp b/dom/serviceworkers/ServiceWorkerInfo.cpp new file mode 100644 index 0000000000..9998cfed6b --- /dev/null +++ b/dom/serviceworkers/ServiceWorkerInfo.cpp @@ -0,0 +1,286 @@ +/* -*- 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 "ServiceWorkerInfo.h" + +#include "ServiceWorkerUtils.h" +#include "ServiceWorkerPrivate.h" +#include "ServiceWorkerScriptCache.h" +#include "mozilla/dom/ClientIPCTypes.h" +#include "mozilla/dom/ClientState.h" +#include "mozilla/dom/RemoteWorkerTypes.h" +#include "mozilla/dom/WorkerPrivate.h" + +namespace mozilla::dom { + +using mozilla::ipc::PrincipalInfo; + +static_assert(nsIServiceWorkerInfo::STATE_PARSED == + static_cast<uint16_t>(ServiceWorkerState::Parsed), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_INSTALLING == + static_cast<uint16_t>(ServiceWorkerState::Installing), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_INSTALLED == + static_cast<uint16_t>(ServiceWorkerState::Installed), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_ACTIVATING == + static_cast<uint16_t>(ServiceWorkerState::Activating), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_ACTIVATED == + static_cast<uint16_t>(ServiceWorkerState::Activated), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_REDUNDANT == + static_cast<uint16_t>(ServiceWorkerState::Redundant), + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); +static_assert(nsIServiceWorkerInfo::STATE_UNKNOWN == + ServiceWorkerStateValues::Count, + "ServiceWorkerState enumeration value should match state values " + "from nsIServiceWorkerInfo."); + +NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo) + +NS_IMETHODIMP +ServiceWorkerInfo::GetId(nsAString& aId) { + MOZ_ASSERT(NS_IsMainThread()); + aId = mWorkerPrivateId; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec) { + MOZ_ASSERT(NS_IsMainThread()); + CopyUTF8toUTF16(mDescriptor.ScriptURL(), aScriptSpec); + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetCacheName(nsAString& aCacheName) { + MOZ_ASSERT(NS_IsMainThread()); + aCacheName = mCacheName; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetState(uint16_t* aState) { + MOZ_ASSERT(aState); + MOZ_ASSERT(NS_IsMainThread()); + *aState = static_cast<uint16_t>(State()); + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger** aResult) { + if (NS_WARN_IF(!aResult)) { + return NS_ERROR_FAILURE; + } + + return mServiceWorkerPrivate->GetDebugger(aResult); +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue) { + MOZ_ASSERT(aValue); + MOZ_ASSERT(NS_IsMainThread()); + + if (mHandlesFetch == Unknown) { + return NS_ERROR_FAILURE; + } + + *aValue = HandlesFetch(); + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetInstalledTime(PRTime* _retval) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(_retval); + *_retval = mInstalledTime; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetActivatedTime(PRTime* _retval) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(_retval); + *_retval = mActivatedTime; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetRedundantTime(PRTime* _retval) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(_retval); + *_retval = mRedundantTime; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetNavigationFaultCount(uint32_t* aNavigationFaultCount) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aNavigationFaultCount); + *aNavigationFaultCount = mNavigationFaultCount; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::GetTestingInjectCancellation( + nsresult* aTestingInjectCancellation) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aTestingInjectCancellation); + *aTestingInjectCancellation = mTestingInjectCancellation; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::SetTestingInjectCancellation( + nsresult aTestingInjectCancellation) { + MOZ_ASSERT(NS_IsMainThread()); + mTestingInjectCancellation = aTestingInjectCancellation; + return NS_OK; +} + +NS_IMETHODIMP +ServiceWorkerInfo::AttachDebugger() { + return mServiceWorkerPrivate->AttachDebugger(); +} + +NS_IMETHODIMP +ServiceWorkerInfo::DetachDebugger() { + return mServiceWorkerPrivate->DetachDebugger(); +} + +void ServiceWorkerInfo::UpdateState(ServiceWorkerState aState) { + MOZ_ASSERT(NS_IsMainThread()); +#ifdef DEBUG + // Any state can directly transition to redundant, but everything else is + // ordered. + if (aState != ServiceWorkerState::Redundant) { + MOZ_ASSERT_IF(State() == ServiceWorkerState::EndGuard_, + aState == ServiceWorkerState::Installing); + MOZ_ASSERT_IF(State() == ServiceWorkerState::Installing, + aState == ServiceWorkerState::Installed); + MOZ_ASSERT_IF(State() == ServiceWorkerState::Installed, + aState == ServiceWorkerState::Activating); + MOZ_ASSERT_IF(State() == ServiceWorkerState::Activating, + aState == ServiceWorkerState::Activated); + } + // Activated can only go to redundant. + MOZ_ASSERT_IF(State() == ServiceWorkerState::Activated, + aState == ServiceWorkerState::Redundant); +#endif + // Flush any pending functional events to the worker when it transitions to + // the activated state. + // TODO: Do we care that these events will race with the propagation of the + // state change? + if (State() != aState) { + mServiceWorkerPrivate->UpdateState(aState); + } + mDescriptor.SetState(aState); + if (State() == ServiceWorkerState::Redundant) { + serviceWorkerScriptCache::PurgeCache(mPrincipal, mCacheName); + mServiceWorkerPrivate->NoteDeadServiceWorkerInfo(); + } +} + +ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal, + const nsACString& aScope, + uint64_t aRegistrationId, + uint64_t aRegistrationVersion, + const nsACString& aScriptSpec, + const nsAString& aCacheName, + nsLoadFlags aImportsLoadFlags) + : mPrincipal(aPrincipal), + mDescriptor(GetNextID(), aRegistrationId, aRegistrationVersion, + aPrincipal, aScope, aScriptSpec, ServiceWorkerState::Parsed), + mCacheName(aCacheName), + mWorkerPrivateId(ComputeWorkerPrivateId()), + mImportsLoadFlags(aImportsLoadFlags), + mCreationTime(PR_Now()), + mCreationTimeStamp(TimeStamp::Now()), + mInstalledTime(0), + mActivatedTime(0), + mRedundantTime(0), + mServiceWorkerPrivate(new ServiceWorkerPrivate(this)), + mSkipWaitingFlag(false), + mHandlesFetch(Unknown), + mNavigationFaultCount(0), + mTestingInjectCancellation(NS_OK) { + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + MOZ_ASSERT(mPrincipal); + // cache origin attributes so we can use them off main thread + mOriginAttributes = mPrincipal->OriginAttributesRef(); + MOZ_ASSERT(!mDescriptor.ScriptURL().IsEmpty()); + MOZ_ASSERT(!mCacheName.IsEmpty()); + MOZ_ASSERT(!mWorkerPrivateId.IsEmpty()); + + // Scripts of a service worker should always be loaded bypass service workers. + // Otherwise, we might not be able to update a service worker correctly, if + // there is a service worker generating the script. + MOZ_DIAGNOSTIC_ASSERT(mImportsLoadFlags & + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); +} + +ServiceWorkerInfo::~ServiceWorkerInfo() { + MOZ_ASSERT(mServiceWorkerPrivate); + mServiceWorkerPrivate->NoteDeadServiceWorkerInfo(); +} + +static uint64_t gServiceWorkerInfoCurrentID = 0; + +uint64_t ServiceWorkerInfo::GetNextID() const { + return ++gServiceWorkerInfoCurrentID; +} + +void ServiceWorkerInfo::PostMessage(RefPtr<ServiceWorkerCloneData>&& aData, + const ClientInfo& aClientInfo, + const ClientState& aClientState) { + mServiceWorkerPrivate->SendMessageEvent( + std::move(aData), + ClientInfoAndState(aClientInfo.ToIPC(), aClientState.ToIPC())); +} + +void ServiceWorkerInfo::UpdateInstalledTime() { + MOZ_ASSERT(State() == ServiceWorkerState::Installed); + MOZ_ASSERT(mInstalledTime == 0); + + mInstalledTime = + mCreationTime + + static_cast<PRTime>( + (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds()); +} + +void ServiceWorkerInfo::UpdateActivatedTime() { + MOZ_ASSERT(State() == ServiceWorkerState::Activated); + MOZ_ASSERT(mActivatedTime == 0); + + mActivatedTime = + mCreationTime + + static_cast<PRTime>( + (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds()); +} + +void ServiceWorkerInfo::UpdateRedundantTime() { + MOZ_ASSERT(State() == ServiceWorkerState::Redundant); + MOZ_ASSERT(mRedundantTime == 0); + + mRedundantTime = + mCreationTime + + static_cast<PRTime>( + (TimeStamp::Now() - mCreationTimeStamp).ToMicroseconds()); +} + +void ServiceWorkerInfo::SetRegistrationVersion(uint64_t aVersion) { + mDescriptor.SetRegistrationVersion(aVersion); +} + +} // namespace mozilla::dom |