Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/serviceworkers/ServiceWorkerManager.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef mozilla_dom_workers_serviceworkermanager_h
8
#define mozilla_dom_workers_serviceworkermanager_h
9
10
#include "nsIServiceWorkerManager.h"
11
#include "nsCOMPtr.h"
12
13
#include "ipc/IPCMessageUtils.h"
14
#include "mozilla/Attributes.h"
15
#include "mozilla/AutoRestore.h"
16
#include "mozilla/ConsoleReportCollector.h"
17
#include "mozilla/LinkedList.h"
18
#include "mozilla/MozPromise.h"
19
#include "mozilla/Preferences.h"
20
#include "mozilla/TypedEnumBits.h"
21
#include "mozilla/UniquePtr.h"
22
#include "mozilla/WeakPtr.h"
23
#include "mozilla/dom/BindingUtils.h"
24
#include "mozilla/dom/ClientHandle.h"
25
#include "mozilla/dom/Promise.h"
26
#include "mozilla/dom/ServiceWorkerRegistrar.h"
27
#include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
28
#include "mozilla/dom/ServiceWorkerRegistrationInfo.h"
29
#include "mozilla/dom/ServiceWorkerUtils.h"
30
#include "mozilla/ipc/BackgroundUtils.h"
31
#include "nsClassHashtable.h"
32
#include "nsDataHashtable.h"
33
#include "nsRefPtrHashtable.h"
34
#include "nsTArrayForwardDeclare.h"
35
36
class nsIConsoleReportCollector;
37
38
namespace mozilla {
39
40
class OriginAttributes;
41
42
namespace ipc {
43
class PrincipalInfo;
44
} // namespace ipc
45
46
namespace dom {
47
48
class ServiceWorkerInfo;
49
class ServiceWorkerJobQueue;
50
class ServiceWorkerManagerChild;
51
class ServiceWorkerPrivate;
52
class ServiceWorkerRegistrar;
53
54
class ServiceWorkerUpdateFinishCallback
55
{
56
protected:
57
  virtual ~ServiceWorkerUpdateFinishCallback()
58
0
  {}
59
60
public:
61
  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
62
63
  virtual
64
  void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) = 0;
65
66
  virtual
67
  void UpdateFailed(ErrorResult& aStatus) = 0;
68
};
69
70
#define NS_SERVICEWORKERMANAGER_IMPL_IID                 \
71
{ /* f4f8755a-69ca-46e8-a65d-775745535990 */             \
72
  0xf4f8755a,                                            \
73
  0x69ca,                                                \
74
  0x46e8,                                                \
75
  { 0xa6, 0x5d, 0x77, 0x57, 0x45, 0x53, 0x59, 0x90 }     \
76
}
77
78
/*
79
 * The ServiceWorkerManager is a per-process global that deals with the
80
 * installation, querying and event dispatch of ServiceWorkers for all the
81
 * origins in the process.
82
 */
83
class ServiceWorkerManager final
84
  : public nsIServiceWorkerManager
85
  , public nsIObserver
86
{
87
  friend class GetRegistrationsRunnable;
88
  friend class GetRegistrationRunnable;
89
  friend class ServiceWorkerJob;
90
  friend class ServiceWorkerRegistrationInfo;
91
  friend class ServiceWorkerUnregisterJob;
92
  friend class ServiceWorkerUpdateJob;
93
  friend class UpdateTimerCallback;
94
95
public:
96
  NS_DECL_ISUPPORTS
97
  NS_DECL_NSISERVICEWORKERMANAGER
98
  NS_DECL_NSIOBSERVER
99
100
  struct RegistrationDataPerPrincipal;
101
  nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal> mRegistrationInfos;
102
103
  struct ControlledClientData
104
  {
105
    RefPtr<ClientHandle> mClientHandle;
106
    RefPtr<ServiceWorkerRegistrationInfo> mRegistrationInfo;
107
108
    ControlledClientData(ClientHandle* aClientHandle,
109
                         ServiceWorkerRegistrationInfo* aRegistrationInfo)
110
      : mClientHandle(aClientHandle)
111
      , mRegistrationInfo(aRegistrationInfo)
112
0
    {
113
0
    }
114
  };
115
116
  nsClassHashtable<nsIDHashKey, ControlledClientData> mControlledClients;
117
118
  struct PendingReadyData
119
  {
120
    RefPtr<ClientHandle> mClientHandle;
121
    RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
122
123
    explicit PendingReadyData(ClientHandle* aClientHandle)
124
      : mClientHandle(aClientHandle)
125
      , mPromise(new ServiceWorkerRegistrationPromise::Private(__func__))
126
0
    { }
127
  };
128
129
  nsTArray<UniquePtr<PendingReadyData>> mPendingReadyList;
130
131
  bool
132
  IsAvailable(nsIPrincipal* aPrincipal, nsIURI* aURI);
133
134
  // Return true if the given content process could potentially be executing
135
  // service worker code with the given principal.  At the current time, this
136
  // just means that we have any registration for the origin, regardless of
137
  // scope.  This is a very weak guarantee but is the best we can do when push
138
  // notifications can currently spin up a service worker in content processes
139
  // without our involvement in the parent process.
140
  //
141
  // In the future when there is only a single ServiceWorkerManager in the
142
  // parent process that is entirely in control of spawning and running service
143
  // worker code, we will be able to authoritatively indicate whether there is
144
  // an activate service worker in the given content process.  At that time we
145
  // will rename this method HasActiveServiceWorkerInstance and provide
146
  // semantics that ensure this method returns true until the worker is known to
147
  // have shut down in order to allow the caller to induce a crash for security
148
  // reasons without having to worry about shutdown races with the worker.
149
  bool
150
  MayHaveActiveServiceWorkerInstance(ContentParent* aContent,
151
                                     nsIPrincipal* aPrincipal);
152
153
  void
154
  DispatchFetchEvent(nsIInterceptedChannel* aChannel, ErrorResult& aRv);
155
156
  void
157
  Update(nsIPrincipal* aPrincipal,
158
         const nsACString& aScope,
159
         ServiceWorkerUpdateFinishCallback* aCallback);
160
161
  void
162
  UpdateInternal(nsIPrincipal* aPrincipal,
163
                 const nsACString& aScope,
164
                 ServiceWorkerUpdateFinishCallback* aCallback);
165
166
  void
167
  SoftUpdate(const OriginAttributes& aOriginAttributes,
168
             const nsACString& aScope);
169
170
  void
171
  SoftUpdateInternal(const OriginAttributes& aOriginAttributes,
172
                     const nsACString& aScope,
173
                     ServiceWorkerUpdateFinishCallback* aCallback);
174
175
176
  void
177
  PropagateSoftUpdate(const OriginAttributes& aOriginAttributes,
178
                      const nsAString& aScope);
179
180
  void
181
  PropagateRemove(const nsACString& aHost);
182
183
  void
184
  Remove(const nsACString& aHost);
185
186
  void
187
  PropagateRemoveAll();
188
189
  void
190
  RemoveAll();
191
192
  RefPtr<ServiceWorkerRegistrationPromise>
193
  Register(const ClientInfo& aClientInfo, const nsACString& aScopeURL,
194
           const nsACString& aScriptURL,
195
           ServiceWorkerUpdateViaCache aUpdateViaCache);
196
197
  RefPtr<ServiceWorkerRegistrationPromise>
198
  GetRegistration(const ClientInfo& aClientInfo, const nsACString& aURL) const;
199
200
  RefPtr<ServiceWorkerRegistrationListPromise>
201
  GetRegistrations(const ClientInfo& aClientInfo) const;
202
203
  already_AddRefed<ServiceWorkerRegistrationInfo>
204
  GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const;
205
206
  already_AddRefed<ServiceWorkerRegistrationInfo>
207
  GetRegistration(const mozilla::ipc::PrincipalInfo& aPrincipal,
208
                  const nsACString& aScope) const;
209
210
  already_AddRefed<ServiceWorkerRegistrationInfo>
211
  CreateNewRegistration(const nsCString& aScope,
212
                        nsIPrincipal* aPrincipal,
213
                        ServiceWorkerUpdateViaCache aUpdateViaCache);
214
215
  void
216
  RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
217
218
  void StoreRegistration(nsIPrincipal* aPrincipal,
219
                         ServiceWorkerRegistrationInfo* aRegistration);
220
221
  void
222
  FinishFetch(ServiceWorkerRegistrationInfo* aRegistration);
223
224
  /**
225
   * Report an error for the given scope to any window we think might be
226
   * interested, failing over to the Browser Console if we couldn't find any.
227
   *
228
   * Error messages should be localized, so you probably want to call
229
   * LocalizeAndReportToAllClients instead, which in turn calls us after
230
   * localizing the error.
231
   */
232
  void
233
  ReportToAllClients(const nsCString& aScope,
234
                     const nsString& aMessage,
235
                     const nsString& aFilename,
236
                     const nsString& aLine,
237
                     uint32_t aLineNumber,
238
                     uint32_t aColumnNumber,
239
                     uint32_t aFlags);
240
241
  /**
242
   * Report a localized error for the given scope to any window we think might
243
   * be interested.
244
   *
245
   * Note that this method takes an nsTArray<nsString> for the parameters, not
246
   * bare chart16_t*[].  You can use a std::initializer_list constructor inline
247
   * so that argument might look like: nsTArray<nsString> { some_nsString,
248
   * PromiseFlatString(some_nsSubString_aka_nsAString),
249
   * NS_ConvertUTF8toUTF16(some_nsCString_or_nsCSubString),
250
   * NS_LITERAL_STRING("some literal") }.  If you have anything else, like a
251
   * number, you can use an nsAutoString with AppendInt/friends.
252
   *
253
   * @param [aFlags]
254
   *   The nsIScriptError flag, one of errorFlag (0x0), warningFlag (0x1),
255
   *   infoFlag (0x8).  We default to error if omitted because usually we're
256
   *   logging exceptional and/or obvious breakage.
257
   */
258
  static void
259
  LocalizeAndReportToAllClients(const nsCString& aScope,
260
                                const char* aStringKey,
261
                                const nsTArray<nsString>& aParamArray,
262
                                uint32_t aFlags = 0x0,
263
                                const nsString& aFilename = EmptyString(),
264
                                const nsString& aLine = EmptyString(),
265
                                uint32_t aLineNumber = 0,
266
                                uint32_t aColumnNumber = 0);
267
268
  // Always consumes the error by reporting to consoles of all controlled
269
  // documents.
270
  void
271
  HandleError(JSContext* aCx,
272
              nsIPrincipal* aPrincipal,
273
              const nsCString& aScope,
274
              const nsString& aWorkerURL,
275
              const nsString& aMessage,
276
              const nsString& aFilename,
277
              const nsString& aLine,
278
              uint32_t aLineNumber,
279
              uint32_t aColumnNumber,
280
              uint32_t aFlags,
281
              JSExnType aExnType);
282
283
  already_AddRefed<GenericPromise>
284
  MaybeClaimClient(const ClientInfo& aClientInfo,
285
                   ServiceWorkerRegistrationInfo* aWorkerRegistration);
286
287
  already_AddRefed<GenericPromise>
288
  MaybeClaimClient(const ClientInfo& aClientInfo,
289
                   const ServiceWorkerDescriptor& aServiceWorker);
290
291
  void
292
  SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope,
293
                     uint64_t aServiceWorkerID);
294
295
  static already_AddRefed<ServiceWorkerManager>
296
  GetInstance();
297
298
  void
299
  LoadRegistration(const ServiceWorkerRegistrationData& aRegistration);
300
301
  void
302
  LoadRegistrations(const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
303
304
  // Used by remove() and removeAll() when clearing history.
305
  // MUST ONLY BE CALLED FROM UnregisterIfMatchesHost!
306
  void
307
  ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData,
308
                  ServiceWorkerRegistrationInfo* aRegistration);
309
310
  void
311
  MaybeCheckNavigationUpdate(const ClientInfo& aClientInfo);
312
313
  nsresult
314
  SendPushEvent(const nsACString& aOriginAttributes,
315
                const nsACString& aScope,
316
                const nsAString& aMessageId,
317
                const Maybe<nsTArray<uint8_t>>& aData);
318
319
  nsresult
320
  NotifyUnregister(nsIPrincipal* aPrincipal, const nsAString& aScope);
321
322
  void
323
  WorkerIsIdle(ServiceWorkerInfo* aWorker);
324
325
  RefPtr<ServiceWorkerRegistrationPromise>
326
  WhenReady(const ClientInfo& aClientInfo);
327
328
  void
329
  CheckPendingReadyPromises();
330
331
  void
332
  RemovePendingReadyPromise(const ClientInfo& aClientInfo);
333
334
  void
335
  NoteInheritedController(const ClientInfo& aClientInfo,
336
                          const ServiceWorkerDescriptor& aController);
337
338
private:
339
  ServiceWorkerManager();
340
  ~ServiceWorkerManager();
341
342
  void
343
  Init(ServiceWorkerRegistrar* aRegistrar);
344
345
  RefPtr<GenericPromise>
346
  StartControllingClient(const ClientInfo& aClientInfo,
347
                         ServiceWorkerRegistrationInfo* aRegistrationInfo,
348
                         bool aControlClientHandle = true);
349
350
  void
351
  StopControllingClient(const ClientInfo& aClientInfo);
352
353
  void
354
  MaybeStartShutdown();
355
356
  already_AddRefed<ServiceWorkerJobQueue>
357
  GetOrCreateJobQueue(const nsACString& aOriginSuffix,
358
                      const nsACString& aScope);
359
360
  void
361
  MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
362
363
  already_AddRefed<ServiceWorkerRegistrationInfo>
364
  GetRegistration(const nsACString& aScopeKey,
365
                  const nsACString& aScope) const;
366
367
  void
368
  AbortCurrentUpdate(ServiceWorkerRegistrationInfo* aRegistration);
369
370
  nsresult
371
  Update(ServiceWorkerRegistrationInfo* aRegistration);
372
373
  nsresult
374
  GetClientRegistration(const ClientInfo& aClientInfo,
375
                        ServiceWorkerRegistrationInfo** aRegistrationInfo);
376
377
  ServiceWorkerInfo*
378
  GetActiveWorkerInfoForScope(const OriginAttributes& aOriginAttributes,
379
                              const nsACString& aScope);
380
381
  void
382
  StopControllingRegistration(ServiceWorkerRegistrationInfo* aRegistration);
383
384
  already_AddRefed<ServiceWorkerRegistrationInfo>
385
  GetServiceWorkerRegistrationInfo(const ClientInfo& aClientInfo) const;
386
387
  already_AddRefed<ServiceWorkerRegistrationInfo>
388
  GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal, nsIURI* aURI) const;
