Backed out changeset 1b14354719c0 (bug 1895254) for causing bustages on NavigationTra...
[gecko.git] / dom / serviceworkers / ServiceWorkerManager.h
blob11c8f2f6723e730089962a74f95305d3815f7192
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_workers_serviceworkermanager_h
8 #define mozilla_dom_workers_serviceworkermanager_h
10 #include <cstdint>
11 #include "ErrorList.h"
12 #include "ServiceWorkerShutdownState.h"
13 #include "js/ErrorReport.h"
14 #include "mozilla/AlreadyAddRefed.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/HashTable.h"
17 #include "mozilla/MozPromise.h"
18 #include "mozilla/RefPtr.h"
19 #include "mozilla/UniquePtr.h"
20 #include "mozilla/dom/ClientHandle.h"
21 #include "mozilla/dom/ClientOpPromise.h"
22 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
23 #include "mozilla/dom/ServiceWorkerRegistrationInfo.h"
24 #include "mozilla/dom/ServiceWorkerUtils.h"
25 #include "mozilla/mozalloc.h"
26 #include "nsClassHashtable.h"
27 #include "nsContentUtils.h"
28 #include "nsHashKeys.h"
29 #include "nsIObserver.h"
30 #include "nsIServiceWorkerManager.h"
31 #include "nsISupports.h"
32 #include "nsStringFwd.h"
33 #include "nsTArray.h"
35 class nsIConsoleReportCollector;
37 namespace mozilla {
39 class OriginAttributes;
41 namespace ipc {
42 class PrincipalInfo;
43 } // namespace ipc
45 namespace dom {
47 extern uint32_t gServiceWorkersRegistered;
48 extern uint32_t gServiceWorkersRegisteredFetch;
50 class ContentParent;
51 class ServiceWorkerInfo;
52 class ServiceWorkerJobQueue;
53 class ServiceWorkerManagerChild;
54 class ServiceWorkerPrivate;
55 class ServiceWorkerRegistrar;
56 class ServiceWorkerShutdownBlocker;
58 class ServiceWorkerUpdateFinishCallback {
59 protected:
60 virtual ~ServiceWorkerUpdateFinishCallback() = default;
62 public:
63 NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
65 virtual void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) = 0;
67 virtual void UpdateFailed(ErrorResult& aStatus) = 0;
70 #define NS_SERVICEWORKERMANAGER_IMPL_IID \
71 { /* f4f8755a-69ca-46e8-a65d-775745535990 */ \
72 0xf4f8755a, 0x69ca, 0x46e8, { \
73 0xa6, 0x5d, 0x77, 0x57, 0x45, 0x53, 0x59, 0x90 \
74 } \
78 * The ServiceWorkerManager is a per-process global that deals with the
79 * installation, querying and event dispatch of ServiceWorkers for all the
80 * origins in the process.
82 * NOTE: the following documentation is a WIP:
84 * The ServiceWorkerManager (SWM) is a main-thread, parent-process singleton
85 * that encapsulates the browser-global state of service workers. This state
86 * includes, but is not limited to, all service worker registrations and all
87 * controlled service worker clients. The SWM also provides methods to read and
88 * mutate this state and to dispatch operations (e.g. DOM events such as a
89 * FetchEvent) to service workers.
91 * Example usage:
93 * MOZ_ASSERT(NS_IsMainThread(), "SWM is main-thread only");
95 * RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
97 * // Nullness must be checked by code that possibly executes during browser
98 * // shutdown, which is when the SWM is destroyed.
99 * if (swm) {
100 * // Do something with the SWM.
103 class ServiceWorkerManager final : public nsIServiceWorkerManager,
104 public nsIObserver {
105 friend class GetRegistrationsRunnable;
106 friend class GetRegistrationRunnable;
107 friend class ServiceWorkerJob;
108 friend class ServiceWorkerRegistrationInfo;
109 friend class ServiceWorkerShutdownBlocker;
110 friend class ServiceWorkerUnregisterJob;
111 friend class ServiceWorkerUpdateJob;
112 friend class UpdateTimerCallback;
114 public:
115 NS_DECL_ISUPPORTS
116 NS_DECL_NSISERVICEWORKERMANAGER
117 NS_DECL_NSIOBSERVER
119 // Return true if the given principal and URI matches a registered service
120 // worker which handles fetch event.
121 // If there is a matched service worker but doesn't handle fetch events, this
122 // method will try to set the matched service worker as the controller of the
123 // passed in channel. Then also schedule a soft-update job for the service
124 // worker.
125 bool IsAvailable(nsIPrincipal* aPrincipal, nsIURI* aURI,
126 nsIChannel* aChannel);
128 void DispatchFetchEvent(nsIInterceptedChannel* aChannel, ErrorResult& aRv);
130 void Update(nsIPrincipal* aPrincipal, const nsACString& aScope,
131 nsCString aNewestWorkerScriptUrl,
132 ServiceWorkerUpdateFinishCallback* aCallback);
134 void UpdateInternal(nsIPrincipal* aPrincipal, const nsACString& aScope,
135 nsCString&& aNewestWorkerScriptUrl,
136 ServiceWorkerUpdateFinishCallback* aCallback);
138 void SoftUpdate(const OriginAttributes& aOriginAttributes,
139 const nsACString& aScope);
141 void SoftUpdateInternal(const OriginAttributes& aOriginAttributes,
142 const nsACString& aScope,
143 ServiceWorkerUpdateFinishCallback* aCallback);
145 RefPtr<ServiceWorkerRegistrationPromise> Register(
146 const ClientInfo& aClientInfo, const nsACString& aScopeURL,
147 const nsACString& aScriptURL,
148 ServiceWorkerUpdateViaCache aUpdateViaCache);
150 RefPtr<ServiceWorkerRegistrationPromise> GetRegistration(
151 const ClientInfo& aClientInfo, const nsACString& aURL) const;
153 RefPtr<ServiceWorkerRegistrationListPromise> GetRegistrations(
154 const ClientInfo& aClientInfo) const;
156 already_AddRefed<ServiceWorkerRegistrationInfo> GetRegistration(
157 nsIPrincipal* aPrincipal, const nsACString& aScope) const;
159 already_AddRefed<ServiceWorkerRegistrationInfo> GetRegistration(
160 const mozilla::ipc::PrincipalInfo& aPrincipal,
161 const nsACString& aScope) const;
163 already_AddRefed<ServiceWorkerRegistrationInfo> CreateNewRegistration(
164 const nsCString& aScope, nsIPrincipal* aPrincipal,
165 ServiceWorkerUpdateViaCache aUpdateViaCache,
166 IPCNavigationPreloadState aNavigationPreloadState =
167 IPCNavigationPreloadState(false, "true"_ns));
169 void RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
171 void StoreRegistration(nsIPrincipal* aPrincipal,
172 ServiceWorkerRegistrationInfo* aRegistration);
175 * Report an error for the given scope to any window we think might be
176 * interested, failing over to the Browser Console if we couldn't find any.
178 * Error messages should be localized, so you probably want to call
179 * LocalizeAndReportToAllClients instead, which in turn calls us after
180 * localizing the error.
182 void ReportToAllClients(const nsCString& aScope, const nsString& aMessage,
183 const nsString& aFilename, const nsString& aLine,
184 uint32_t aLineNumber, uint32_t aColumnNumber,
185 uint32_t aFlags);
188 * Report a localized error for the given scope to any window we think might
189 * be interested.
191 * Note that this method takes an nsTArray<nsString> for the parameters, not
192 * bare chart16_t*[]. You can use a std::initializer_list constructor inline
193 * so that argument might look like: nsTArray<nsString> { some_nsString,
194 * PromiseFlatString(some_nsSubString_aka_nsAString),
195 * NS_ConvertUTF8toUTF16(some_nsCString_or_nsCSubString),
196 * u"some literal"_ns }. If you have anything else, like a
197 * number, you can use an nsAutoString with AppendInt/friends.
199 * @param [aFlags]
200 * The nsIScriptError flag, one of errorFlag (0x0), warningFlag (0x1),
201 * infoFlag (0x8). We default to error if omitted because usually we're
202 * logging exceptional and/or obvious breakage.
204 static void LocalizeAndReportToAllClients(
205 const nsCString& aScope, const char* aStringKey,
206 const nsTArray<nsString>& aParamArray, uint32_t aFlags = 0x0,
207 const nsString& aFilename = u""_ns, const nsString& aLine = u""_ns,
208 uint32_t aLineNumber = 0, uint32_t aColumnNumber = 0);
210 // Always consumes the error by reporting to consoles of all controlled
211 // documents.
212 void HandleError(JSContext* aCx, nsIPrincipal* aPrincipal,
213 const nsCString& aScope, const nsString& aWorkerURL,
214 const nsString& aMessage, const nsString& aFilename,
215 const nsString& aLine, uint32_t aLineNumber,
216 uint32_t aColumnNumber, uint32_t aFlags, JSExnType aExnType);
218 [[nodiscard]] RefPtr<GenericErrorResultPromise> MaybeClaimClient(
219 const ClientInfo& aClientInfo,
220 ServiceWorkerRegistrationInfo* aWorkerRegistration);
222 [[nodiscard]] RefPtr<GenericErrorResultPromise> MaybeClaimClient(
223 const ClientInfo& aClientInfo,
224 const ServiceWorkerDescriptor& aServiceWorker);
226 static already_AddRefed<ServiceWorkerManager> GetInstance();
228 void LoadRegistration(const ServiceWorkerRegistrationData& aRegistration);
230 void LoadRegistrations(
231 const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
233 void MaybeCheckNavigationUpdate(const ClientInfo& aClientInfo);
235 nsresult SendPushEvent(const nsACString& aOriginAttributes,
236 const nsACString& aScope, const nsAString& aMessageId,
237 const Maybe<nsTArray<uint8_t>>& aData);
239 void WorkerIsIdle(ServiceWorkerInfo* aWorker);
241 RefPtr<ServiceWorkerRegistrationPromise> WhenReady(
242 const ClientInfo& aClientInfo);
244 void CheckPendingReadyPromises();
246 void RemovePendingReadyPromise(const ClientInfo& aClientInfo);
248 void NoteInheritedController(const ClientInfo& aClientInfo,
249 const ServiceWorkerDescriptor& aController);
251 void BlockShutdownOn(GenericNonExclusivePromise* aPromise,
252 uint32_t aShutdownStateId);
254 nsresult GetClientRegistration(
255 const ClientInfo& aClientInfo,
256 ServiceWorkerRegistrationInfo** aRegistrationInfo);
258 int32_t GetPrincipalQuotaUsageCheckCount(nsIPrincipal* aPrincipal);
260 void CheckPrincipalQuotaUsage(nsIPrincipal* aPrincipal,
261 const nsACString& aScope);
263 // Returns the shutdown state ID (may be an invalid ID if an
264 // nsIAsyncShutdownBlocker is not used).
265 uint32_t MaybeInitServiceWorkerShutdownProgress() const;
267 void ReportServiceWorkerShutdownProgress(
268 uint32_t aShutdownStateId,
269 ServiceWorkerShutdownState::Progress aProgress) const;
271 // Record periodic telemetry on number of running ServiceWorkers. When
272 // the number of running ServiceWorkers changes (or on shutdown),
273 // ServiceWorkerPrivateImpl will call RecordTelemetry with the number of
274 // running serviceworkers and those supporting Fetch. We use
275 // mTelemetryLastChange to determine how many datapoints to inject into
276 // Telemetry, and dispatch a background runnable to call
277 // RecordTelemetryGap() and Accumulate them.
278 void RecordTelemetry(uint32_t aNumber, uint32_t aFetch);
280 void EvictFromBFCache(ServiceWorkerRegistrationInfo* aRegistration);
282 private:
283 struct RegistrationDataPerPrincipal;
285 static bool FindScopeForPath(const nsACString& aScopeKey,
286 const nsACString& aPath,
287 RegistrationDataPerPrincipal** aData,
288 nsACString& aMatch);
290 ServiceWorkerManager();
291 ~ServiceWorkerManager();
293 void Init(ServiceWorkerRegistrar* aRegistrar);
295 RefPtr<GenericErrorResultPromise> StartControllingClient(
296 const ClientInfo& aClientInfo,
297 ServiceWorkerRegistrationInfo* aRegistrationInfo,
298 bool aControlClientHandle = true);
300 void StopControllingClient(const ClientInfo& aClientInfo);
302 void MaybeStartShutdown();
304 void MaybeFinishShutdown();
306 already_AddRefed<ServiceWorkerJobQueue> GetOrCreateJobQueue(
307 const nsACString& aOriginSuffix, const nsACString& aScope);
309 void MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
311 already_AddRefed<ServiceWorkerRegistrationInfo> GetRegistration(
312 const nsACString& aScopeKey, const nsACString& aScope) const;
314 void AbortCurrentUpdate(ServiceWorkerRegistrationInfo* aRegistration);
316 nsresult Update(ServiceWorkerRegistrationInfo* aRegistration);
318 ServiceWorkerInfo* GetActiveWorkerInfoForScope(
319 const OriginAttributes& aOriginAttributes, const nsACString& aScope);
321 void StopControllingRegistration(
322 ServiceWorkerRegistrationInfo* aRegistration);
324 already_AddRefed<ServiceWorkerRegistrationInfo>
325 GetServiceWorkerRegistrationInfo(const ClientInfo& aClientInfo) const;
327 already_AddRefed<ServiceWorkerRegistrationInfo>
328 GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal,
329 nsIURI* aURI) const;
331 already_AddRefed<ServiceWorkerRegistrationInfo>
332 GetServiceWorkerRegistrationInfo(const nsACString& aScopeKey,
333 nsIURI* aURI) const;
335 // This method generates a key using isInElementBrowser from the principal. We
336 // don't use the origin because it can change during the loading.
337 static nsresult PrincipalToScopeKey(nsIPrincipal* aPrincipal,
338 nsACString& aKey);
340 static nsresult PrincipalInfoToScopeKey(
341 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, nsACString& aKey);
343 static void AddScopeAndRegistration(
344 const nsACString& aScope, ServiceWorkerRegistrationInfo* aRegistation);
346 static bool HasScope(nsIPrincipal* aPrincipal, const nsACString& aScope);
348 static void RemoveScopeAndRegistration(
349 ServiceWorkerRegistrationInfo* aRegistration);
351 void QueueFireEventOnServiceWorkerRegistrations(
352 ServiceWorkerRegistrationInfo* aRegistration, const nsAString& aName);
354 void UpdateClientControllers(ServiceWorkerRegistrationInfo* aRegistration);
356 void MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
358 void PurgeServiceWorker(const ServiceWorkerRegistrationData& aRegistration,
359 nsIPrincipal* aPrincipal);
361 RefPtr<ServiceWorkerManagerChild> mActor;
363 bool mShuttingDown;
365 nsTArray<nsCOMPtr<nsIServiceWorkerManagerListener>> mListeners;
367 void NotifyListenersOnRegister(
368 nsIServiceWorkerRegistrationInfo* aRegistration);
370 void NotifyListenersOnUnregister(
371 nsIServiceWorkerRegistrationInfo* aRegistration);
373 void NotifyListenersOnQuotaUsageCheckFinish(
374 nsIServiceWorkerRegistrationInfo* aRegistration);
376 void ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope);
378 void UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope);
380 void MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
382 nsresult SendNotificationEvent(const nsAString& aEventName,
383 const nsACString& aOriginSuffix,
384 const nsACString& aScope, const nsAString& aID,
385 const nsAString& aTitle, const nsAString& aDir,
386 const nsAString& aLang, const nsAString& aBody,
387 const nsAString& aTag, const nsAString& aIcon,
388 const nsAString& aData,
389 const nsAString& aBehavior);
391 // Used by remove() and removeAll() when clearing history.
392 // MUST ONLY BE CALLED FROM UnregisterIfMatchesHost!
393 void ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData,
394 ServiceWorkerRegistrationInfo* aRegistration);
396 // An "orphaned" registration is one that is unregistered and not controlling
397 // clients. The ServiceWorkerManager must know about all orphaned
398 // registrations to forcefully shutdown all Service Workers during browser
399 // shutdown.
400 void AddOrphanedRegistration(ServiceWorkerRegistrationInfo* aRegistration);
402 void RemoveOrphanedRegistration(ServiceWorkerRegistrationInfo* aRegistration);
404 HashSet<RefPtr<ServiceWorkerRegistrationInfo>,
405 PointerHasher<ServiceWorkerRegistrationInfo*>>
406 mOrphanedRegistrations;
408 RefPtr<ServiceWorkerShutdownBlocker> mShutdownBlocker;
410 nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal>
411 mRegistrationInfos;
413 struct ControlledClientData {
414 RefPtr<ClientHandle> mClientHandle;
415 RefPtr<ServiceWorkerRegistrationInfo> mRegistrationInfo;
417 ControlledClientData(ClientHandle* aClientHandle,
418 ServiceWorkerRegistrationInfo* aRegistrationInfo)
419 : mClientHandle(aClientHandle), mRegistrationInfo(aRegistrationInfo) {}
422 nsClassHashtable<nsIDHashKey, ControlledClientData> mControlledClients;
424 struct PendingReadyData {
425 RefPtr<ClientHandle> mClientHandle;
426 RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
428 explicit PendingReadyData(ClientHandle* aClientHandle)
429 : mClientHandle(aClientHandle),
430 mPromise(new ServiceWorkerRegistrationPromise::Private(__func__)) {}
433 nsTArray<UniquePtr<PendingReadyData>> mPendingReadyList;
435 const uint32_t mTelemetryPeriodMs = 5 * 1000;
436 TimeStamp mTelemetryLastChange;
439 } // namespace dom
440 } // namespace mozilla
442 #endif // mozilla_dom_workers_serviceworkermanager_h