summaryrefslogtreecommitdiffstats
path: root/dom/serviceworkers/ServiceWorkerInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/serviceworkers/ServiceWorkerInfo.cpp')
-rw-r--r--dom/serviceworkers/ServiceWorkerInfo.cpp286
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