tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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