1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "ServiceWorkerPrivateImpl.h"
8 
9 #include <utility>
10 
11 #include "MainThreadUtils.h"
12 #include "js/ErrorReport.h"
13 #include "nsContentUtils.h"
14 #include "nsDebug.h"
15 #include "nsError.h"
16 #include "nsIChannel.h"
17 #include "nsIHttpChannel.h"
18 #include "nsIHttpChannelInternal.h"
19 #include "nsIHttpHeaderVisitor.h"
20 #include "nsINetworkInterceptController.h"
21 #include "nsIObserverService.h"
22 #include "nsIScriptError.h"
23 #include "nsIURI.h"
24 #include "nsIUploadChannel2.h"
25 #include "nsThreadUtils.h"
26 #include "nsICacheInfoChannel.h"
27 #include "nsNetUtil.h"
28 
29 #include "ServiceWorkerCloneData.h"
30 #include "ServiceWorkerManager.h"
31 #include "ServiceWorkerRegistrationInfo.h"
32 #include "mozilla/Assertions.h"
33 #include "mozilla/ErrorResult.h"
34 #include "mozilla/ipc/PBackgroundChild.h"
35 #include "mozilla/Maybe.h"
36 #include "mozilla/Result.h"
37 #include "mozilla/ResultExtensions.h"
38 #include "mozilla/ScopeExit.h"
39 #include "mozilla/Services.h"
40 #include "mozilla/StaticPrefs_dom.h"
41 #include "mozilla/StoragePrincipalHelper.h"
42 #include "mozilla/Unused.h"
43 #include "mozilla/dom/ClientIPCTypes.h"
44 #include "mozilla/dom/DOMTypes.h"
45 #include "mozilla/dom/FetchEventOpChild.h"
46 #include "mozilla/dom/InternalHeaders.h"
47 #include "mozilla/dom/InternalRequest.h"
48 #include "mozilla/dom/ReferrerInfo.h"
49 #include "mozilla/dom/RemoteWorkerControllerChild.h"
50 #include "mozilla/dom/RemoteWorkerManager.h"  // RemoteWorkerManager::GetRemoteType
51 #include "mozilla/dom/ServiceWorkerBinding.h"
52 #include "mozilla/ipc/BackgroundChild.h"
53 #include "mozilla/ipc/IPCStreamUtils.h"
54 #include "mozilla/ipc/URIUtils.h"
55 #include "mozilla/net/CookieJarSettings.h"
56 #include "mozilla/RemoteLazyInputStreamStorage.h"
57 
58 namespace mozilla {
59 
60 using namespace ipc;
61 
62 namespace dom {
63 
RAIIActorPtrHolder(already_AddRefed<RemoteWorkerControllerChild> aActor)64 ServiceWorkerPrivateImpl::RAIIActorPtrHolder::RAIIActorPtrHolder(
65     already_AddRefed<RemoteWorkerControllerChild> aActor)
66     : mActor(aActor) {
67   AssertIsOnMainThread();
68   MOZ_ASSERT(mActor);
69   MOZ_ASSERT(mActor->Manager());
70 }
71 
~RAIIActorPtrHolder()72 ServiceWorkerPrivateImpl::RAIIActorPtrHolder::~RAIIActorPtrHolder() {
73   AssertIsOnMainThread();
74 
75   mDestructorPromiseHolder.ResolveIfExists(true, __func__);
76 
77   mActor->MaybeSendDelete();
78 }
79 
80 RemoteWorkerControllerChild*
operator ->() const81 ServiceWorkerPrivateImpl::RAIIActorPtrHolder::operator->() const {
82   AssertIsOnMainThread();
83 
84   return get();
85 }
86 
get() const87 RemoteWorkerControllerChild* ServiceWorkerPrivateImpl::RAIIActorPtrHolder::get()
88     const {
89   AssertIsOnMainThread();
90 
91   return mActor.get();
92 }
93 
94 RefPtr<GenericPromise>
OnDestructor()95 ServiceWorkerPrivateImpl::RAIIActorPtrHolder::OnDestructor() {
96   AssertIsOnMainThread();
97 
98   return mDestructorPromiseHolder.Ensure(__func__);
99 }
100 
ServiceWorkerPrivateImpl(RefPtr<ServiceWorkerPrivate> aOuter)101 ServiceWorkerPrivateImpl::ServiceWorkerPrivateImpl(
102     RefPtr<ServiceWorkerPrivate> aOuter)
103     : mOuter(std::move(aOuter)) {
104   AssertIsOnMainThread();
105   MOZ_ASSERT(mOuter);
106   MOZ_ASSERT(WorkerIsDead());
107 }
108 
Initialize()109 nsresult ServiceWorkerPrivateImpl::Initialize() {
110   AssertIsOnMainThread();
111   MOZ_ASSERT(mOuter);
112   MOZ_ASSERT(mOuter->mInfo);
113 
114   nsCOMPtr<nsIPrincipal> principal = mOuter->mInfo->Principal();
115 
116   nsCOMPtr<nsIURI> uri;
117   auto* basePrin = BasePrincipal::Cast(principal);
118   nsresult rv = basePrin->GetURI(getter_AddRefs(uri));
119 
120   if (NS_WARN_IF(NS_FAILED(rv))) {
121     return rv;
122   }
123 
124   if (NS_WARN_IF(!uri)) {
125     return NS_ERROR_FAILURE;
126   }
127 
128   URIParams baseScriptURL;
129   SerializeURI(uri, baseScriptURL);
130 
131   nsString id;
132   rv = mOuter->mInfo->GetId(id);
133 
134   if (NS_WARN_IF(NS_FAILED(rv))) {
135     return rv;
136   }
137 
138   PrincipalInfo principalInfo;
139   rv = PrincipalToPrincipalInfo(principal, &principalInfo);
140   if (NS_WARN_IF(NS_FAILED(rv))) {
141     return rv;
142   }
143 
144   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
145 
146   if (NS_WARN_IF(!swm)) {
147     return NS_ERROR_DOM_ABORT_ERR;
148   }
149 
150   RefPtr<ServiceWorkerRegistrationInfo> regInfo =
151       swm->GetRegistration(principal, mOuter->mInfo->Scope());
152 
153   if (NS_WARN_IF(!regInfo)) {
154     return NS_ERROR_DOM_INVALID_STATE_ERR;
155   }
156 
157   nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
158       net::CookieJarSettings::Create(principal);
159   MOZ_ASSERT(cookieJarSettings);
160 
161   net::CookieJarSettings::Cast(cookieJarSettings)->SetPartitionKey(uri);
162 
163   net::CookieJarSettingsArgs cjsData;
164   net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(cjsData);
165 
166   nsCOMPtr<nsIPrincipal> partitionedPrincipal;
167   rv = StoragePrincipalHelper::CreatePartitionedPrincipalForServiceWorker(
168       principal, cookieJarSettings, getter_AddRefs(partitionedPrincipal));
169   if (NS_WARN_IF(NS_FAILED(rv))) {
170     return rv;
171   }
172 
173   PrincipalInfo partitionedPrincipalInfo;
174   rv =
175       PrincipalToPrincipalInfo(partitionedPrincipal, &partitionedPrincipalInfo);
176   if (NS_WARN_IF(NS_FAILED(rv))) {
177     return rv;
178   }
179 
180   StorageAccess storageAccess =
181       StorageAllowedForServiceWorker(principal, cookieJarSettings);
182 
183   ServiceWorkerData serviceWorkerData;
184   serviceWorkerData.cacheName() = mOuter->mInfo->CacheName();
185   serviceWorkerData.loadFlags() =
186       static_cast<uint32_t>(mOuter->mInfo->GetImportsLoadFlags() |
187                             nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
188   serviceWorkerData.id() = std::move(id);
189 
190   nsAutoCString domain;
191   rv = uri->GetHost(domain);
192   if (NS_WARN_IF(NS_FAILED(rv))) {
193     return rv;
194   }
195 
196   auto remoteType = RemoteWorkerManager::GetRemoteType(
197       principal, WorkerKind::WorkerKindService);
198   if (NS_WARN_IF(remoteType.isErr())) {
199     return remoteType.unwrapErr();
200   }
201 
202   mRemoteWorkerData = RemoteWorkerData(
203       NS_ConvertUTF8toUTF16(mOuter->mInfo->ScriptSpec()), baseScriptURL,
204       baseScriptURL, /* name */ VoidString(),
205       /* loading principal */ principalInfo, principalInfo,
206       partitionedPrincipalInfo,
207       /* useRegularPrincipal */ true,
208 
209       // ServiceWorkers run as first-party, no storage-access permission needed.
210       /* hasStorageAccessPermissionGranted */ false,
211 
212       cjsData, domain,
213       /* isSecureContext */ true,
214       /* clientInfo*/ Nothing(),
215 
216       // The RemoteWorkerData CTOR doesn't allow to set the referrerInfo via
217       // already_AddRefed<>. Let's set it to null.
218       /* referrerInfo */ nullptr,
219 
220       storageAccess, std::move(serviceWorkerData), regInfo->AgentClusterId(),
221       remoteType.unwrap());
222 
223   mRemoteWorkerData.referrerInfo() = MakeAndAddRef<ReferrerInfo>();
224 
225   // This fills in the rest of mRemoteWorkerData.serviceWorkerData().
226   RefreshRemoteWorkerData(regInfo);
227 
228   return NS_OK;
229 }
230 
SetSkipWaitingFlag()231 RefPtr<GenericPromise> ServiceWorkerPrivateImpl::SetSkipWaitingFlag() {
232   AssertIsOnMainThread();
233   MOZ_ASSERT(mOuter);
234   MOZ_ASSERT(mOuter->mInfo);
235 
236   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
237 
238   if (!swm) {
239     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
240   }
241 
242   RefPtr<ServiceWorkerRegistrationInfo> regInfo =
243       swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
244 
245   if (!regInfo) {
246     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
247   }
248 
249   mOuter->mInfo->SetSkipWaitingFlag();
250 
251   RefPtr<GenericPromise::Private> promise =
252       new GenericPromise::Private(__func__);
253 
254   regInfo->TryToActivateAsync([promise] { promise->Resolve(true, __func__); });
255 
256   return promise;
257 }
258 
RefreshRemoteWorkerData(const RefPtr<ServiceWorkerRegistrationInfo> & aRegistration)259 void ServiceWorkerPrivateImpl::RefreshRemoteWorkerData(
260     const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) {
261   AssertIsOnMainThread();
262   MOZ_ASSERT(mOuter);
263   MOZ_ASSERT(mOuter->mInfo);
264 
265   ServiceWorkerData& serviceWorkerData =
266       mRemoteWorkerData.serviceWorkerData().get_ServiceWorkerData();
267   serviceWorkerData.descriptor() = mOuter->mInfo->Descriptor().ToIPC();
268   serviceWorkerData.registrationDescriptor() =
269       aRegistration->Descriptor().ToIPC();
270 }
271 
SpawnWorkerIfNeeded()272 nsresult ServiceWorkerPrivateImpl::SpawnWorkerIfNeeded() {
273   AssertIsOnMainThread();
274   MOZ_ASSERT(mOuter);
275   MOZ_ASSERT(mOuter->mInfo);
276 
277   if (mControllerChild) {
278     mOuter->RenewKeepAliveToken(ServiceWorkerPrivate::WakeUpReason::Unknown);
279     return NS_OK;
280   }
281 
282   PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread();
283 
284   if (NS_WARN_IF(!bgChild)) {
285     return NS_ERROR_DOM_INVALID_STATE_ERR;
286   }
287 
288   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
289 
290   if (NS_WARN_IF(!swm)) {
291     return NS_ERROR_DOM_ABORT_ERR;
292   }
293 
294   RefPtr<ServiceWorkerRegistrationInfo> regInfo =
295       swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
296 
297   if (NS_WARN_IF(!regInfo)) {
298     return NS_ERROR_DOM_INVALID_STATE_ERR;
299   }
300 
301   RefreshRemoteWorkerData(regInfo);
302 
303   RefPtr<RemoteWorkerControllerChild> controllerChild =
304       new RemoteWorkerControllerChild(this);
305 
306   if (NS_WARN_IF(!bgChild->SendPRemoteWorkerControllerConstructor(
307           controllerChild, mRemoteWorkerData))) {
308     return NS_ERROR_DOM_INVALID_STATE_ERR;
309   }
310 
311   /**
312    * Manutally `AddRef()` because `DeallocPRemoteWorkerControllerChild()`
313    * calls `Release()` and the `AllocPRemoteWorkerControllerChild()` function
314    * is not called.
315    */
316   // NOLINTNEXTLINE(readability-redundant-smartptr-get)
317   controllerChild.get()->AddRef();
318 
319   mControllerChild = new RAIIActorPtrHolder(controllerChild.forget());
320 
321   return NS_OK;
322 }
323 
~ServiceWorkerPrivateImpl()324 ServiceWorkerPrivateImpl::~ServiceWorkerPrivateImpl() {
325   AssertIsOnMainThread();
326   MOZ_ASSERT(!mOuter);
327   MOZ_ASSERT(WorkerIsDead());
328 }
329 
SendMessageEvent(RefPtr<ServiceWorkerCloneData> && aData,const ClientInfoAndState & aClientInfoAndState)330 nsresult ServiceWorkerPrivateImpl::SendMessageEvent(
331     RefPtr<ServiceWorkerCloneData>&& aData,
332     const ClientInfoAndState& aClientInfoAndState) {
333   AssertIsOnMainThread();
334   MOZ_ASSERT(mOuter);
335   MOZ_ASSERT(aData);
336 
337   auto scopeExit = MakeScopeExit([&] { Shutdown(); });
338 
339   PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread();
340 
341   if (NS_WARN_IF(!bgChild)) {
342     return NS_ERROR_DOM_INVALID_STATE_ERR;
343   }
344 
345   ServiceWorkerMessageEventOpArgs args;
346   args.clientInfoAndState() = aClientInfoAndState;
347   if (!aData->BuildClonedMessageDataForBackgroundChild(bgChild,
348                                                        args.clonedData())) {
349     return NS_ERROR_DOM_DATA_CLONE_ERR;
350   }
351 
352   scopeExit.release();
353 
354   return ExecServiceWorkerOp(
355       std::move(args), [](ServiceWorkerOpResult&& aResult) {
356         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
357       });
358 }
359 
CheckScriptEvaluation(RefPtr<LifeCycleEventCallback> aCallback)360 nsresult ServiceWorkerPrivateImpl::CheckScriptEvaluation(
361     RefPtr<LifeCycleEventCallback> aCallback) {
362   MOZ_ASSERT(NS_IsMainThread());
363   MOZ_ASSERT(mOuter);
364   MOZ_ASSERT(aCallback);
365 
366   RefPtr<ServiceWorkerPrivateImpl> self = this;
367 
368   /**
369    * We need to capture the actor associated with the current Service Worker so
370    * we can terminate it if script evaluation failed.
371    */
372   nsresult rv = SpawnWorkerIfNeeded();
373 
374   if (NS_WARN_IF(NS_FAILED(rv))) {
375     aCallback->SetResult(false);
376     aCallback->Run();
377 
378     return rv;
379   }
380 
381   MOZ_ASSERT(mControllerChild);
382 
383   RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
384 
385   return ExecServiceWorkerOp(
386       ServiceWorkerCheckScriptEvaluationOpArgs(),
387       [self = std::move(self), holder = std::move(holder),
388        callback = aCallback](ServiceWorkerOpResult&& aResult) mutable {
389         if (aResult.type() == ServiceWorkerOpResult::
390                                   TServiceWorkerCheckScriptEvaluationOpResult) {
391           auto& result =
392               aResult.get_ServiceWorkerCheckScriptEvaluationOpResult();
393 
394           if (result.workerScriptExecutedSuccessfully()) {
395             if (self->mOuter) {
396               self->mOuter->SetHandlesFetch(result.fetchHandlerWasAdded());
397             }
398 
399             Unused << NS_WARN_IF(!self->mOuter);
400 
401             callback->SetResult(result.workerScriptExecutedSuccessfully());
402             callback->Run();
403 
404             return;
405           }
406         }
407 
408         /**
409          * If script evaluation failed, first terminate the Service Worker
410          * before invoking the callback.
411          */
412         MOZ_ASSERT_IF(aResult.type() == ServiceWorkerOpResult::Tnsresult,
413                       NS_FAILED(aResult.get_nsresult()));
414 
415         // If a termination operation was already issued using `holder`...
416         if (self->mControllerChild != holder) {
417           holder->OnDestructor()->Then(
418               GetCurrentSerialEventTarget(), __func__,
419               [callback = std::move(callback)](
420                   const GenericPromise::ResolveOrRejectValue&) {
421                 callback->SetResult(false);
422                 callback->Run();
423               });
424 
425           return;
426         }
427 
428         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
429         MOZ_ASSERT(swm);
430 
431         auto shutdownStateId = swm->MaybeInitServiceWorkerShutdownProgress();
432 
433         RefPtr<GenericNonExclusivePromise> promise =
434             self->ShutdownInternal(shutdownStateId);
435 
436         swm->BlockShutdownOn(promise, shutdownStateId);
437 
438         promise->Then(
439             GetCurrentSerialEventTarget(), __func__,
440             [callback = std::move(callback)](
441                 const GenericNonExclusivePromise::ResolveOrRejectValue&) {
442               callback->SetResult(false);
443               callback->Run();
444             });
445       },
446       [callback = aCallback] {
447         callback->SetResult(false);
448         callback->Run();
449       });
450 }
451 
SendLifeCycleEvent(const nsAString & aEventName,RefPtr<LifeCycleEventCallback> aCallback)452 nsresult ServiceWorkerPrivateImpl::SendLifeCycleEvent(
453     const nsAString& aEventName, RefPtr<LifeCycleEventCallback> aCallback) {
454   AssertIsOnMainThread();
455   MOZ_ASSERT(mOuter);
456   MOZ_ASSERT(aCallback);
457 
458   return ExecServiceWorkerOp(
459       ServiceWorkerLifeCycleEventOpArgs(nsString(aEventName)),
460       [callback = aCallback](ServiceWorkerOpResult&& aResult) {
461         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
462 
463         callback->SetResult(NS_SUCCEEDED(aResult.get_nsresult()));
464         callback->Run();
465       },
466       [callback = aCallback] {
467         callback->SetResult(false);
468         callback->Run();
469       });
470 }
471 
SendPushEvent(RefPtr<ServiceWorkerRegistrationInfo> aRegistration,const nsAString & aMessageId,const Maybe<nsTArray<uint8_t>> & aData)472 nsresult ServiceWorkerPrivateImpl::SendPushEvent(
473     RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
474     const nsAString& aMessageId, const Maybe<nsTArray<uint8_t>>& aData) {
475   AssertIsOnMainThread();
476   MOZ_ASSERT(mOuter);
477   MOZ_ASSERT(aRegistration);
478 
479   ServiceWorkerPushEventOpArgs args;
480   args.messageId() = nsString(aMessageId);
481 
482   if (aData) {
483     args.data() = aData.ref();
484   } else {
485     args.data() = void_t();
486   }
487 
488   if (mOuter->mInfo->State() == ServiceWorkerState::Activating) {
489     UniquePtr<PendingFunctionalEvent> pendingEvent =
490         MakeUnique<PendingPushEvent>(this, std::move(aRegistration),
491                                      std::move(args));
492 
493     mPendingFunctionalEvents.AppendElement(std::move(pendingEvent));
494 
495     return NS_OK;
496   }
497 
498   MOZ_ASSERT(mOuter->mInfo->State() == ServiceWorkerState::Activated);
499 
500   return SendPushEventInternal(std::move(aRegistration), std::move(args));
501 }
502 
SendPushEventInternal(RefPtr<ServiceWorkerRegistrationInfo> && aRegistration,ServiceWorkerPushEventOpArgs && aArgs)503 nsresult ServiceWorkerPrivateImpl::SendPushEventInternal(
504     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
505     ServiceWorkerPushEventOpArgs&& aArgs) {
506   AssertIsOnMainThread();
507   MOZ_ASSERT(mOuter);
508   MOZ_ASSERT(aRegistration);
509 
510   return ExecServiceWorkerOp(
511       std::move(aArgs),
512       [registration = aRegistration](ServiceWorkerOpResult&& aResult) {
513         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
514 
515         registration->MaybeScheduleTimeCheckAndUpdate();
516       },
517       [registration = aRegistration]() {
518         registration->MaybeScheduleTimeCheckAndUpdate();
519       });
520 }
521 
SendPushSubscriptionChangeEvent()522 nsresult ServiceWorkerPrivateImpl::SendPushSubscriptionChangeEvent() {
523   AssertIsOnMainThread();
524   MOZ_ASSERT(mOuter);
525 
526   return ExecServiceWorkerOp(
527       ServiceWorkerPushSubscriptionChangeEventOpArgs(),
528       [](ServiceWorkerOpResult&& aResult) {
529         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
530       });
531 }
532 
SendNotificationEvent(const nsAString & aEventName,const nsAString & aID,const nsAString & aTitle,const nsAString & aDir,const nsAString & aLang,const nsAString & aBody,const nsAString & aTag,const nsAString & aIcon,const nsAString & aData,const nsAString & aBehavior,const nsAString & aScope,uint32_t aDisableOpenClickDelay)533 nsresult ServiceWorkerPrivateImpl::SendNotificationEvent(
534     const nsAString& aEventName, const nsAString& aID, const nsAString& aTitle,
535     const nsAString& aDir, const nsAString& aLang, const nsAString& aBody,
536     const nsAString& aTag, const nsAString& aIcon, const nsAString& aData,
537     const nsAString& aBehavior, const nsAString& aScope,
538     uint32_t aDisableOpenClickDelay) {
539   AssertIsOnMainThread();
540   MOZ_ASSERT(mOuter);
541 
542   ServiceWorkerNotificationEventOpArgs args;
543   args.eventName() = nsString(aEventName);
544   args.id() = nsString(aID);
545   args.title() = nsString(aTitle);
546   args.dir() = nsString(aDir);
547   args.lang() = nsString(aLang);
548   args.body() = nsString(aBody);
549   args.tag() = nsString(aTag);
550   args.icon() = nsString(aIcon);
551   args.data() = nsString(aData);
552   args.behavior() = nsString(aBehavior);
553   args.scope() = nsString(aScope);
554   args.disableOpenClickDelay() = aDisableOpenClickDelay;
555 
556   return ExecServiceWorkerOp(
557       std::move(args), [](ServiceWorkerOpResult&& aResult) {
558         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
559       });
560 }
561 
PendingFunctionalEvent(ServiceWorkerPrivateImpl * aOwner,RefPtr<ServiceWorkerRegistrationInfo> && aRegistration)562 ServiceWorkerPrivateImpl::PendingFunctionalEvent::PendingFunctionalEvent(
563     ServiceWorkerPrivateImpl* aOwner,
564     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration)
565     : mOwner(aOwner), mRegistration(std::move(aRegistration)) {
566   AssertIsOnMainThread();
567   MOZ_ASSERT(mOwner);
568   MOZ_ASSERT(mOwner->mOuter);
569   MOZ_ASSERT(mOwner->mOuter->mInfo);
570   MOZ_ASSERT(mOwner->mOuter->mInfo->State() == ServiceWorkerState::Activating);
571   MOZ_ASSERT(mRegistration);
572 }
573 
~PendingFunctionalEvent()574 ServiceWorkerPrivateImpl::PendingFunctionalEvent::~PendingFunctionalEvent() {
575   AssertIsOnMainThread();
576 }
577 
PendingPushEvent(ServiceWorkerPrivateImpl * aOwner,RefPtr<ServiceWorkerRegistrationInfo> && aRegistration,ServiceWorkerPushEventOpArgs && aArgs)578 ServiceWorkerPrivateImpl::PendingPushEvent::PendingPushEvent(
579     ServiceWorkerPrivateImpl* aOwner,
580     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
581     ServiceWorkerPushEventOpArgs&& aArgs)
582     : PendingFunctionalEvent(aOwner, std::move(aRegistration)),
583       mArgs(std::move(aArgs)) {
584   AssertIsOnMainThread();
585 }
586 
Send()587 nsresult ServiceWorkerPrivateImpl::PendingPushEvent::Send() {
588   AssertIsOnMainThread();
589   MOZ_ASSERT(mOwner->mOuter);
590   MOZ_ASSERT(mOwner->mOuter->mInfo);
591 
592   return mOwner->SendPushEventInternal(std::move(mRegistration),
593                                        std::move(mArgs));
594 }
595 
PendingFetchEvent(ServiceWorkerPrivateImpl * aOwner,RefPtr<ServiceWorkerRegistrationInfo> && aRegistration,ServiceWorkerFetchEventOpArgs && aArgs,nsCOMPtr<nsIInterceptedChannel> && aChannel)596 ServiceWorkerPrivateImpl::PendingFetchEvent::PendingFetchEvent(
597     ServiceWorkerPrivateImpl* aOwner,
598     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
599     ServiceWorkerFetchEventOpArgs&& aArgs,
600     nsCOMPtr<nsIInterceptedChannel>&& aChannel)
601     : PendingFunctionalEvent(aOwner, std::move(aRegistration)),
602       mArgs(std::move(aArgs)),
603       mChannel(std::move(aChannel)) {
604   AssertIsOnMainThread();
605   MOZ_ASSERT(mChannel);
606 }
607 
Send()608 nsresult ServiceWorkerPrivateImpl::PendingFetchEvent::Send() {
609   AssertIsOnMainThread();
610   MOZ_ASSERT(mOwner->mOuter);
611   MOZ_ASSERT(mOwner->mOuter->mInfo);
612 
613   return mOwner->SendFetchEventInternal(std::move(mRegistration),
614                                         std::move(mArgs), std::move(mChannel));
615 }
616 
~PendingFetchEvent()617 ServiceWorkerPrivateImpl::PendingFetchEvent::~PendingFetchEvent() {
618   AssertIsOnMainThread();
619 
620   if (NS_WARN_IF(mChannel)) {
621     mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
622   }
623 }
624 
625 namespace {
626 
627 class HeaderFiller final : public nsIHttpHeaderVisitor {
628  public:
629   NS_DECL_ISUPPORTS
630 
HeaderFiller(HeadersGuardEnum aGuard)631   explicit HeaderFiller(HeadersGuardEnum aGuard)
632       : mInternalHeaders(new InternalHeaders(aGuard)) {
633     MOZ_ASSERT(mInternalHeaders);
634   }
635 
636   NS_IMETHOD
VisitHeader(const nsACString & aHeader,const nsACString & aValue)637   VisitHeader(const nsACString& aHeader, const nsACString& aValue) override {
638     ErrorResult result;
639     mInternalHeaders->Append(aHeader, aValue, result);
640 
641     if (NS_WARN_IF(result.Failed())) {
642       return result.StealNSResult();
643     }
644 
645     return NS_OK;
646   }
647 
Extract()648   RefPtr<InternalHeaders> Extract() {
649     return RefPtr<InternalHeaders>(std::move(mInternalHeaders));
650   }
651 
652  private:
653   ~HeaderFiller() = default;
654 
655   RefPtr<InternalHeaders> mInternalHeaders;
656 };
657 
NS_IMPL_ISUPPORTS(HeaderFiller,nsIHttpHeaderVisitor)658 NS_IMPL_ISUPPORTS(HeaderFiller, nsIHttpHeaderVisitor)
659 
660 Result<IPCInternalRequest, nsresult> GetIPCInternalRequest(
661     nsIInterceptedChannel* aChannel) {
662   AssertIsOnMainThread();
663 
664   nsCOMPtr<nsIURI> uri;
665   MOZ_TRY(aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri)));
666 
667   nsCOMPtr<nsIURI> uriNoFragment;
668   MOZ_TRY(NS_GetURIWithoutRef(uri, getter_AddRefs(uriNoFragment)));
669 
670   nsCOMPtr<nsIChannel> underlyingChannel;
671   MOZ_TRY(aChannel->GetChannel(getter_AddRefs(underlyingChannel)));
672 
673   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(underlyingChannel);
674   MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
675 
676   nsCOMPtr<nsIHttpChannelInternal> internalChannel =
677       do_QueryInterface(httpChannel);
678   NS_ENSURE_TRUE(internalChannel, Err(NS_ERROR_NOT_AVAILABLE));
679 
680   nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel =
681       do_QueryInterface(underlyingChannel);
682 
683   nsAutoCString spec;
684   MOZ_TRY(uriNoFragment->GetSpec(spec));
685 
686   nsAutoCString fragment;
687   MOZ_TRY(uri->GetRef(fragment));
688 
689   nsAutoCString method;
690   MOZ_TRY(httpChannel->GetRequestMethod(method));
691 
692   // This is safe due to static_asserts in ServiceWorkerManager.cpp
693   uint32_t cacheModeInt;
694   MOZ_ALWAYS_SUCCEEDS(internalChannel->GetFetchCacheMode(&cacheModeInt));
695   RequestCache cacheMode = static_cast<RequestCache>(cacheModeInt);
696 
697   RequestMode requestMode =
698       InternalRequest::MapChannelToRequestMode(underlyingChannel);
699 
700   // This is safe due to static_asserts in ServiceWorkerManager.cpp
701   uint32_t redirectMode;
702   MOZ_ALWAYS_SUCCEEDS(internalChannel->GetRedirectMode(&redirectMode));
703   RequestRedirect requestRedirect = static_cast<RequestRedirect>(redirectMode);
704 
705   RequestCredentials requestCredentials =
706       InternalRequest::MapChannelToRequestCredentials(underlyingChannel);
707 
708   nsAutoString referrer;
709   ReferrerPolicy referrerPolicy = ReferrerPolicy::_empty;
710 
711   nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo();
712   if (referrerInfo) {
713     referrerPolicy = referrerInfo->ReferrerPolicy();
714     Unused << referrerInfo->GetComputedReferrerSpec(referrer);
715   }
716 
717   uint32_t loadFlags;
718   MOZ_TRY(underlyingChannel->GetLoadFlags(&loadFlags));
719 
720   nsCOMPtr<nsILoadInfo> loadInfo = underlyingChannel->LoadInfo();
721   nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType();
722 
723   nsAutoString integrity;
724   MOZ_TRY(internalChannel->GetIntegrityMetadata(integrity));
725 
726   RefPtr<HeaderFiller> headerFiller =
727       MakeRefPtr<HeaderFiller>(HeadersGuardEnum::Request);
728   MOZ_TRY(httpChannel->VisitNonDefaultRequestHeaders(headerFiller));
729 
730   RefPtr<InternalHeaders> internalHeaders = headerFiller->Extract();
731 
732   ErrorResult result;
733   internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result);
734   if (NS_WARN_IF(result.Failed())) {
735     return Err(result.StealNSResult());
736   }
737 
738   nsTArray<HeadersEntry> ipcHeaders;
739   HeadersGuardEnum ipcHeadersGuard;
740   internalHeaders->ToIPC(ipcHeaders, ipcHeadersGuard);
741 
742   nsAutoCString alternativeDataType;
743   if (cacheInfoChannel &&
744       !cacheInfoChannel->PreferredAlternativeDataTypes().IsEmpty()) {
745     // TODO: the internal request probably needs all the preferred types.
746     alternativeDataType.Assign(
747         cacheInfoChannel->PreferredAlternativeDataTypes()[0].type());
748   }
749 
750   Maybe<PrincipalInfo> principalInfo;
751 
752   if (loadInfo->TriggeringPrincipal()) {
753     principalInfo.emplace();
754     MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo(
755         loadInfo->TriggeringPrincipal(), principalInfo.ptr()));
756   }
757 
758   // Note: all the arguments are copied rather than moved, which would be more
759   // efficient, because there's no move-friendly constructor generated.
760   return IPCInternalRequest(
761       method, {spec}, ipcHeadersGuard, ipcHeaders, Nothing(), -1,
762       alternativeDataType, contentPolicyType, referrer, referrerPolicy,
763       requestMode, requestCredentials, cacheMode, requestRedirect, integrity,
764       fragment, principalInfo);
765 }
766 
MaybeStoreStreamForBackgroundThread(nsIInterceptedChannel * aChannel,IPCInternalRequest & aIPCRequest)767 nsresult MaybeStoreStreamForBackgroundThread(nsIInterceptedChannel* aChannel,
768                                              IPCInternalRequest& aIPCRequest) {
769   nsCOMPtr<nsIChannel> channel;
770   MOZ_ALWAYS_SUCCEEDS(aChannel->GetChannel(getter_AddRefs(channel)));
771 
772   Maybe<BodyStreamVariant> body;
773   int64_t bodySize = -1;
774   nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
775 
776   if (uploadChannel) {
777     nsCOMPtr<nsIInputStream> uploadStream;
778     MOZ_TRY(uploadChannel->CloneUploadStream(&aIPCRequest.bodySize(),
779                                              getter_AddRefs(uploadStream)));
780 
781     if (uploadStream) {
782       Maybe<BodyStreamVariant>& body = aIPCRequest.body();
783       body.emplace(ParentToParentStream());
784 
785       MOZ_TRY(nsContentUtils::GenerateUUIDInPlace(
786           body->get_ParentToParentStream().uuid()));
787 
788       auto storageOrErr = RemoteLazyInputStreamStorage::Get();
789       if (NS_WARN_IF(storageOrErr.isErr())) {
790         return storageOrErr.unwrapErr();
791       }
792 
793       auto storage = storageOrErr.unwrap();
794       storage->AddStream(uploadStream, body->get_ParentToParentStream().uuid(),
795                          bodySize, 0);
796     }
797   }
798 
799   return NS_OK;
800 }
801 
802 }  // anonymous namespace
803 
SendFetchEvent(RefPtr<ServiceWorkerRegistrationInfo> aRegistration,nsCOMPtr<nsIInterceptedChannel> aChannel,const nsAString & aClientId,const nsAString & aResultingClientId)804 nsresult ServiceWorkerPrivateImpl::SendFetchEvent(
805     RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
806     nsCOMPtr<nsIInterceptedChannel> aChannel, const nsAString& aClientId,
807     const nsAString& aResultingClientId) {
808   AssertIsOnMainThread();
809   MOZ_ASSERT(mOuter);
810   MOZ_ASSERT(mOuter->mInfo);
811   MOZ_ASSERT(aRegistration);
812   MOZ_ASSERT(aChannel);
813 
814   auto scopeExit = MakeScopeExit([&] {
815     aChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
816     Shutdown();
817   });
818 
819   nsCOMPtr<nsIChannel> channel;
820   MOZ_TRY(aChannel->GetChannel(getter_AddRefs(channel)));
821 
822   IPCInternalRequest request;
823   MOZ_TRY_VAR(request, GetIPCInternalRequest(aChannel));
824 
825   scopeExit.release();
826 
827   ServiceWorkerFetchEventOpArgs args(
828       mOuter->mInfo->ScriptSpec(), std::move(request), nsString(aClientId),
829       nsString(aResultingClientId),
830       nsContentUtils::IsNonSubresourceRequest(channel),
831       mOuter->mInfo->TestingInjectCancellation());
832 
833   if (mOuter->mInfo->State() == ServiceWorkerState::Activating) {
834     UniquePtr<PendingFunctionalEvent> pendingEvent =
835         MakeUnique<PendingFetchEvent>(this, std::move(aRegistration),
836                                       std::move(args), std::move(aChannel));
837 
838     mPendingFunctionalEvents.AppendElement(std::move(pendingEvent));
839 
840     return NS_OK;
841   }
842 
843   MOZ_ASSERT(mOuter->mInfo->State() == ServiceWorkerState::Activated);
844 
845   return SendFetchEventInternal(std::move(aRegistration), std::move(args),
846                                 std::move(aChannel));
847 }
848 
SendFetchEventInternal(RefPtr<ServiceWorkerRegistrationInfo> && aRegistration,ServiceWorkerFetchEventOpArgs && aArgs,nsCOMPtr<nsIInterceptedChannel> && aChannel)849 nsresult ServiceWorkerPrivateImpl::SendFetchEventInternal(
850     RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
851     ServiceWorkerFetchEventOpArgs&& aArgs,
852     nsCOMPtr<nsIInterceptedChannel>&& aChannel) {
853   AssertIsOnMainThread();
854   MOZ_ASSERT(mOuter);
855 
856   auto scopeExit = MakeScopeExit([&] { Shutdown(); });
857 
858   if (NS_WARN_IF(!mOuter->mInfo)) {
859     return NS_ERROR_DOM_INVALID_STATE_ERR;
860   }
861 
862   MOZ_TRY(SpawnWorkerIfNeeded());
863   MOZ_TRY(
864       MaybeStoreStreamForBackgroundThread(aChannel, aArgs.internalRequest()));
865 
866   scopeExit.release();
867 
868   MOZ_ASSERT(mControllerChild);
869 
870   RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
871 
872   FetchEventOpChild::SendFetchEvent(
873       mControllerChild->get(), std::move(aArgs), std::move(aChannel),
874       std::move(aRegistration), mOuter->CreateEventKeepAliveToken())
875       ->Then(GetCurrentSerialEventTarget(), __func__,
876              [holder = std::move(holder)](
877                  const GenericPromise::ResolveOrRejectValue& aResult) {
878                Unused << NS_WARN_IF(aResult.IsReject());
879              });
880 
881   return NS_OK;
882 }
883 
TerminateWorker()884 void ServiceWorkerPrivateImpl::TerminateWorker() {
885   AssertIsOnMainThread();
886   MOZ_ASSERT(mOuter);
887 
888   mOuter->mIdleWorkerTimer->Cancel();
889   mOuter->mIdleKeepAliveToken = nullptr;
890 
891   Shutdown();
892 }
893 
Shutdown()894 void ServiceWorkerPrivateImpl::Shutdown() {
895   AssertIsOnMainThread();
896 
897   if (!WorkerIsDead()) {
898     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
899 
900     MOZ_ASSERT(swm,
901                "All Service Workers should start shutting down before the "
902                "ServiceWorkerManager does!");
903 
904     auto shutdownStateId = swm->MaybeInitServiceWorkerShutdownProgress();
905 
906     RefPtr<GenericNonExclusivePromise> promise =
907         ShutdownInternal(shutdownStateId);
908     swm->BlockShutdownOn(promise, shutdownStateId);
909   }
910 
911   MOZ_ASSERT(WorkerIsDead());
912 }
913 
ShutdownInternal(uint32_t aShutdownStateId)914 RefPtr<GenericNonExclusivePromise> ServiceWorkerPrivateImpl::ShutdownInternal(
915     uint32_t aShutdownStateId) {
916   AssertIsOnMainThread();
917   MOZ_ASSERT(mControllerChild);
918 
919   mPendingFunctionalEvents.Clear();
920 
921   mControllerChild->get()->RevokeObserver(this);
922 
923   if (StaticPrefs::dom_serviceWorkers_testing_enabled()) {
924     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
925     if (os) {
926       os->NotifyObservers(nullptr, "service-worker-shutdown", nullptr);
927     }
928   }
929 
930   RefPtr<GenericNonExclusivePromise::Private> promise =
931       new GenericNonExclusivePromise::Private(__func__);
932 
933   Unused << ExecServiceWorkerOp(
934       ServiceWorkerTerminateWorkerOpArgs(aShutdownStateId),
935       [promise](ServiceWorkerOpResult&& aResult) {
936         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
937         promise->Resolve(true, __func__);
938       },
939       [promise]() { promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__); });
940 
941   /**
942    * After dispatching a termination operation, no new operations should
943    * be routed through this actor anymore.
944    */
945   mControllerChild = nullptr;
946 
947   return promise;
948 }
949 
UpdateState(ServiceWorkerState aState)950 void ServiceWorkerPrivateImpl::UpdateState(ServiceWorkerState aState) {
951   AssertIsOnMainThread();
952   MOZ_ASSERT(mOuter);
953 
954   if (WorkerIsDead()) {
955     return;
956   }
957 
958   nsresult rv = ExecServiceWorkerOp(
959       ServiceWorkerUpdateStateOpArgs(aState),
960       [](ServiceWorkerOpResult&& aResult) {
961         MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
962       });
963 
964   if (NS_WARN_IF(NS_FAILED(rv))) {
965     Shutdown();
966     return;
967   }
968 
969   if (aState != ServiceWorkerState::Activated) {
970     return;
971   }
972 
973   for (auto& event : mPendingFunctionalEvents) {
974     Unused << NS_WARN_IF(NS_FAILED(event->Send()));
975   }
976 
977   mPendingFunctionalEvents.Clear();
978 }
979 
NoteDeadOuter()980 void ServiceWorkerPrivateImpl::NoteDeadOuter() {
981   AssertIsOnMainThread();
982   MOZ_ASSERT(mOuter);
983 
984   Shutdown();
985   mOuter = nullptr;
986 }
987 
CreationFailed()988 void ServiceWorkerPrivateImpl::CreationFailed() {
989   MOZ_ASSERT(NS_IsMainThread());
990   MOZ_ASSERT(mOuter);
991   MOZ_ASSERT(mControllerChild);
992 
993   Shutdown();
994 }
995 
CreationSucceeded()996 void ServiceWorkerPrivateImpl::CreationSucceeded() {
997   AssertIsOnMainThread();
998   MOZ_ASSERT(NS_IsMainThread());
999   MOZ_ASSERT(mOuter);
1000   MOZ_ASSERT(mControllerChild);
1001 
1002   mOuter->RenewKeepAliveToken(ServiceWorkerPrivate::WakeUpReason::Unknown);
1003 }
1004 
ErrorReceived(const ErrorValue & aError)1005 void ServiceWorkerPrivateImpl::ErrorReceived(const ErrorValue& aError) {
1006   AssertIsOnMainThread();
1007   MOZ_ASSERT(mOuter);
1008   MOZ_ASSERT(mOuter->mInfo);
1009   MOZ_ASSERT(mControllerChild);
1010 
1011   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
1012   MOZ_ASSERT(swm);
1013 
1014   ServiceWorkerInfo* info = mOuter->mInfo;
1015 
1016   swm->HandleError(nullptr, info->Principal(), info->Scope(),
1017                    NS_ConvertUTF8toUTF16(info->ScriptSpec()), u""_ns, u""_ns,
1018                    u""_ns, 0, 0, nsIScriptError::errorFlag, JSEXN_ERR);
1019 }
1020 
Terminated()1021 void ServiceWorkerPrivateImpl::Terminated() {
1022   AssertIsOnMainThread();
1023   MOZ_ASSERT(mOuter);
1024   MOZ_ASSERT(mControllerChild);
1025 
1026   Shutdown();
1027 }
1028 
WorkerIsDead() const1029 bool ServiceWorkerPrivateImpl::WorkerIsDead() const {
1030   AssertIsOnMainThread();
1031 
1032   return !mControllerChild;
1033 }
1034 
ExecServiceWorkerOp(ServiceWorkerOpArgs && aArgs,std::function<void (ServiceWorkerOpResult &&)> && aSuccessCallback,std::function<void ()> && aFailureCallback)1035 nsresult ServiceWorkerPrivateImpl::ExecServiceWorkerOp(
1036     ServiceWorkerOpArgs&& aArgs,
1037     std::function<void(ServiceWorkerOpResult&&)>&& aSuccessCallback,
1038     std::function<void()>&& aFailureCallback) {
1039   AssertIsOnMainThread();
1040   MOZ_ASSERT(mOuter);
1041   MOZ_ASSERT(
1042       aArgs.type() != ServiceWorkerOpArgs::TServiceWorkerFetchEventOpArgs,
1043       "FetchEvent operations should be sent through FetchEventOp(Proxy) "
1044       "actors!");
1045   MOZ_ASSERT(aSuccessCallback);
1046 
1047   nsresult rv = SpawnWorkerIfNeeded();
1048 
1049   if (NS_WARN_IF(NS_FAILED(rv))) {
1050     aFailureCallback();
1051     return rv;
1052   }
1053 
1054   MOZ_ASSERT(mControllerChild);
1055 
1056   RefPtr<ServiceWorkerPrivateImpl> self = this;
1057   RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
1058   RefPtr<KeepAliveToken> token =
1059       aArgs.type() == ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs
1060           ? nullptr
1061           : mOuter->CreateEventKeepAliveToken();
1062 
1063   /**
1064    * NOTE: moving `aArgs` won't do anything until IPDL `SendMethod()` methods
1065    * can accept rvalue references rather than just const references.
1066    */
1067   mControllerChild->get()->SendExecServiceWorkerOp(aArgs)->Then(
1068       GetCurrentSerialEventTarget(), __func__,
1069       [self = std::move(self), holder = std::move(holder),
1070        token = std::move(token), onSuccess = std::move(aSuccessCallback),
1071        onFailure = std::move(aFailureCallback)](
1072           PRemoteWorkerControllerChild::ExecServiceWorkerOpPromise::
1073               ResolveOrRejectValue&& aResult) {
1074         if (NS_WARN_IF(aResult.IsReject())) {
1075           onFailure();
1076           return;
1077         }
1078 
1079         onSuccess(std::move(aResult.ResolveValue()));
1080       });
1081 
1082   return NS_OK;
1083 }
1084 
1085 }  // namespace dom
1086 }  // namespace mozilla
1087