389
390
  already_AddRefed<ServiceWorkerRegistrationInfo>
391
  GetServiceWorkerRegistrationInfo(const nsACString& aScopeKey,
392
                                   nsIURI* aURI) const;
393
394
  // This method generates a key using appId and isInElementBrowser from the
395
  // principal. We don't use the origin because it can change during the
396
  // loading.
397
  static nsresult
398
  PrincipalToScopeKey(nsIPrincipal* aPrincipal, nsACString& aKey);
399
400
  static nsresult
401
  PrincipalInfoToScopeKey(const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
402
                          nsACString& aKey);
403
404
  static void
405
  AddScopeAndRegistration(const nsACString& aScope,
406
                          ServiceWorkerRegistrationInfo* aRegistation);
407
408
  static bool
409
  FindScopeForPath(const nsACString& aScopeKey,
410
                   const nsACString& aPath,
411
                   RegistrationDataPerPrincipal** aData, nsACString& aMatch);
412
413
  static bool
414
  HasScope(nsIPrincipal* aPrincipal, const nsACString& aScope);
415
416
  static void
417
  RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration);
418
419
  void
420
  QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
421
                                             const nsAString& aName);
422
423
  void
424
  UpdateClientControllers(ServiceWorkerRegistrationInfo* aRegistration);
