ServiceWorkerPrivate.cpp 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126
  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. #include "ServiceWorkerPrivate.h"
  6. #include "ServiceWorkerManager.h"
  7. #include "nsContentUtils.h"
  8. #include "nsIHttpChannelInternal.h"
  9. #include "nsIHttpHeaderVisitor.h"
  10. #include "nsINetworkInterceptController.h"
  11. #include "nsIPushErrorReporter.h"
  12. #include "nsISupportsImpl.h"
  13. #include "nsITimedChannel.h"
  14. #include "nsIUploadChannel2.h"
  15. #include "nsNetUtil.h"
  16. #include "nsProxyRelease.h"
  17. #include "nsQueryObject.h"
  18. #include "nsStreamUtils.h"
  19. #include "nsStringStream.h"
  20. #include "WorkerRunnable.h"
  21. #include "WorkerScope.h"
  22. #include "mozilla/Assertions.h"
  23. #include "mozilla/dom/FetchUtil.h"
  24. #include "mozilla/dom/IndexedDatabaseManager.h"
  25. #include "mozilla/dom/InternalHeaders.h"
  26. #include "mozilla/dom/NotificationEvent.h"
  27. #include "mozilla/dom/PromiseNativeHandler.h"
  28. #include "mozilla/dom/PushEventBinding.h"
  29. #include "mozilla/dom/RequestBinding.h"
  30. #include "mozilla/Unused.h"
  31. using namespace mozilla;
  32. using namespace mozilla::dom;
  33. BEGIN_WORKERS_NAMESPACE
  34. NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerPrivate)
  35. NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerPrivate)
  36. NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
  37. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerPrivate)
  38. NS_INTERFACE_MAP_ENTRY(nsISupports)
  39. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
  40. NS_INTERFACE_MAP_END
  41. // Tracks the "dom.disable_open_click_delay" preference. Modified on main
  42. // thread, read on worker threads.
  43. // It is updated every time a "notificationclick" event is dispatched. While
  44. // this is done without synchronization, at the worst, the thread will just get
  45. // an older value within which a popup is allowed to be displayed, which will
  46. // still be a valid value since it was set prior to dispatching the runnable.
  47. Atomic<uint32_t> gDOMDisableOpenClickDelay(0);
  48. // Used to keep track of pending waitUntil as well as in-flight extendable events.
  49. // When the last token is released, we attempt to terminate the worker.
  50. class KeepAliveToken final : public nsISupports
  51. {
  52. public:
  53. NS_DECL_ISUPPORTS
  54. explicit KeepAliveToken(ServiceWorkerPrivate* aPrivate)
  55. : mPrivate(aPrivate)
  56. {
  57. AssertIsOnMainThread();
  58. MOZ_ASSERT(aPrivate);
  59. mPrivate->AddToken();
  60. }
  61. private:
  62. ~KeepAliveToken()
  63. {
  64. AssertIsOnMainThread();
  65. mPrivate->ReleaseToken();
  66. }
  67. RefPtr<ServiceWorkerPrivate> mPrivate;
  68. };
  69. NS_IMPL_ISUPPORTS0(KeepAliveToken)
  70. ServiceWorkerPrivate::ServiceWorkerPrivate(ServiceWorkerInfo* aInfo)
  71. : mInfo(aInfo)
  72. , mDebuggerCount(0)
  73. , mTokenCount(0)
  74. {
  75. AssertIsOnMainThread();
  76. MOZ_ASSERT(aInfo);
  77. mIdleWorkerTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  78. MOZ_ASSERT(mIdleWorkerTimer);
  79. }
  80. ServiceWorkerPrivate::~ServiceWorkerPrivate()
  81. {
  82. MOZ_ASSERT(!mWorkerPrivate);
  83. MOZ_ASSERT(!mTokenCount);
  84. MOZ_ASSERT(!mInfo);
  85. MOZ_ASSERT(mSupportsArray.IsEmpty());
  86. mIdleWorkerTimer->Cancel();
  87. }
  88. namespace {
  89. class MessageWaitUntilHandler final : public PromiseNativeHandler
  90. {
  91. nsMainThreadPtrHandle<nsISupports> mKeepAliveToken;
  92. ~MessageWaitUntilHandler()
  93. {
  94. }
  95. public:
  96. explicit MessageWaitUntilHandler(const nsMainThreadPtrHandle<nsISupports>& aKeepAliveToken)
  97. : mKeepAliveToken(aKeepAliveToken)
  98. {
  99. MOZ_ASSERT(mKeepAliveToken);
  100. }
  101. void
  102. ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  103. {
  104. mKeepAliveToken = nullptr;
  105. }
  106. void
  107. RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  108. {
  109. mKeepAliveToken = nullptr;
  110. }
  111. NS_DECL_THREADSAFE_ISUPPORTS
  112. };
  113. NS_IMPL_ISUPPORTS0(MessageWaitUntilHandler)
  114. } // anonymous namespace
  115. nsresult
  116. ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
  117. JS::Handle<JS::Value> aMessage,
  118. const Optional<Sequence<JS::Value>>& aTransferable,
  119. UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
  120. {
  121. ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent, nullptr));
  122. if (NS_WARN_IF(rv.Failed())) {
  123. return rv.StealNSResult();
  124. }
  125. nsMainThreadPtrHandle<nsISupports> token(
  126. new nsMainThreadPtrHolder<nsISupports>(CreateEventKeepAliveToken()));
  127. RefPtr<PromiseNativeHandler> handler = new MessageWaitUntilHandler(token);
  128. mWorkerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
  129. Move(aClientInfo), handler,
  130. rv);
  131. return rv.StealNSResult();
  132. }
  133. namespace {
  134. class CheckScriptEvaluationWithCallback final : public WorkerRunnable
  135. {
  136. nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
  137. RefPtr<LifeCycleEventCallback> mCallback;
  138. #ifdef DEBUG
  139. bool mDone;
  140. #endif
  141. public:
  142. CheckScriptEvaluationWithCallback(WorkerPrivate* aWorkerPrivate,
  143. KeepAliveToken* aKeepAliveToken,
  144. LifeCycleEventCallback* aCallback)
  145. : WorkerRunnable(aWorkerPrivate)
  146. , mKeepAliveToken(new nsMainThreadPtrHolder<KeepAliveToken>(aKeepAliveToken))
  147. , mCallback(aCallback)
  148. #ifdef DEBUG
  149. , mDone(false)
  150. #endif
  151. {
  152. AssertIsOnMainThread();
  153. }
  154. ~CheckScriptEvaluationWithCallback()
  155. {
  156. MOZ_ASSERT(mDone);
  157. }
  158. bool
  159. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  160. {
  161. aWorkerPrivate->AssertIsOnWorkerThread();
  162. Done(aWorkerPrivate->WorkerScriptExecutedSuccessfully());
  163. return true;
  164. }
  165. nsresult
  166. Cancel() override
  167. {
  168. Done(false);
  169. return WorkerRunnable::Cancel();
  170. }
  171. private:
  172. void
  173. Done(bool aResult)
  174. {
  175. #ifdef DEBUG
  176. mDone = true;
  177. #endif
  178. mCallback->SetResult(aResult);
  179. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback));
  180. }
  181. };
  182. } // anonymous namespace
  183. nsresult
  184. ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback)
  185. {
  186. nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, nullptr);
  187. NS_ENSURE_SUCCESS(rv, rv);
  188. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  189. RefPtr<WorkerRunnable> r = new CheckScriptEvaluationWithCallback(mWorkerPrivate,
  190. token,
  191. aCallback);
  192. if (NS_WARN_IF(!r->Dispatch())) {
  193. return NS_ERROR_FAILURE;
  194. }
  195. return NS_OK;
  196. }
  197. namespace {
  198. // Holds the worker alive until the waitUntil promise is resolved or
  199. // rejected.
  200. class KeepAliveHandler final
  201. {
  202. // Use an internal class to listen for the promise resolve/reject
  203. // callbacks. This class also registers a feature so that it can
  204. // preemptively cleanup if the service worker is timed out and
  205. // terminated.
  206. class InternalHandler final : public PromiseNativeHandler
  207. , public WorkerHolder
  208. {
  209. nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
  210. // Worker thread only
  211. WorkerPrivate* mWorkerPrivate;
  212. RefPtr<Promise> mPromise;
  213. bool mWorkerHolderAdded;
  214. ~InternalHandler()
  215. {
  216. MaybeCleanup();
  217. }
  218. bool
  219. UseWorkerHolder()
  220. {
  221. MOZ_ASSERT(mWorkerPrivate);
  222. mWorkerPrivate->AssertIsOnWorkerThread();
  223. MOZ_ASSERT(!mWorkerHolderAdded);
  224. mWorkerHolderAdded = HoldWorker(mWorkerPrivate, Terminating);
  225. return mWorkerHolderAdded;
  226. }
  227. void
  228. MaybeCleanup()
  229. {
  230. MOZ_ASSERT(mWorkerPrivate);
  231. mWorkerPrivate->AssertIsOnWorkerThread();
  232. if (!mPromise) {
  233. return;
  234. }
  235. if (mWorkerHolderAdded) {
  236. ReleaseWorker();
  237. }
  238. mPromise = nullptr;
  239. mKeepAliveToken = nullptr;
  240. }
  241. void
  242. ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  243. {
  244. MOZ_ASSERT(mWorkerPrivate);
  245. mWorkerPrivate->AssertIsOnWorkerThread();
  246. MaybeCleanup();
  247. }
  248. void
  249. RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  250. {
  251. MOZ_ASSERT(mWorkerPrivate);
  252. mWorkerPrivate->AssertIsOnWorkerThread();
  253. MaybeCleanup();
  254. }
  255. bool
  256. Notify(Status aStatus) override
  257. {
  258. MOZ_ASSERT(mWorkerPrivate);
  259. mWorkerPrivate->AssertIsOnWorkerThread();
  260. if (aStatus < Terminating) {
  261. return true;
  262. }
  263. MaybeCleanup();
  264. return true;
  265. }
  266. InternalHandler(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
  267. WorkerPrivate* aWorkerPrivate,
  268. Promise* aPromise)
  269. : mKeepAliveToken(aKeepAliveToken)
  270. , mWorkerPrivate(aWorkerPrivate)
  271. , mPromise(aPromise)
  272. , mWorkerHolderAdded(false)
  273. {
  274. MOZ_ASSERT(mKeepAliveToken);
  275. MOZ_ASSERT(mWorkerPrivate);
  276. MOZ_ASSERT(mPromise);
  277. }
  278. public:
  279. static already_AddRefed<InternalHandler>
  280. Create(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
  281. WorkerPrivate* aWorkerPrivate,
  282. Promise* aPromise)
  283. {
  284. RefPtr<InternalHandler> ref = new InternalHandler(aKeepAliveToken,
  285. aWorkerPrivate,
  286. aPromise);
  287. if (NS_WARN_IF(!ref->UseWorkerHolder())) {
  288. return nullptr;
  289. }
  290. return ref.forget();
  291. }
  292. NS_DECL_ISUPPORTS
  293. };
  294. // This is really just a wrapper class to keep the InternalHandler
  295. // private. We don't want any code to accidentally call
  296. // Promise::AppendNativeHandler() without also referencing the promise.
  297. // Therefore we force all code through the static CreateAndAttachToPromise()
  298. // and use the private InternalHandler object.
  299. KeepAliveHandler() = delete;
  300. ~KeepAliveHandler() = delete;
  301. public:
  302. // Create a private handler object and attach it to the given Promise.
  303. // This will also create a strong ref to the Promise in a ref cycle. The
  304. // ref cycle is broken when the Promise is fulfilled or the worker thread
  305. // is Terminated.
  306. static void
  307. CreateAndAttachToPromise(const nsMainThreadPtrHandle<KeepAliveToken>& aKeepAliveToken,
  308. Promise* aPromise)
  309. {
  310. WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  311. MOZ_ASSERT(workerPrivate);
  312. workerPrivate->AssertIsOnWorkerThread();
  313. MOZ_ASSERT(aKeepAliveToken);
  314. MOZ_ASSERT(aPromise);
  315. // This creates a strong ref to the promise.
  316. RefPtr<InternalHandler> handler = InternalHandler::Create(aKeepAliveToken,
  317. workerPrivate,
  318. aPromise);
  319. if (NS_WARN_IF(!handler)) {
  320. return;
  321. }
  322. // This then creates a strong ref cycle between the promise and the
  323. // handler. The cycle is broken when the Promise is fulfilled or
  324. // the worker thread is Terminated.
  325. aPromise->AppendNativeHandler(handler);
  326. }
  327. };
  328. NS_IMPL_ISUPPORTS0(KeepAliveHandler::InternalHandler)
  329. class RegistrationUpdateRunnable : public Runnable
  330. {
  331. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
  332. const bool mNeedTimeCheck;
  333. public:
  334. RegistrationUpdateRunnable(nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
  335. bool aNeedTimeCheck)
  336. : mRegistration(aRegistration)
  337. , mNeedTimeCheck(aNeedTimeCheck)
  338. {
  339. MOZ_DIAGNOSTIC_ASSERT(mRegistration);
  340. }
  341. NS_IMETHOD
  342. Run() override
  343. {
  344. if (mNeedTimeCheck) {
  345. mRegistration->MaybeScheduleTimeCheckAndUpdate();
  346. } else {
  347. mRegistration->MaybeScheduleUpdate();
  348. }
  349. return NS_OK;
  350. }
  351. };
  352. class ExtendableEventWorkerRunnable : public WorkerRunnable
  353. {
  354. protected:
  355. nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
  356. public:
  357. ExtendableEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
  358. KeepAliveToken* aKeepAliveToken)
  359. : WorkerRunnable(aWorkerPrivate)
  360. {
  361. AssertIsOnMainThread();
  362. MOZ_ASSERT(aWorkerPrivate);
  363. MOZ_ASSERT(aKeepAliveToken);
  364. mKeepAliveToken =
  365. new nsMainThreadPtrHolder<KeepAliveToken>(aKeepAliveToken);
  366. }
  367. bool
  368. DispatchExtendableEventOnWorkerScope(JSContext* aCx,
  369. WorkerGlobalScope* aWorkerScope,
  370. ExtendableEvent* aEvent,
  371. PromiseNativeHandler* aPromiseHandler)
  372. {
  373. MOZ_ASSERT(aWorkerScope);
  374. MOZ_ASSERT(aEvent);
  375. nsCOMPtr<nsIGlobalObject> sgo = aWorkerScope;
  376. WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
  377. ErrorResult result;
  378. result = aWorkerScope->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
  379. if (NS_WARN_IF(result.Failed()) || internalEvent->mFlags.mExceptionWasRaised) {
  380. result.SuppressException();
  381. return false;
  382. }
  383. RefPtr<Promise> waitUntilPromise = aEvent->GetPromise();
  384. if (!waitUntilPromise) {
  385. waitUntilPromise =
  386. Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result);
  387. MOZ_RELEASE_ASSERT(!result.Failed());
  388. }
  389. MOZ_ASSERT(waitUntilPromise);
  390. // Make sure to append the caller's promise handler before attaching
  391. // our keep alive handler. This can avoid terminating the worker
  392. // before a success result is delivered to the caller in cases where
  393. // the idle timeout has been set to zero. This low timeout value is
  394. // sometimes set in tests.
  395. if (aPromiseHandler) {
  396. waitUntilPromise->AppendNativeHandler(aPromiseHandler);
  397. }
  398. KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
  399. waitUntilPromise);
  400. return true;
  401. }
  402. };
  403. // Handle functional event
  404. // 9.9.7 If the time difference in seconds calculated by the current time minus
  405. // registration's last update check time is greater than 86400, invoke Soft Update
  406. // algorithm.
  407. class ExtendableFunctionalEventWorkerRunnable : public ExtendableEventWorkerRunnable
  408. {
  409. protected:
  410. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
  411. public:
  412. ExtendableFunctionalEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
  413. KeepAliveToken* aKeepAliveToken,
  414. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
  415. : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
  416. , mRegistration(aRegistration)
  417. {
  418. MOZ_DIAGNOSTIC_ASSERT(aRegistration);
  419. }
  420. void
  421. PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
  422. {
  423. // Sub-class PreRun() or WorkerRun() methods could clear our mRegistration.
  424. if (mRegistration) {
  425. nsCOMPtr<nsIRunnable> runnable =
  426. new RegistrationUpdateRunnable(mRegistration, true /* time check */);
  427. NS_DispatchToMainThread(runnable.forget());
  428. }
  429. ExtendableEventWorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
  430. }
  431. };
  432. /*
  433. * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  434. * since it fires the event. This is ok since there can't be nested
  435. * ServiceWorkers, so the parent thread -> worker thread requirement for
  436. * runnables is satisfied.
  437. */
  438. class LifecycleEventWorkerRunnable : public ExtendableEventWorkerRunnable
  439. {
  440. nsString mEventName;
  441. RefPtr<LifeCycleEventCallback> mCallback;
  442. public:
  443. LifecycleEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
  444. KeepAliveToken* aToken,
  445. const nsAString& aEventName,
  446. LifeCycleEventCallback* aCallback)
  447. : ExtendableEventWorkerRunnable(aWorkerPrivate, aToken)
  448. , mEventName(aEventName)
  449. , mCallback(aCallback)
  450. {
  451. AssertIsOnMainThread();
  452. }
  453. bool
  454. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  455. {
  456. MOZ_ASSERT(aWorkerPrivate);
  457. return DispatchLifecycleEvent(aCx, aWorkerPrivate);
  458. }
  459. nsresult
  460. Cancel() override
  461. {
  462. mCallback->SetResult(false);
  463. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(mCallback));
  464. return WorkerRunnable::Cancel();
  465. }
  466. private:
  467. bool
  468. DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
  469. };
  470. /*
  471. * Used to handle ExtendableEvent::waitUntil() and catch abnormal worker
  472. * termination during the execution of life cycle events. It is responsible
  473. * with advancing the job queue for install/activate tasks.
  474. */
  475. class LifeCycleEventWatcher final : public PromiseNativeHandler,
  476. public WorkerHolder
  477. {
  478. WorkerPrivate* mWorkerPrivate;
  479. RefPtr<LifeCycleEventCallback> mCallback;
  480. bool mDone;
  481. ~LifeCycleEventWatcher()
  482. {
  483. if (mDone) {
  484. return;
  485. }
  486. MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
  487. // XXXcatalinb: If all the promises passed to waitUntil go out of scope,
  488. // the resulting Promise.all will be cycle collected and it will drop its
  489. // native handlers (including this object). Instead of waiting for a timeout
  490. // we report the failure now.
  491. ReportResult(false);
  492. }
  493. public:
  494. NS_DECL_ISUPPORTS
  495. LifeCycleEventWatcher(WorkerPrivate* aWorkerPrivate,
  496. LifeCycleEventCallback* aCallback)
  497. : mWorkerPrivate(aWorkerPrivate)
  498. , mCallback(aCallback)
  499. , mDone(false)
  500. {
  501. MOZ_ASSERT(aWorkerPrivate);
  502. aWorkerPrivate->AssertIsOnWorkerThread();
  503. }
  504. bool
  505. Init()
  506. {
  507. MOZ_ASSERT(mWorkerPrivate);
  508. mWorkerPrivate->AssertIsOnWorkerThread();
  509. // We need to listen for worker termination in case the event handler
  510. // never completes or never resolves the waitUntil promise. There are
  511. // two possible scenarios:
  512. // 1. The keepAlive token expires and the worker is terminated, in which
  513. // case the registration/update promise will be rejected
  514. // 2. A new service worker is registered which will terminate the current
  515. // installing worker.
  516. if (NS_WARN_IF(!HoldWorker(mWorkerPrivate, Terminating))) {
  517. NS_WARNING("LifeCycleEventWatcher failed to add feature.");
  518. ReportResult(false);
  519. return false;
  520. }
  521. return true;
  522. }
  523. bool
  524. Notify(Status aStatus) override
  525. {
  526. if (aStatus < Terminating) {
  527. return true;
  528. }
  529. MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
  530. ReportResult(false);
  531. return true;
  532. }
  533. void
  534. ReportResult(bool aResult)
  535. {
  536. mWorkerPrivate->AssertIsOnWorkerThread();
  537. if (mDone) {
  538. return;
  539. }
  540. mDone = true;
  541. mCallback->SetResult(aResult);
  542. nsresult rv = NS_DispatchToMainThread(mCallback);
  543. if (NS_WARN_IF(NS_FAILED(rv))) {
  544. NS_RUNTIMEABORT("Failed to dispatch life cycle event handler.");
  545. }
  546. ReleaseWorker();
  547. }
  548. void
  549. ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  550. {
  551. MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
  552. mWorkerPrivate->AssertIsOnWorkerThread();
  553. ReportResult(true);
  554. }
  555. void
  556. RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  557. {
  558. MOZ_ASSERT(GetCurrentThreadWorkerPrivate() == mWorkerPrivate);
  559. mWorkerPrivate->AssertIsOnWorkerThread();
  560. ReportResult(false);
  561. // Note, all WaitUntil() rejections are reported to client consoles
  562. // by the WaitUntilHandler in ServiceWorkerEvents. This ensures that
  563. // errors in non-lifecycle events like FetchEvent and PushEvent are
  564. // reported properly.
  565. }
  566. };
  567. NS_IMPL_ISUPPORTS0(LifeCycleEventWatcher)
  568. bool
  569. LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx,
  570. WorkerPrivate* aWorkerPrivate)
  571. {
  572. aWorkerPrivate->AssertIsOnWorkerThread();
  573. MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
  574. RefPtr<ExtendableEvent> event;
  575. RefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
  576. if (mEventName.EqualsASCII("install") || mEventName.EqualsASCII("activate")) {
  577. ExtendableEventInit init;
  578. init.mBubbles = false;
  579. init.mCancelable = false;
  580. event = ExtendableEvent::Constructor(target, mEventName, init);
  581. } else {
  582. MOZ_CRASH("Unexpected lifecycle event");
  583. }
  584. event->SetTrusted(true);
  585. // It is important to initialize the watcher before actually dispatching
  586. // the event in order to catch worker termination while the event handler
  587. // is still executing. This can happen with infinite loops, for example.
  588. RefPtr<LifeCycleEventWatcher> watcher =
  589. new LifeCycleEventWatcher(aWorkerPrivate, mCallback);
  590. if (!watcher->Init()) {
  591. return true;
  592. }
  593. if (!DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
  594. event, watcher)) {
  595. watcher->ReportResult(false);
  596. }
  597. return true;
  598. }
  599. } // anonymous namespace
  600. nsresult
  601. ServiceWorkerPrivate::SendLifeCycleEvent(const nsAString& aEventType,
  602. LifeCycleEventCallback* aCallback,
  603. nsIRunnable* aLoadFailure)
  604. {
  605. nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, aLoadFailure);
  606. NS_ENSURE_SUCCESS(rv, rv);
  607. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  608. RefPtr<WorkerRunnable> r = new LifecycleEventWorkerRunnable(mWorkerPrivate,
  609. token,
  610. aEventType,
  611. aCallback);
  612. if (NS_WARN_IF(!r->Dispatch())) {
  613. return NS_ERROR_FAILURE;
  614. }
  615. return NS_OK;
  616. }
  617. namespace {
  618. class PushErrorReporter final : public PromiseNativeHandler
  619. {
  620. WorkerPrivate* mWorkerPrivate;
  621. nsString mMessageId;
  622. ~PushErrorReporter()
  623. {
  624. }
  625. public:
  626. NS_DECL_THREADSAFE_ISUPPORTS
  627. PushErrorReporter(WorkerPrivate* aWorkerPrivate,
  628. const nsAString& aMessageId)
  629. : mWorkerPrivate(aWorkerPrivate)
  630. , mMessageId(aMessageId)
  631. {
  632. mWorkerPrivate->AssertIsOnWorkerThread();
  633. }
  634. void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  635. {
  636. mWorkerPrivate->AssertIsOnWorkerThread();
  637. mWorkerPrivate = nullptr;
  638. // Do nothing; we only use this to report errors to the Push service.
  639. }
  640. void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  641. {
  642. Report(nsIPushErrorReporter::DELIVERY_UNHANDLED_REJECTION);
  643. }
  644. void Report(uint16_t aReason = nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR)
  645. {
  646. mWorkerPrivate->AssertIsOnWorkerThread();
  647. mWorkerPrivate = nullptr;
  648. if (NS_WARN_IF(aReason > nsIPushErrorReporter::DELIVERY_INTERNAL_ERROR) ||
  649. mMessageId.IsEmpty()) {
  650. return;
  651. }
  652. nsCOMPtr<nsIRunnable> runnable =
  653. NewRunnableMethod<uint16_t>(this,
  654. &PushErrorReporter::ReportOnMainThread, aReason);
  655. MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
  656. NS_DispatchToMainThread(runnable.forget())));
  657. }
  658. void ReportOnMainThread(uint16_t aReason)
  659. {
  660. AssertIsOnMainThread();
  661. nsCOMPtr<nsIPushErrorReporter> reporter =
  662. do_GetService("@mozilla.org/push/Service;1");
  663. if (reporter) {
  664. nsresult rv = reporter->ReportDeliveryError(mMessageId, aReason);
  665. Unused << NS_WARN_IF(NS_FAILED(rv));
  666. }
  667. }
  668. };
  669. NS_IMPL_ISUPPORTS0(PushErrorReporter)
  670. class SendPushEventRunnable final : public ExtendableFunctionalEventWorkerRunnable
  671. {
  672. nsString mMessageId;
  673. Maybe<nsTArray<uint8_t>> mData;
  674. public:
  675. SendPushEventRunnable(WorkerPrivate* aWorkerPrivate,
  676. KeepAliveToken* aKeepAliveToken,
  677. const nsAString& aMessageId,
  678. const Maybe<nsTArray<uint8_t>>& aData,
  679. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> aRegistration)
  680. : ExtendableFunctionalEventWorkerRunnable(
  681. aWorkerPrivate, aKeepAliveToken, aRegistration)
  682. , mMessageId(aMessageId)
  683. , mData(aData)
  684. {
  685. AssertIsOnMainThread();
  686. MOZ_ASSERT(aWorkerPrivate);
  687. MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
  688. }
  689. bool
  690. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  691. {
  692. MOZ_ASSERT(aWorkerPrivate);
  693. GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
  694. RefPtr<PushErrorReporter> errorReporter =
  695. new PushErrorReporter(aWorkerPrivate, mMessageId);
  696. PushEventInit pei;
  697. if (mData) {
  698. const nsTArray<uint8_t>& bytes = mData.ref();
  699. JSObject* data = Uint8Array::Create(aCx, bytes.Length(), bytes.Elements());
  700. if (!data) {
  701. errorReporter->Report();
  702. return false;
  703. }
  704. pei.mData.Construct().SetAsArrayBufferView().Init(data);
  705. }
  706. pei.mBubbles = false;
  707. pei.mCancelable = false;
  708. ErrorResult result;
  709. RefPtr<PushEvent> event =
  710. PushEvent::Constructor(globalObj, NS_LITERAL_STRING("push"), pei, result);
  711. if (NS_WARN_IF(result.Failed())) {
  712. result.SuppressException();
  713. errorReporter->Report();
  714. return false;
  715. }
  716. event->SetTrusted(true);
  717. if (!DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
  718. event, errorReporter)) {
  719. errorReporter->Report(nsIPushErrorReporter::DELIVERY_UNCAUGHT_EXCEPTION);
  720. }
  721. return true;
  722. }
  723. };
  724. class SendPushSubscriptionChangeEventRunnable final : public ExtendableEventWorkerRunnable
  725. {
  726. public:
  727. explicit SendPushSubscriptionChangeEventRunnable(
  728. WorkerPrivate* aWorkerPrivate, KeepAliveToken* aKeepAliveToken)
  729. : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
  730. {
  731. AssertIsOnMainThread();
  732. MOZ_ASSERT(aWorkerPrivate);
  733. MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
  734. }
  735. bool
  736. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  737. {
  738. MOZ_ASSERT(aWorkerPrivate);
  739. RefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
  740. ExtendableEventInit init;
  741. init.mBubbles = false;
  742. init.mCancelable = false;
  743. RefPtr<ExtendableEvent> event =
  744. ExtendableEvent::Constructor(target,
  745. NS_LITERAL_STRING("pushsubscriptionchange"),
  746. init);
  747. event->SetTrusted(true);
  748. DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
  749. event, nullptr);
  750. return true;
  751. }
  752. };
  753. } // anonymous namespace
  754. nsresult
  755. ServiceWorkerPrivate::SendPushEvent(const nsAString& aMessageId,
  756. const Maybe<nsTArray<uint8_t>>& aData,
  757. ServiceWorkerRegistrationInfo* aRegistration)
  758. {
  759. nsresult rv = SpawnWorkerIfNeeded(PushEvent, nullptr);
  760. NS_ENSURE_SUCCESS(rv, rv);
  761. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  762. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
  763. new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(aRegistration, false));
  764. RefPtr<WorkerRunnable> r = new SendPushEventRunnable(mWorkerPrivate,
  765. token,
  766. aMessageId,
  767. aData,
  768. regInfo);
  769. if (mInfo->State() == ServiceWorkerState::Activating) {
  770. mPendingFunctionalEvents.AppendElement(r.forget());
  771. return NS_OK;
  772. }
  773. MOZ_ASSERT(mInfo->State() == ServiceWorkerState::Activated);
  774. if (NS_WARN_IF(!r->Dispatch())) {
  775. return NS_ERROR_FAILURE;
  776. }
  777. return NS_OK;
  778. }
  779. nsresult
  780. ServiceWorkerPrivate::SendPushSubscriptionChangeEvent()
  781. {
  782. nsresult rv = SpawnWorkerIfNeeded(PushSubscriptionChangeEvent, nullptr);
  783. NS_ENSURE_SUCCESS(rv, rv);
  784. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  785. RefPtr<WorkerRunnable> r =
  786. new SendPushSubscriptionChangeEventRunnable(mWorkerPrivate, token);
  787. if (NS_WARN_IF(!r->Dispatch())) {
  788. return NS_ERROR_FAILURE;
  789. }
  790. return NS_OK;
  791. }
  792. namespace {
  793. static void
  794. DummyNotificationTimerCallback(nsITimer* aTimer, void* aClosure)
  795. {
  796. // Nothing.
  797. }
  798. class AllowWindowInteractionHandler;
  799. class ClearWindowAllowedRunnable final : public WorkerRunnable
  800. {
  801. public:
  802. ClearWindowAllowedRunnable(WorkerPrivate* aWorkerPrivate,
  803. AllowWindowInteractionHandler* aHandler)
  804. : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
  805. , mHandler(aHandler)
  806. { }
  807. private:
  808. bool
  809. PreDispatch(WorkerPrivate* aWorkerPrivate) override
  810. {
  811. // WorkerRunnable asserts that the dispatch is from parent thread if
  812. // the busy count modification is WorkerThreadUnchangedBusyCount.
  813. // Since this runnable will be dispatched from the timer thread, we override
  814. // PreDispatch and PostDispatch to skip the check.
  815. return true;
  816. }
  817. void
  818. PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
  819. {
  820. // Silence bad assertions.
  821. }
  822. bool
  823. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
  824. nsresult
  825. Cancel() override
  826. {
  827. // Always ensure the handler is released on the worker thread, even if we
  828. // are cancelled.
  829. mHandler = nullptr;
  830. return WorkerRunnable::Cancel();
  831. }
  832. RefPtr<AllowWindowInteractionHandler> mHandler;
  833. };
  834. class AllowWindowInteractionHandler final : public PromiseNativeHandler
  835. {
  836. friend class ClearWindowAllowedRunnable;
  837. nsCOMPtr<nsITimer> mTimer;
  838. ~AllowWindowInteractionHandler()
  839. {
  840. }
  841. void
  842. ClearWindowAllowed(WorkerPrivate* aWorkerPrivate)
  843. {
  844. MOZ_ASSERT(aWorkerPrivate);
  845. aWorkerPrivate->AssertIsOnWorkerThread();
  846. if (!mTimer) {
  847. return;
  848. }
  849. // XXXcatalinb: This *might* be executed after the global was unrooted, in
  850. // which case GlobalScope() will return null. Making the check here just
  851. // to be safe.
  852. WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope();
  853. if (!globalScope) {
  854. return;
  855. }
  856. globalScope->ConsumeWindowInteraction();
  857. mTimer->Cancel();
  858. mTimer = nullptr;
  859. MOZ_ALWAYS_TRUE(aWorkerPrivate->ModifyBusyCountFromWorker(false));
  860. }
  861. void
  862. StartClearWindowTimer(WorkerPrivate* aWorkerPrivate)
  863. {
  864. MOZ_ASSERT(aWorkerPrivate);
  865. aWorkerPrivate->AssertIsOnWorkerThread();
  866. MOZ_ASSERT(!mTimer);
  867. nsresult rv;
  868. nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
  869. if (NS_WARN_IF(NS_FAILED(rv))) {
  870. return;
  871. }
  872. RefPtr<ClearWindowAllowedRunnable> r =
  873. new ClearWindowAllowedRunnable(aWorkerPrivate, this);
  874. RefPtr<TimerThreadEventTarget> target =
  875. new TimerThreadEventTarget(aWorkerPrivate, r);
  876. rv = timer->SetTarget(target);
  877. if (NS_WARN_IF(NS_FAILED(rv))) {
  878. return;
  879. }
  880. // The important stuff that *has* to be reversed.
  881. if (NS_WARN_IF(!aWorkerPrivate->ModifyBusyCountFromWorker(true))) {
  882. return;
  883. }
  884. aWorkerPrivate->GlobalScope()->AllowWindowInteraction();
  885. timer.swap(mTimer);
  886. // We swap first and then initialize the timer so that even if initializing
  887. // fails, we still clean the busy count and interaction count correctly.
  888. // The timer can't be initialized before modifying the busy count since the
  889. // timer thread could run and call the timeout but the worker may
  890. // already be terminating and modifying the busy count could fail.
  891. rv = mTimer->InitWithFuncCallback(DummyNotificationTimerCallback, nullptr,
  892. gDOMDisableOpenClickDelay,
  893. nsITimer::TYPE_ONE_SHOT);
  894. if (NS_WARN_IF(NS_FAILED(rv))) {
  895. ClearWindowAllowed(aWorkerPrivate);
  896. return;
  897. }
  898. }
  899. public:
  900. NS_DECL_ISUPPORTS
  901. explicit AllowWindowInteractionHandler(WorkerPrivate* aWorkerPrivate)
  902. {
  903. StartClearWindowTimer(aWorkerPrivate);
  904. }
  905. void
  906. ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  907. {
  908. WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  909. ClearWindowAllowed(workerPrivate);
  910. }
  911. void
  912. RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  913. {
  914. WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  915. ClearWindowAllowed(workerPrivate);
  916. }
  917. };
  918. NS_IMPL_ISUPPORTS0(AllowWindowInteractionHandler)
  919. bool
  920. ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
  921. {
  922. mHandler->ClearWindowAllowed(aWorkerPrivate);
  923. mHandler = nullptr;
  924. return true;
  925. }
  926. class SendNotificationEventRunnable final : public ExtendableEventWorkerRunnable
  927. {
  928. const nsString mEventName;
  929. const nsString mID;
  930. const nsString mTitle;
  931. const nsString mDir;
  932. const nsString mLang;
  933. const nsString mBody;
  934. const nsString mTag;
  935. const nsString mIcon;
  936. const nsString mData;
  937. const nsString mBehavior;
  938. const nsString mScope;
  939. public:
  940. SendNotificationEventRunnable(WorkerPrivate* aWorkerPrivate,
  941. KeepAliveToken* aKeepAliveToken,
  942. const nsAString& aEventName,
  943. const nsAString& aID,
  944. const nsAString& aTitle,
  945. const nsAString& aDir,
  946. const nsAString& aLang,
  947. const nsAString& aBody,
  948. const nsAString& aTag,
  949. const nsAString& aIcon,
  950. const nsAString& aData,
  951. const nsAString& aBehavior,
  952. const nsAString& aScope)
  953. : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
  954. , mEventName(aEventName)
  955. , mID(aID)
  956. , mTitle(aTitle)
  957. , mDir(aDir)
  958. , mLang(aLang)
  959. , mBody(aBody)
  960. , mTag(aTag)
  961. , mIcon(aIcon)
  962. , mData(aData)
  963. , mBehavior(aBehavior)
  964. , mScope(aScope)
  965. {
  966. AssertIsOnMainThread();
  967. MOZ_ASSERT(aWorkerPrivate);
  968. MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
  969. }
  970. bool
  971. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  972. {
  973. MOZ_ASSERT(aWorkerPrivate);
  974. RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
  975. ErrorResult result;
  976. RefPtr<Notification> notification =
  977. Notification::ConstructFromFields(aWorkerPrivate->GlobalScope(), mID,
  978. mTitle, mDir, mLang, mBody, mTag, mIcon,
  979. mData, mScope, result);
  980. if (NS_WARN_IF(result.Failed())) {
  981. return false;
  982. }
  983. NotificationEventInit nei;
  984. nei.mNotification = notification;
  985. nei.mBubbles = false;
  986. nei.mCancelable = false;
  987. RefPtr<NotificationEvent> event =
  988. NotificationEvent::Constructor(target, mEventName,
  989. nei, result);
  990. if (NS_WARN_IF(result.Failed())) {
  991. return false;
  992. }
  993. event->SetTrusted(true);
  994. aWorkerPrivate->GlobalScope()->AllowWindowInteraction();
  995. RefPtr<AllowWindowInteractionHandler> allowWindowInteraction =
  996. new AllowWindowInteractionHandler(aWorkerPrivate);
  997. if (!DispatchExtendableEventOnWorkerScope(aCx, aWorkerPrivate->GlobalScope(),
  998. event, allowWindowInteraction)) {
  999. allowWindowInteraction->RejectedCallback(aCx, JS::UndefinedHandleValue);
  1000. }
  1001. aWorkerPrivate->GlobalScope()->ConsumeWindowInteraction();
  1002. return true;
  1003. }
  1004. };
  1005. } // namespace anonymous
  1006. nsresult
  1007. ServiceWorkerPrivate::SendNotificationEvent(const nsAString& aEventName,
  1008. const nsAString& aID,
  1009. const nsAString& aTitle,
  1010. const nsAString& aDir,
  1011. const nsAString& aLang,
  1012. const nsAString& aBody,
  1013. const nsAString& aTag,
  1014. const nsAString& aIcon,
  1015. const nsAString& aData,
  1016. const nsAString& aBehavior,
  1017. const nsAString& aScope)
  1018. {
  1019. WakeUpReason why;
  1020. if (aEventName.EqualsLiteral(NOTIFICATION_CLICK_EVENT_NAME)) {
  1021. why = NotificationClickEvent;
  1022. gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
  1023. } else if (aEventName.EqualsLiteral(NOTIFICATION_CLOSE_EVENT_NAME)) {
  1024. why = NotificationCloseEvent;
  1025. } else {
  1026. MOZ_ASSERT_UNREACHABLE("Invalid notification event name");
  1027. return NS_ERROR_FAILURE;
  1028. }
  1029. nsresult rv = SpawnWorkerIfNeeded(why, nullptr);
  1030. NS_ENSURE_SUCCESS(rv, rv);
  1031. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  1032. RefPtr<WorkerRunnable> r =
  1033. new SendNotificationEventRunnable(mWorkerPrivate, token,
  1034. aEventName, aID, aTitle, aDir, aLang,
  1035. aBody, aTag, aIcon, aData, aBehavior,
  1036. aScope);
  1037. if (NS_WARN_IF(!r->Dispatch())) {
  1038. return NS_ERROR_FAILURE;
  1039. }
  1040. return NS_OK;
  1041. }
  1042. namespace {
  1043. // Inheriting ExtendableEventWorkerRunnable so that the worker is not terminated
  1044. // while handling the fetch event, though that's very unlikely.
  1045. class FetchEventRunnable : public ExtendableFunctionalEventWorkerRunnable
  1046. , public nsIHttpHeaderVisitor {
  1047. nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
  1048. const nsCString mScriptSpec;
  1049. nsTArray<nsCString> mHeaderNames;
  1050. nsTArray<nsCString> mHeaderValues;
  1051. nsCString mSpec;
  1052. nsCString mFragment;
  1053. nsCString mMethod;
  1054. nsString mClientId;
  1055. bool mIsReload;
  1056. bool mMarkLaunchServiceWorkerEnd;
  1057. RequestCache mCacheMode;
  1058. RequestMode mRequestMode;
  1059. RequestRedirect mRequestRedirect;
  1060. RequestCredentials mRequestCredentials;
  1061. nsContentPolicyType mContentPolicyType;
  1062. nsCOMPtr<nsIInputStream> mUploadStream;
  1063. nsCString mReferrer;
  1064. ReferrerPolicy mReferrerPolicy;
  1065. nsString mIntegrity;
  1066. public:
  1067. FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
  1068. KeepAliveToken* aKeepAliveToken,
  1069. nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
  1070. // CSP checks might require the worker script spec
  1071. // later on.
  1072. const nsACString& aScriptSpec,
  1073. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
  1074. const nsAString& aDocumentId,
  1075. bool aIsReload,
  1076. bool aMarkLaunchServiceWorkerEnd)
  1077. : ExtendableFunctionalEventWorkerRunnable(
  1078. aWorkerPrivate, aKeepAliveToken, aRegistration)
  1079. , mInterceptedChannel(aChannel)
  1080. , mScriptSpec(aScriptSpec)
  1081. , mClientId(aDocumentId)
  1082. , mIsReload(aIsReload)
  1083. , mMarkLaunchServiceWorkerEnd(aMarkLaunchServiceWorkerEnd)
  1084. , mCacheMode(RequestCache::Default)
  1085. , mRequestMode(RequestMode::No_cors)
  1086. , mRequestRedirect(RequestRedirect::Follow)
  1087. // By default we set it to same-origin since normal HTTP fetches always
  1088. // send credentials to same-origin websites unless explicitly forbidden.
  1089. , mRequestCredentials(RequestCredentials::Same_origin)
  1090. , mContentPolicyType(nsIContentPolicy::TYPE_INVALID)
  1091. , mReferrer(kFETCH_CLIENT_REFERRER_STR)
  1092. , mReferrerPolicy(ReferrerPolicy::_empty)
  1093. {
  1094. MOZ_ASSERT(aWorkerPrivate);
  1095. }
  1096. NS_DECL_ISUPPORTS_INHERITED
  1097. NS_IMETHOD
  1098. VisitHeader(const nsACString& aHeader, const nsACString& aValue) override
  1099. {
  1100. mHeaderNames.AppendElement(aHeader);
  1101. mHeaderValues.AppendElement(aValue);
  1102. return NS_OK;
  1103. }
  1104. nsresult
  1105. Init()
  1106. {
  1107. AssertIsOnMainThread();
  1108. nsCOMPtr<nsIChannel> channel;
  1109. nsresult rv = mInterceptedChannel->GetChannel(getter_AddRefs(channel));
  1110. NS_ENSURE_SUCCESS(rv, rv);
  1111. nsCOMPtr<nsIURI> uri;
  1112. rv = mInterceptedChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri));
  1113. NS_ENSURE_SUCCESS(rv, rv);
  1114. // Normally we rely on the Request constructor to strip the fragment, but
  1115. // when creating the FetchEvent we bypass the constructor. So strip the
  1116. // fragment manually here instead. We can't do it later when we create
  1117. // the Request because that code executes off the main thread.
  1118. nsCOMPtr<nsIURI> uriNoFragment;
  1119. rv = uri->CloneIgnoringRef(getter_AddRefs(uriNoFragment));
  1120. NS_ENSURE_SUCCESS(rv, rv);
  1121. rv = uriNoFragment->GetSpec(mSpec);
  1122. NS_ENSURE_SUCCESS(rv, rv);
  1123. rv = uri->GetRef(mFragment);
  1124. NS_ENSURE_SUCCESS(rv, rv);
  1125. uint32_t loadFlags;
  1126. rv = channel->GetLoadFlags(&loadFlags);
  1127. NS_ENSURE_SUCCESS(rv, rv);
  1128. nsCOMPtr<nsILoadInfo> loadInfo;
  1129. rv = channel->GetLoadInfo(getter_AddRefs(loadInfo));
  1130. NS_ENSURE_SUCCESS(rv, rv);
  1131. mContentPolicyType = loadInfo->InternalContentPolicyType();
  1132. nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
  1133. MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
  1134. nsAutoCString referrer;
  1135. // Ignore the return value since the Referer header may not exist.
  1136. httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"), referrer);
  1137. if (!referrer.IsEmpty()) {
  1138. mReferrer = referrer;
  1139. }
  1140. uint32_t referrerPolicy = 0;
  1141. rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
  1142. NS_ENSURE_SUCCESS(rv, rv);
  1143. switch (referrerPolicy) {
  1144. case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER:
  1145. mReferrerPolicy = ReferrerPolicy::No_referrer;
  1146. break;
  1147. case nsIHttpChannel::REFERRER_POLICY_ORIGIN:
  1148. mReferrerPolicy = ReferrerPolicy::Origin;
  1149. break;
  1150. case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE:
  1151. mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
  1152. break;
  1153. case nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN:
  1154. mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
  1155. break;
  1156. case nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL:
  1157. mReferrerPolicy = ReferrerPolicy::Unsafe_url;
  1158. break;
  1159. default:
  1160. MOZ_ASSERT_UNREACHABLE("Invalid Referrer Policy enum value?");
  1161. break;
  1162. }
  1163. rv = httpChannel->GetRequestMethod(mMethod);
  1164. NS_ENSURE_SUCCESS(rv, rv);
  1165. nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
  1166. NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
  1167. mRequestMode = InternalRequest::MapChannelToRequestMode(channel);
  1168. // This is safe due to static_asserts in ServiceWorkerManager.cpp.
  1169. uint32_t redirectMode;
  1170. internalChannel->GetRedirectMode(&redirectMode);
  1171. mRequestRedirect = static_cast<RequestRedirect>(redirectMode);
  1172. // This is safe due to static_asserts in ServiceWorkerManager.cpp.
  1173. uint32_t cacheMode;
  1174. internalChannel->GetFetchCacheMode(&cacheMode);
  1175. mCacheMode = static_cast<RequestCache>(cacheMode);
  1176. internalChannel->GetIntegrityMetadata(mIntegrity);
  1177. mRequestCredentials = InternalRequest::MapChannelToRequestCredentials(channel);
  1178. rv = httpChannel->VisitNonDefaultRequestHeaders(this);
  1179. NS_ENSURE_SUCCESS(rv, rv);
  1180. nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
  1181. if (uploadChannel) {
  1182. MOZ_ASSERT(!mUploadStream);
  1183. bool bodyHasHeaders = false;
  1184. rv = uploadChannel->GetUploadStreamHasHeaders(&bodyHasHeaders);
  1185. NS_ENSURE_SUCCESS(rv, rv);
  1186. nsCOMPtr<nsIInputStream> uploadStream;
  1187. rv = uploadChannel->CloneUploadStream(getter_AddRefs(uploadStream));
  1188. NS_ENSURE_SUCCESS(rv, rv);
  1189. if (bodyHasHeaders) {
  1190. HandleBodyWithHeaders(uploadStream);
  1191. } else {
  1192. mUploadStream = uploadStream;
  1193. }
  1194. }
  1195. return NS_OK;
  1196. }
  1197. bool
  1198. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  1199. {
  1200. MOZ_ASSERT(aWorkerPrivate);
  1201. if (mMarkLaunchServiceWorkerEnd) {
  1202. mInterceptedChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
  1203. }
  1204. mInterceptedChannel->SetDispatchFetchEventEnd(TimeStamp::Now());
  1205. return DispatchFetchEvent(aCx, aWorkerPrivate);
  1206. }
  1207. nsresult
  1208. Cancel() override
  1209. {
  1210. nsCOMPtr<nsIRunnable> runnable = new ResumeRequest(mInterceptedChannel);
  1211. if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
  1212. NS_WARNING("Failed to resume channel on FetchEventRunnable::Cancel()!\n");
  1213. }
  1214. WorkerRunnable::Cancel();
  1215. return NS_OK;
  1216. }
  1217. private:
  1218. ~FetchEventRunnable() {}
  1219. class ResumeRequest final : public Runnable {
  1220. nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
  1221. public:
  1222. explicit ResumeRequest(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
  1223. : mChannel(aChannel)
  1224. {
  1225. }
  1226. NS_IMETHOD Run() override
  1227. {
  1228. AssertIsOnMainThread();
  1229. mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
  1230. mChannel->SaveTimeStampsToUnderlyingChannel();
  1231. nsresult rv = mChannel->ResetInterception();
  1232. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
  1233. "Failed to resume intercepted network request");
  1234. return rv;
  1235. }
  1236. };
  1237. bool
  1238. DispatchFetchEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
  1239. {
  1240. MOZ_ASSERT(aCx);
  1241. MOZ_ASSERT(aWorkerPrivate);
  1242. MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
  1243. GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
  1244. RefPtr<InternalHeaders> internalHeaders = new InternalHeaders(HeadersGuardEnum::Request);
  1245. MOZ_ASSERT(mHeaderNames.Length() == mHeaderValues.Length());
  1246. for (uint32_t i = 0; i < mHeaderNames.Length(); i++) {
  1247. ErrorResult result;
  1248. internalHeaders->Set(mHeaderNames[i], mHeaderValues[i], result);
  1249. if (NS_WARN_IF(result.Failed())) {
  1250. result.SuppressException();
  1251. return false;
  1252. }
  1253. }
  1254. ErrorResult result;
  1255. internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result);
  1256. if (NS_WARN_IF(result.Failed())) {
  1257. result.SuppressException();
  1258. return false;
  1259. }
  1260. RefPtr<InternalRequest> internalReq = new InternalRequest(mSpec,
  1261. mFragment,
  1262. mMethod,
  1263. internalHeaders.forget(),
  1264. mCacheMode,
  1265. mRequestMode,
  1266. mRequestRedirect,
  1267. mRequestCredentials,
  1268. NS_ConvertUTF8toUTF16(mReferrer),
  1269. mReferrerPolicy,
  1270. mContentPolicyType,
  1271. mIntegrity);
  1272. internalReq->SetBody(mUploadStream);
  1273. // For Telemetry, note that this Request object was created by a Fetch event.
  1274. internalReq->SetCreatedByFetchEvent();
  1275. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(globalObj.GetAsSupports());
  1276. if (NS_WARN_IF(!global)) {
  1277. return false;
  1278. }
  1279. RefPtr<Request> request = new Request(global, internalReq, nullptr);
  1280. MOZ_ASSERT_IF(internalReq->IsNavigationRequest(),
  1281. request->Redirect() == RequestRedirect::Manual);
  1282. RootedDictionary<FetchEventInit> init(aCx);
  1283. init.mRequest = request;
  1284. init.mBubbles = false;
  1285. init.mCancelable = true;
  1286. if (!mClientId.IsEmpty()) {
  1287. init.mClientId = mClientId;
  1288. }
  1289. init.mIsReload = mIsReload;
  1290. RefPtr<FetchEvent> event =
  1291. FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, result);
  1292. if (NS_WARN_IF(result.Failed())) {
  1293. result.SuppressException();
  1294. return false;
  1295. }
  1296. event->PostInit(mInterceptedChannel, mRegistration, mScriptSpec);
  1297. event->SetTrusted(true);
  1298. mInterceptedChannel->SetHandleFetchEventStart(TimeStamp::Now());
  1299. RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
  1300. nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
  1301. if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
  1302. nsCOMPtr<nsIRunnable> runnable;
  1303. if (event->DefaultPrevented(aCx)) {
  1304. event->ReportCanceled();
  1305. } else if (event->WidgetEventPtr()->mFlags.mExceptionWasRaised) {
  1306. // Exception logged via the WorkerPrivate ErrorReporter
  1307. } else {
  1308. runnable = new ResumeRequest(mInterceptedChannel);
  1309. }
  1310. if (!runnable) {
  1311. runnable = new CancelChannelRunnable(mInterceptedChannel,
  1312. mRegistration,
  1313. NS_ERROR_INTERCEPTION_FAILED);
  1314. }
  1315. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
  1316. }
  1317. RefPtr<Promise> waitUntilPromise = event->GetPromise();
  1318. if (waitUntilPromise) {
  1319. KeepAliveHandler::CreateAndAttachToPromise(mKeepAliveToken,
  1320. waitUntilPromise);
  1321. }
  1322. return true;
  1323. }
  1324. nsresult
  1325. HandleBodyWithHeaders(nsIInputStream* aUploadStream)
  1326. {
  1327. // We are dealing with an nsMIMEInputStream which uses string input streams
  1328. // under the hood, so all of the data is available synchronously.
  1329. bool nonBlocking = false;
  1330. nsresult rv = aUploadStream->IsNonBlocking(&nonBlocking);
  1331. NS_ENSURE_SUCCESS(rv, rv);
  1332. if (NS_WARN_IF(!nonBlocking)) {
  1333. return NS_ERROR_NOT_AVAILABLE;
  1334. }
  1335. nsAutoCString body;
  1336. rv = NS_ConsumeStream(aUploadStream, UINT32_MAX, body);
  1337. NS_ENSURE_SUCCESS(rv, rv);
  1338. // Extract the headers in the beginning of the buffer
  1339. nsAutoCString::const_iterator begin, end;
  1340. body.BeginReading(begin);
  1341. body.EndReading(end);
  1342. const nsAutoCString::const_iterator body_end = end;
  1343. nsAutoCString headerName, headerValue;
  1344. bool emptyHeader = false;
  1345. while (FetchUtil::ExtractHeader(begin, end, headerName,
  1346. headerValue, &emptyHeader) &&
  1347. !emptyHeader) {
  1348. mHeaderNames.AppendElement(headerName);
  1349. mHeaderValues.AppendElement(headerValue);
  1350. headerName.Truncate();
  1351. headerValue.Truncate();
  1352. }
  1353. // Replace the upload stream with one only containing the body text.
  1354. nsCOMPtr<nsIStringInputStream> strStream =
  1355. do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
  1356. NS_ENSURE_SUCCESS(rv, rv);
  1357. // Skip past the "\r\n" that separates the headers and the body.
  1358. ++begin;
  1359. ++begin;
  1360. body.Assign(Substring(begin, body_end));
  1361. rv = strStream->SetData(body.BeginReading(), body.Length());
  1362. NS_ENSURE_SUCCESS(rv, rv);
  1363. mUploadStream = strStream;
  1364. return NS_OK;
  1365. }
  1366. };
  1367. NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
  1368. } // anonymous namespace
  1369. nsresult
  1370. ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
  1371. nsILoadGroup* aLoadGroup,
  1372. const nsAString& aDocumentId,
  1373. bool aIsReload)
  1374. {
  1375. AssertIsOnMainThread();
  1376. // if the ServiceWorker script fails to load for some reason, just resume
  1377. // the original channel.
  1378. nsCOMPtr<nsIRunnable> failRunnable =
  1379. NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
  1380. aChannel->SetLaunchServiceWorkerStart(TimeStamp::Now());
  1381. aChannel->SetDispatchFetchEventStart(TimeStamp::Now());
  1382. bool newWorkerCreated = false;
  1383. nsresult rv = SpawnWorkerIfNeeded(FetchEvent,
  1384. failRunnable,
  1385. &newWorkerCreated,
  1386. aLoadGroup);
  1387. NS_ENSURE_SUCCESS(rv, rv);
  1388. if (!newWorkerCreated) {
  1389. aChannel->SetLaunchServiceWorkerEnd(TimeStamp::Now());
  1390. }
  1391. nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
  1392. new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
  1393. RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
  1394. if (NS_WARN_IF(!mInfo || !swm)) {
  1395. return NS_ERROR_FAILURE;
  1396. }
  1397. RefPtr<ServiceWorkerRegistrationInfo> registration =
  1398. swm->GetRegistration(mInfo->GetPrincipal(), mInfo->Scope());
  1399. // Its possible the registration is removed between starting the interception
  1400. // and actually dispatching the fetch event. In these cases we simply
  1401. // want to restart the original network request. Since this is a normal
  1402. // condition we handle the reset here instead of returning an error which
  1403. // would in turn trigger a console report.
  1404. if (!registration) {
  1405. aChannel->ResetInterception();
  1406. return NS_OK;
  1407. }
  1408. nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
  1409. new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(registration, false));
  1410. RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
  1411. RefPtr<FetchEventRunnable> r =
  1412. new FetchEventRunnable(mWorkerPrivate, token, handle,
  1413. mInfo->ScriptSpec(), regInfo,
  1414. aDocumentId, aIsReload, newWorkerCreated);
  1415. rv = r->Init();
  1416. if (NS_WARN_IF(NS_FAILED(rv))) {
  1417. return rv;
  1418. }
  1419. if (mInfo->State() == ServiceWorkerState::Activating) {
  1420. mPendingFunctionalEvents.AppendElement(r.forget());
  1421. return NS_OK;
  1422. }
  1423. MOZ_ASSERT(mInfo->State() == ServiceWorkerState::Activated);
  1424. if (NS_WARN_IF(!r->Dispatch())) {
  1425. return NS_ERROR_FAILURE;
  1426. }
  1427. return NS_OK;
  1428. }
  1429. nsresult
  1430. ServiceWorkerPrivate::SpawnWorkerIfNeeded(WakeUpReason aWhy,
  1431. nsIRunnable* aLoadFailedRunnable,
  1432. bool* aNewWorkerCreated,
  1433. nsILoadGroup* aLoadGroup)
  1434. {
  1435. AssertIsOnMainThread();
  1436. // XXXcatalinb: We need to have a separate load group that's linked to
  1437. // an existing tab child to pass security checks on b2g.
  1438. // This should be fixed in bug 1125961, but for now we enforce updating
  1439. // the overriden load group when intercepting a fetch.
  1440. MOZ_ASSERT_IF(aWhy == FetchEvent, aLoadGroup);
  1441. // Defaults to no new worker created, but if there is one, we'll set the value
  1442. // to true at the end of this function.
  1443. if (aNewWorkerCreated) {
  1444. *aNewWorkerCreated = false;
  1445. }
  1446. if (mWorkerPrivate) {
  1447. mWorkerPrivate->UpdateOverridenLoadGroup(aLoadGroup);
  1448. RenewKeepAliveToken(aWhy);
  1449. return NS_OK;
  1450. }
  1451. // Sanity check: mSupportsArray should be empty if we're about to
  1452. // spin up a new worker.
  1453. MOZ_ASSERT(mSupportsArray.IsEmpty());
  1454. if (NS_WARN_IF(!mInfo)) {
  1455. NS_WARNING("Trying to wake up a dead service worker.");
  1456. return NS_ERROR_FAILURE;
  1457. }
  1458. // TODO(catalinb): Bug 1192138 - Add telemetry for service worker wake-ups.
  1459. // Ensure that the IndexedDatabaseManager is initialized
  1460. Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
  1461. WorkerLoadInfo info;
  1462. nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI), mInfo->ScriptSpec(),
  1463. nullptr, nullptr);
  1464. if (NS_WARN_IF(NS_FAILED(rv))) {
  1465. return rv;
  1466. }
  1467. info.mResolvedScriptURI = info.mBaseURI;
  1468. MOZ_ASSERT(!mInfo->CacheName().IsEmpty());
  1469. info.mServiceWorkerCacheName = mInfo->CacheName();
  1470. info.mServiceWorkerID = mInfo->ID();
  1471. info.mLoadGroup = aLoadGroup;
  1472. info.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
  1473. rv = info.mBaseURI->GetHost(info.mDomain);
  1474. if (NS_WARN_IF(NS_FAILED(rv))) {
  1475. return rv;
  1476. }
  1477. info.mPrincipal = mInfo->GetPrincipal();
  1478. nsContentUtils::StorageAccess access =
  1479. nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
  1480. info.mStorageAllowed = access > nsContentUtils::StorageAccess::ePrivateBrowsing;
  1481. info.mOriginAttributes = mInfo->GetOriginAttributes();
  1482. nsCOMPtr<nsIContentSecurityPolicy> csp;
  1483. rv = info.mPrincipal->GetCsp(getter_AddRefs(csp));
  1484. if (NS_WARN_IF(NS_FAILED(rv))) {
  1485. return rv;
  1486. }
  1487. info.mCSP = csp;
  1488. if (info.mCSP) {
  1489. rv = info.mCSP->GetAllowsEval(&info.mReportCSPViolations,
  1490. &info.mEvalAllowed);
  1491. if (NS_WARN_IF(NS_FAILED(rv))) {
  1492. return rv;
  1493. }
  1494. } else {
  1495. info.mEvalAllowed = true;
  1496. info.mReportCSPViolations = false;
  1497. }
  1498. WorkerPrivate::OverrideLoadInfoLoadGroup(info);
  1499. AutoJSAPI jsapi;
  1500. jsapi.Init();
  1501. ErrorResult error;
  1502. NS_ConvertUTF8toUTF16 scriptSpec(mInfo->ScriptSpec());
  1503. mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
  1504. scriptSpec,
  1505. false, WorkerTypeService,
  1506. mInfo->Scope(), &info, error);
  1507. if (NS_WARN_IF(error.Failed())) {
  1508. return error.StealNSResult();
  1509. }
  1510. RenewKeepAliveToken(aWhy);
  1511. if (aNewWorkerCreated) {
  1512. *aNewWorkerCreated = true;
  1513. }
  1514. return NS_OK;
  1515. }
  1516. void
  1517. ServiceWorkerPrivate::StoreISupports(nsISupports* aSupports)
  1518. {
  1519. AssertIsOnMainThread();
  1520. MOZ_ASSERT(mWorkerPrivate);
  1521. MOZ_ASSERT(!mSupportsArray.Contains(aSupports));
  1522. mSupportsArray.AppendElement(aSupports);
  1523. }
  1524. void
  1525. ServiceWorkerPrivate::RemoveISupports(nsISupports* aSupports)
  1526. {
  1527. AssertIsOnMainThread();
  1528. mSupportsArray.RemoveElement(aSupports);
  1529. }
  1530. void
  1531. ServiceWorkerPrivate::TerminateWorker()
  1532. {
  1533. AssertIsOnMainThread();
  1534. mIdleWorkerTimer->Cancel();
  1535. mIdleKeepAliveToken = nullptr;
  1536. if (mWorkerPrivate) {
  1537. if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) {
  1538. nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1539. if (os) {
  1540. os->NotifyObservers(this, "service-worker-shutdown", nullptr);
  1541. }
  1542. }
  1543. Unused << NS_WARN_IF(!mWorkerPrivate->Terminate());
  1544. mWorkerPrivate = nullptr;
  1545. mSupportsArray.Clear();
  1546. // Any pending events are never going to fire on this worker. Cancel
  1547. // them so that intercepted channels can be reset and other resources
  1548. // cleaned up.
  1549. nsTArray<RefPtr<WorkerRunnable>> pendingEvents;
  1550. mPendingFunctionalEvents.SwapElements(pendingEvents);
  1551. for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
  1552. pendingEvents[i]->Cancel();
  1553. }
  1554. }
  1555. }
  1556. void
  1557. ServiceWorkerPrivate::NoteDeadServiceWorkerInfo()
  1558. {
  1559. AssertIsOnMainThread();
  1560. mInfo = nullptr;
  1561. TerminateWorker();
  1562. }
  1563. void
  1564. ServiceWorkerPrivate::Activated()
  1565. {
  1566. AssertIsOnMainThread();
  1567. // If we had to queue up events due to the worker activating, that means
  1568. // the worker must be currently running. We should be called synchronously
  1569. // when the worker becomes activated.
  1570. MOZ_ASSERT_IF(!mPendingFunctionalEvents.IsEmpty(), mWorkerPrivate);
  1571. nsTArray<RefPtr<WorkerRunnable>> pendingEvents;
  1572. mPendingFunctionalEvents.SwapElements(pendingEvents);
  1573. for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
  1574. RefPtr<WorkerRunnable> r = pendingEvents[i].forget();
  1575. if (NS_WARN_IF(!r->Dispatch())) {
  1576. NS_WARNING("Failed to dispatch pending functional event!");
  1577. }
  1578. }
  1579. }
  1580. nsresult
  1581. ServiceWorkerPrivate::GetDebugger(nsIWorkerDebugger** aResult)
  1582. {
  1583. AssertIsOnMainThread();
  1584. MOZ_ASSERT(aResult);
  1585. if (!mDebuggerCount) {
  1586. return NS_OK;
  1587. }
  1588. MOZ_ASSERT(mWorkerPrivate);
  1589. nsCOMPtr<nsIWorkerDebugger> debugger = do_QueryInterface(mWorkerPrivate->Debugger());
  1590. debugger.forget(aResult);
  1591. return NS_OK;
  1592. }
  1593. nsresult
  1594. ServiceWorkerPrivate::AttachDebugger()
  1595. {
  1596. AssertIsOnMainThread();
  1597. // When the first debugger attaches to a worker, we spawn a worker if needed,
  1598. // and cancel the idle timeout. The idle timeout should not be reset until
  1599. // the last debugger detached from the worker.
  1600. if (!mDebuggerCount) {
  1601. nsresult rv = SpawnWorkerIfNeeded(AttachEvent, nullptr);
  1602. NS_ENSURE_SUCCESS(rv, rv);
  1603. mIdleWorkerTimer->Cancel();
  1604. }
  1605. ++mDebuggerCount;
  1606. return NS_OK;
  1607. }
  1608. nsresult
  1609. ServiceWorkerPrivate::DetachDebugger()
  1610. {
  1611. AssertIsOnMainThread();
  1612. if (!mDebuggerCount) {
  1613. return NS_ERROR_UNEXPECTED;
  1614. }
  1615. --mDebuggerCount;
  1616. // When the last debugger detaches from a worker, we either reset the idle
  1617. // timeout, or terminate the worker if there are no more active tokens.
  1618. if (!mDebuggerCount) {
  1619. if (mTokenCount) {
  1620. ResetIdleTimeout();
  1621. } else {
  1622. TerminateWorker();
  1623. }
  1624. }
  1625. return NS_OK;
  1626. }
  1627. bool
  1628. ServiceWorkerPrivate::IsIdle() const
  1629. {
  1630. AssertIsOnMainThread();
  1631. return mTokenCount == 0 || (mTokenCount == 1 && mIdleKeepAliveToken);
  1632. }
  1633. namespace {
  1634. class ServiceWorkerPrivateTimerCallback final : public nsITimerCallback
  1635. {
  1636. public:
  1637. typedef void (ServiceWorkerPrivate::*Method)(nsITimer*);
  1638. ServiceWorkerPrivateTimerCallback(ServiceWorkerPrivate* aServiceWorkerPrivate,
  1639. Method aMethod)
  1640. : mServiceWorkerPrivate(aServiceWorkerPrivate)
  1641. , mMethod(aMethod)
  1642. {
  1643. }
  1644. NS_IMETHOD
  1645. Notify(nsITimer* aTimer) override
  1646. {
  1647. (mServiceWorkerPrivate->*mMethod)(aTimer);
  1648. mServiceWorkerPrivate = nullptr;
  1649. return NS_OK;
  1650. }
  1651. private:
  1652. ~ServiceWorkerPrivateTimerCallback() = default;
  1653. RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
  1654. Method mMethod;
  1655. NS_DECL_THREADSAFE_ISUPPORTS
  1656. };
  1657. NS_IMPL_ISUPPORTS(ServiceWorkerPrivateTimerCallback, nsITimerCallback);
  1658. } // anonymous namespace
  1659. void
  1660. ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer)
  1661. {
  1662. AssertIsOnMainThread();
  1663. MOZ_ASSERT(aTimer == mIdleWorkerTimer, "Invalid timer!");
  1664. // Release ServiceWorkerPrivate's token, since the grace period has ended.
  1665. mIdleKeepAliveToken = nullptr;
  1666. if (mWorkerPrivate) {
  1667. // If we still have a workerPrivate at this point it means there are pending
  1668. // waitUntil promises. Wait a bit more until we forcibly terminate the
  1669. // worker.
  1670. uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_extended_timeout");
  1671. nsCOMPtr<nsITimerCallback> cb = new ServiceWorkerPrivateTimerCallback(
  1672. this, &ServiceWorkerPrivate::TerminateWorkerCallback);
  1673. DebugOnly<nsresult> rv =
  1674. mIdleWorkerTimer->InitWithCallback(cb, timeout, nsITimer::TYPE_ONE_SHOT);
  1675. MOZ_ASSERT(NS_SUCCEEDED(rv));
  1676. }
  1677. }
  1678. void
  1679. ServiceWorkerPrivate::TerminateWorkerCallback(nsITimer* aTimer)
  1680. {
  1681. AssertIsOnMainThread();
  1682. MOZ_ASSERT(aTimer == this->mIdleWorkerTimer, "Invalid timer!");
  1683. // mInfo must be non-null at this point because NoteDeadServiceWorkerInfo
  1684. // which zeroes it calls TerminateWorker which cancels our timer which will
  1685. // ensure we don't get invoked even if the nsTimerEvent is in the event queue.
  1686. ServiceWorkerManager::LocalizeAndReportToAllClients(
  1687. mInfo->Scope(),
  1688. "ServiceWorkerGraceTimeoutTermination",
  1689. nsTArray<nsString> { NS_ConvertUTF8toUTF16(mInfo->Scope()) });
  1690. TerminateWorker();
  1691. }
  1692. void
  1693. ServiceWorkerPrivate::RenewKeepAliveToken(WakeUpReason aWhy)
  1694. {
  1695. // We should have an active worker if we're renewing the keep alive token.
  1696. MOZ_ASSERT(mWorkerPrivate);
  1697. // If there is at least one debugger attached to the worker, the idle worker
  1698. // timeout was canceled when the first debugger attached to the worker. It
  1699. // should not be reset until the last debugger detaches from the worker.
  1700. if (!mDebuggerCount) {
  1701. ResetIdleTimeout();
  1702. }
  1703. if (!mIdleKeepAliveToken) {
  1704. mIdleKeepAliveToken = new KeepAliveToken(this);
  1705. }
  1706. }
  1707. void
  1708. ServiceWorkerPrivate::ResetIdleTimeout()
  1709. {
  1710. uint32_t timeout = Preferences::GetInt("dom.serviceWorkers.idle_timeout");
  1711. nsCOMPtr<nsITimerCallback> cb = new ServiceWorkerPrivateTimerCallback(
  1712. this, &ServiceWorkerPrivate::NoteIdleWorkerCallback);
  1713. DebugOnly<nsresult> rv =
  1714. mIdleWorkerTimer->InitWithCallback(cb, timeout, nsITimer::TYPE_ONE_SHOT);
  1715. MOZ_ASSERT(NS_SUCCEEDED(rv));
  1716. }
  1717. void
  1718. ServiceWorkerPrivate::AddToken()
  1719. {
  1720. AssertIsOnMainThread();
  1721. ++mTokenCount;
  1722. }
  1723. void
  1724. ServiceWorkerPrivate::ReleaseToken()
  1725. {
  1726. AssertIsOnMainThread();
  1727. MOZ_ASSERT(mTokenCount > 0);
  1728. --mTokenCount;
  1729. if (!mTokenCount) {
  1730. TerminateWorker();
  1731. }
  1732. // mInfo can be nullptr here if NoteDeadServiceWorkerInfo() is called while
  1733. // the KeepAliveToken is being proxy released as a runnable.
  1734. else if (mInfo && IsIdle()) {
  1735. RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
  1736. if (swm) {
  1737. swm->WorkerIsIdle(mInfo);
  1738. }
  1739. }
  1740. }
  1741. already_AddRefed<KeepAliveToken>
  1742. ServiceWorkerPrivate::CreateEventKeepAliveToken()
  1743. {
  1744. AssertIsOnMainThread();
  1745. MOZ_ASSERT(mWorkerPrivate);
  1746. MOZ_ASSERT(mIdleKeepAliveToken);
  1747. RefPtr<KeepAliveToken> ref = new KeepAliveToken(this);
  1748. return ref.forget();
  1749. }
  1750. void
  1751. ServiceWorkerPrivate::AddPendingWindow(Runnable* aPendingWindow)
  1752. {
  1753. AssertIsOnMainThread();
  1754. pendingWindows.AppendElement(aPendingWindow);
  1755. }
  1756. nsresult
  1757. ServiceWorkerPrivate::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
  1758. {
  1759. AssertIsOnMainThread();
  1760. nsCString topic(aTopic);
  1761. if (!topic.Equals(NS_LITERAL_CSTRING("BrowserChrome:Ready"))) {
  1762. MOZ_ASSERT(false, "Unexpected topic.");
  1763. return NS_ERROR_FAILURE;
  1764. }
  1765. nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1766. NS_ENSURE_STATE(os);
  1767. os->RemoveObserver(static_cast<nsIObserver*>(this), "BrowserChrome:Ready");
  1768. size_t len = pendingWindows.Length();
  1769. for (int i = len-1; i >= 0; i--) {
  1770. RefPtr<Runnable> runnable = pendingWindows[i];
  1771. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
  1772. pendingWindows.RemoveElementAt(i);
  1773. }
  1774. return NS_OK;
  1775. }
  1776. END_WORKERS_NAMESPACE