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 #ifndef mozilla_dom_serviceworkerprivate_h
8 #define mozilla_dom_serviceworkerprivate_h
11 #include <type_traits>
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/MozPromise.h"
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/TimeStamp.h"
18 #include "mozilla/UniquePtr.h"
19 #include "mozilla/dom/FetchService.h"
20 #include "mozilla/dom/Promise.h"
21 #include "mozilla/dom/RemoteWorkerController.h"
22 #include "mozilla/dom/RemoteWorkerTypes.h"
23 #include "mozilla/dom/ServiceWorkerLifetimeExtension.h"
24 #include "mozilla/dom/ServiceWorkerOpArgs.h"
26 #include "nsISupportsImpl.h"
29 #define NOTIFICATION_CLICK_EVENT_NAME u"notificationclick"
30 #define NOTIFICATION_CLOSE_EVENT_NAME u"notificationclose"
32 class nsIInterceptedChannel
;
33 class nsIWorkerDebugger
;
44 class PostMessageSource
;
45 class RemoteWorkerControllerChild
;
46 class ServiceWorkerCloneData
;
47 class ServiceWorkerInfo
;
48 class ServiceWorkerPrivate
;
49 class ServiceWorkerRegistrationInfo
;
52 class StructuredCloneData
;
55 class LifeCycleEventCallback
: public Runnable
{
57 LifeCycleEventCallback() : Runnable("dom::LifeCycleEventCallback") {}
59 // Called on the worker thread.
60 virtual void SetResult(bool aResult
) = 0;
63 // Used to keep track of pending waitUntil as well as in-flight extendable
64 // events. When the last token is released, we attempt to terminate the worker.
65 class KeepAliveToken final
: public nsISupports
{
69 explicit KeepAliveToken(ServiceWorkerPrivate
* aPrivate
);
74 RefPtr
<ServiceWorkerPrivate
> mPrivate
;
77 class ServiceWorkerPrivate final
: public RemoteWorkerObserver
{
78 friend class KeepAliveToken
;
81 NS_INLINE_DECL_REFCOUNTING(ServiceWorkerPrivate
, override
);
83 using PromiseExtensionWorkerHasListener
= MozPromise
<bool, nsresult
, false>;
86 explicit ServiceWorkerPrivate(ServiceWorkerInfo
* aInfo
);
88 Maybe
<ClientInfo
> GetClientInfo() { return mClientInfo
; }
90 nsresult
SendMessageEvent(
91 RefPtr
<ServiceWorkerCloneData
>&& aData
,
92 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
,
93 const PostMessageSource
& aSource
);
95 // This is used to validate the worker script and continue the installation
97 nsresult
CheckScriptEvaluation(
98 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
,
99 RefPtr
<LifeCycleEventCallback
> aCallback
);
101 nsresult
SendLifeCycleEvent(
102 const nsAString
& aEventType
,
103 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
,
104 const RefPtr
<LifeCycleEventCallback
>& aCallback
);
106 nsresult
SendPushEvent(const nsAString
& aMessageId
,
107 const Maybe
<nsTArray
<uint8_t>>& aData
,
108 RefPtr
<ServiceWorkerRegistrationInfo
> aRegistration
);
110 nsresult
SendPushSubscriptionChangeEvent();
112 nsresult
SendNotificationEvent(const nsAString
& aEventName
,
113 const nsAString
& aID
, const nsAString
& aTitle
,
114 const nsAString
& aDir
, const nsAString
& aLang
,
115 const nsAString
& aBody
, const nsAString
& aTag
,
116 const nsAString
& aIcon
, const nsAString
& aData
,
117 const nsAString
& aScope
);
119 nsresult
SendFetchEvent(nsCOMPtr
<nsIInterceptedChannel
> aChannel
,
120 nsILoadGroup
* aLoadGroup
, const nsAString
& aClientId
,
121 const nsAString
& aResultingClientId
);
123 Result
<RefPtr
<PromiseExtensionWorkerHasListener
>, nsresult
>
124 WakeForExtensionAPIEvent(const nsAString
& aExtensionAPINamespace
,
125 const nsAString
& aEXtensionAPIEventName
);
127 // This will terminate the current running worker thread and drop the
128 // workerPrivate reference.
129 // Called by ServiceWorkerInfo when [[Clear Registration]] is invoked
130 // or whenever the spec mandates that we terminate the worker.
131 // This is a no-op if the worker has already been stopped.
133 // Now takes an optional promise that will be resolved when the worker is
134 // dead, including if the worker was not running at all.
135 void TerminateWorker(Maybe
<RefPtr
<Promise
>> aMaybePromise
= Nothing());
137 void NoteDeadServiceWorkerInfo();
139 void NoteStoppedControllingDocuments();
141 void UpdateState(ServiceWorkerState aState
);
143 void UpdateIsOnContentBlockingAllowList(bool aOnContentBlockingAllowList
);
145 nsresult
GetDebugger(nsIWorkerDebugger
** aResult
);
147 nsresult
AttachDebugger();
149 nsresult
DetachDebugger();
151 // Return the current lifetime deadline for this ServiceWorker; this value may
152 // be null or in the past.
154 // This value always only reflects the explicit lifetime extensions
155 // resulting from functional events and will never reflect the extra "grace
157 TimeStamp
GetLifetimeDeadline() { return mIdleDeadline
; }
159 uint32_t GetLaunchCount() { return mLaunchCount
; }
163 // This promise is used schedule clearing of the owning registrations and its
164 // associated Service Workers if that registration becomes "unreachable" by
165 // the ServiceWorkerManager. This occurs under two conditions, which are the
166 // preconditions to calling this method:
167 // - The owning registration must be unregistered.
168 // - The associated Service Worker must *not* be controlling clients.
170 // Additionally, perhaps stating the obvious, the associated Service Worker
171 // must *not* be idle (whatever must be done "when idle" can just be done
173 RefPtr
<GenericPromise
> GetIdlePromise();
175 void SetHandlesFetch(bool aValue
);
177 RefPtr
<GenericPromise
> SetSkipWaitingFlag();
179 static void RunningShutdown() {
180 // Force a final update of the number of running ServiceWorkers
182 MOZ_ASSERT(sRunningServiceWorkers
== 0);
183 MOZ_ASSERT(sRunningServiceWorkersFetch
== 0);
187 * Update Telemetry for # of running ServiceWorkers
189 static void UpdateRunning(int32_t aDelta
, int32_t aFetchDelta
);
193 void NoteIdleWorkerCallback(nsITimer
* aTimer
);
195 void TerminateWorkerCallback(nsITimer
* aTimer
);
197 void RenewKeepAliveToken(
198 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
);
200 void ResetIdleTimeout(
201 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
);
207 already_AddRefed
<KeepAliveToken
> CreateEventKeepAliveToken();
209 nsresult
SpawnWorkerIfNeeded(
210 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
);
212 ~ServiceWorkerPrivate();
214 nsresult
Initialize();
216 void RegenerateClientInfo();
219 * RemoteWorkerObserver
221 void CreationFailed() override
;
223 void CreationSucceeded() override
;
225 void ErrorReceived(const ErrorValue
& aError
) override
;
227 void LockNotified(bool aCreated
) final
{
228 // no-op for service workers
231 void WebTransportNotified(bool aCreated
) final
{
232 // no-op for service workers
235 void Terminated() override
;
237 // Refreshes only the parts of mRemoteWorkerData that may change over time.
238 void RefreshRemoteWorkerData(
239 const RefPtr
<ServiceWorkerRegistrationInfo
>& aRegistration
);
241 nsresult
SendPushEventInternal(
242 RefPtr
<ServiceWorkerRegistrationInfo
>&& aRegistration
,
243 ServiceWorkerPushEventOpArgs
&& aArgs
);
245 // Setup the navigation preload by the intercepted channel and the
247 RefPtr
<FetchServicePromises
> SetupNavigationPreload(
248 nsCOMPtr
<nsIInterceptedChannel
>& aChannel
,
249 const RefPtr
<ServiceWorkerRegistrationInfo
>& aRegistration
);
251 nsresult
SendFetchEventInternal(
252 RefPtr
<ServiceWorkerRegistrationInfo
>&& aRegistration
,
253 ParentToParentServiceWorkerFetchEventOpArgs
&& aArgs
,
254 nsCOMPtr
<nsIInterceptedChannel
>&& aChannel
,
255 RefPtr
<FetchServicePromises
>&& aPreloadResponseReadyPromises
);
257 void Shutdown(Maybe
<RefPtr
<Promise
>>&& aMaybePromise
= Nothing());
259 RefPtr
<GenericNonExclusivePromise
> ShutdownInternal(
260 uint32_t aShutdownStateId
);
262 nsresult
ExecServiceWorkerOp(
263 ServiceWorkerOpArgs
&& aArgs
,
264 const ServiceWorkerLifetimeExtension
& aLifetimeExtension
,
265 std::function
<void(ServiceWorkerOpResult
&&)>&& aSuccessCallback
,
266 std::function
<void()>&& aFailureCallback
= [] {});
268 class PendingFunctionalEvent
{
270 PendingFunctionalEvent(
271 ServiceWorkerPrivate
* aOwner
,
272 RefPtr
<ServiceWorkerRegistrationInfo
>&& aRegistration
);
274 virtual ~PendingFunctionalEvent();
276 virtual nsresult
Send() = 0;
279 ServiceWorkerPrivate
* const MOZ_NON_OWNING_REF mOwner
;
280 RefPtr
<ServiceWorkerRegistrationInfo
> mRegistration
;
283 class PendingPushEvent final
: public PendingFunctionalEvent
{
285 PendingPushEvent(ServiceWorkerPrivate
* aOwner
,
286 RefPtr
<ServiceWorkerRegistrationInfo
>&& aRegistration
,
287 ServiceWorkerPushEventOpArgs
&& aArgs
);
289 nsresult
Send() override
;
292 ServiceWorkerPushEventOpArgs mArgs
;
295 class PendingFetchEvent final
: public PendingFunctionalEvent
{
298 ServiceWorkerPrivate
* aOwner
,
299 RefPtr
<ServiceWorkerRegistrationInfo
>&& aRegistration
,
300 ParentToParentServiceWorkerFetchEventOpArgs
&& aArgs
,
301 nsCOMPtr
<nsIInterceptedChannel
>&& aChannel
,
302 RefPtr
<FetchServicePromises
>&& aPreloadResponseReadyPromises
);
304 nsresult
Send() override
;
306 ~PendingFetchEvent();
309 ParentToParentServiceWorkerFetchEventOpArgs mArgs
;
310 nsCOMPtr
<nsIInterceptedChannel
> mChannel
;
311 // The promises from FetchService. It indicates if the preload response is
312 // ready or not. The promise's resolve/reject value should be handled in
313 // FetchEventOpChild, such that the preload result can be propagated to the
314 // ServiceWorker through IPC. However, FetchEventOpChild creation could be
315 // pending here, so this member is needed. And it will be forwarded to
316 // FetchEventOpChild when crearting the FetchEventOpChild.
317 RefPtr
<FetchServicePromises
> mPreloadResponseReadyPromises
;
320 nsTArray
<UniquePtr
<PendingFunctionalEvent
>> mPendingFunctionalEvents
;
323 * It's possible that there are still in-progress operations when a
324 * a termination operation is issued. In this case, it's important to keep
325 * the RemoteWorkerControllerChild actor alive until all pending operations
326 * have completed before destroying it with Send__delete__().
328 * RAIIActorPtrHolder holds a singular, owning reference to a
329 * RemoteWorkerControllerChild actor and is responsible for destroying the
330 * actor in its (i.e. the holder's) destructor. This implies that all
331 * in-progress operations must maintain a strong reference to their
332 * corresponding holders and release the reference once completed/canceled.
334 * Additionally a RAIIActorPtrHolder must be initialized with a non-null actor
335 * and cannot be moved or copied. Therefore, the identities of two held
336 * actors can be compared by simply comparing their holders' addresses.
338 class RAIIActorPtrHolder final
{
340 NS_INLINE_DECL_REFCOUNTING(RAIIActorPtrHolder
)
342 explicit RAIIActorPtrHolder(
343 already_AddRefed
<RemoteWorkerControllerChild
> aActor
);
345 RAIIActorPtrHolder(const RAIIActorPtrHolder
& aOther
) = delete;
346 RAIIActorPtrHolder
& operator=(const RAIIActorPtrHolder
& aOther
) = delete;
348 RAIIActorPtrHolder(RAIIActorPtrHolder
&& aOther
) = delete;
349 RAIIActorPtrHolder
& operator=(RAIIActorPtrHolder
&& aOther
) = delete;
351 RemoteWorkerControllerChild
* operator->() const
352 MOZ_NO_ADDREF_RELEASE_ON_RETURN
;
354 RemoteWorkerControllerChild
* get() const;
356 RefPtr
<GenericPromise
> OnDestructor();
359 ~RAIIActorPtrHolder();
361 MozPromiseHolder
<GenericPromise
> mDestructorPromiseHolder
;
363 const RefPtr
<RemoteWorkerControllerChild
> mActor
;
366 RefPtr
<RAIIActorPtrHolder
> mControllerChild
;
368 RemoteWorkerData mRemoteWorkerData
;
369 Maybe
<ClientInfo
> mClientInfo
;
371 TimeStamp mServiceWorkerLaunchTimeStart
;
373 // Counters for Telemetry - totals running simultaneously, and those that
374 // handle Fetch, plus Max values for each
375 static uint32_t sRunningServiceWorkers
;
376 static uint32_t sRunningServiceWorkersFetch
;
377 static uint32_t sRunningServiceWorkersMax
;
378 static uint32_t sRunningServiceWorkersFetchMax
;
380 // We know the state after we've evaluated the worker, and we then store
381 // it in the registration. The only valid state transition should be
382 // from Unknown to Enabled or Disabled.
383 enum { Unknown
, Enabled
, Disabled
} mHandlesFetch
{Unknown
};
385 // The info object owns us. It is possible to outlive it for a brief period
386 // of time if there are pending waitUntil promises, in which case it
387 // will be null and |SpawnWorkerIfNeeded| will always fail.
388 ServiceWorkerInfo
* MOZ_NON_OWNING_REF mInfo
;
390 nsCOMPtr
<nsITimer
> mIdleWorkerTimer
;
392 ServiceWorkerLifetimeExtension mPendingSpawnLifetime
;
394 // This is the current time in the future that the idle timer is set to expire
395 // for keepalive purposes. This will not be updated for the
396 // "dom.serviceWorkers.idle_extended_timeout" grace period after the time
398 TimeStamp mIdleDeadline
;
400 // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
401 // worker a grace period after each event.
402 RefPtr
<KeepAliveToken
> mIdleKeepAliveToken
;
404 uint64_t mDebuggerCount
;
406 uint64_t mTokenCount
;
408 uint32_t mLaunchCount
;
410 // Used by the owning `ServiceWorkerRegistrationInfo` when it wants to call
411 // `Clear` after being unregistered and isn't controlling any clients but this
412 // worker (i.e. the registration's active worker) isn't idle yet. Note that
413 // such an event should happen at most once in a
414 // `ServiceWorkerRegistrationInfo`s lifetime, so this promise should also only
415 // be obtained at most once.
416 MozPromiseHolder
<GenericPromise
> mIdlePromiseHolder
;
419 bool mIdlePromiseObtained
= false;
424 } // namespace mozilla
426 #endif // mozilla_dom_serviceworkerprivate_h