ServiceWorkerManager.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef mozilla_dom_workers_serviceworkermanager_h
  6. #define mozilla_dom_workers_serviceworkermanager_h
  7. #include "nsIServiceWorkerManager.h"
  8. #include "nsCOMPtr.h"
  9. #include "ipc/IPCMessageUtils.h"
  10. #include "mozilla/Attributes.h"
  11. #include "mozilla/AutoRestore.h"
  12. #include "mozilla/ConsoleReportCollector.h"
  13. #include "mozilla/LinkedList.h"
  14. #include "mozilla/Preferences.h"
  15. #include "mozilla/TypedEnumBits.h"
  16. #include "mozilla/UniquePtr.h"
  17. #include "mozilla/WeakPtr.h"
  18. #include "mozilla/dom/BindingUtils.h"
  19. #include "mozilla/dom/Promise.h"
  20. #include "mozilla/dom/ServiceWorkerCommon.h"
  21. #include "mozilla/dom/ServiceWorkerRegistrar.h"
  22. #include "mozilla/dom/ServiceWorkerRegistrarTypes.h"
  23. #include "mozilla/dom/workers/ServiceWorkerRegistrationInfo.h"
  24. #include "mozilla/ipc/BackgroundUtils.h"
  25. #include "nsClassHashtable.h"
  26. #include "nsDataHashtable.h"
  27. #include "nsIIPCBackgroundChildCreateCallback.h"
  28. #include "nsRefPtrHashtable.h"
  29. #include "nsTArrayForwardDeclare.h"
  30. #include "nsTObserverArray.h"
  31. class mozIApplicationClearPrivateDataParams;
  32. class nsIConsoleReportCollector;
  33. namespace mozilla {
  34. class PrincipalOriginAttributes;
  35. namespace dom {
  36. class ServiceWorkerRegistrar;
  37. class ServiceWorkerRegistrationListener;
  38. namespace workers {
  39. class ServiceWorkerClientInfo;
  40. class ServiceWorkerInfo;
  41. class ServiceWorkerJobQueue;
  42. class ServiceWorkerManagerChild;
  43. class ServiceWorkerPrivate;
  44. class ServiceWorkerUpdateFinishCallback
  45. {
  46. protected:
  47. virtual ~ServiceWorkerUpdateFinishCallback()
  48. {}
  49. public:
  50. NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateFinishCallback)
  51. virtual
  52. void UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) = 0;
  53. virtual
  54. void UpdateFailed(ErrorResult& aStatus) = 0;
  55. };
  56. #define NS_SERVICEWORKERMANAGER_IMPL_IID \
  57. { /* f4f8755a-69ca-46e8-a65d-775745535990 */ \
  58. 0xf4f8755a, \
  59. 0x69ca, \
  60. 0x46e8, \
  61. { 0xa6, 0x5d, 0x77, 0x57, 0x45, 0x53, 0x59, 0x90 } \
  62. }
  63. /*
  64. * The ServiceWorkerManager is a per-process global that deals with the
  65. * installation, querying and event dispatch of ServiceWorkers for all the
  66. * origins in the process.
  67. */
  68. class ServiceWorkerManager final
  69. : public nsIServiceWorkerManager
  70. , public nsIIPCBackgroundChildCreateCallback
  71. , public nsIObserver
  72. {
  73. friend class GetReadyPromiseRunnable;
  74. friend class GetRegistrationsRunnable;
  75. friend class GetRegistrationRunnable;
  76. friend class ServiceWorkerJob;
  77. friend class ServiceWorkerRegistrationInfo;
  78. friend class ServiceWorkerUnregisterJob;
  79. friend class ServiceWorkerUpdateJob;
  80. friend class UpdateTimerCallback;
  81. public:
  82. NS_DECL_ISUPPORTS
  83. NS_DECL_NSISERVICEWORKERMANAGER
  84. NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
  85. NS_DECL_NSIOBSERVER
  86. struct RegistrationDataPerPrincipal;
  87. nsClassHashtable<nsCStringHashKey, RegistrationDataPerPrincipal> mRegistrationInfos;
  88. nsTObserverArray<ServiceWorkerRegistrationListener*> mServiceWorkerRegistrationListeners;
  89. nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments;
  90. // Track all documents that have attempted to register a service worker for a
  91. // given scope.
  92. typedef nsTArray<nsCOMPtr<nsIWeakReference>> WeakDocumentList;
  93. nsClassHashtable<nsCStringHashKey, WeakDocumentList> mRegisteringDocuments;
  94. // Track all intercepted navigation channels for a given scope. Channels are
  95. // placed in the appropriate list before dispatch the FetchEvent to the worker
  96. // thread and removed once FetchEvent processing dispatches back to the main
  97. // thread.
  98. //
  99. // Note: Its safe to use weak references here because a RAII-style callback
  100. // is registered with the channel before its added to this list. We
  101. // are guaranteed the callback will fire before and remove the ref
  102. // from this list before the channel is destroyed.
  103. typedef nsTArray<nsIInterceptedChannel*> InterceptionList;
  104. nsClassHashtable<nsCStringHashKey, InterceptionList> mNavigationInterceptions;
  105. bool
  106. IsAvailable(nsIPrincipal* aPrincipal, nsIURI* aURI);
  107. bool
  108. IsControlled(nsIDocument* aDocument, ErrorResult& aRv);
  109. // Return true if the given content process could potentially be executing
  110. // service worker code with the given principal. At the current time, this
  111. // just means that we have any registration for the origin, regardless of
  112. // scope. This is a very weak guarantee but is the best we can do when push
  113. // notifications can currently spin up a service worker in content processes
  114. // without our involvement in the parent process.
  115. //
  116. // In the future when there is only a single ServiceWorkerManager in the
  117. // parent process that is entirely in control of spawning and running service
  118. // worker code, we will be able to authoritatively indicate whether there is
  119. // an activate service worker in the given content process. At that time we
  120. // will rename this method HasActiveServiceWorkerInstance and provide
  121. // semantics that ensure this method returns true until the worker is known to
  122. // have shut down in order to allow the caller to induce a crash for security
  123. // reasons without having to worry about shutdown races with the worker.
  124. bool
  125. MayHaveActiveServiceWorkerInstance(ContentParent* aContent,
  126. nsIPrincipal* aPrincipal);
  127. void
  128. DispatchFetchEvent(const PrincipalOriginAttributes& aOriginAttributes,
  129. nsIDocument* aDoc,
  130. const nsAString& aDocumentIdForTopLevelNavigation,
  131. nsIInterceptedChannel* aChannel,
  132. bool aIsReload,
  133. bool aIsSubresourceLoad,
  134. ErrorResult& aRv);
  135. void
  136. Update(nsIPrincipal* aPrincipal,
  137. const nsACString& aScope,
  138. ServiceWorkerUpdateFinishCallback* aCallback);
  139. void
  140. SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes,
  141. const nsACString& aScope);
  142. void
  143. PropagateSoftUpdate(const PrincipalOriginAttributes& aOriginAttributes,
  144. const nsAString& aScope);
  145. void
  146. PropagateRemove(const nsACString& aHost);
  147. void
  148. Remove(const nsACString& aHost);
  149. void
  150. PropagateRemoveAll();
  151. void
  152. RemoveAll();
  153. already_AddRefed<ServiceWorkerRegistrationInfo>
  154. GetRegistration(nsIPrincipal* aPrincipal, const nsACString& aScope) const;
  155. already_AddRefed<ServiceWorkerRegistrationInfo>
  156. CreateNewRegistration(const nsCString& aScope, nsIPrincipal* aPrincipal);
  157. void
  158. RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
  159. void StoreRegistration(nsIPrincipal* aPrincipal,
  160. ServiceWorkerRegistrationInfo* aRegistration);
  161. void
  162. FinishFetch(ServiceWorkerRegistrationInfo* aRegistration);
  163. /**
  164. * Report an error for the given scope to any window we think might be
  165. * interested, failing over to the Browser Console if we couldn't find any.
  166. *
  167. * Error messages should be localized, so you probably want to call
  168. * LocalizeAndReportToAllClients instead, which in turn calls us after
  169. * localizing the error.
  170. */
  171. void
  172. ReportToAllClients(const nsCString& aScope,
  173. const nsString& aMessage,
  174. const nsString& aFilename,
  175. const nsString& aLine,
  176. uint32_t aLineNumber,
  177. uint32_t aColumnNumber,
  178. uint32_t aFlags);
  179. /**
  180. * Report a localized error for the given scope to any window we think might
  181. * be interested.
  182. *
  183. * Note that this method takes an nsTArray<nsString> for the parameters, not
  184. * bare chart16_t*[]. You can use a std::initializer_list constructor inline
  185. * so that argument might look like: nsTArray<nsString> { some_nsString,
  186. * PromiseFlatString(some_nsSubString_aka_nsAString),
  187. * NS_ConvertUTF8toUTF16(some_nsCString_or_nsCSubString),
  188. * NS_LITERAL_STRING("some literal") }. If you have anything else, like a
  189. * number, you can use an nsAutoString with AppendInt/friends.
  190. *
  191. * @param [aFlags]
  192. * The nsIScriptError flag, one of errorFlag (0x0), warningFlag (0x1),
  193. * infoFlag (0x8). We default to error if omitted because usually we're
  194. * logging exceptional and/or obvious breakage.
  195. */
  196. static void
  197. LocalizeAndReportToAllClients(const nsCString& aScope,
  198. const char* aStringKey,
  199. const nsTArray<nsString>& aParamArray,
  200. uint32_t aFlags = 0x0,
  201. const nsString& aFilename = EmptyString(),
  202. const nsString& aLine = EmptyString(),
  203. uint32_t aLineNumber = 0,
  204. uint32_t aColumnNumber = 0);
  205. void
  206. FlushReportsToAllClients(const nsACString& aScope,
  207. nsIConsoleReportCollector* aReporter);
  208. // Always consumes the error by reporting to consoles of all controlled
  209. // documents.
  210. void
  211. HandleError(JSContext* aCx,
  212. nsIPrincipal* aPrincipal,
  213. const nsCString& aScope,
  214. const nsString& aWorkerURL,
  215. const nsString& aMessage,
  216. const nsString& aFilename,
  217. const nsString& aLine,
  218. uint32_t aLineNumber,
  219. uint32_t aColumnNumber,
  220. uint32_t aFlags,
  221. JSExnType aExnType);
  222. UniquePtr<ServiceWorkerClientInfo>
  223. GetClient(nsIPrincipal* aPrincipal,
  224. const nsAString& aClientId,
  225. ErrorResult& aRv);
  226. void
  227. GetAllClients(nsIPrincipal* aPrincipal,
  228. const nsCString& aScope,
  229. bool aIncludeUncontrolled,
  230. nsTArray<ServiceWorkerClientInfo>& aDocuments);
  231. void
  232. MaybeClaimClient(nsIDocument* aDocument,
  233. ServiceWorkerRegistrationInfo* aWorkerRegistration);
  234. nsresult
  235. ClaimClients(nsIPrincipal* aPrincipal, const nsCString& aScope, uint64_t aId);
  236. void
  237. SetSkipWaitingFlag(nsIPrincipal* aPrincipal, const nsCString& aScope,
  238. uint64_t aServiceWorkerID);
  239. static already_AddRefed<ServiceWorkerManager>
  240. GetInstance();
  241. void
  242. LoadRegistration(const ServiceWorkerRegistrationData& aRegistration);
  243. void
  244. LoadRegistrations(const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
  245. // Used by remove() and removeAll() when clearing history.
  246. // MUST ONLY BE CALLED FROM UnregisterIfMatchesHost!
  247. void
  248. ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData,
  249. ServiceWorkerRegistrationInfo* aRegistration);
  250. NS_IMETHOD
  251. AddRegistrationEventListener(const nsAString& aScope,
  252. ServiceWorkerRegistrationListener* aListener);
  253. NS_IMETHOD
  254. RemoveRegistrationEventListener(const nsAString& aScope,
  255. ServiceWorkerRegistrationListener* aListener);
  256. void
  257. MaybeCheckNavigationUpdate(nsIDocument* aDoc);
  258. nsresult
  259. SendPushEvent(const nsACString& aOriginAttributes,
  260. const nsACString& aScope,
  261. const nsAString& aMessageId,
  262. const Maybe<nsTArray<uint8_t>>& aData);
  263. nsresult
  264. NotifyUnregister(nsIPrincipal* aPrincipal, const nsAString& aScope);
  265. void
  266. WorkerIsIdle(ServiceWorkerInfo* aWorker);
  267. private:
  268. ServiceWorkerManager();
  269. ~ServiceWorkerManager();
  270. void
  271. Init(ServiceWorkerRegistrar* aRegistrar);
  272. void
  273. MaybeStartShutdown();
  274. already_AddRefed<ServiceWorkerJobQueue>
  275. GetOrCreateJobQueue(const nsACString& aOriginSuffix,
  276. const nsACString& aScope);
  277. void
  278. MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
  279. already_AddRefed<ServiceWorkerRegistrationInfo>
  280. GetRegistration(const nsACString& aScopeKey,
  281. const nsACString& aScope) const;
  282. void
  283. AbortCurrentUpdate(ServiceWorkerRegistrationInfo* aRegistration);
  284. nsresult
  285. Update(ServiceWorkerRegistrationInfo* aRegistration);
  286. nsresult
  287. GetDocumentRegistration(nsIDocument* aDoc,
  288. ServiceWorkerRegistrationInfo** aRegistrationInfo);
  289. nsresult
  290. GetServiceWorkerForScope(nsPIDOMWindowInner* aWindow,
  291. const nsAString& aScope,
  292. WhichServiceWorker aWhichWorker,
  293. nsISupports** aServiceWorker);
  294. ServiceWorkerInfo*
  295. GetActiveWorkerInfoForScope(const PrincipalOriginAttributes& aOriginAttributes,
  296. const nsACString& aScope);
  297. ServiceWorkerInfo*
  298. GetActiveWorkerInfoForDocument(nsIDocument* aDocument);
  299. void
  300. InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
  301. WhichServiceWorker aWhichOnes);
  302. void
  303. NotifyServiceWorkerRegistrationRemoved(ServiceWorkerRegistrationInfo* aRegistration);
  304. void
  305. StartControllingADocument(ServiceWorkerRegistrationInfo* aRegistration,
  306. nsIDocument* aDoc,
  307. const nsAString& aDocumentId);
  308. void
  309. StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration);
  310. already_AddRefed<ServiceWorkerRegistrationInfo>
  311. GetServiceWorkerRegistrationInfo(nsPIDOMWindowInner* aWindow);
  312. already_AddRefed<ServiceWorkerRegistrationInfo>
  313. GetServiceWorkerRegistrationInfo(nsIDocument* aDoc);
  314. already_AddRefed<ServiceWorkerRegistrationInfo>
  315. GetServiceWorkerRegistrationInfo(nsIPrincipal* aPrincipal, nsIURI* aURI);
  316. already_AddRefed<ServiceWorkerRegistrationInfo>
  317. GetServiceWorkerRegistrationInfo(const nsACString& aScopeKey,
  318. nsIURI* aURI);
  319. // This method generates a key using appId and isInElementBrowser from the
  320. // principal. We don't use the origin because it can change during the
  321. // loading.
  322. static nsresult
  323. PrincipalToScopeKey(nsIPrincipal* aPrincipal, nsACString& aKey);
  324. static void
  325. AddScopeAndRegistration(const nsACString& aScope,
  326. ServiceWorkerRegistrationInfo* aRegistation);
  327. static bool
  328. FindScopeForPath(const nsACString& aScopeKey,
  329. const nsACString& aPath,
  330. RegistrationDataPerPrincipal** aData, nsACString& aMatch);
  331. static bool
  332. HasScope(nsIPrincipal* aPrincipal, const nsACString& aScope);
  333. static void
  334. RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration);
  335. void
  336. QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
  337. const nsAString& aName);
  338. void
  339. FireUpdateFoundOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration);
  340. void
  341. FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);
  342. void
  343. StorePendingReadyPromise(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
  344. Promise* aPromise);
  345. void
  346. CheckPendingReadyPromises();
  347. bool
  348. CheckReadyPromise(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
  349. Promise* aPromise);
  350. struct PendingReadyPromise final
  351. {
  352. PendingReadyPromise(nsIURI* aURI, Promise* aPromise)
  353. : mURI(aURI), mPromise(aPromise)
  354. {}
  355. nsCOMPtr<nsIURI> mURI;
  356. RefPtr<Promise> mPromise;
  357. };
  358. void AppendPendingOperation(nsIRunnable* aRunnable);
  359. bool HasBackgroundActor() const
  360. {
  361. return !!mActor;
  362. }
  363. nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
  364. void
  365. MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
  366. // Removes all service worker registrations that matches the given pattern.
  367. void
  368. RemoveAllRegistrations(OriginAttributesPattern* aPattern);
  369. RefPtr<ServiceWorkerManagerChild> mActor;
  370. nsTArray<nsCOMPtr<nsIRunnable>> mPendingOperations;
  371. bool mShuttingDown;
  372. nsTArray<nsCOMPtr<nsIServiceWorkerManagerListener>> mListeners;
  373. void
  374. NotifyListenersOnRegister(nsIServiceWorkerRegistrationInfo* aRegistration);
  375. void
  376. NotifyListenersOnUnregister(nsIServiceWorkerRegistrationInfo* aRegistration);
  377. void
  378. AddRegisteringDocument(const nsACString& aScope, nsIDocument* aDoc);
  379. class InterceptionReleaseHandle;
  380. void
  381. AddNavigationInterception(const nsACString& aScope,
  382. nsIInterceptedChannel* aChannel);
  383. void
  384. RemoveNavigationInterception(const nsACString& aScope,
  385. nsIInterceptedChannel* aChannel);
  386. void
  387. ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope);
  388. void
  389. UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope);
  390. void
  391. MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
  392. nsresult
  393. SendNotificationEvent(const nsAString& aEventName,
  394. const nsACString& aOriginSuffix,
  395. const nsACString& aScope,
  396. const nsAString& aID,
  397. const nsAString& aTitle,
  398. const nsAString& aDir,
  399. const nsAString& aLang,
  400. const nsAString& aBody,
  401. const nsAString& aTag,
  402. const nsAString& aIcon,
  403. const nsAString& aData,
  404. const nsAString& aBehavior);
  405. };
  406. } // namespace workers
  407. } // namespace dom
  408. } // namespace mozilla
  409. #endif // mozilla_dom_workers_serviceworkermanager_h