425
426
  void
427
  MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
428
429
  // Removes all service worker registrations that matches the given pattern.
430
  void
431
  RemoveAllRegistrations(OriginAttributesPattern* aPattern);
432
433
  RefPtr<ServiceWorkerManagerChild> mActor;
434
435
  bool mShuttingDown;
436
437
  nsTArray<nsCOMPtr<nsIServiceWorkerManagerListener>> mListeners;
438
439
  void
440
  NotifyListenersOnRegister(nsIServiceWorkerRegistrationInfo* aRegistration);
441
442
  void
443
  NotifyListenersOnUnregister(nsIServiceWorkerRegistrationInfo* aRegistration);
444
445
  void
446
  ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope);
447
448
  void
449
  UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope);
450
451
  void
452
  MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
453
454
  nsresult
455
  SendNotificationEvent(const nsAString& aEventName,
456
                        const nsACString& aOriginSuffix,
457
                        const nsACString& aScope,
458
                        const nsAString& aID,
459
                        const nsAString& aTitle,
460
                        const nsAString& aDir,
461
                        const nsAString& aLang,
462
                        const nsAString& aBody,
463
                        const nsAString& aTag,
464
                        const nsAString& aIcon,
465
                        const nsAString& aData,
466
                        const nsAString& aBehavior);
467
};
468
469
} // namespace dom
470
} // namespace mozilla
471
472
#endif // mozilla_dom_workers_serviceworkermanager_h