ServiceWorkerPrivate.cpp (71210B)
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 "ServiceWorkerPrivate.h" 8 9 #include <utility> 10 11 #include "MainThreadUtils.h" 12 #include "ServiceWorkerCloneData.h" 13 #include "ServiceWorkerManager.h" 14 #include "ServiceWorkerRegistrationInfo.h" 15 #include "ServiceWorkerUtils.h" 16 #include "js/ErrorReport.h" 17 #include "mozIThirdPartyUtil.h" 18 #include "mozilla/Assertions.h" 19 #include "mozilla/ContentBlockingAllowList.h" 20 #include "mozilla/CycleCollectedJSContext.h" // for MicroTaskRunnable 21 #include "mozilla/ErrorResult.h" 22 #include "mozilla/JSObjectHolder.h" 23 #include "mozilla/Maybe.h" 24 #include "mozilla/OriginAttributes.h" 25 #include "mozilla/Preferences.h" 26 #include "mozilla/RemoteLazyInputStreamStorage.h" 27 #include "mozilla/Result.h" 28 #include "mozilla/ScopeExit.h" 29 #include "mozilla/Services.h" 30 #include "mozilla/StaticPrefs_dom.h" 31 #include "mozilla/StaticPrefs_privacy.h" 32 #include "mozilla/StoragePrincipalHelper.h" 33 #include "mozilla/dom/Client.h" 34 #include "mozilla/dom/ClientIPCTypes.h" 35 #include "mozilla/dom/ClientManager.h" 36 #include "mozilla/dom/DOMTypes.h" 37 #include "mozilla/dom/FetchEventOpChild.h" 38 #include "mozilla/dom/FetchUtil.h" 39 #include "mozilla/dom/IndexedDatabaseManager.h" 40 #include "mozilla/dom/InternalHeaders.h" 41 #include "mozilla/dom/InternalRequest.h" 42 #include "mozilla/dom/NotificationEvent.h" 43 #include "mozilla/dom/PromiseNativeHandler.h" 44 #include "mozilla/dom/PushEventBinding.h" 45 #include "mozilla/dom/PushManager.h" 46 #include "mozilla/dom/ReferrerInfo.h" 47 #include "mozilla/dom/RemoteType.h" 48 #include "mozilla/dom/RemoteWorkerControllerChild.h" 49 #include "mozilla/dom/RemoteWorkerManager.h" // RemoteWorkerManager::GetRemoteType 50 #include "mozilla/dom/RequestBinding.h" 51 #include "mozilla/dom/RootedDictionary.h" 52 #include "mozilla/dom/ServiceWorkerBinding.h" 53 #include "mozilla/dom/ServiceWorkerLifetimeExtension.h" 54 #include "mozilla/dom/WorkerDebugger.h" 55 #include "mozilla/dom/WorkerRef.h" 56 #include "mozilla/dom/WorkerRunnable.h" 57 #include "mozilla/dom/WorkerScope.h" 58 #include "mozilla/dom/ipc/StructuredCloneData.h" 59 #include "mozilla/extensions/WebExtensionPolicy.h" // WebExtensionPolicy 60 #include "mozilla/glean/DomServiceworkersMetrics.h" 61 #include "mozilla/ipc/BackgroundChild.h" 62 #include "mozilla/ipc/BackgroundUtils.h" 63 #include "mozilla/ipc/IPCStreamUtils.h" 64 #include "mozilla/ipc/PBackgroundChild.h" 65 #include "mozilla/ipc/URIUtils.h" 66 #include "mozilla/net/CookieJarSettings.h" 67 #include "mozilla/net/CookieService.h" 68 #include "mozilla/net/NeckoChannelParams.h" 69 #include "nsContentUtils.h" 70 #include "nsDebug.h" 71 #include "nsError.h" 72 #include "nsICacheInfoChannel.h" 73 #include "nsIChannel.h" 74 #include "nsIHttpChannel.h" 75 #include "nsIHttpChannelInternal.h" 76 #include "nsIHttpHeaderVisitor.h" 77 #include "nsINamed.h" 78 #include "nsINetworkInterceptController.h" 79 #include "nsIObserverService.h" 80 #include "nsIRedirectHistoryEntry.h" 81 #include "nsIReferrerInfo.h" 82 #include "nsIScriptError.h" 83 #include "nsIScriptSecurityManager.h" 84 #include "nsISupportsImpl.h" 85 #include "nsISupportsPriority.h" 86 #include "nsIURI.h" 87 #include "nsIUploadChannel2.h" 88 #include "nsNetUtil.h" 89 #include "nsProxyRelease.h" 90 #include "nsQueryObject.h" 91 #include "nsRFPService.h" 92 #include "nsStreamUtils.h" 93 #include "nsStringStream.h" 94 #include "nsThreadUtils.h" 95 96 extern mozilla::LazyLogModule sWorkerTelemetryLog; 97 98 #ifdef LOG 99 # undef LOG 100 #endif 101 #define LOG(_args) MOZ_LOG(sWorkerTelemetryLog, LogLevel::Debug, _args); 102 103 using namespace mozilla; 104 using namespace mozilla::dom; 105 using namespace mozilla::ipc; 106 107 namespace mozilla::dom { 108 109 uint32_t ServiceWorkerPrivate::sRunningServiceWorkers = 0; 110 uint32_t ServiceWorkerPrivate::sRunningServiceWorkersFetch = 0; 111 uint32_t ServiceWorkerPrivate::sRunningServiceWorkersMax = 0; 112 uint32_t ServiceWorkerPrivate::sRunningServiceWorkersFetchMax = 0; 113 114 /** 115 * KeepAliveToken 116 */ 117 KeepAliveToken::KeepAliveToken(ServiceWorkerPrivate* aPrivate) 118 : mPrivate(aPrivate) { 119 MOZ_ASSERT(NS_IsMainThread()); 120 MOZ_ASSERT(aPrivate); 121 mPrivate->AddToken(); 122 } 123 124 KeepAliveToken::~KeepAliveToken() { 125 MOZ_ASSERT(NS_IsMainThread()); 126 mPrivate->ReleaseToken(); 127 } 128 129 NS_IMPL_ISUPPORTS0(KeepAliveToken) 130 131 /** 132 * RAIIActorPtrHolder 133 */ 134 ServiceWorkerPrivate::RAIIActorPtrHolder::RAIIActorPtrHolder( 135 already_AddRefed<RemoteWorkerControllerChild> aActor) 136 : mActor(aActor) { 137 AssertIsOnMainThread(); 138 MOZ_ASSERT(mActor); 139 MOZ_ASSERT(mActor->Manager()); 140 } 141 142 ServiceWorkerPrivate::RAIIActorPtrHolder::~RAIIActorPtrHolder() { 143 AssertIsOnMainThread(); 144 145 mDestructorPromiseHolder.ResolveIfExists(true, __func__); 146 147 mActor->MaybeSendDelete(); 148 } 149 150 RemoteWorkerControllerChild* 151 ServiceWorkerPrivate::RAIIActorPtrHolder::operator->() const { 152 AssertIsOnMainThread(); 153 154 return get(); 155 } 156 157 RemoteWorkerControllerChild* ServiceWorkerPrivate::RAIIActorPtrHolder::get() 158 const { 159 AssertIsOnMainThread(); 160 161 return mActor.get(); 162 } 163 164 RefPtr<GenericPromise> 165 ServiceWorkerPrivate::RAIIActorPtrHolder::OnDestructor() { 166 AssertIsOnMainThread(); 167 168 return mDestructorPromiseHolder.Ensure(__func__); 169 } 170 171 /** 172 * PendingFunctionEvent 173 */ 174 ServiceWorkerPrivate::PendingFunctionalEvent::PendingFunctionalEvent( 175 ServiceWorkerPrivate* aOwner, 176 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration) 177 : mOwner(aOwner), mRegistration(std::move(aRegistration)) { 178 AssertIsOnMainThread(); 179 MOZ_ASSERT(mOwner); 180 MOZ_ASSERT(mOwner->mInfo); 181 MOZ_ASSERT(mOwner->mInfo->State() == ServiceWorkerState::Activating); 182 MOZ_ASSERT(mRegistration); 183 } 184 185 ServiceWorkerPrivate::PendingFunctionalEvent::~PendingFunctionalEvent() { 186 AssertIsOnMainThread(); 187 } 188 189 ServiceWorkerPrivate::PendingCookieChangeEvent::PendingCookieChangeEvent( 190 ServiceWorkerPrivate* aOwner, 191 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 192 ServiceWorkerCookieChangeEventOpArgs&& aArgs) 193 : PendingFunctionalEvent(aOwner, std::move(aRegistration)), 194 mArgs(std::move(aArgs)) { 195 AssertIsOnMainThread(); 196 } 197 198 nsresult ServiceWorkerPrivate::PendingCookieChangeEvent::Send() { 199 AssertIsOnMainThread(); 200 MOZ_ASSERT(mOwner); 201 MOZ_ASSERT(mOwner->mInfo); 202 203 return mOwner->SendCookieChangeEventInternal(std::move(mRegistration), 204 std::move(mArgs)); 205 } 206 207 ServiceWorkerPrivate::PendingPushEvent::PendingPushEvent( 208 ServiceWorkerPrivate* aOwner, 209 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 210 ServiceWorkerPushEventOpArgs&& aArgs) 211 : PendingFunctionalEvent(aOwner, std::move(aRegistration)), 212 mArgs(std::move(aArgs)) { 213 AssertIsOnMainThread(); 214 } 215 216 nsresult ServiceWorkerPrivate::PendingPushEvent::Send() { 217 AssertIsOnMainThread(); 218 MOZ_ASSERT(mOwner); 219 MOZ_ASSERT(mOwner->mInfo); 220 221 return mOwner->SendPushEventInternal(std::move(mRegistration), 222 std::move(mArgs)); 223 } 224 225 ServiceWorkerPrivate::PendingFetchEvent::PendingFetchEvent( 226 ServiceWorkerPrivate* aOwner, 227 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 228 ParentToParentServiceWorkerFetchEventOpArgs&& aArgs, 229 nsCOMPtr<nsIInterceptedChannel>&& aChannel, 230 RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises) 231 : PendingFunctionalEvent(aOwner, std::move(aRegistration)), 232 mArgs(std::move(aArgs)), 233 mChannel(std::move(aChannel)), 234 mPreloadResponseReadyPromises(std::move(aPreloadResponseReadyPromises)) { 235 AssertIsOnMainThread(); 236 MOZ_ASSERT(mChannel); 237 } 238 239 nsresult ServiceWorkerPrivate::PendingFetchEvent::Send() { 240 AssertIsOnMainThread(); 241 MOZ_ASSERT(mOwner); 242 MOZ_ASSERT(mOwner->mInfo); 243 244 return mOwner->SendFetchEventInternal( 245 std::move(mRegistration), std::move(mArgs), std::move(mChannel), 246 std::move(mPreloadResponseReadyPromises)); 247 } 248 249 ServiceWorkerPrivate::PendingFetchEvent::~PendingFetchEvent() { 250 AssertIsOnMainThread(); 251 252 if (NS_WARN_IF(mChannel)) { 253 mChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); 254 } 255 } 256 257 namespace { 258 259 class HeaderFiller final : public nsIHttpHeaderVisitor { 260 public: 261 NS_DECL_ISUPPORTS 262 263 explicit HeaderFiller(HeadersGuardEnum aGuard) 264 : mInternalHeaders(new InternalHeaders(aGuard)) { 265 MOZ_ASSERT(mInternalHeaders); 266 } 267 268 NS_IMETHOD 269 VisitHeader(const nsACString& aHeader, const nsACString& aValue) override { 270 ErrorResult result; 271 mInternalHeaders->Append(aHeader, aValue, result); 272 273 if (NS_WARN_IF(result.Failed())) { 274 return result.StealNSResult(); 275 } 276 277 return NS_OK; 278 } 279 280 RefPtr<InternalHeaders> Extract() { 281 return RefPtr<InternalHeaders>(std::move(mInternalHeaders)); 282 } 283 284 private: 285 ~HeaderFiller() = default; 286 287 RefPtr<InternalHeaders> mInternalHeaders; 288 }; 289 290 NS_IMPL_ISUPPORTS(HeaderFiller, nsIHttpHeaderVisitor) 291 292 Result<IPCInternalRequest, nsresult> GetIPCInternalRequest( 293 nsIInterceptedChannel* aChannel) { 294 AssertIsOnMainThread(); 295 296 nsCOMPtr<nsIURI> uri; 297 MOZ_TRY(aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri))); 298 299 nsCOMPtr<nsIURI> uriNoFragment; 300 MOZ_TRY(NS_GetURIWithoutRef(uri, getter_AddRefs(uriNoFragment))); 301 302 nsCOMPtr<nsIChannel> underlyingChannel; 303 MOZ_TRY(aChannel->GetChannel(getter_AddRefs(underlyingChannel))); 304 305 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(underlyingChannel); 306 MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?"); 307 308 nsCOMPtr<nsIHttpChannelInternal> internalChannel = 309 do_QueryInterface(httpChannel); 310 NS_ENSURE_TRUE(internalChannel, Err(NS_ERROR_NOT_AVAILABLE)); 311 312 nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel = 313 do_QueryInterface(underlyingChannel); 314 315 nsAutoCString spec; 316 MOZ_TRY(uriNoFragment->GetSpec(spec)); 317 318 nsAutoCString fragment; 319 MOZ_TRY(uri->GetRef(fragment)); 320 321 nsAutoCString method; 322 MOZ_TRY(httpChannel->GetRequestMethod(method)); 323 324 // This is safe due to static_asserts in ServiceWorkerManager.cpp 325 uint32_t cacheModeInt; 326 MOZ_ALWAYS_SUCCEEDS(internalChannel->GetFetchCacheMode(&cacheModeInt)); 327 RequestCache cacheMode = static_cast<RequestCache>(cacheModeInt); 328 329 RequestMode requestMode = 330 InternalRequest::MapChannelToRequestMode(underlyingChannel); 331 332 // This is safe due to static_asserts in ServiceWorkerManager.cpp 333 uint32_t redirectMode; 334 MOZ_ALWAYS_SUCCEEDS(internalChannel->GetRedirectMode(&redirectMode)); 335 RequestRedirect requestRedirect = static_cast<RequestRedirect>(redirectMode); 336 337 // request's priority is not copied by the new Request() constructor used by 338 // a fetch() call while request's internal priority is. So let's use the 339 // default, otherwise a fetch(event.request) from a worker on an intercepted 340 // fetch event would adjust priority twice. 341 // https://fetch.spec.whatwg.org/#dom-global-fetch 342 // https://fetch.spec.whatwg.org/#dom-request 343 RequestPriority requestPriority = RequestPriority::Auto; 344 345 RequestCredentials requestCredentials = 346 InternalRequest::MapChannelToRequestCredentials(underlyingChannel); 347 348 nsAutoCString referrer; 349 ReferrerPolicy referrerPolicy = ReferrerPolicy::_empty; 350 ReferrerPolicy environmentReferrerPolicy = ReferrerPolicy::_empty; 351 352 nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo(); 353 if (referrerInfo) { 354 referrerPolicy = referrerInfo->ReferrerPolicy(); 355 (void)referrerInfo->GetComputedReferrerSpec(referrer); 356 } 357 358 uint32_t loadFlags; 359 MOZ_TRY(underlyingChannel->GetLoadFlags(&loadFlags)); 360 361 nsCOMPtr<nsILoadInfo> loadInfo = underlyingChannel->LoadInfo(); 362 nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType(); 363 364 int32_t internalPriority = nsISupportsPriority::PRIORITY_NORMAL; 365 if (nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(underlyingChannel)) { 366 p->GetPriority(&internalPriority); 367 } 368 369 nsAutoString integrity; 370 MOZ_TRY(loadInfo->GetIntegrityMetadata(integrity)); 371 372 RefPtr<HeaderFiller> headerFiller = 373 MakeRefPtr<HeaderFiller>(HeadersGuardEnum::Request); 374 MOZ_TRY(httpChannel->VisitNonDefaultRequestHeaders(headerFiller)); 375 376 RefPtr<InternalHeaders> internalHeaders = headerFiller->Extract(); 377 378 ErrorResult result; 379 internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result); 380 if (NS_WARN_IF(result.Failed())) { 381 return Err(result.StealNSResult()); 382 } 383 384 nsTArray<HeadersEntry> ipcHeaders; 385 HeadersGuardEnum ipcHeadersGuard; 386 internalHeaders->ToIPC(ipcHeaders, ipcHeadersGuard); 387 388 nsAutoCString alternativeDataType; 389 if (cacheInfoChannel && 390 !cacheInfoChannel->PreferredAlternativeDataTypes().IsEmpty()) { 391 // TODO: the internal request probably needs all the preferred types. 392 alternativeDataType.Assign( 393 cacheInfoChannel->PreferredAlternativeDataTypes()[0].type()); 394 } 395 396 Maybe<PrincipalInfo> principalInfo; 397 Maybe<PrincipalInfo> interceptionPrincipalInfo; 398 if (loadInfo->TriggeringPrincipal()) { 399 principalInfo.emplace(); 400 interceptionPrincipalInfo.emplace(); 401 MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo( 402 loadInfo->TriggeringPrincipal(), principalInfo.ptr())); 403 MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo( 404 loadInfo->TriggeringPrincipal(), interceptionPrincipalInfo.ptr())); 405 } 406 407 nsTArray<RedirectHistoryEntryInfo> redirectChain; 408 for (const nsCOMPtr<nsIRedirectHistoryEntry>& redirectEntry : 409 loadInfo->RedirectChain()) { 410 RedirectHistoryEntryInfo* entry = redirectChain.AppendElement(); 411 MOZ_ALWAYS_SUCCEEDS(RHEntryToRHEntryInfo(redirectEntry, entry)); 412 } 413 414 bool isThirdPartyChannel; 415 // ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance(); 416 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = 417 do_GetService(THIRDPARTYUTIL_CONTRACTID); 418 if (thirdPartyUtil) { 419 nsCOMPtr<nsIURI> uri; 420 MOZ_TRY(underlyingChannel->GetURI(getter_AddRefs(uri))); 421 MOZ_TRY(thirdPartyUtil->IsThirdPartyChannel(underlyingChannel, uri, 422 &isThirdPartyChannel)); 423 } 424 425 nsILoadInfo::CrossOriginEmbedderPolicy embedderPolicy = 426 loadInfo->GetLoadingEmbedderPolicy(); 427 428 // Note: all the arguments are copied rather than moved, which would be more 429 // efficient, because there's no move-friendly constructor generated. 430 return IPCInternalRequest( 431 method, {spec}, ipcHeadersGuard, ipcHeaders, Nothing(), -1, 432 alternativeDataType, contentPolicyType, internalPriority, referrer, 433 referrerPolicy, environmentReferrerPolicy, requestMode, 434 requestCredentials, cacheMode, requestRedirect, requestPriority, 435 integrity, false, fragment, principalInfo, interceptionPrincipalInfo, 436 contentPolicyType, redirectChain, isThirdPartyChannel, embedderPolicy); 437 } 438 439 nsresult MaybeStoreStreamForBackgroundThread(nsIInterceptedChannel* aChannel, 440 IPCInternalRequest& aIPCRequest) { 441 nsCOMPtr<nsIChannel> channel; 442 MOZ_ALWAYS_SUCCEEDS(aChannel->GetChannel(getter_AddRefs(channel))); 443 444 Maybe<BodyStreamVariant> body; 445 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel); 446 447 if (uploadChannel) { 448 nsCOMPtr<nsIInputStream> uploadStream; 449 MOZ_TRY(uploadChannel->CloneUploadStream(&aIPCRequest.bodySize(), 450 getter_AddRefs(uploadStream))); 451 452 if (uploadStream) { 453 Maybe<BodyStreamVariant>& body = aIPCRequest.body(); 454 body.emplace(ParentToParentStream()); 455 456 MOZ_TRY( 457 nsID::GenerateUUIDInPlace(body->get_ParentToParentStream().uuid())); 458 459 auto storageOrErr = RemoteLazyInputStreamStorage::Get(); 460 if (NS_WARN_IF(storageOrErr.isErr())) { 461 return storageOrErr.unwrapErr(); 462 } 463 464 auto storage = storageOrErr.unwrap(); 465 storage->AddStream(uploadStream, body->get_ParentToParentStream().uuid()); 466 } 467 } 468 469 return NS_OK; 470 } 471 472 } // anonymous namespace 473 474 /** 475 * ServiceWorkerPrivate 476 */ 477 ServiceWorkerPrivate::ServiceWorkerPrivate(ServiceWorkerInfo* aInfo) 478 : mInfo(aInfo), 479 mPendingSpawnLifetime( 480 ServiceWorkerLifetimeExtension(NoLifetimeExtension{})), 481 mDebuggerCount(0), 482 mTokenCount(0), 483 mLaunchCount(0) { 484 MOZ_ASSERT(NS_IsMainThread()); 485 MOZ_ASSERT(aInfo); 486 MOZ_ASSERT(!mControllerChild); 487 488 mIdleWorkerTimer = NS_NewTimer(); 489 MOZ_ASSERT(mIdleWorkerTimer); 490 491 // Assert in all debug builds as well as non-debug Nightly and Dev Edition. 492 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 493 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(Initialize())); 494 #else 495 MOZ_ALWAYS_SUCCEEDS(Initialize()); 496 #endif 497 } 498 499 ServiceWorkerPrivate::~ServiceWorkerPrivate() { 500 MOZ_ASSERT(!mTokenCount); 501 MOZ_ASSERT(!mInfo); 502 MOZ_ASSERT(!mControllerChild); 503 MOZ_ASSERT(mIdlePromiseHolder.IsEmpty()); 504 505 mIdleWorkerTimer->Cancel(); 506 } 507 508 nsresult ServiceWorkerPrivate::Initialize() { 509 AssertIsOnMainThread(); 510 MOZ_ASSERT(mInfo); 511 512 nsCOMPtr<nsIPrincipal> principal = mInfo->Principal(); 513 514 nsCOMPtr<nsIURI> uri; 515 auto* basePrin = BasePrincipal::Cast(principal); 516 nsresult rv = basePrin->GetURI(getter_AddRefs(uri)); 517 518 if (NS_WARN_IF(NS_FAILED(rv))) { 519 return rv; 520 } 521 522 if (NS_WARN_IF(!uri)) { 523 return NS_ERROR_FAILURE; 524 } 525 526 URIParams baseScriptURL; 527 SerializeURI(uri, baseScriptURL); 528 529 nsString id; 530 rv = mInfo->GetId(id); 531 532 if (NS_WARN_IF(NS_FAILED(rv))) { 533 return rv; 534 } 535 536 PrincipalInfo principalInfo; 537 rv = PrincipalToPrincipalInfo(principal, &principalInfo); 538 if (NS_WARN_IF(NS_FAILED(rv))) { 539 return rv; 540 } 541 542 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 543 544 if (NS_WARN_IF(!swm)) { 545 return NS_ERROR_DOM_ABORT_ERR; 546 } 547 548 RefPtr<ServiceWorkerRegistrationInfo> regInfo = 549 swm->GetRegistration(principal, mInfo->Scope()); 550 551 if (NS_WARN_IF(!regInfo)) { 552 return NS_ERROR_DOM_INVALID_STATE_ERR; 553 } 554 555 nsCOMPtr<nsICookieJarSettings> cookieJarSettings = 556 net::CookieJarSettings::Create(principal); 557 MOZ_ASSERT(cookieJarSettings); 558 559 // We can populate the partitionKey and the fingerprinting protection 560 // overrides using the originAttribute of the principal. If it has 561 // partitionKey set, It's a foreign partitioned principal and it implies that 562 // it's a third-party service worker. So, the cookieJarSettings can directly 563 // use the partitionKey from it. For first-party case, we can populate the 564 // partitionKey from the principal URI. 565 Maybe<RFPTargetSet> overriddenFingerprintingSettingsArg; 566 Maybe<RFPTargetSet> overriddenFingerprintingSettings; 567 nsCOMPtr<nsIURI> firstPartyURI; 568 bool foreignByAncestorContext = false; 569 bool isOn3PCBExceptionList = false; 570 // Firefox doesn't support service workers in PBM, 571 // but we add this just so that when we do, 572 // we can handle it correctly. 573 bool isPBM = principal->GetIsInPrivateBrowsing(); 574 if (!principal->OriginAttributesRef().mPartitionKey.IsEmpty()) { 575 net::CookieJarSettings::Cast(cookieJarSettings) 576 ->SetPartitionKey(principal->OriginAttributesRef().mPartitionKey); 577 578 // The service worker is for a third-party context, we get first-party 579 // domain from the partitionKey and the third-party domain from the 580 // principal of the service worker. Then, we can get the fingerprinting 581 // protection overrides using them. 582 nsAutoString scheme; 583 nsAutoString pkBaseDomain; 584 int32_t unused; 585 bool _foreignByAncestorContext; 586 587 if (OriginAttributes::ParsePartitionKey( 588 principal->OriginAttributesRef().mPartitionKey, scheme, 589 pkBaseDomain, unused, _foreignByAncestorContext)) { 590 foreignByAncestorContext = _foreignByAncestorContext; 591 rv = NS_NewURI(getter_AddRefs(firstPartyURI), 592 scheme + u"://"_ns + pkBaseDomain); 593 if (NS_SUCCEEDED(rv)) { 594 overriddenFingerprintingSettings = 595 nsRFPService::GetOverriddenFingerprintingSettingsForURI( 596 firstPartyURI, uri, isPBM); 597 if (overriddenFingerprintingSettings.isSome()) { 598 overriddenFingerprintingSettingsArg.emplace( 599 overriddenFingerprintingSettings.ref()); 600 } 601 602 RefPtr<net::CookieService> csSingleton = 603 net::CookieService::GetSingleton(); 604 isOn3PCBExceptionList = 605 csSingleton->ThirdPartyCookieBlockingExceptionsRef() 606 .CheckExceptionForURIs(firstPartyURI, uri); 607 } 608 } 609 } else if (!principal->OriginAttributesRef().mFirstPartyDomain.IsEmpty()) { 610 // Using the first party domain to know the context of the service worker. 611 // We will run into here if FirstPartyIsolation is enabled. In this case, 612 // the PartitionKey won't get populated. 613 // Because the service worker is only available in secure contexts, so we 614 // don't need to consider http and only use https as scheme to create 615 // the first-party URI 616 rv = NS_NewURI( 617 getter_AddRefs(firstPartyURI), 618 u"https://"_ns + principal->OriginAttributesRef().mFirstPartyDomain); 619 if (NS_SUCCEEDED(rv)) { 620 // If the first party domain is not a third-party domain, the service 621 // worker is running in first-party context. 622 bool isThirdParty; 623 rv = principal->IsThirdPartyURI(firstPartyURI, &isThirdParty); 624 NS_ENSURE_SUCCESS(rv, rv); 625 626 overriddenFingerprintingSettings = 627 isThirdParty 628 ? nsRFPService::GetOverriddenFingerprintingSettingsForURI( 629 firstPartyURI, uri, isPBM) 630 : nsRFPService::GetOverriddenFingerprintingSettingsForURI( 631 uri, nullptr, isPBM); 632 633 RefPtr<net::CookieService> csSingleton = 634 net::CookieService::GetSingleton(); 635 isOn3PCBExceptionList = 636 isThirdParty ? csSingleton->ThirdPartyCookieBlockingExceptionsRef() 637 .CheckExceptionForURIs(firstPartyURI, uri) 638 : false; 639 640 if (overriddenFingerprintingSettings.isSome()) { 641 overriddenFingerprintingSettingsArg.emplace( 642 overriddenFingerprintingSettings.ref()); 643 } 644 } 645 } else { 646 net::CookieJarSettings::Cast(cookieJarSettings)->SetPartitionKey(uri); 647 firstPartyURI = uri; 648 649 // The service worker is for a first-party context, we can use the uri of 650 // the service worker as the first-party domain to get the fingerprinting 651 // protection overrides. 652 overriddenFingerprintingSettings = 653 nsRFPService::GetOverriddenFingerprintingSettingsForURI(uri, nullptr, 654 isPBM); 655 656 if (overriddenFingerprintingSettings.isSome()) { 657 overriddenFingerprintingSettingsArg.emplace( 658 overriddenFingerprintingSettings.ref()); 659 } 660 } 661 662 if (ContentBlockingAllowList::Check(principal, isPBM)) { 663 net::CookieJarSettings::Cast(cookieJarSettings) 664 ->SetIsOnContentBlockingAllowList(true); 665 } 666 667 bool shouldResistFingerprinting = 668 nsContentUtils::ShouldResistFingerprinting_dangerous( 669 principal, 670 "Service Workers exist outside a Document or Channel; as a property " 671 "of the domain (and origin attributes). We don't have a " 672 "CookieJarSettings to perform the *nested check*, but we can rely on" 673 "the FPI/dFPI partition key check. The WorkerPrivate's " 674 "ShouldResistFingerprinting function for the ServiceWorker depends " 675 "on this boolean and will also consider an explicit RFPTarget.", 676 RFPTarget::IsAlwaysEnabledForPrecompute) && 677 !nsContentUtils::ETPSaysShouldNotResistFingerprinting(cookieJarSettings, 678 isPBM); 679 680 if (shouldResistFingerprinting && NS_SUCCEEDED(rv) && firstPartyURI) { 681 auto rfpKey = nsRFPService::GenerateKeyForServiceWorker( 682 firstPartyURI, principal, foreignByAncestorContext); 683 if (rfpKey.isSome()) { 684 net::CookieJarSettings::Cast(cookieJarSettings) 685 ->SetFingerprintingRandomizationKey(rfpKey.ref()); 686 } 687 } 688 689 net::CookieJarSettingsArgs cjsData; 690 net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(cjsData); 691 692 nsCOMPtr<nsIPrincipal> partitionedPrincipal; 693 rv = StoragePrincipalHelper::CreatePartitionedPrincipalForServiceWorker( 694 principal, cookieJarSettings, getter_AddRefs(partitionedPrincipal)); 695 if (NS_WARN_IF(NS_FAILED(rv))) { 696 return rv; 697 } 698 699 PrincipalInfo partitionedPrincipalInfo; 700 rv = 701 PrincipalToPrincipalInfo(partitionedPrincipal, &partitionedPrincipalInfo); 702 if (NS_WARN_IF(NS_FAILED(rv))) { 703 return rv; 704 } 705 706 StorageAccess storageAccess = 707 StorageAllowedForServiceWorker(principal, cookieJarSettings); 708 709 ServiceWorkerData serviceWorkerData; 710 serviceWorkerData.cacheName() = mInfo->CacheName(); 711 serviceWorkerData.loadFlags() = static_cast<uint32_t>( 712 mInfo->GetImportsLoadFlags() | nsIChannel::LOAD_BYPASS_SERVICE_WORKER); 713 serviceWorkerData.id() = std::move(id); 714 715 nsAutoCString domain; 716 rv = uri->GetHost(domain); 717 if (NS_WARN_IF(NS_FAILED(rv))) { 718 return rv; 719 } 720 721 auto remoteType = RemoteWorkerManager::GetRemoteType( 722 principal, WorkerKind::WorkerKindService); 723 if (NS_WARN_IF(remoteType.isErr())) { 724 return remoteType.unwrapErr(); 725 } 726 727 // Determine if the service worker is registered under a third-party context 728 // by checking if it's running under a partitioned principal. 729 bool isThirdPartyContextToTopWindow = 730 !principal->OriginAttributesRef().mPartitionKey.IsEmpty(); 731 732 mClientInfo = ClientManager::CreateInfo( 733 ClientType::Serviceworker, 734 // The partitioned principal for ServiceWorkers is currently always 735 // partitioned and so we only use it when in a third party context. 736 isThirdPartyContextToTopWindow ? partitionedPrincipal : principal); 737 if (NS_WARN_IF(!mClientInfo.isSome())) { 738 return NS_ERROR_DOM_INVALID_STATE_ERR; 739 } 740 741 mClientInfo->SetAgentClusterId(regInfo->AgentClusterId()); 742 mClientInfo->SetURL(mInfo->ScriptSpec()); 743 mClientInfo->SetFrameType(FrameType::None); 744 745 WorkerOptions workerOptions; 746 workerOptions.mCredentials = RequestCredentials::Omit; 747 workerOptions.mType = mInfo->Type(); 748 749 mRemoteWorkerData = RemoteWorkerData( 750 NS_ConvertUTF8toUTF16(mInfo->ScriptSpec()), baseScriptURL, baseScriptURL, 751 workerOptions, 752 /* loading principal */ principalInfo, principalInfo, 753 partitionedPrincipalInfo, 754 /* useRegularPrincipal */ true, 755 756 // ServiceWorkers run as first-party, no storage-access permission needed. 757 /* usingStorageAccess */ false, 758 759 cjsData, domain, 760 /* isSecureContext */ true, 761 /* clientInfo*/ Some(mClientInfo.ref().ToIPC()), 762 763 // The RemoteWorkerData CTOR doesn't allow to set the referrerInfo via 764 // already_AddRefed<>. Let's set it to null. 765 /* referrerInfo */ nullptr, 766 767 storageAccess, isThirdPartyContextToTopWindow, shouldResistFingerprinting, 768 overriddenFingerprintingSettingsArg, isOn3PCBExceptionList, 769 // Origin trials are associated to a window, so it doesn't make sense on 770 // service workers. 771 OriginTrials(), std::move(serviceWorkerData), regInfo->AgentClusterId(), 772 remoteType.unwrap()); 773 774 mRemoteWorkerData.referrerInfo() = MakeAndAddRef<ReferrerInfo>(); 775 776 // This fills in the rest of mRemoteWorkerData.serviceWorkerData(). 777 RefreshRemoteWorkerData(regInfo); 778 779 return NS_OK; 780 } 781 782 void ServiceWorkerPrivate::RegenerateClientInfo() { 783 // inductively, this object can only still be alive after Initialize() if the 784 // mClientInfo was correctly initialized. 785 MOZ_DIAGNOSTIC_ASSERT(mClientInfo.isSome()); 786 787 mClientInfo = ClientManager::CreateInfo( 788 ClientType::Serviceworker, mClientInfo->GetPrincipal().unwrap().get()); 789 mRemoteWorkerData.clientInfo().ref() = mClientInfo.ref().ToIPC(); 790 } 791 792 nsresult ServiceWorkerPrivate::CheckScriptEvaluation( 793 const ServiceWorkerLifetimeExtension& aLifetimeExtension, 794 RefPtr<LifeCycleEventCallback> aCallback) { 795 MOZ_ASSERT(NS_IsMainThread()); 796 MOZ_ASSERT(aCallback); 797 798 RefPtr<ServiceWorkerPrivate> self = this; 799 800 /** 801 * We need to capture the actor associated with the current Service Worker so 802 * we can terminate it if script evaluation failed. 803 */ 804 nsresult rv = SpawnWorkerIfNeeded(aLifetimeExtension); 805 806 if (NS_WARN_IF(NS_FAILED(rv))) { 807 aCallback->SetResult(false); 808 aCallback->Run(); 809 810 return rv; 811 } 812 813 MOZ_ASSERT(mControllerChild); 814 815 RefPtr<RAIIActorPtrHolder> holder = mControllerChild; 816 817 return ExecServiceWorkerOp( 818 ServiceWorkerCheckScriptEvaluationOpArgs(), aLifetimeExtension, 819 [self = std::move(self), holder = std::move(holder), 820 callback = aCallback](ServiceWorkerOpResult&& aResult) mutable { 821 if (aResult.type() == ServiceWorkerOpResult:: 822 TServiceWorkerCheckScriptEvaluationOpResult) { 823 auto& result = 824 aResult.get_ServiceWorkerCheckScriptEvaluationOpResult(); 825 826 if (result.workerScriptExecutedSuccessfully()) { 827 self->SetHandlesFetch(result.fetchHandlerWasAdded()); 828 if (self->mHandlesFetch == Unknown) { 829 self->mHandlesFetch = 830 result.fetchHandlerWasAdded() ? Enabled : Disabled; 831 // Update telemetry for # of running SW - the already-running SW 832 // handles fetch 833 if (self->mHandlesFetch == Enabled) { 834 self->UpdateRunning(0, 1); 835 } 836 } 837 838 callback->SetResult(result.workerScriptExecutedSuccessfully()); 839 callback->Run(); 840 return; 841 } 842 } 843 844 /** 845 * If script evaluation failed, first terminate the Service Worker 846 * before invoking the callback. 847 */ 848 MOZ_ASSERT_IF(aResult.type() == ServiceWorkerOpResult::Tnsresult, 849 NS_FAILED(aResult.get_nsresult())); 850 851 // If a termination operation was already issued using `holder`... 852 if (self->mControllerChild != holder) { 853 holder->OnDestructor()->Then( 854 GetCurrentSerialEventTarget(), __func__, 855 [callback = std::move(callback)]( 856 const GenericPromise::ResolveOrRejectValue&) { 857 callback->SetResult(false); 858 callback->Run(); 859 }); 860 861 return; 862 } 863 864 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 865 MOZ_ASSERT(swm); 866 867 auto shutdownStateId = swm->MaybeInitServiceWorkerShutdownProgress(); 868 869 RefPtr<GenericNonExclusivePromise> promise = 870 self->ShutdownInternal(shutdownStateId); 871 872 swm->BlockShutdownOn(promise, shutdownStateId); 873 874 promise->Then( 875 GetCurrentSerialEventTarget(), __func__, 876 [callback = std::move(callback)]( 877 const GenericNonExclusivePromise::ResolveOrRejectValue&) { 878 callback->SetResult(false); 879 callback->Run(); 880 }); 881 }, 882 [callback = aCallback] { 883 callback->SetResult(false); 884 callback->Run(); 885 }); 886 } 887 888 nsresult ServiceWorkerPrivate::SendMessageEvent( 889 RefPtr<ServiceWorkerCloneData>&& aData, 890 const ServiceWorkerLifetimeExtension& aLifetimeExtension, 891 const PostMessageSource& aSource) { 892 AssertIsOnMainThread(); 893 MOZ_ASSERT(aData); 894 895 auto scopeExit = MakeScopeExit([&] { Shutdown(); }); 896 897 PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread(); 898 899 if (NS_WARN_IF(!bgChild)) { 900 return NS_ERROR_DOM_INVALID_STATE_ERR; 901 } 902 903 ServiceWorkerMessageEventOpArgs args; 904 args.source() = aSource; 905 if (!aData->BuildClonedMessageData(args.clonedData())) { 906 return NS_ERROR_DOM_DATA_CLONE_ERR; 907 } 908 909 scopeExit.release(); 910 911 return ExecServiceWorkerOp( 912 std::move(args), aLifetimeExtension, [](ServiceWorkerOpResult&& aResult) { 913 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 914 }); 915 } 916 917 nsresult ServiceWorkerPrivate::SendLifeCycleEvent( 918 const nsAString& aEventType, 919 const ServiceWorkerLifetimeExtension& aLifetimeExtension, 920 const RefPtr<LifeCycleEventCallback>& aCallback) { 921 AssertIsOnMainThread(); 922 MOZ_ASSERT(aCallback); 923 924 return ExecServiceWorkerOp( 925 ServiceWorkerLifeCycleEventOpArgs(nsString(aEventType)), 926 aLifetimeExtension, 927 [callback = aCallback](ServiceWorkerOpResult&& aResult) { 928 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 929 930 callback->SetResult(NS_SUCCEEDED(aResult.get_nsresult())); 931 callback->Run(); 932 }, 933 [callback = aCallback] { 934 callback->SetResult(false); 935 callback->Run(); 936 }); 937 } 938 939 nsresult ServiceWorkerPrivate::SendCookieChangeEvent( 940 const net::CookieStruct& aCookie, bool aCookieDeleted, 941 RefPtr<ServiceWorkerRegistrationInfo> aRegistration) { 942 AssertIsOnMainThread(); 943 MOZ_ASSERT(mInfo); 944 MOZ_ASSERT(aRegistration); 945 946 ServiceWorkerCookieChangeEventOpArgs args; 947 args.cookie() = aCookie; 948 args.deleted() = aCookieDeleted; 949 950 if (mInfo->State() == ServiceWorkerState::Activating) { 951 UniquePtr<PendingFunctionalEvent> pendingEvent = 952 MakeUnique<PendingCookieChangeEvent>(this, std::move(aRegistration), 953 std::move(args)); 954 955 mPendingFunctionalEvents.AppendElement(std::move(pendingEvent)); 956 957 return NS_OK; 958 } 959 960 MOZ_ASSERT(mInfo->State() == ServiceWorkerState::Activated); 961 962 return SendCookieChangeEventInternal(std::move(aRegistration), 963 std::move(args)); 964 } 965 966 nsresult ServiceWorkerPrivate::SendCookieChangeEventInternal( 967 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 968 ServiceWorkerCookieChangeEventOpArgs&& aArgs) { 969 MOZ_ASSERT(aRegistration); 970 971 return ExecServiceWorkerOp( 972 std::move(aArgs), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 973 [registration = aRegistration](ServiceWorkerOpResult&& aResult) { 974 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 975 976 registration->MaybeScheduleTimeCheckAndUpdate(); 977 }, 978 [registration = aRegistration]() { 979 registration->MaybeScheduleTimeCheckAndUpdate(); 980 }); 981 } 982 983 nsresult ServiceWorkerPrivate::SendPushEvent( 984 const nsAString& aMessageId, const Maybe<nsTArray<uint8_t>>& aData, 985 RefPtr<ServiceWorkerRegistrationInfo> aRegistration) { 986 AssertIsOnMainThread(); 987 MOZ_ASSERT(mInfo); 988 MOZ_ASSERT(aRegistration); 989 990 ServiceWorkerPushEventOpArgs args; 991 args.messageId() = nsString(aMessageId); 992 993 if (aData) { 994 args.data() = aData.ref(); 995 } else { 996 args.data() = void_t(); 997 } 998 999 if (mInfo->State() == ServiceWorkerState::Activating) { 1000 UniquePtr<PendingFunctionalEvent> pendingEvent = 1001 MakeUnique<PendingPushEvent>(this, std::move(aRegistration), 1002 std::move(args)); 1003 1004 mPendingFunctionalEvents.AppendElement(std::move(pendingEvent)); 1005 1006 return NS_OK; 1007 } 1008 1009 MOZ_ASSERT(mInfo->State() == ServiceWorkerState::Activated); 1010 1011 return SendPushEventInternal(std::move(aRegistration), std::move(args)); 1012 } 1013 1014 nsresult ServiceWorkerPrivate::SendPushEventInternal( 1015 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 1016 ServiceWorkerPushEventOpArgs&& aArgs) { 1017 MOZ_ASSERT(aRegistration); 1018 1019 return ExecServiceWorkerOp( 1020 std::move(aArgs), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 1021 [registration = aRegistration](ServiceWorkerOpResult&& aResult) { 1022 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1023 1024 registration->MaybeScheduleTimeCheckAndUpdate(); 1025 }, 1026 [registration = aRegistration]() { 1027 registration->MaybeScheduleTimeCheckAndUpdate(); 1028 }); 1029 } 1030 1031 nsresult ServiceWorkerPrivate::SendPushSubscriptionChangeEvent( 1032 const RefPtr<nsIPushSubscription>& aOldSubscription) { 1033 AssertIsOnMainThread(); 1034 1035 ServiceWorkerPushSubscriptionChangeEventOpArgs args{}; 1036 if (aOldSubscription) { 1037 PushSubscriptionData oldSubscription{}; 1038 MOZ_TRY(GetSubscriptionParams(aOldSubscription, oldSubscription.endpoint(), 1039 oldSubscription.rawP256dhKey(), 1040 oldSubscription.authSecret(), 1041 oldSubscription.appServerKey())); 1042 args.oldSubscription().emplace(oldSubscription); 1043 } 1044 1045 return ExecServiceWorkerOp( 1046 std::move(args), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 1047 [](ServiceWorkerOpResult&& aResult) { 1048 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1049 }); 1050 } 1051 1052 nsresult ServiceWorkerPrivate::SendNotificationClickEvent( 1053 const IPCNotification& aNotification, const nsAString& aAction) { 1054 MOZ_ASSERT(NS_IsMainThread()); 1055 1056 ServiceWorkerNotificationClickEventOpArgs clickArgs; 1057 clickArgs.notification() = aNotification; 1058 clickArgs.action() = aAction; 1059 1060 ServiceWorkerNotificationEventOpArgs args(std::move(clickArgs)); 1061 1062 return ExecServiceWorkerOp( 1063 std::move(args), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 1064 [](ServiceWorkerOpResult&& aResult) { 1065 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1066 }); 1067 } 1068 1069 nsresult ServiceWorkerPrivate::SendNotificationCloseEvent( 1070 const IPCNotification& aNotification) { 1071 MOZ_ASSERT(NS_IsMainThread()); 1072 1073 ServiceWorkerNotificationCloseEventOpArgs closeArgs; 1074 closeArgs.notification() = aNotification; 1075 1076 ServiceWorkerNotificationEventOpArgs args(std::move(closeArgs)); 1077 1078 return ExecServiceWorkerOp( 1079 std::move(args), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 1080 [](ServiceWorkerOpResult&& aResult) { 1081 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1082 }); 1083 } 1084 1085 nsresult ServiceWorkerPrivate::SendFetchEvent( 1086 nsCOMPtr<nsIInterceptedChannel> aChannel, nsILoadGroup* aLoadGroup, 1087 const nsAString& aClientId, const nsAString& aResultingClientId) { 1088 MOZ_ASSERT(NS_IsMainThread()); 1089 MOZ_ASSERT(aChannel); 1090 1091 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1092 if (NS_WARN_IF(!mInfo || !swm)) { 1093 return NS_ERROR_FAILURE; 1094 } 1095 1096 nsCOMPtr<nsIChannel> channel; 1097 nsresult rv = aChannel->GetChannel(getter_AddRefs(channel)); 1098 NS_ENSURE_SUCCESS(rv, rv); 1099 bool isNonSubresourceRequest = 1100 nsContentUtils::IsNonSubresourceRequest(channel); 1101 1102 RefPtr<ServiceWorkerRegistrationInfo> registration; 1103 if (isNonSubresourceRequest) { 1104 registration = swm->GetRegistration(mInfo->Principal(), mInfo->Scope()); 1105 } else { 1106 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo(); 1107 1108 // We'll check for a null registration below rather than an error code here. 1109 (void)swm->GetClientRegistration(loadInfo->GetClientInfo().ref(), 1110 getter_AddRefs(registration)); 1111 } 1112 1113 // Its possible the registration is removed between starting the interception 1114 // and actually dispatching the fetch event. In these cases we simply 1115 // want to restart the original network request. Since this is a normal 1116 // condition we handle the reset here instead of returning an error which 1117 // would in turn trigger a console report. 1118 if (!registration) { 1119 nsresult rv = aChannel->ResetInterception(false); 1120 if (NS_FAILED(rv)) { 1121 NS_WARNING("Failed to resume intercepted network request"); 1122 aChannel->CancelInterception(rv); 1123 } 1124 return NS_OK; 1125 } 1126 1127 // Handle Fetch algorithm - step 16. If the service worker didn't register 1128 // any fetch event handlers, then abort the interception and maybe trigger 1129 // the soft update algorithm. 1130 if (!mInfo->HandlesFetch()) { 1131 nsresult rv = aChannel->ResetInterception(false); 1132 if (NS_FAILED(rv)) { 1133 NS_WARNING("Failed to resume intercepted network request"); 1134 aChannel->CancelInterception(rv); 1135 } 1136 1137 // Trigger soft updates if necessary. 1138 registration->MaybeScheduleTimeCheckAndUpdate(); 1139 1140 return NS_OK; 1141 } 1142 1143 auto scopeExit = MakeScopeExit([&] { 1144 aChannel->CancelInterception(NS_ERROR_INTERCEPTION_FAILED); 1145 Shutdown(); 1146 }); 1147 1148 IPCInternalRequest request = MOZ_TRY(GetIPCInternalRequest(aChannel)); 1149 1150 scopeExit.release(); 1151 1152 bool preloadNavigation = isNonSubresourceRequest && 1153 request.method().LowerCaseEqualsASCII("get") && 1154 registration->GetNavigationPreloadState().enabled(); 1155 1156 RefPtr<FetchServicePromises> preloadResponsePromises; 1157 if (preloadNavigation) { 1158 preloadResponsePromises = SetupNavigationPreload(aChannel, registration); 1159 } 1160 1161 ParentToParentServiceWorkerFetchEventOpArgs args( 1162 ServiceWorkerFetchEventOpArgsCommon( 1163 mInfo->ScriptSpec(), request, nsString(aClientId), 1164 nsString(aResultingClientId), isNonSubresourceRequest, 1165 preloadNavigation, mInfo->TestingInjectCancellation()), 1166 Nothing(), Nothing(), Nothing()); 1167 1168 if (mInfo->State() == ServiceWorkerState::Activating) { 1169 UniquePtr<PendingFunctionalEvent> pendingEvent = 1170 MakeUnique<PendingFetchEvent>(this, std::move(registration), 1171 std::move(args), std::move(aChannel), 1172 std::move(preloadResponsePromises)); 1173 1174 mPendingFunctionalEvents.AppendElement(std::move(pendingEvent)); 1175 1176 return NS_OK; 1177 } 1178 1179 MOZ_ASSERT(mInfo->State() == ServiceWorkerState::Activated); 1180 1181 return SendFetchEventInternal(std::move(registration), std::move(args), 1182 std::move(aChannel), 1183 std::move(preloadResponsePromises)); 1184 } 1185 1186 nsresult ServiceWorkerPrivate::SendFetchEventInternal( 1187 RefPtr<ServiceWorkerRegistrationInfo>&& aRegistration, 1188 ParentToParentServiceWorkerFetchEventOpArgs&& aArgs, 1189 nsCOMPtr<nsIInterceptedChannel>&& aChannel, 1190 RefPtr<FetchServicePromises>&& aPreloadResponseReadyPromises) { 1191 AssertIsOnMainThread(); 1192 1193 auto scopeExit = MakeScopeExit([&] { Shutdown(); }); 1194 1195 if (NS_WARN_IF(!mInfo)) { 1196 return NS_ERROR_DOM_INVALID_STATE_ERR; 1197 } 1198 1199 MOZ_TRY(SpawnWorkerIfNeeded( 1200 ServiceWorkerLifetimeExtension(FullLifetimeExtension{}))); 1201 MOZ_TRY(MaybeStoreStreamForBackgroundThread( 1202 aChannel, aArgs.common().internalRequest())); 1203 1204 scopeExit.release(); 1205 1206 MOZ_ASSERT(mControllerChild); 1207 1208 RefPtr<RAIIActorPtrHolder> holder = mControllerChild; 1209 1210 FetchEventOpChild::SendFetchEvent( 1211 mControllerChild->get(), std::move(aArgs), std::move(aChannel), 1212 std::move(aRegistration), std::move(aPreloadResponseReadyPromises), 1213 CreateEventKeepAliveToken()) 1214 ->Then(GetCurrentSerialEventTarget(), __func__, 1215 [holder = std::move(holder)]( 1216 const GenericPromise::ResolveOrRejectValue& aResult) { 1217 (void)NS_WARN_IF(aResult.IsReject()); 1218 }); 1219 1220 return NS_OK; 1221 } 1222 1223 Result<RefPtr<ServiceWorkerPrivate::PromiseExtensionWorkerHasListener>, 1224 nsresult> 1225 ServiceWorkerPrivate::WakeForExtensionAPIEvent( 1226 const nsAString& aExtensionAPINamespace, 1227 const nsAString& aExtensionAPIEventName) { 1228 AssertIsOnMainThread(); 1229 1230 ServiceWorkerExtensionAPIEventOpArgs args; 1231 args.apiNamespace() = nsString(aExtensionAPINamespace); 1232 args.apiEventName() = nsString(aExtensionAPIEventName); 1233 1234 auto promise = 1235 MakeRefPtr<PromiseExtensionWorkerHasListener::Private>(__func__); 1236 1237 nsresult rv = ExecServiceWorkerOp( 1238 std::move(args), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}), 1239 [promise](ServiceWorkerOpResult&& aResult) { 1240 MOZ_ASSERT( 1241 aResult.type() == 1242 ServiceWorkerOpResult::TServiceWorkerExtensionAPIEventOpResult); 1243 auto& result = aResult.get_ServiceWorkerExtensionAPIEventOpResult(); 1244 promise->Resolve(result.extensionAPIEventListenerWasAdded(), __func__); 1245 }, 1246 [promise]() { promise->Reject(NS_ERROR_FAILURE, __func__); }); 1247 1248 if (NS_FAILED(rv)) { 1249 promise->Reject(rv, __func__); 1250 } 1251 1252 RefPtr<PromiseExtensionWorkerHasListener> outPromise(promise); 1253 return outPromise; 1254 } 1255 1256 nsresult ServiceWorkerPrivate::SpawnWorkerIfNeeded( 1257 const ServiceWorkerLifetimeExtension& aLifetimeExtension) { 1258 AssertIsOnMainThread(); 1259 1260 // We don't need to spawn if we already have a spawned, non-terminated worker. 1261 if (mControllerChild) { 1262 // We only need to renew the keepalive token if we actually want to extend 1263 // the worker's lifetime; we don't for termination requests. 1264 if (aLifetimeExtension.LifetimeExtendsIntoTheFuture()) { 1265 RenewKeepAliveToken(aLifetimeExtension); 1266 } 1267 return NS_OK; 1268 } 1269 1270 if (!mInfo) { 1271 return NS_ERROR_DOM_INVALID_STATE_ERR; 1272 } 1273 1274 // Don't spawn the ServiceWorker if we don't want to extend its life. 1275 if (NS_WARN_IF(!aLifetimeExtension.LifetimeExtendsIntoTheFuture())) { 1276 return NS_ERROR_DOM_TIMEOUT_ERR; 1277 } 1278 1279 mServiceWorkerLaunchTimeStart = TimeStamp::Now(); 1280 1281 PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread(); 1282 1283 if (NS_WARN_IF(!bgChild)) { 1284 return NS_ERROR_DOM_INVALID_STATE_ERR; 1285 } 1286 1287 // If the worker principal is an extension principal, then we should not spawn 1288 // a worker if there is no WebExtensionPolicy associated to that principal 1289 // or if the WebExtensionPolicy is not active. 1290 auto* principal = mInfo->Principal(); 1291 if (principal->SchemeIs("moz-extension")) { 1292 auto* addonPolicy = BasePrincipal::Cast(principal)->AddonPolicy(); 1293 if (!addonPolicy || !addonPolicy->Active()) { 1294 NS_WARNING( 1295 "Trying to wake up a service worker for a disabled webextension."); 1296 return NS_ERROR_DOM_INVALID_STATE_ERR; 1297 } 1298 } 1299 1300 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1301 1302 if (NS_WARN_IF(!swm)) { 1303 return NS_ERROR_DOM_ABORT_ERR; 1304 } 1305 1306 RefPtr<ServiceWorkerRegistrationInfo> regInfo = 1307 swm->GetRegistration(principal, mInfo->Scope()); 1308 1309 if (NS_WARN_IF(!regInfo)) { 1310 return NS_ERROR_DOM_INVALID_STATE_ERR; 1311 } 1312 1313 RefreshRemoteWorkerData(regInfo); 1314 1315 mLaunchCount++; 1316 1317 RefPtr<RemoteWorkerControllerChild> controllerChild = 1318 new RemoteWorkerControllerChild(this); 1319 1320 if (NS_WARN_IF(!bgChild->SendPRemoteWorkerControllerConstructor( 1321 controllerChild, mRemoteWorkerData))) { 1322 return NS_ERROR_DOM_INVALID_STATE_ERR; 1323 } 1324 1325 mPendingSpawnLifetime = aLifetimeExtension; 1326 1327 mControllerChild = new RAIIActorPtrHolder(controllerChild.forget()); 1328 1329 // Update Running count here because we may Terminate before we get 1330 // CreationSucceeded(). We'll update if it handles Fetch if that changes 1331 // ( 1332 UpdateRunning(1, mHandlesFetch == Enabled ? 1 : 0); 1333 1334 return NS_OK; 1335 } 1336 1337 void ServiceWorkerPrivate::TerminateWorker( 1338 Maybe<RefPtr<Promise>> aMaybePromise) { 1339 MOZ_ASSERT(NS_IsMainThread()); 1340 mIdleWorkerTimer->Cancel(); 1341 mIdleDeadline = TimeStamp(); 1342 // We call the shutdown method prior to dropping mIdleKeepAliveToken in order 1343 // to ensure that the passed-in promise tracks the shutdown of the current 1344 // worker. 1345 // 1346 // More detail: Dropping the token can cause re-entrance to this method via 1347 // ReleaseToken if it is not already the method calling. Shutdown() is 1348 // idempotent except for the promise we pass in; it will only be chained to 1349 // track the actual termination if mControllerChild is not null. On the 1350 // second call when mControllerChild is null, it will resolved immediately 1351 // with undefined. The call from ReleaseToken does not pass a Promise and 1352 // does not care, so it goes second. 1353 // 1354 // We of course could hold onto the underlying shutdown promise until it 1355 // resolves so that new calls could chain, but because it's conceptually 1356 // possible to have multiple spawns and shutdowns in flight and our promise 1357 // argument is really only for testing / devtools where we only expect a 1358 // single actively involved party at a time, this way works sufficiently. 1359 Shutdown(std::move(aMaybePromise)); 1360 // As per the above, this may potentially 1361 mIdleKeepAliveToken = nullptr; 1362 } 1363 1364 void ServiceWorkerPrivate::NoteDeadServiceWorkerInfo() { 1365 MOZ_ASSERT(NS_IsMainThread()); 1366 1367 TerminateWorker(); 1368 mInfo = nullptr; 1369 } 1370 1371 void ServiceWorkerPrivate::UpdateState(ServiceWorkerState aState) { 1372 AssertIsOnMainThread(); 1373 1374 if (!mControllerChild) { 1375 return; 1376 } 1377 1378 nsresult rv = ExecServiceWorkerOp( 1379 ServiceWorkerUpdateStateOpArgs(aState), 1380 // Lifecycle events potentially update the lifetime for ServiceWorkers 1381 // controlling a page, but there's no need to update the lifetime to tell 1382 // a SW that its state has changed. 1383 ServiceWorkerLifetimeExtension(NoLifetimeExtension{}), 1384 [](ServiceWorkerOpResult&& aResult) { 1385 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1386 }); 1387 1388 if (NS_WARN_IF(NS_FAILED(rv))) { 1389 Shutdown(); 1390 return; 1391 } 1392 1393 if (aState != ServiceWorkerState::Activated) { 1394 return; 1395 } 1396 1397 for (auto& event : mPendingFunctionalEvents) { 1398 (void)NS_WARN_IF(NS_FAILED(event->Send())); 1399 } 1400 1401 mPendingFunctionalEvents.Clear(); 1402 } 1403 1404 void ServiceWorkerPrivate::UpdateIsOnContentBlockingAllowList( 1405 bool aOnContentBlockingAllowList) { 1406 AssertIsOnMainThread(); 1407 1408 if (!mControllerChild) { 1409 return; 1410 } 1411 1412 ExecServiceWorkerOp( 1413 ServiceWorkerUpdateIsOnContentBlockingAllowListOpArgs( 1414 aOnContentBlockingAllowList), 1415 ServiceWorkerLifetimeExtension(NoLifetimeExtension{}), 1416 [](ServiceWorkerOpResult&& aResult) { 1417 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1418 }); 1419 } 1420 1421 nsresult ServiceWorkerPrivate::GetDebugger(nsIWorkerDebugger** aResult) { 1422 MOZ_ASSERT(NS_IsMainThread()); 1423 MOZ_ASSERT(aResult); 1424 1425 return NS_ERROR_NOT_IMPLEMENTED; 1426 } 1427 1428 nsresult ServiceWorkerPrivate::AttachDebugger() { 1429 MOZ_ASSERT(NS_IsMainThread()); 1430 1431 // When the first debugger attaches to a worker, we spawn a worker if needed, 1432 // and cancel the idle timeout. The idle timeout should not be reset until 1433 // the last debugger detached from the worker. 1434 if (!mDebuggerCount) { 1435 nsresult rv = SpawnWorkerIfNeeded( 1436 ServiceWorkerLifetimeExtension(FullLifetimeExtension{})); 1437 NS_ENSURE_SUCCESS(rv, rv); 1438 1439 /** 1440 * Renewing the idle KeepAliveToken for spawning workers happens 1441 * asynchronously, rather than synchronously. 1442 * The asynchronous renewal is because the actual spawning of workers occurs 1443 * in a content process, so we will only renew once notified that the worker 1444 * has been successfully created 1445 * 1446 * This means that the DevTools way of starting up a worker by calling 1447 * `AttachDebugger` immediately followed by `DetachDebugger` will spawn and 1448 * immediately terminate a worker (because `mTokenCount` is possibly 0 1449 * due to the idle KeepAliveToken being created asynchronously). So, just 1450 * renew the KeepAliveToken right now. 1451 */ 1452 RenewKeepAliveToken( 1453 ServiceWorkerLifetimeExtension(FullLifetimeExtension{})); 1454 mIdleWorkerTimer->Cancel(); 1455 } 1456 1457 ++mDebuggerCount; 1458 1459 return NS_OK; 1460 } 1461 1462 nsresult ServiceWorkerPrivate::DetachDebugger() { 1463 MOZ_ASSERT(NS_IsMainThread()); 1464 1465 if (!mDebuggerCount) { 1466 return NS_ERROR_UNEXPECTED; 1467 } 1468 1469 --mDebuggerCount; 1470 1471 // When the last debugger detaches from a worker, we either reset the idle 1472 // timeout, or terminate the worker if there are no more active tokens. 1473 if (!mDebuggerCount) { 1474 if (mTokenCount) { 1475 ResetIdleTimeout(ServiceWorkerLifetimeExtension(FullLifetimeExtension{})); 1476 } else { 1477 TerminateWorker(); 1478 } 1479 } 1480 1481 return NS_OK; 1482 } 1483 1484 bool ServiceWorkerPrivate::IsIdle() const { 1485 MOZ_ASSERT(NS_IsMainThread()); 1486 return mTokenCount == 0 || (mTokenCount == 1 && mIdleKeepAliveToken); 1487 } 1488 1489 RefPtr<GenericPromise> ServiceWorkerPrivate::GetIdlePromise() { 1490 #ifdef DEBUG 1491 MOZ_ASSERT(NS_IsMainThread()); 1492 MOZ_ASSERT(!IsIdle()); 1493 MOZ_ASSERT(!mIdlePromiseObtained, "Idle promise may only be obtained once!"); 1494 mIdlePromiseObtained = true; 1495 #endif 1496 1497 RefPtr<GenericPromise> promise = mIdlePromiseHolder.Ensure(__func__); 1498 mIdlePromiseHolder.UseDirectTaskDispatch(__func__); 1499 1500 return promise; 1501 } 1502 1503 namespace { 1504 1505 class ServiceWorkerPrivateTimerCallback final : public nsITimerCallback, 1506 public nsINamed { 1507 public: 1508 using Method = void (ServiceWorkerPrivate::*)(nsITimer*); 1509 1510 ServiceWorkerPrivateTimerCallback(ServiceWorkerPrivate* aServiceWorkerPrivate, 1511 Method aMethod) 1512 : mServiceWorkerPrivate(aServiceWorkerPrivate), mMethod(aMethod) {} 1513 1514 NS_IMETHOD 1515 Notify(nsITimer* aTimer) override { 1516 (mServiceWorkerPrivate->*mMethod)(aTimer); 1517 mServiceWorkerPrivate = nullptr; 1518 return NS_OK; 1519 } 1520 1521 NS_IMETHOD 1522 GetName(nsACString& aName) override { 1523 aName.AssignLiteral("ServiceWorkerPrivateTimerCallback"); 1524 return NS_OK; 1525 } 1526 1527 private: 1528 ~ServiceWorkerPrivateTimerCallback() = default; 1529 1530 RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate; 1531 Method mMethod; 1532 1533 NS_DECL_THREADSAFE_ISUPPORTS 1534 }; 1535 1536 NS_IMPL_ISUPPORTS(ServiceWorkerPrivateTimerCallback, nsITimerCallback, 1537 nsINamed); 1538 1539 } // anonymous namespace 1540 1541 void ServiceWorkerPrivate::NoteIdleWorkerCallback(nsITimer* aTimer) { 1542 MOZ_ASSERT(NS_IsMainThread()); 1543 1544 MOZ_ASSERT(aTimer == mIdleWorkerTimer, "Invalid timer!"); 1545 1546 // Release ServiceWorkerPrivate's token, since the grace period has ended. 1547 mIdleKeepAliveToken = nullptr; 1548 // Null out our deadline as well. 1549 mIdleDeadline = TimeStamp(); 1550 1551 if (mControllerChild) { 1552 // If we still have a living worker at this point it means that either there 1553 // are pending waitUntil promises or the worker is doing some long-running 1554 // computation. Wait a bit more until we forcibly terminate the worker. 1555 uint32_t timeout = 1556 Preferences::GetInt("dom.serviceWorkers.idle_extended_timeout"); 1557 nsCOMPtr<nsITimerCallback> cb = new ServiceWorkerPrivateTimerCallback( 1558 this, &ServiceWorkerPrivate::TerminateWorkerCallback); 1559 DebugOnly<nsresult> rv = mIdleWorkerTimer->InitWithCallback( 1560 cb, timeout, nsITimer::TYPE_ONE_SHOT); 1561 MOZ_ASSERT(NS_SUCCEEDED(rv)); 1562 } 1563 } 1564 1565 void ServiceWorkerPrivate::TerminateWorkerCallback(nsITimer* aTimer) { 1566 MOZ_ASSERT(NS_IsMainThread()); 1567 1568 MOZ_ASSERT(aTimer == this->mIdleWorkerTimer, "Invalid timer!"); 1569 1570 // mInfo must be non-null at this point because NoteDeadServiceWorkerInfo 1571 // which zeroes it calls TerminateWorker which cancels our timer which will 1572 // ensure we don't get invoked even if the nsTimerEvent is in the event queue. 1573 ServiceWorkerManager::LocalizeAndReportToAllClients( 1574 mInfo->Scope(), "ServiceWorkerGraceTimeoutTermination", 1575 nsTArray<nsString>{NS_ConvertUTF8toUTF16(mInfo->Scope())}); 1576 1577 TerminateWorker(); 1578 } 1579 1580 void ServiceWorkerPrivate::RenewKeepAliveToken( 1581 const ServiceWorkerLifetimeExtension& aLifetimeExtension) { 1582 // We should have an active worker if we're renewing the keep alive token. 1583 MOZ_ASSERT(mControllerChild); 1584 1585 // If there is at least one debugger attached to the worker, the idle worker 1586 // timeout was canceled when the first debugger attached to the worker. It 1587 // should not be reset until the last debugger detaches from the worker. 1588 if (!mDebuggerCount) { 1589 ResetIdleTimeout(aLifetimeExtension); 1590 } 1591 1592 if (!mIdleKeepAliveToken) { 1593 mIdleKeepAliveToken = new KeepAliveToken(this); 1594 } 1595 } 1596 1597 void ServiceWorkerPrivate::ResetIdleTimeout( 1598 const ServiceWorkerLifetimeExtension& aLifetimeExtension) { 1599 TimeStamp now = TimeStamp::NowLoRes(); 1600 TimeStamp existing = mIdleDeadline; 1601 // Normalize the extension, returning a Null TimeStamp if the lifetime 1602 // extension does not actually extend our lifetime. 1603 TimeStamp normalizedExtension = aLifetimeExtension.match( 1604 // No extension means no extension! 1605 [](const NoLifetimeExtension& nle) { return TimeStamp(); }, 1606 [&existing, &now](const PropagatedLifetimeExtension& ple) { 1607 // Ignore null deadlines or deadlines that are in the past. 1608 if (ple.mDeadline.IsNull() || ple.mDeadline < now) { 1609 return TimeStamp(); 1610 } 1611 // Use this new deadline if our existing deadline is null or the 1612 // received deadline is after our current deadline. 1613 if (existing.IsNull() || ple.mDeadline > existing) { 1614 return ple.mDeadline; 1615 } 1616 // (This means our existing deadline extends further into the future so 1617 // we don't want to change our deadline.) 1618 return TimeStamp(); 1619 }, 1620 [&now](const FullLifetimeExtension& fle) { 1621 return now + TimeDuration::FromMilliseconds(Preferences::GetInt( 1622 "dom.serviceWorkers.idle_timeout")); 1623 }); 1624 1625 if (normalizedExtension.IsNull()) { 1626 // Convert the unlikely situation where we are trying to reset the timeout 1627 // without extension and where we have no existing timeout into a 0 timeout. 1628 // This is important because we don't want to let the ServiceWorker live 1629 // forever! 1630 MOZ_ASSERT(!existing.IsNull()); 1631 if (NS_WARN_IF(existing.IsNull())) { 1632 normalizedExtension = now; 1633 } else { 1634 // Return without altering the deadline or churning the timer. 1635 return; 1636 } 1637 } 1638 1639 mIdleDeadline = normalizedExtension; 1640 1641 nsCOMPtr<nsITimerCallback> cb = new ServiceWorkerPrivateTimerCallback( 1642 this, &ServiceWorkerPrivate::NoteIdleWorkerCallback); 1643 // We don't need high resolution but TimeDuration provides better type safety. 1644 DebugOnly<nsresult> rv = mIdleWorkerTimer->InitHighResolutionWithCallback( 1645 cb, mIdleDeadline - now, nsITimer::TYPE_ONE_SHOT); 1646 MOZ_ASSERT(NS_SUCCEEDED(rv)); 1647 } 1648 1649 void ServiceWorkerPrivate::AddToken() { 1650 MOZ_ASSERT(NS_IsMainThread()); 1651 ++mTokenCount; 1652 } 1653 1654 void ServiceWorkerPrivate::ReleaseToken() { 1655 MOZ_ASSERT(NS_IsMainThread()); 1656 1657 MOZ_ASSERT(mTokenCount > 0); 1658 --mTokenCount; 1659 1660 if (IsIdle()) { 1661 mIdlePromiseHolder.ResolveIfExists(true, __func__); 1662 1663 if (!mTokenCount) { 1664 TerminateWorker(); 1665 } 1666 1667 // mInfo can be nullptr here if NoteDeadServiceWorkerInfo() is called while 1668 // the KeepAliveToken is being proxy released as a runnable. 1669 else if (mInfo) { 1670 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1671 if (swm) { 1672 swm->WorkerIsIdle(mInfo); 1673 } 1674 } 1675 } 1676 } 1677 1678 already_AddRefed<KeepAliveToken> 1679 ServiceWorkerPrivate::CreateEventKeepAliveToken() { 1680 MOZ_ASSERT(NS_IsMainThread()); 1681 1682 // When the WorkerPrivate is in a separate process, we first hold a normal 1683 // KeepAliveToken. Then, after we're notified that the worker is alive, we 1684 // create the idle KeepAliveToken. 1685 MOZ_ASSERT(mIdleKeepAliveToken || mControllerChild); 1686 1687 RefPtr<KeepAliveToken> ref = new KeepAliveToken(this); 1688 return ref.forget(); 1689 } 1690 1691 void ServiceWorkerPrivate::SetHandlesFetch(bool aValue) { 1692 MOZ_ASSERT(NS_IsMainThread()); 1693 1694 if (NS_WARN_IF(!mInfo)) { 1695 return; 1696 } 1697 1698 mInfo->SetHandlesFetch(aValue); 1699 } 1700 1701 RefPtr<GenericPromise> ServiceWorkerPrivate::SetSkipWaitingFlag() { 1702 AssertIsOnMainThread(); 1703 MOZ_ASSERT(mInfo); 1704 1705 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1706 1707 if (!swm) { 1708 return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); 1709 } 1710 1711 RefPtr<ServiceWorkerRegistrationInfo> regInfo = 1712 swm->GetRegistration(mInfo->Principal(), mInfo->Scope()); 1713 1714 if (!regInfo) { 1715 return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); 1716 } 1717 1718 mInfo->SetSkipWaitingFlag(); 1719 1720 RefPtr<GenericPromise::Private> promise = 1721 new GenericPromise::Private(__func__); 1722 1723 // The ServiceWorker calling skipWaiting on itself is not a basis for lifetime 1724 // extension on its own. `TryToActivate` will upgrade the lifetime to a full 1725 // extension iff there are any controlled pages. 1726 auto lifetime = ServiceWorkerLifetimeExtension(NoLifetimeExtension{}); 1727 1728 regInfo->TryToActivateAsync(lifetime, 1729 [promise] { promise->Resolve(true, __func__); }); 1730 1731 return promise; 1732 } 1733 1734 /* static */ 1735 void ServiceWorkerPrivate::UpdateRunning(int32_t aDelta, int32_t aFetchDelta) { 1736 // Record values for time we were running at the current values 1737 RefPtr<ServiceWorkerManager> manager(ServiceWorkerManager::GetInstance()); 1738 manager->RecordTelemetry(sRunningServiceWorkers, sRunningServiceWorkersFetch); 1739 1740 MOZ_ASSERT(((int64_t)sRunningServiceWorkers) + aDelta >= 0); 1741 sRunningServiceWorkers += aDelta; 1742 if (sRunningServiceWorkers > sRunningServiceWorkersMax) { 1743 sRunningServiceWorkersMax = sRunningServiceWorkers; 1744 LOG(("ServiceWorker max now %d", sRunningServiceWorkersMax)); 1745 } 1746 MOZ_ASSERT(((int64_t)sRunningServiceWorkersFetch) + aFetchDelta >= 0); 1747 sRunningServiceWorkersFetch += aFetchDelta; 1748 if (sRunningServiceWorkersFetch > sRunningServiceWorkersFetchMax) { 1749 sRunningServiceWorkersFetchMax = sRunningServiceWorkersFetch; 1750 LOG(("ServiceWorker Fetch max now %d", sRunningServiceWorkersFetchMax)); 1751 } 1752 LOG(("ServiceWorkers running now %d/%d", sRunningServiceWorkers, 1753 sRunningServiceWorkersFetch)); 1754 } 1755 1756 void ServiceWorkerPrivate::CreationFailed() { 1757 MOZ_ASSERT(NS_IsMainThread()); 1758 MOZ_ASSERT(mControllerChild); 1759 1760 if (mRemoteWorkerData.remoteType().Find(SERVICEWORKER_REMOTE_TYPE) != 1761 kNotFound) { 1762 glean::service_worker::isolated_launch_time.AccumulateRawDuration( 1763 TimeStamp::Now() - mServiceWorkerLaunchTimeStart); 1764 } else { 1765 glean::service_worker::launch_time.AccumulateRawDuration( 1766 TimeStamp::Now() - mServiceWorkerLaunchTimeStart); 1767 } 1768 1769 mPendingSpawnLifetime = ServiceWorkerLifetimeExtension(NoLifetimeExtension{}); 1770 Shutdown(); 1771 } 1772 1773 void ServiceWorkerPrivate::CreationSucceeded() { 1774 AssertIsOnMainThread(); 1775 MOZ_ASSERT(NS_IsMainThread()); 1776 MOZ_ASSERT(mInfo); 1777 1778 // It's possible for a request to terminate the worker to happen while the 1779 // worker is starting up, in which case we do not want to renew the keepalive 1780 // timer and we probably don't want to update the telemetry below either. 1781 if (NS_WARN_IF(!mControllerChild)) { 1782 mPendingSpawnLifetime = 1783 ServiceWorkerLifetimeExtension(NoLifetimeExtension{}); 1784 return; 1785 } 1786 1787 if (mRemoteWorkerData.remoteType().Find(SERVICEWORKER_REMOTE_TYPE) != 1788 kNotFound) { 1789 glean::service_worker::isolated_launch_time.AccumulateRawDuration( 1790 TimeStamp::Now() - mServiceWorkerLaunchTimeStart); 1791 } else { 1792 glean::service_worker::launch_time.AccumulateRawDuration( 1793 TimeStamp::Now() - mServiceWorkerLaunchTimeStart); 1794 } 1795 1796 RenewKeepAliveToken(mPendingSpawnLifetime); 1797 mPendingSpawnLifetime = ServiceWorkerLifetimeExtension(NoLifetimeExtension{}); 1798 1799 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1800 nsCOMPtr<nsIPrincipal> principal = mInfo->Principal(); 1801 RefPtr<ServiceWorkerRegistrationInfo> regInfo = 1802 swm->GetRegistration(principal, mInfo->Scope()); 1803 if (regInfo) { 1804 // If it's already set, we're done and the running count is already set 1805 if (mHandlesFetch == Unknown) { 1806 if (regInfo->GetActive()) { 1807 mHandlesFetch = 1808 regInfo->GetActive()->HandlesFetch() ? Enabled : Disabled; 1809 if (mHandlesFetch == Enabled) { 1810 UpdateRunning(0, 1); 1811 } 1812 } 1813 // else we're likely still in Evaluating state, and don't know if it 1814 // handles fetch. If so, defer updating the counter for Fetch until we 1815 // finish evaluation. We already updated the Running count for All in 1816 // SpawnWorkerIfNeeded(). 1817 } 1818 } 1819 } 1820 1821 void ServiceWorkerPrivate::ErrorReceived(const ErrorValue& aError) { 1822 AssertIsOnMainThread(); 1823 MOZ_ASSERT(mInfo); 1824 MOZ_ASSERT(mControllerChild); 1825 1826 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1827 MOZ_ASSERT(swm); 1828 1829 ServiceWorkerInfo* info = mInfo; 1830 1831 swm->HandleError(nullptr, info->Principal(), info->Scope(), 1832 info->ScriptSpec(), u""_ns, ""_ns, u""_ns, 0, 0, 1833 nsIScriptError::errorFlag, JSEXN_ERR); 1834 } 1835 1836 void ServiceWorkerPrivate::Terminated() { 1837 AssertIsOnMainThread(); 1838 MOZ_ASSERT(mInfo); 1839 MOZ_ASSERT(mControllerChild); 1840 1841 Shutdown(); 1842 } 1843 1844 void ServiceWorkerPrivate::RefreshRemoteWorkerData( 1845 const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) { 1846 AssertIsOnMainThread(); 1847 MOZ_ASSERT(mInfo); 1848 1849 ServiceWorkerData& serviceWorkerData = 1850 mRemoteWorkerData.serviceWorkerData().get_ServiceWorkerData(); 1851 serviceWorkerData.descriptor() = mInfo->Descriptor().ToIPC(); 1852 serviceWorkerData.registrationDescriptor() = 1853 aRegistration->Descriptor().ToIPC(); 1854 } 1855 1856 RefPtr<FetchServicePromises> ServiceWorkerPrivate::SetupNavigationPreload( 1857 nsCOMPtr<nsIInterceptedChannel>& aChannel, 1858 const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) { 1859 MOZ_ASSERT(XRE_IsParentProcess()); 1860 AssertIsOnMainThread(); 1861 1862 // create IPC request from the intercepted channel. 1863 auto result = GetIPCInternalRequest(aChannel); 1864 if (result.isErr()) { 1865 return nullptr; 1866 } 1867 IPCInternalRequest ipcRequest = result.unwrap(); 1868 1869 // Step 1. Clone the request for preload 1870 // Create the InternalResponse from the created IPCRequest. 1871 SafeRefPtr<InternalRequest> preloadRequest = 1872 MakeSafeRefPtr<InternalRequest>(ipcRequest); 1873 // Copy the request body from uploadChannel 1874 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(aChannel); 1875 if (uploadChannel) { 1876 nsCOMPtr<nsIInputStream> uploadStream; 1877 nsresult rv = uploadChannel->CloneUploadStream( 1878 &ipcRequest.bodySize(), getter_AddRefs(uploadStream)); 1879 // Fail to get the request's body, stop navigation preload by returning 1880 // nullptr. 1881 if (NS_WARN_IF(NS_FAILED(rv))) { 1882 return FetchService::NetworkErrorResponse(rv); 1883 } 1884 preloadRequest->SetBody(uploadStream, ipcRequest.bodySize()); 1885 } 1886 1887 // Set SkipServiceWorker for the navigation preload request 1888 preloadRequest->SetSkipServiceWorker(); 1889 1890 // Step 2. Append Service-Worker-Navigation-Preload header with 1891 // registration->GetNavigationPreloadState().headerValue() on 1892 // request's header list. 1893 IgnoredErrorResult err; 1894 auto headersGuard = preloadRequest->Headers()->Guard(); 1895 preloadRequest->Headers()->SetGuard(HeadersGuardEnum::None, err); 1896 preloadRequest->Headers()->Append( 1897 "Service-Worker-Navigation-Preload"_ns, 1898 aRegistration->GetNavigationPreloadState().headerValue(), err); 1899 preloadRequest->Headers()->SetGuard(headersGuard, err); 1900 1901 // Step 3. Perform fetch through FetchService with the cloned request 1902 if (!err.Failed()) { 1903 nsCOMPtr<nsIChannel> underlyingChannel; 1904 MOZ_ALWAYS_SUCCEEDS( 1905 aChannel->GetChannel(getter_AddRefs(underlyingChannel))); 1906 RefPtr<FetchService> fetchService = FetchService::GetInstance(); 1907 return fetchService->Fetch(AsVariant(FetchService::NavigationPreloadArgs{ 1908 std::move(preloadRequest), underlyingChannel})); 1909 } 1910 return FetchService::NetworkErrorResponse(NS_ERROR_UNEXPECTED); 1911 } 1912 1913 void ServiceWorkerPrivate::Shutdown(Maybe<RefPtr<Promise>>&& aMaybePromise) { 1914 AssertIsOnMainThread(); 1915 1916 if (mControllerChild) { 1917 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); 1918 1919 MOZ_ASSERT(swm, 1920 "All Service Workers should start shutting down before the " 1921 "ServiceWorkerManager does!"); 1922 1923 auto shutdownStateId = swm->MaybeInitServiceWorkerShutdownProgress(); 1924 1925 RefPtr<GenericNonExclusivePromise> promise = 1926 ShutdownInternal(shutdownStateId); 1927 swm->BlockShutdownOn(promise, shutdownStateId); 1928 if (aMaybePromise.isSome() && aMaybePromise.ref()) { 1929 promise->Then( 1930 GetCurrentSerialEventTarget(), __func__, 1931 [listener = aMaybePromise.ref()] { 1932 listener->MaybeResolveWithUndefined(); 1933 }, 1934 [listener = aMaybePromise.ref()] { 1935 listener->MaybeResolveWithUndefined(); 1936 }); 1937 } 1938 } else if (aMaybePromise.isSome() && aMaybePromise.ref()) { 1939 aMaybePromise.ref()->MaybeResolveWithUndefined(); 1940 } 1941 1942 MOZ_ASSERT(!mControllerChild); 1943 } 1944 1945 RefPtr<GenericNonExclusivePromise> ServiceWorkerPrivate::ShutdownInternal( 1946 uint32_t aShutdownStateId) { 1947 AssertIsOnMainThread(); 1948 MOZ_ASSERT(mControllerChild); 1949 1950 mPendingFunctionalEvents.Clear(); 1951 1952 mControllerChild->get()->RevokeObserver(this); 1953 1954 if (StaticPrefs::dom_serviceWorkers_testing_enabled()) { 1955 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); 1956 if (os) { 1957 os->NotifyObservers(nullptr, "service-worker-shutdown", nullptr); 1958 } 1959 } 1960 1961 RefPtr<GenericNonExclusivePromise::Private> promise = 1962 new GenericNonExclusivePromise::Private(__func__); 1963 1964 (void)ExecServiceWorkerOp( 1965 ServiceWorkerTerminateWorkerOpArgs(aShutdownStateId), 1966 // It doesn't make sense to extend the lifetime in this case. This will 1967 // also ensure that we don't try and spawn the ServiceWorker, but as our 1968 // assert at the top of this method makes clear, we don't expect to be in 1969 // that situation. 1970 ServiceWorkerLifetimeExtension(NoLifetimeExtension{}), 1971 [promise](ServiceWorkerOpResult&& aResult) { 1972 MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult); 1973 promise->Resolve(true, __func__); 1974 }, 1975 [promise]() { promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__); }); 1976 1977 /** 1978 * After dispatching a termination operation, no new operations should 1979 * be routed through this actor anymore so we can drop the controller 1980 * reference. This also means that the next time SpawnWorkerIfNeeded is 1981 * invoked we will spawn a new worker, creating a new mControllerChild. 1982 */ 1983 mControllerChild = nullptr; 1984 // Create a new ClientInfo for the next time we potentially spawn this 1985 // ServiceWorker. We do this now rather than immediately before spawning the 1986 // ServiceWorker so it's possible to know what the client id will be before 1987 // triggering the next spawn. 1988 RegenerateClientInfo(); 1989 1990 // Update here, since Evaluation failures directly call ShutdownInternal 1991 UpdateRunning(-1, mHandlesFetch == Enabled ? -1 : 0); 1992 1993 return promise; 1994 } 1995 1996 nsresult ServiceWorkerPrivate::ExecServiceWorkerOp( 1997 ServiceWorkerOpArgs&& aArgs, 1998 const ServiceWorkerLifetimeExtension& aLifetimeExtension, 1999 std::function<void(ServiceWorkerOpResult&&)>&& aSuccessCallback, 2000 std::function<void()>&& aFailureCallback) { 2001 AssertIsOnMainThread(); 2002 MOZ_ASSERT( 2003 aArgs.type() != 2004 ServiceWorkerOpArgs::TParentToChildServiceWorkerFetchEventOpArgs, 2005 "FetchEvent operations should be sent through FetchEventOp(Proxy) " 2006 "actors!"); 2007 MOZ_ASSERT(aSuccessCallback); 2008 2009 nsresult rv = SpawnWorkerIfNeeded(aLifetimeExtension); 2010 2011 if (NS_WARN_IF(NS_FAILED(rv))) { 2012 aFailureCallback(); 2013 return rv; 2014 } 2015 2016 MOZ_ASSERT(mControllerChild); 2017 2018 RefPtr<ServiceWorkerPrivate> self = this; 2019 RefPtr<RAIIActorPtrHolder> holder = mControllerChild; 2020 RefPtr<KeepAliveToken> token = 2021 aArgs.type() == ServiceWorkerOpArgs::TServiceWorkerTerminateWorkerOpArgs 2022 ? nullptr 2023 : CreateEventKeepAliveToken(); 2024 2025 /** 2026 * NOTE: moving `aArgs` won't do anything until IPDL `SendMethod()` methods 2027 * can accept rvalue references rather than just const references. 2028 */ 2029 mControllerChild->get()->SendExecServiceWorkerOp(aArgs)->Then( 2030 GetCurrentSerialEventTarget(), __func__, 2031 [self = std::move(self), holder = std::move(holder), 2032 token = std::move(token), onSuccess = std::move(aSuccessCallback), 2033 onFailure = std::move(aFailureCallback)]( 2034 PRemoteWorkerControllerChild::ExecServiceWorkerOpPromise:: 2035 ResolveOrRejectValue&& aResult) { 2036 if (NS_WARN_IF(aResult.IsReject())) { 2037 onFailure(); 2038 return; 2039 } 2040 2041 onSuccess(std::move(aResult.ResolveValue())); 2042 }); 2043 2044 return NS_OK; 2045 } 2046 2047 } // namespace mozilla::dom