1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ServiceWorkerInfo.h"
9 #include "ServiceWorkerUtils.h"
10 #include "ServiceWorkerPrivate.h"
11 #include "ServiceWorkerScriptCache.h"
12 #include "mozilla/dom/ClientIPCTypes.h"
13 #include "mozilla/dom/ClientState.h"
14 #include "mozilla/dom/RemoteWorkerTypes.h"
15 #include "mozilla/dom/WorkerPrivate.h"
17 namespace mozilla::dom
{
19 using mozilla::ipc::PrincipalInfo
;
21 static_assert(nsIServiceWorkerInfo::STATE_PARSED
==
22 static_cast<uint16_t>(ServiceWorkerState::Parsed
),
23 "ServiceWorkerState enumeration value should match state values "
24 "from nsIServiceWorkerInfo.");
25 static_assert(nsIServiceWorkerInfo::STATE_INSTALLING
==
26 static_cast<uint16_t>(ServiceWorkerState::Installing
),
27 "ServiceWorkerState enumeration value should match state values "
28 "from nsIServiceWorkerInfo.");
29 static_assert(nsIServiceWorkerInfo::STATE_INSTALLED
==
30 static_cast<uint16_t>(ServiceWorkerState::Installed
),
31 "ServiceWorkerState enumeration value should match state values "
32 "from nsIServiceWorkerInfo.");
33 static_assert(nsIServiceWorkerInfo::STATE_ACTIVATING
==
34 static_cast<uint16_t>(ServiceWorkerState::Activating
),
35 "ServiceWorkerState enumeration value should match state values "
36 "from nsIServiceWorkerInfo.");
37 static_assert(nsIServiceWorkerInfo::STATE_ACTIVATED
==
38 static_cast<uint16_t>(ServiceWorkerState::Activated
),
39 "ServiceWorkerState enumeration value should match state values "
40 "from nsIServiceWorkerInfo.");
41 static_assert(nsIServiceWorkerInfo::STATE_REDUNDANT
==
42 static_cast<uint16_t>(ServiceWorkerState::Redundant
),
43 "ServiceWorkerState enumeration value should match state values "
44 "from nsIServiceWorkerInfo.");
45 static_assert(nsIServiceWorkerInfo::STATE_UNKNOWN
==
46 ServiceWorkerStateValues::Count
,
47 "ServiceWorkerState enumeration value should match state values "
48 "from nsIServiceWorkerInfo.");
50 NS_IMPL_ISUPPORTS(ServiceWorkerInfo
, nsIServiceWorkerInfo
)
53 ServiceWorkerInfo::GetId(nsAString
& aId
) {
54 MOZ_ASSERT(NS_IsMainThread());
55 aId
= mWorkerPrivateId
;
60 ServiceWorkerInfo::GetScriptSpec(nsAString
& aScriptSpec
) {
61 MOZ_ASSERT(NS_IsMainThread());
62 CopyUTF8toUTF16(mDescriptor
.ScriptURL(), aScriptSpec
);
67 ServiceWorkerInfo::GetCacheName(nsAString
& aCacheName
) {
68 MOZ_ASSERT(NS_IsMainThread());
69 aCacheName
= mCacheName
;
74 ServiceWorkerInfo::GetState(uint16_t* aState
) {
76 MOZ_ASSERT(NS_IsMainThread());
77 *aState
= static_cast<uint16_t>(State());
82 ServiceWorkerInfo::GetDebugger(nsIWorkerDebugger
** aResult
) {
83 if (NS_WARN_IF(!aResult
)) {
84 return NS_ERROR_FAILURE
;
87 return mServiceWorkerPrivate
->GetDebugger(aResult
);
91 ServiceWorkerInfo::GetHandlesFetchEvents(bool* aValue
) {
93 MOZ_ASSERT(NS_IsMainThread());
95 if (mHandlesFetch
== Unknown
) {
96 return NS_ERROR_FAILURE
;
99 *aValue
= HandlesFetch();
104 ServiceWorkerInfo::GetInstalledTime(PRTime
* _retval
) {
105 MOZ_ASSERT(NS_IsMainThread());
107 *_retval
= mInstalledTime
;
112 ServiceWorkerInfo::GetActivatedTime(PRTime
* _retval
) {
113 MOZ_ASSERT(NS_IsMainThread());
115 *_retval
= mActivatedTime
;
120 ServiceWorkerInfo::GetRedundantTime(PRTime
* _retval
) {
121 MOZ_ASSERT(NS_IsMainThread());
123 *_retval
= mRedundantTime
;
128 ServiceWorkerInfo::GetNavigationFaultCount(uint32_t* aNavigationFaultCount
) {
129 MOZ_ASSERT(NS_IsMainThread());
130 MOZ_ASSERT(aNavigationFaultCount
);
131 *aNavigationFaultCount
= mNavigationFaultCount
;
136 ServiceWorkerInfo::GetTestingInjectCancellation(
137 nsresult
* aTestingInjectCancellation
) {
138 MOZ_ASSERT(NS_IsMainThread());
139 MOZ_ASSERT(aTestingInjectCancellation
);
140 *aTestingInjectCancellation
= mTestingInjectCancellation
;
145 ServiceWorkerInfo::SetTestingInjectCancellation(
146 nsresult aTestingInjectCancellation
) {
147 MOZ_ASSERT(NS_IsMainThread());
148 mTestingInjectCancellation
= aTestingInjectCancellation
;
153 ServiceWorkerInfo::AttachDebugger() {
154 return mServiceWorkerPrivate
->AttachDebugger();
158 ServiceWorkerInfo::DetachDebugger() {
159 return mServiceWorkerPrivate
->DetachDebugger();
162 void ServiceWorkerInfo::UpdateState(ServiceWorkerState aState
) {
163 MOZ_ASSERT(NS_IsMainThread());
165 // Any state can directly transition to redundant, but everything else is
167 if (aState
!= ServiceWorkerState::Redundant
) {
168 MOZ_ASSERT_IF(State() == ServiceWorkerState::EndGuard_
,
169 aState
== ServiceWorkerState::Installing
);
170 MOZ_ASSERT_IF(State() == ServiceWorkerState::Installing
,
171 aState
== ServiceWorkerState::Installed
);
172 MOZ_ASSERT_IF(State() == ServiceWorkerState::Installed
,
173 aState
== ServiceWorkerState::Activating
);
174 MOZ_ASSERT_IF(State() == ServiceWorkerState::Activating
,
175 aState
== ServiceWorkerState::Activated
);
177 // Activated can only go to redundant.
178 MOZ_ASSERT_IF(State() == ServiceWorkerState::Activated
,
179 aState
== ServiceWorkerState::Redundant
);
181 // Flush any pending functional events to the worker when it transitions to
182 // the activated state.
183 // TODO: Do we care that these events will race with the propagation of the
185 if (State() != aState
) {
186 mServiceWorkerPrivate
->UpdateState(aState
);
188 mDescriptor
.SetState(aState
);
189 if (State() == ServiceWorkerState::Redundant
) {
190 serviceWorkerScriptCache::PurgeCache(mPrincipal
, mCacheName
);
191 mServiceWorkerPrivate
->NoteDeadServiceWorkerInfo();
195 ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal
* aPrincipal
,
196 const nsACString
& aScope
,
197 uint64_t aRegistrationId
,
198 uint64_t aRegistrationVersion
,
199 const nsACString
& aScriptSpec
,
200 const nsAString
& aCacheName
,
201 nsLoadFlags aImportsLoadFlags
)
202 : mPrincipal(aPrincipal
),
203 mDescriptor(GetNextID(), aRegistrationId
, aRegistrationVersion
,
204 aPrincipal
, aScope
, aScriptSpec
, ServiceWorkerState::Parsed
),
205 mCacheName(aCacheName
),
206 mWorkerPrivateId(ComputeWorkerPrivateId()),
207 mImportsLoadFlags(aImportsLoadFlags
),
208 mCreationTime(PR_Now()),
209 mCreationTimeStamp(TimeStamp::Now()),
213 mServiceWorkerPrivate(new ServiceWorkerPrivate(this)),
214 mSkipWaitingFlag(false),
215 mHandlesFetch(Unknown
),
216 mNavigationFaultCount(0),
217 mTestingInjectCancellation(NS_OK
) {
218 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
219 MOZ_ASSERT(mPrincipal
);
220 // cache origin attributes so we can use them off main thread
221 mOriginAttributes
= mPrincipal
->OriginAttributesRef();
222 MOZ_ASSERT(!mDescriptor
.ScriptURL().IsEmpty());
223 MOZ_ASSERT(!mCacheName
.IsEmpty());
224 MOZ_ASSERT(!mWorkerPrivateId
.IsEmpty());
226 // Scripts of a service worker should always be loaded bypass service workers.
227 // Otherwise, we might not be able to update a service worker correctly, if
228 // there is a service worker generating the script.
229 MOZ_DIAGNOSTIC_ASSERT(mImportsLoadFlags
&
230 nsIChannel::LOAD_BYPASS_SERVICE_WORKER
);
233 ServiceWorkerInfo::~ServiceWorkerInfo() {
234 MOZ_ASSERT(mServiceWorkerPrivate
);
235 mServiceWorkerPrivate
->NoteDeadServiceWorkerInfo();
238 static uint64_t gServiceWorkerInfoCurrentID
= 0;
240 uint64_t ServiceWorkerInfo::GetNextID() const {
241 return ++gServiceWorkerInfoCurrentID
;
244 void ServiceWorkerInfo::PostMessage(RefPtr
<ServiceWorkerCloneData
>&& aData
,
245 const ClientInfo
& aClientInfo
,
246 const ClientState
& aClientState
) {
247 mServiceWorkerPrivate
->SendMessageEvent(
249 ClientInfoAndState(aClientInfo
.ToIPC(), aClientState
.ToIPC()));
252 void ServiceWorkerInfo::UpdateInstalledTime() {
253 MOZ_ASSERT(State() == ServiceWorkerState::Installed
);
254 MOZ_ASSERT(mInstalledTime
== 0);
259 (TimeStamp::Now() - mCreationTimeStamp
).ToMicroseconds());
262 void ServiceWorkerInfo::UpdateActivatedTime() {
263 MOZ_ASSERT(State() == ServiceWorkerState::Activated
);
264 MOZ_ASSERT(mActivatedTime
== 0);
269 (TimeStamp::Now() - mCreationTimeStamp
).ToMicroseconds());
272 void ServiceWorkerInfo::UpdateRedundantTime() {
273 MOZ_ASSERT(State() == ServiceWorkerState::Redundant
);
274 MOZ_ASSERT(mRedundantTime
== 0);
279 (TimeStamp::Now() - mCreationTimeStamp
).ToMicroseconds());
282 void ServiceWorkerInfo::SetRegistrationVersion(uint64_t aVersion
) {
283 mDescriptor
.SetRegistrationVersion(aVersion
);
286 } // namespace mozilla::dom