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