Source code

Revision control

Other Tools

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 "nsINetworkInterceptController.h"
18
#include "nsIObserverService.h"
19
#include "nsIURI.h"
20
#include "nsThreadUtils.h"
21
22
#include "ServiceWorkerManager.h"
23
#include "ServiceWorkerRegistrationInfo.h"
24
#include "mozilla/Assertions.h"
25
#include "mozilla/ErrorResult.h"
26
#include "mozilla/Maybe.h"
27
#include "mozilla/ScopeExit.h"
28
#include "mozilla/Services.h"
29
#include "mozilla/StaticPrefs_dom.h"
30
#include "mozilla/SystemGroup.h"
31
#include "mozilla/Unused.h"
32
#include "mozilla/dom/ClientIPCTypes.h"
33
#include "mozilla/dom/DOMTypes.h"
34
#include "mozilla/dom/FetchEventOpChild.h"
35
#include "mozilla/dom/InternalHeaders.h"
36
#include "mozilla/dom/ReferrerInfo.h"
37
#include "mozilla/dom/RemoteWorkerControllerChild.h"
38
#include "mozilla/dom/ServiceWorkerBinding.h"
39
#include "mozilla/ipc/BackgroundChild.h"
40
#include "mozilla/ipc/IPCStreamUtils.h"
41
42
namespace mozilla {
43
44
using namespace ipc;
45
46
namespace dom {
47
48
ServiceWorkerPrivateImpl::RAIIActorPtrHolder::RAIIActorPtrHolder(
49
already_AddRefed<RemoteWorkerControllerChild> aActor)
50
: mActor(aActor) {
51
AssertIsOnMainThread();
52
MOZ_ASSERT(mActor);
53
MOZ_ASSERT(mActor->Manager());
54
}
55
56
ServiceWorkerPrivateImpl::RAIIActorPtrHolder::~RAIIActorPtrHolder() {
57
AssertIsOnMainThread();
58
59
mDestructorPromiseHolder.ResolveIfExists(true, __func__);
60
61
mActor->MaybeSendDelete();
62
}
63
64
RemoteWorkerControllerChild*
65
ServiceWorkerPrivateImpl::RAIIActorPtrHolder::operator->() const {
66
AssertIsOnMainThread();
67
68
return get();
69
}
70
71
RemoteWorkerControllerChild* ServiceWorkerPrivateImpl::RAIIActorPtrHolder::get()
72
const {
73
AssertIsOnMainThread();
74
75
return mActor.get();
76
}
77
78
RefPtr<GenericPromise>
79
ServiceWorkerPrivateImpl::RAIIActorPtrHolder::OnDestructor() {
80
AssertIsOnMainThread();
81
82
return mDestructorPromiseHolder.Ensure(__func__);
83
}
84
85
ServiceWorkerPrivateImpl::ServiceWorkerPrivateImpl(
86
RefPtr<ServiceWorkerPrivate> aOuter)
87
: mOuter(std::move(aOuter)) {
88
AssertIsOnMainThread();
89
MOZ_ASSERT(mOuter);
90
MOZ_ASSERT(WorkerIsDead());
91
}
92
93
nsresult ServiceWorkerPrivateImpl::Initialize() {
94
AssertIsOnMainThread();
95
MOZ_ASSERT(mOuter);
96
MOZ_ASSERT(mOuter->mInfo);
97
98
nsCOMPtr<nsIPrincipal> principal = mOuter->mInfo->Principal();
99
100
nsCOMPtr<nsIURI> uri;
101
nsresult rv = principal->GetURI(getter_AddRefs(uri));
102
103
if (NS_WARN_IF(NS_FAILED(rv))) {
104
return rv;
105
}
106
107
if (NS_WARN_IF(!uri)) {
108
return NS_ERROR_FAILURE;
109
}
110
111
URIParams baseScriptURL;
112
SerializeURI(uri, baseScriptURL);
113
114
nsString id;
115
rv = mOuter->mInfo->GetId(id);
116
117
if (NS_WARN_IF(NS_FAILED(rv))) {
118
return rv;
119
}
120
121
PrincipalInfo principalInfo;
122
rv = PrincipalToPrincipalInfo(principal, &principalInfo);
123
124
if (NS_WARN_IF(NS_FAILED(rv))) {
125
return rv;
126
}
127
128
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
129
130
if (NS_WARN_IF(!swm)) {
131
return NS_ERROR_DOM_ABORT_ERR;
132
}
133
134
RefPtr<ServiceWorkerRegistrationInfo> regInfo =
135
swm->GetRegistration(principal, mOuter->mInfo->Scope());
136
137
if (NS_WARN_IF(!regInfo)) {
138
return NS_ERROR_DOM_INVALID_STATE_ERR;
139
}
140
141
nsCOMPtr<nsICookieSettings> cookieSettings =
142
mozilla::net::CookieSettings::Create();
143
MOZ_ASSERT(cookieSettings);
144
145
StorageAccess storageAccess =
146
StorageAllowedForServiceWorker(principal, cookieSettings);
147
148
ServiceWorkerData serviceWorkerData;
149
serviceWorkerData.cacheName() = mOuter->mInfo->CacheName();
150
serviceWorkerData.loadFlags() =
151
static_cast<uint32_t>(mOuter->mInfo->GetImportsLoadFlags() |
152
nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
153
serviceWorkerData.id() = std::move(id);
154
155
mRemoteWorkerData.originalScriptURL() =
156
NS_ConvertUTF8toUTF16(mOuter->mInfo->ScriptSpec());
157
mRemoteWorkerData.baseScriptURL() = baseScriptURL;
158
mRemoteWorkerData.resolvedScriptURL() = baseScriptURL;
159
mRemoteWorkerData.name() = VoidString();
160
161
mRemoteWorkerData.loadingPrincipalInfo() = principalInfo;
162
mRemoteWorkerData.principalInfo() = principalInfo;
163
// storagePrincipalInfo for ServiceWorkers is equal to principalInfo because,
164
// at the moment, ServiceWorkers are not exposed in partitioned contexts.
165
mRemoteWorkerData.storagePrincipalInfo() = principalInfo;
166
167
rv = uri->GetHost(mRemoteWorkerData.domain());
168
NS_ENSURE_SUCCESS(rv, rv);
169
mRemoteWorkerData.isSecureContext() = true;
170
mRemoteWorkerData.referrerInfo() = MakeAndAddRef<ReferrerInfo>();
171
mRemoteWorkerData.storageAccess() = storageAccess;
172
mRemoteWorkerData.serviceWorkerData() = std::move(serviceWorkerData);
173
174
mRemoteWorkerData.agentClusterId() = regInfo->AgentClusterId();
175
176
// This fills in the rest of mRemoteWorkerData.serviceWorkerData().
177
RefreshRemoteWorkerData(regInfo);
178
179
return NS_OK;
180
}
181
182
RefPtr<GenericPromise> ServiceWorkerPrivateImpl::SetSkipWaitingFlag() {
183
AssertIsOnMainThread();
184
MOZ_ASSERT(mOuter);
185
MOZ_ASSERT(mOuter->mInfo);
186
187
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
188
189
if (!swm) {
190
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
191
}
192
193
RefPtr<ServiceWorkerRegistrationInfo> regInfo =
194
swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
195
196
if (!regInfo) {
197
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
198
}
199
200
mOuter->mInfo->SetSkipWaitingFlag();
201
202
RefPtr<GenericPromise::Private> promise =
203
new GenericPromise::Private(__func__);
204
205
regInfo->TryToActivateAsync([promise] { promise->Resolve(true, __func__); });
206
207
return promise;
208
}
209
210
void ServiceWorkerPrivateImpl::RefreshRemoteWorkerData(
211
const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) {
212
AssertIsOnMainThread();
213
MOZ_ASSERT(mOuter);
214
MOZ_ASSERT(mOuter->mInfo);
215
216
ServiceWorkerData& serviceWorkerData =
217
mRemoteWorkerData.serviceWorkerData().get_ServiceWorkerData();
218
serviceWorkerData.descriptor() = mOuter->mInfo->Descriptor().ToIPC();
219
serviceWorkerData.registrationDescriptor() =
220
aRegistration->Descriptor().ToIPC();
221
}
222
223
nsresult ServiceWorkerPrivateImpl::SpawnWorkerIfNeeded() {
224
AssertIsOnMainThread();
225
MOZ_ASSERT(mOuter);
226
MOZ_ASSERT(mOuter->mInfo);
227
228
if (mControllerChild) {
229
mOuter->RenewKeepAliveToken(ServiceWorkerPrivate::WakeUpReason::Unknown);
230
return NS_OK;
231
}
232
233
PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread();
234
235
if (NS_WARN_IF(!bgChild)) {
236
return NS_ERROR_DOM_INVALID_STATE_ERR;
237
}
238
239
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
240
241
if (NS_WARN_IF(!swm)) {
242
return NS_ERROR_DOM_ABORT_ERR;
243
}
244
245
RefPtr<ServiceWorkerRegistrationInfo> regInfo =
246
swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
247
248
if (NS_WARN_IF(!regInfo)) {
249
return NS_ERROR_DOM_INVALID_STATE_ERR;
250
}
251
252
RefreshRemoteWorkerData(regInfo);
253
254
RefPtr<RemoteWorkerControllerChild> controllerChild =
255
new RemoteWorkerControllerChild(this);
256
257
if (NS_WARN_IF(!bgChild->SendPRemoteWorkerControllerConstructor(
258
controllerChild, mRemoteWorkerData))) {
259
return NS_ERROR_DOM_INVALID_STATE_ERR;
260
}
261
262
/**
263
* Manutally `AddRef()` because `DeallocPRemoteWorkerControllerChild()`
264
* calls `Release()` and the `AllocPRemoteWorkerControllerChild()` function
265
* is not called.
266
*/
267
// NOLINTNEXTLINE(readability-redundant-smartptr-get)
268
controllerChild.get()->AddRef();
269
270
mControllerChild = new RAIIActorPtrHolder(controllerChild.forget());
271
272
return NS_OK;
273
}
274
275
ServiceWorkerPrivateImpl::~ServiceWorkerPrivateImpl() {
276
AssertIsOnMainThread();
277
MOZ_ASSERT(!mOuter);
278
MOZ_ASSERT(WorkerIsDead());
279
}
280
281
nsresult ServiceWorkerPrivateImpl::SendMessageEvent(
282
RefPtr<ServiceWorkerCloneData>&& aData,
283
const ClientInfoAndState& aClientInfoAndState) {
284
AssertIsOnMainThread();
285
MOZ_ASSERT(mOuter);
286
MOZ_ASSERT(aData);
287
288
auto scopeExit = MakeScopeExit([&] { Shutdown(); });
289
290
PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread();
291
292
if (NS_WARN_IF(!bgChild)) {
293
return NS_ERROR_DOM_INVALID_STATE_ERR;
294
}
295
296
ServiceWorkerMessageEventOpArgs args;
297
args.clientInfoAndState() = aClientInfoAndState;
298
if (!aData->BuildClonedMessageDataForBackgroundChild(bgChild,
299
args.clonedData())) {
300
return NS_ERROR_DOM_DATA_CLONE_ERR;
301
}
302
303
scopeExit.release();
304
305
return ExecServiceWorkerOp(
306
std::move(args), [](ServiceWorkerOpResult&& aResult) {
307
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
308
});
309
}
310
311
nsresult ServiceWorkerPrivateImpl::CheckScriptEvaluation(
312
RefPtr<LifeCycleEventCallback> aCallback) {
313
MOZ_ASSERT(NS_IsMainThread());
314
MOZ_ASSERT(mOuter);
315
MOZ_ASSERT(aCallback);
316
317
RefPtr<ServiceWorkerPrivateImpl> self = this;
318
319
/**
320
* We need to capture the actor associated with the current Service Worker so
321
* we can terminate it if script evaluation failed.
322
*/
323
nsresult rv = SpawnWorkerIfNeeded();
324
325
if (NS_WARN_IF(NS_FAILED(rv))) {
326
aCallback->SetResult(false);
327
aCallback->Run();
328
329
return rv;
330
}
331
332
MOZ_ASSERT(mControllerChild);
333
334
RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
335
336
return ExecServiceWorkerOp(
337
ServiceWorkerCheckScriptEvaluationOpArgs(),
338
[self = std::move(self), holder = std::move(holder),
339
callback = aCallback](ServiceWorkerOpResult&& aResult) mutable {
340
if (aResult.type() == ServiceWorkerOpResult::
341
TServiceWorkerCheckScriptEvaluationOpResult) {
342
auto& result =
343
aResult.get_ServiceWorkerCheckScriptEvaluationOpResult();
344
345
if (result.workerScriptExecutedSuccessfully()) {
346
if (self->mOuter) {
347
self->mOuter->SetHandlesFetch(result.fetchHandlerWasAdded());
348
}
349
350
Unused << NS_WARN_IF(!self->mOuter);
351
352
callback->SetResult(result.workerScriptExecutedSuccessfully());
353
callback->Run();
354
355
return;
356
}
357
}
358
359
/**
360
* If script evaluation failed, first terminate the Service Worker
361
* before invoking the callback.
362
*/
363
MOZ_ASSERT_IF(aResult.type() == ServiceWorkerOpResult::Tnsresult,
364
NS_FAILED(aResult.get_nsresult()));
365
366
// If a termination operation was already issued using `holder`...
367
if (self->mControllerChild != holder) {
368
holder->OnDestructor()->Then(
369
GetCurrentThreadSerialEventTarget(), __func__,
370
[callback = std::move(callback)](
371
const GenericPromise::ResolveOrRejectValue&) {
372
callback->SetResult(false);
373
callback->Run();
374
});
375
376
return;
377
}
378
379
RefPtr<GenericNonExclusivePromise> promise = self->ShutdownInternal();
380
381
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
382
MOZ_ASSERT(swm);
383
384
swm->BlockShutdownOn(promise);
385
386
promise->Then(
387
GetCurrentThreadSerialEventTarget(), __func__,
388
[callback = std::move(callback)](
389
const GenericNonExclusivePromise::ResolveOrRejectValue&) {
390
callback->SetResult(false);
391
callback->Run();
392
});
393
},
394
[callback = aCallback] {
395
callback->SetResult(false);
396
callback->Run();
397
});
398
}
399
400
nsresult ServiceWorkerPrivateImpl::SendLifeCycleEvent(
401
const nsAString& aEventName, RefPtr<LifeCycleEventCallback> aCallback) {
402
AssertIsOnMainThread();
403
MOZ_ASSERT(mOuter);
404
MOZ_ASSERT(aCallback);
405
406
return ExecServiceWorkerOp(
407
ServiceWorkerLifeCycleEventOpArgs(nsString(aEventName)),
408
[callback = aCallback](ServiceWorkerOpResult&& aResult) {
409
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
410
411
callback->SetResult(NS_SUCCEEDED(aResult.get_nsresult()));
412
callback->Run();
413
},
414
[callback = aCallback] {
415
callback->SetResult(false);
416
callback->Run();
417
});
418
}
419
420
nsresult ServiceWorkerPrivateImpl::SendPushEvent(
421
RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
422
const nsAString& aMessageId, const Maybe<nsTArray<uint8_t>>& aData) {
423
AssertIsOnMainThread();
424
MOZ_ASSERT(mOuter);
425
MOZ_ASSERT(aRegistration);
426
427
ServiceWorkerPushEventOpArgs args;
428
args.messageId() = nsString(aMessageId);
429
430
if (aData) {
431
args.data() = aData.ref();
432
} else {
433
args.data() = void_t();
434
}
435
436
if (mOuter->mInfo->State() == ServiceWorkerState::Activating) {
437
UniquePtr<PendingFunctionalEvent> pendingEvent =
438
MakeUnique<PendingPushEvent>(this, std::move(aRegistration),
439
std::move(args));
440
441
mPendingFunctionalEvents.AppendElement(std::move(pendingEvent));
442
443
return NS_OK;
444
}
445
446
MOZ_ASSERT(mOuter->mInfo->State() == ServiceWorkerState::Activated);
447
448
return SendPushEventInternal(std::move(aRegistration), std::move(args));
449
}
450
451
nsresult ServiceWorkerPrivateImpl::SendPushEventInternal(
452
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
453
ServiceWorkerPushEventOpArgs&& aArgs) {
454
AssertIsOnMainThread();
455
MOZ_ASSERT(mOuter);
456
MOZ_ASSERT(aRegistration);
457
458
return ExecServiceWorkerOp(
459
std::move(aArgs),
460
[registration = aRegistration](ServiceWorkerOpResult&& aResult) {
461
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
462
463
registration->MaybeScheduleTimeCheckAndUpdate();
464
},
465
[registration = aRegistration]() {
466
registration->MaybeScheduleTimeCheckAndUpdate();
467
});
468
}
469
470
nsresult ServiceWorkerPrivateImpl::SendPushSubscriptionChangeEvent() {
471
AssertIsOnMainThread();
472
MOZ_ASSERT(mOuter);
473
474
return ExecServiceWorkerOp(
475
ServiceWorkerPushSubscriptionChangeEventOpArgs(),
476
[](ServiceWorkerOpResult&& aResult) {
477
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
478
});
479
}
480
481
nsresult ServiceWorkerPrivateImpl::SendNotificationEvent(
482
const nsAString& aEventName, const nsAString& aID, const nsAString& aTitle,
483
const nsAString& aDir, const nsAString& aLang, const nsAString& aBody,
484
const nsAString& aTag, const nsAString& aIcon, const nsAString& aData,
485
const nsAString& aBehavior, const nsAString& aScope,
486
uint32_t aDisableOpenClickDelay) {
487
AssertIsOnMainThread();
488
MOZ_ASSERT(mOuter);
489
490
ServiceWorkerNotificationEventOpArgs args;
491
args.eventName() = nsString(aEventName);
492
args.id() = nsString(aID);
493
args.title() = nsString(aTitle);
494
args.dir() = nsString(aDir);
495
args.lang() = nsString(aLang);
496
args.body() = nsString(aBody);
497
args.tag() = nsString(aTag);
498
args.icon() = nsString(aIcon);
499
args.data() = nsString(aData);
500
args.behavior() = nsString(aBehavior);
501
args.scope() = nsString(aScope);
502
args.disableOpenClickDelay() = aDisableOpenClickDelay;
503
504
return ExecServiceWorkerOp(
505
std::move(args), [](ServiceWorkerOpResult&& aResult) {
506
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
507
});
508
}
509
510
ServiceWorkerPrivateImpl::PendingFunctionalEvent::PendingFunctionalEvent(
511
ServiceWorkerPrivateImpl* aOwner,
512
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration)
513
: mOwner(aOwner), mRegistration(std::move(aRegistration)) {
514
AssertIsOnMainThread();
515
MOZ_ASSERT(mOwner);
516
MOZ_ASSERT(mOwner->mOuter);
517
MOZ_ASSERT(mOwner->mOuter->mInfo);
518
MOZ_ASSERT(mOwner->mOuter->mInfo->State() == ServiceWorkerState::Activating);
519
MOZ_ASSERT(mRegistration);
520
}
521
522
ServiceWorkerPrivateImpl::PendingFunctionalEvent::~PendingFunctionalEvent() {
523
AssertIsOnMainThread();
524
}
525
526
ServiceWorkerPrivateImpl::PendingPushEvent::PendingPushEvent(
527
ServiceWorkerPrivateImpl* aOwner,
528
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
529
ServiceWorkerPushEventOpArgs&& aArgs)
530
: PendingFunctionalEvent(aOwner, std::move(aRegistration)),
531
mArgs(std::move(aArgs)) {
532
AssertIsOnMainThread();
533
}
534
535
nsresult ServiceWorkerPrivateImpl::PendingPushEvent::Send() {
536
AssertIsOnMainThread();
537
MOZ_ASSERT(mOwner->mOuter);
538
MOZ_ASSERT(mOwner->mOuter->mInfo);
539
540
return mOwner->SendPushEventInternal(std::move(mRegistration),
541
std::move(mArgs));
542
}
543
544
ServiceWorkerPrivateImpl::PendingFetchEvent::PendingFetchEvent(
545
ServiceWorkerPrivateImpl* aOwner,
546
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
547
ServiceWorkerFetchEventOpArgs&& aArgs,
548
nsCOMPtr<nsIInterceptedChannel>&& aChannel)
549
: PendingFunctionalEvent(aOwner, std::move(aRegistration)),
550
mArgs(std::move(aArgs)),
551
mChannel(std::move(aChannel)) {
552
AssertIsOnMainThread();
553
MOZ_ASSERT(mChannel);
554
}
555
556
nsresult ServiceWorkerPrivateImpl::PendingFetchEvent::Send() {
557
AssertIsOnMainThread();
558
MOZ_ASSERT(mOwner->mOuter);
559
MOZ_ASSERT(mOwner->mOuter->mInfo);
560
561
return mOwner->SendFetchEventInternal(std::move(mRegistration),
562
std::move(mArgs), std::move(mChannel));
563
}
564
565
ServiceWorkerPrivateImpl::PendingFetchEvent::~PendingFetchEvent() {
566
AssertIsOnMainThread();
567
568
if (NS_WARN_IF(mChannel)) {
569
mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
570
}
571
}
572
573
nsresult ServiceWorkerPrivateImpl::SendFetchEvent(
574
RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
575
nsCOMPtr<nsIInterceptedChannel> aChannel, const nsAString& aClientId,
576
const nsAString& aResultingClientId, bool aIsReload) {
577
AssertIsOnMainThread();
578
MOZ_ASSERT(mOuter);
579
MOZ_ASSERT(aRegistration);
580
MOZ_ASSERT(aChannel);
581
582
auto scopeExit = MakeScopeExit([&] {
583
aChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED);
584
Shutdown();
585
});
586
587
nsCOMPtr<nsIChannel> channel;
588
nsresult rv = aChannel->GetChannel(getter_AddRefs(channel));
589
590
if (NS_WARN_IF(NS_FAILED(rv))) {
591
return rv;
592
}
593
594
scopeExit.release();
595
596
MOZ_ASSERT(mOuter->mInfo);
597
598
// FetchEventOpChild will fill in the IPCInternalRequest.
599
ServiceWorkerFetchEventOpArgs args(
600
mOuter->mInfo->ScriptSpec(), IPCInternalRequest(), nsString(aClientId),
601
nsString(aResultingClientId), aIsReload,
602
nsContentUtils::IsNonSubresourceRequest(channel));
603
604
if (mOuter->mInfo->State() == ServiceWorkerState::Activating) {
605
UniquePtr<PendingFunctionalEvent> pendingEvent =
606
MakeUnique<PendingFetchEvent>(this, std::move(aRegistration),
607
std::move(args), std::move(aChannel));
608
609
mPendingFunctionalEvents.AppendElement(std::move(pendingEvent));
610
611
return NS_OK;
612
}
613
614
MOZ_ASSERT(mOuter->mInfo->State() == ServiceWorkerState::Activated);
615
616
return SendFetchEventInternal(std::move(aRegistration), std::move(args),
617
std::move(aChannel));
618
}
619
620
nsresult ServiceWorkerPrivateImpl::SendFetchEventInternal(
621
RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration,
622
ServiceWorkerFetchEventOpArgs&& aArgs,
623
nsCOMPtr<nsIInterceptedChannel>&& aChannel) {
624
AssertIsOnMainThread();
625
MOZ_ASSERT(mOuter);
626
627
auto scopeExit = MakeScopeExit([&] { Shutdown(); });
628
629
if (NS_WARN_IF(!mOuter->mInfo)) {
630
return NS_ERROR_DOM_INVALID_STATE_ERR;
631
}
632
633
nsresult rv = SpawnWorkerIfNeeded();
634
635
if (NS_WARN_IF(NS_FAILED(rv))) {
636
return rv;
637
}
638
639
scopeExit.release();
640
641
MOZ_ASSERT(mControllerChild);
642
643
RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
644
645
FetchEventOpChild::SendFetchEvent(
646
mControllerChild->get(), std::move(aArgs), std::move(aChannel),
647
std::move(aRegistration), mOuter->CreateEventKeepAliveToken())
648
->Then(GetCurrentThreadSerialEventTarget(), __func__,
649
[holder = std::move(holder)](
650
const GenericPromise::ResolveOrRejectValue& aResult) {
651
Unused << NS_WARN_IF(aResult.IsReject());
652
});
653
654
return NS_OK;
655
}
656
657
void ServiceWorkerPrivateImpl::TerminateWorker() {
658
AssertIsOnMainThread();
659
MOZ_ASSERT(mOuter);
660
661
mOuter->mIdleWorkerTimer->Cancel();
662
mOuter->mIdleKeepAliveToken = nullptr;
663
664
Shutdown();
665
}
666
667
void ServiceWorkerPrivateImpl::Shutdown() {
668
AssertIsOnMainThread();
669
670
if (!WorkerIsDead()) {
671
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
672
673
MOZ_ASSERT(swm,
674
"All Service Workers should start shutting down before the "
675
"ServiceWorkerManager does!");
676
677
RefPtr<GenericNonExclusivePromise> promise = ShutdownInternal();
678
swm->BlockShutdownOn(promise);
679
}
680
681
MOZ_ASSERT(WorkerIsDead());
682
}
683
684
RefPtr<GenericNonExclusivePromise>
685
ServiceWorkerPrivateImpl::ShutdownInternal() {
686
AssertIsOnMainThread();
687
MOZ_ASSERT(mControllerChild);
688
689
mPendingFunctionalEvents.Clear();
690
691
mControllerChild->get()->RevokeObserver(this);
692
693
if (StaticPrefs::dom_serviceWorkers_testing_enabled()) {
694
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
695
if (os) {
696
os->NotifyObservers(nullptr, "service-worker-shutdown", nullptr);
697
}
698
}
699
700
RefPtr<GenericNonExclusivePromise::Private> promise =
701
new GenericNonExclusivePromise::Private(__func__);
702
703
Unused << ExecServiceWorkerOp(
704
ServiceWorkerTerminateWorkerOpArgs(),
705
[promise](ServiceWorkerOpResult&& aResult) {
706
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
707
promise->Resolve(true, __func__);
708
},
709
[promise]() { promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__); });
710
711
/**
712
* After dispatching a termination operation, no new operations should
713
* be routed through this actor anymore.
714
*/
715
mControllerChild = nullptr;
716
717
return promise;
718
}
719
720
void ServiceWorkerPrivateImpl::UpdateState(ServiceWorkerState aState) {
721
AssertIsOnMainThread();
722
MOZ_ASSERT(mOuter);
723
724
if (WorkerIsDead()) {
725
return;
726
}
727
728
nsresult rv = ExecServiceWorkerOp(
729
ServiceWorkerUpdateStateOpArgs(aState),
730
[](ServiceWorkerOpResult&& aResult) {
731
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
732
});
733
734
if (NS_WARN_IF(NS_FAILED(rv))) {
735
Shutdown();
736
return;
737
}
738
739
if (aState != ServiceWorkerState::Activated) {
740
return;
741
}
742
743
for (auto& event : mPendingFunctionalEvents) {
744
Unused << NS_WARN_IF(NS_FAILED(event->Send()));
745
}
746
747
mPendingFunctionalEvents.Clear();
748
}
749
750
void ServiceWorkerPrivateImpl::NoteDeadOuter() {
751
AssertIsOnMainThread();
752
MOZ_ASSERT(mOuter);
753
754
Shutdown();
755
mOuter = nullptr;
756
}
757
758
void ServiceWorkerPrivateImpl::CreationFailed() {
759
MOZ_ASSERT(NS_IsMainThread());
760
MOZ_ASSERT(mOuter);
761
MOZ_ASSERT(mControllerChild);
762
763
Shutdown();
764
}
765
766
void ServiceWorkerPrivateImpl::CreationSucceeded() {
767
AssertIsOnMainThread();
768
MOZ_ASSERT(NS_IsMainThread());
769
MOZ_ASSERT(mOuter);
770
MOZ_ASSERT(mControllerChild);
771
772
mOuter->RenewKeepAliveToken(ServiceWorkerPrivate::WakeUpReason::Unknown);
773
}
774
775
void ServiceWorkerPrivateImpl::ErrorReceived(const ErrorValue& aError) {
776
AssertIsOnMainThread();
777
MOZ_ASSERT(mOuter);
778
MOZ_ASSERT(mOuter->mInfo);
779
MOZ_ASSERT(mControllerChild);
780
781
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
782
MOZ_ASSERT(swm);
783
784
ServiceWorkerInfo* info = mOuter->mInfo;
785
786
swm->HandleError(nullptr, info->Principal(), info->Scope(),
787
NS_ConvertUTF8toUTF16(info->ScriptSpec()), EmptyString(),
788
EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
789
JSEXN_ERR);
790
}
791
792
void ServiceWorkerPrivateImpl::Terminated() {
793
AssertIsOnMainThread();
794
MOZ_ASSERT(mOuter);
795
MOZ_ASSERT(mControllerChild);
796
797
Shutdown();
798
}
799
800
bool ServiceWorkerPrivateImpl::WorkerIsDead() const {
801
AssertIsOnMainThread();
802
803
return !mControllerChild;
804
}
805
806
nsresult ServiceWorkerPrivateImpl::ExecServiceWorkerOp(
807
ServiceWorkerOpArgs&& aArgs,
808
std::function<void(ServiceWorkerOpResult&&)>&& aSuccessCallback,
809
std::function<void()>&& aFailureCallback) {
810
AssertIsOnMainThread();
811
MOZ_ASSERT(mOuter);
812
MOZ_ASSERT(
813
aArgs.type() != ServiceWorkerOpArgs::TServiceWorkerFetchEventOpArgs,
814
"FetchEvent operations should be sent through FetchEventOp(Proxy) "
815
"actors!");
816
MOZ_ASSERT(aSuccessCallback);
817
818
nsresult rv = SpawnWorkerIfNeeded();
819
820
if (NS_WARN_IF(NS_FAILED(rv))) {
821
aFailureCallback();
822
return rv;
823
}
824
825
MOZ_ASSERT(mControllerChild);
826
827
RefPtr<ServiceWorkerPrivateImpl> self = this;
828
RefPtr<RAIIActorPtrHolder> holder = mControllerChild;
829
RefPtr<KeepAliveToken> token =
830
aArgs.type() == ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs
831
? nullptr
832
: mOuter->CreateEventKeepAliveToken();
833
834
/**
835
* NOTE: moving `aArgs` won't do anything until IPDL `SendMethod()` methods
836
* can accept rvalue references rather than just const references.
837
*/
838
mControllerChild->get()->SendExecServiceWorkerOp(aArgs)->Then(
839
GetCurrentThreadSerialEventTarget(), __func__,
840
[self = std::move(self), holder = std::move(holder),
841
token = std::move(token), onSuccess = std::move(aSuccessCallback),
842
onFailure = std::move(aFailureCallback)](
843
PRemoteWorkerControllerChild::ExecServiceWorkerOpPromise::
844
ResolveOrRejectValue&& aResult) {
845
if (NS_WARN_IF(aResult.IsReject())) {
846
onFailure();
847
return;
848
}
849
850
onSuccess(std::move(aResult.ResolveValue()));
851
});
852
853
return NS_OK;
854
}
855
856
} // namespace dom
857
} // namespace mozilla