tor-browser

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

FetchService.cpp (30968B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mozilla/dom/FetchService.h"
      6 
      7 #include "FetchLog.h"
      8 #include "FetchParent.h"
      9 #include "mozilla/BasePrincipal.h"
     10 #include "mozilla/ClearOnShutdown.h"
     11 #include "mozilla/SchedulerGroup.h"
     12 #include "mozilla/UniquePtr.h"
     13 #include "mozilla/dom/ClientInfo.h"
     14 #include "mozilla/dom/InternalRequest.h"
     15 #include "mozilla/dom/InternalResponse.h"
     16 #include "mozilla/dom/PerformanceStorage.h"
     17 #include "mozilla/dom/PerformanceTiming.h"
     18 #include "mozilla/dom/ServiceWorkerDescriptor.h"
     19 #include "mozilla/ipc/BackgroundUtils.h"
     20 #include "mozilla/net/CookieJarSettings.h"
     21 #include "nsContentUtils.h"
     22 #include "nsIContentSecurityPolicy.h"
     23 #include "nsICookieJarSettings.h"
     24 #include "nsIIOService.h"
     25 #include "nsILoadGroup.h"
     26 #include "nsILoadInfo.h"
     27 #include "nsIObserverService.h"
     28 #include "nsIPrincipal.h"
     29 #include "nsIScriptSecurityManager.h"
     30 #include "nsNetUtil.h"
     31 #include "nsThreadUtils.h"
     32 #include "nsXULAppAPI.h"
     33 
     34 namespace mozilla::dom {
     35 
     36 mozilla::LazyLogModule gFetchLog("Fetch");
     37 
     38 // FetchServicePromises
     39 
     40 FetchServicePromises::FetchServicePromises()
     41    : mAvailablePromise(
     42          MakeRefPtr<FetchServiceResponseAvailablePromise::Private>(__func__)),
     43      mTimingPromise(
     44          MakeRefPtr<FetchServiceResponseTimingPromise::Private>(__func__)),
     45      mEndPromise(
     46          MakeRefPtr<FetchServiceResponseEndPromise::Private>(__func__)) {
     47  mAvailablePromise->UseDirectTaskDispatch(__func__);
     48  mTimingPromise->UseDirectTaskDispatch(__func__);
     49  mEndPromise->UseDirectTaskDispatch(__func__);
     50 }
     51 
     52 RefPtr<FetchServiceResponseAvailablePromise>
     53 FetchServicePromises::GetResponseAvailablePromise() {
     54  return mAvailablePromise;
     55 }
     56 
     57 RefPtr<FetchServiceResponseTimingPromise>
     58 FetchServicePromises::GetResponseTimingPromise() {
     59  return mTimingPromise;
     60 }
     61 
     62 RefPtr<FetchServiceResponseEndPromise>
     63 FetchServicePromises::GetResponseEndPromise() {
     64  return mEndPromise;
     65 }
     66 
     67 void FetchServicePromises::ResolveResponseAvailablePromise(
     68    FetchServiceResponse&& aResponse, StaticString aMethodName) {
     69  if (mAvailablePromise) {
     70    mAvailablePromiseResolved = true;
     71    mAvailablePromise->Resolve(std::move(aResponse), aMethodName);
     72  }
     73 }
     74 
     75 void FetchServicePromises::RejectResponseAvailablePromise(
     76    const CopyableErrorResult&& aError, StaticString aMethodName) {
     77  if (mAvailablePromise) {
     78    mAvailablePromise->Reject(aError, aMethodName);
     79  }
     80 }
     81 
     82 void FetchServicePromises::ResolveResponseTimingPromise(
     83    ResponseTiming&& aTiming, StaticString aMethodName) {
     84  if (mTimingPromise) {
     85    mTimingPromiseResolved = true;
     86    mTimingPromise->Resolve(std::move(aTiming), aMethodName);
     87  }
     88 }
     89 
     90 void FetchServicePromises::RejectResponseTimingPromise(
     91    const CopyableErrorResult&& aError, StaticString aMethodName) {
     92  if (mTimingPromise) {
     93    mTimingPromise->Reject(aError, aMethodName);
     94  }
     95 }
     96 
     97 void FetchServicePromises::ResolveResponseEndPromise(ResponseEndArgs&& aArgs,
     98                                                     StaticString aMethodName) {
     99  if (mEndPromise) {
    100    mEndPromiseResolved = true;
    101    mEndPromise->Resolve(std::move(aArgs), aMethodName);
    102  }
    103 }
    104 
    105 void FetchServicePromises::RejectResponseEndPromise(
    106    const CopyableErrorResult&& aError, StaticString aMethodName) {
    107  if (mEndPromise) {
    108    mEndPromise->Reject(aError, aMethodName);
    109  }
    110 }
    111 
    112 // FetchInstance
    113 
    114 nsresult FetchService::FetchInstance::Initialize(FetchArgs&& aArgs) {
    115  MOZ_ASSERT(XRE_IsParentProcess());
    116  MOZ_ASSERT(NS_IsMainThread());
    117  MOZ_ASSERT(!aArgs.is<UnknownArgs>() && mArgs.is<UnknownArgs>());
    118 
    119  mArgs = std::move(aArgs);
    120 
    121  // Get needed information for FetchDriver from passed-in channel.
    122  if (mArgs.is<NavigationPreloadArgs>()) {
    123    mRequest = mArgs.as<NavigationPreloadArgs>().mRequest.clonePtr();
    124    mArgsType = FetchArgsType::NavigationPreload;
    125    nsIChannel* channel = mArgs.as<NavigationPreloadArgs>().mChannel;
    126    FETCH_LOG(("FetchInstance::Initialize [%p] request[%p], channel[%p]", this,
    127               mRequest.unsafeGetRawPtr(), channel));
    128 
    129    nsresult rv;
    130    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
    131    MOZ_ASSERT(loadInfo);
    132 
    133    nsCOMPtr<nsIURI> channelURI;
    134    rv = channel->GetURI(getter_AddRefs(channelURI));
    135    if (NS_WARN_IF(NS_FAILED(rv))) {
    136      return rv;
    137    }
    138 
    139    nsIScriptSecurityManager* securityManager =
    140        nsContentUtils::GetSecurityManager();
    141    if (securityManager) {
    142      securityManager->GetChannelResultPrincipal(channel,
    143                                                 getter_AddRefs(mPrincipal));
    144    }
    145 
    146    if (!mPrincipal) {
    147      return NS_ERROR_UNEXPECTED;
    148    }
    149 
    150    // Get loadGroup from channel
    151    rv = channel->GetLoadGroup(getter_AddRefs(mLoadGroup));
    152    if (NS_WARN_IF(NS_FAILED(rv))) {
    153      return rv;
    154    }
    155    if (!mLoadGroup) {
    156      rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal);
    157      if (NS_WARN_IF(NS_FAILED(rv))) {
    158        return rv;
    159      }
    160    }
    161 
    162    // Get CookieJarSettings from channel
    163    rv = loadInfo->GetCookieJarSettings(getter_AddRefs(mCookieJarSettings));
    164    if (NS_WARN_IF(NS_FAILED(rv))) {
    165      return rv;
    166    }
    167 
    168    // Get PerformanceStorage from channel
    169    mPerformanceStorage = loadInfo->GetPerformanceStorage();
    170  } else if (mArgs.is<MainThreadFetchArgs>()) {
    171    mArgsType = FetchArgsType::MainThreadFetch;
    172 
    173    mRequest = mArgs.as<MainThreadFetchArgs>().mRequest.clonePtr();
    174 
    175    FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this,
    176               mRequest.unsafeGetRawPtr()));
    177 
    178    auto principalOrErr = PrincipalInfoToPrincipal(
    179        mArgs.as<MainThreadFetchArgs>().mPrincipalInfo);
    180    if (principalOrErr.isErr()) {
    181      return principalOrErr.unwrapErr();
    182    }
    183    mPrincipal = principalOrErr.unwrap();
    184    nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal);
    185    if (NS_WARN_IF(NS_FAILED(rv))) {
    186      return rv;
    187    }
    188 
    189    if (mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.isSome()) {
    190      net::CookieJarSettings::Deserialize(
    191          mArgs.as<MainThreadFetchArgs>().mCookieJarSettings.ref(),
    192          getter_AddRefs(mCookieJarSettings));
    193    }
    194 
    195    return NS_OK;
    196 
    197  } else {
    198    mRequest = mArgs.as<WorkerFetchArgs>().mRequest.clonePtr();
    199    mArgsType = FetchArgsType::WorkerFetch;
    200 
    201    FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this,
    202               mRequest.unsafeGetRawPtr()));
    203 
    204    auto principalOrErr =
    205        PrincipalInfoToPrincipal(mArgs.as<WorkerFetchArgs>().mPrincipalInfo);
    206    if (principalOrErr.isErr()) {
    207      return principalOrErr.unwrapErr();
    208    }
    209    mPrincipal = principalOrErr.unwrap();
    210    nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), mPrincipal);
    211    if (NS_WARN_IF(NS_FAILED(rv))) {
    212      return rv;
    213    }
    214 
    215    if (mArgs.as<WorkerFetchArgs>().mCookieJarSettings.isSome()) {
    216      net::CookieJarSettings::Deserialize(
    217          mArgs.as<WorkerFetchArgs>().mCookieJarSettings.ref(),
    218          getter_AddRefs(mCookieJarSettings));
    219    }
    220  }
    221 
    222  return NS_OK;
    223 }
    224 
    225 RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
    226  MOZ_ASSERT(XRE_IsParentProcess());
    227  MOZ_ASSERT(NS_IsMainThread());
    228 
    229  MOZ_ASSERT(mPrincipal);
    230  MOZ_ASSERT(mLoadGroup);
    231 
    232  nsAutoCString principalSpec;
    233  MOZ_ALWAYS_SUCCEEDS(mPrincipal->GetAsciiSpec(principalSpec));
    234  nsAutoCString requestURL;
    235  mRequest->GetURL(requestURL);
    236  FETCH_LOG(("FetchInstance::Fetch [%p], mRequest URL: %s mPrincipal: %s", this,
    237             requestURL.BeginReading(), principalSpec.BeginReading()));
    238 
    239  nsresult rv;
    240 
    241  if (mRequest->GetKeepalive()) {
    242    nsAutoCString origin;
    243    MOZ_ASSERT(mPrincipal);
    244    mPrincipal->GetOrigin(origin);
    245 
    246    RefPtr<FetchService> fetchService = FetchService::GetInstance();
    247    MOZ_ASSERT(fetchService);
    248    if (fetchService->DoesExceedsKeepaliveResourceLimits(origin)) {
    249      FETCH_LOG(("FetchInstance::Fetch Keepalive request exceeds limit"));
    250      return FetchService::NetworkErrorResponse(NS_ERROR_DOM_ABORT_ERR, mArgs);
    251    }
    252    fetchService->IncrementKeepAliveRequestCount(origin);
    253  }
    254 
    255  // Create a FetchDriver instance
    256  mFetchDriver = MakeRefPtr<FetchDriver>(
    257      mRequest.clonePtr(),               // Fetch Request
    258      mPrincipal,                        // Principal
    259      mLoadGroup,                        // LoadGroup
    260      GetMainThreadSerialEventTarget(),  // MainThreadEventTarget
    261      mCookieJarSettings,                // CookieJarSettings
    262      mPerformanceStorage,               // PerformanceStorage
    263      // For service workers we set
    264      // tracking fetch to false, but for Keepalive
    265      // requests from main thread this needs to be
    266      // changed. See Bug 1892406
    267      net::ClassificationFlags({0, 0})  // TrackingFlags
    268  );
    269 
    270  if (mArgsType == FetchArgsType::WorkerFetch) {
    271    auto& args = mArgs.as<WorkerFetchArgs>();
    272    mFetchDriver->SetWorkerScript(args.mWorkerScript);
    273    MOZ_ASSERT(args.mClientInfo.isSome());
    274    mFetchDriver->SetClientInfo(args.mClientInfo.ref());
    275    mFetchDriver->SetController(args.mController);
    276    if (args.mCSPEventListener) {
    277      mFetchDriver->SetCSPEventListener(args.mCSPEventListener);
    278    }
    279    mFetchDriver->SetAssociatedBrowsingContextID(
    280        args.mAssociatedBrowsingContextID);
    281    mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext));
    282    mFetchDriver->SetIsOn3PCBExceptionList(args.mIsOn3PCBExceptionList);
    283  }
    284 
    285  if (mArgsType == FetchArgsType::MainThreadFetch) {
    286    auto& args = mArgs.as<MainThreadFetchArgs>();
    287    mFetchDriver->SetAssociatedBrowsingContextID(
    288        args.mAssociatedBrowsingContextID);
    289    mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext));
    290  }
    291 
    292  mFetchDriver->EnableNetworkInterceptControl();
    293  mPromises = MakeRefPtr<FetchServicePromises>();
    294 
    295  // Call FetchDriver::Fetch to start fetching.
    296  // Pass AbortSignalImpl as nullptr since we no need support AbortSignalImpl
    297  // with FetchService. AbortSignalImpl related information should be passed
    298  // through PFetch or InterceptedHttpChannel, then call
    299  // FetchService::CancelFetch() to abort the running fetch.
    300  rv = mFetchDriver->Fetch(nullptr, this);
    301  if (NS_WARN_IF(NS_FAILED(rv))) {
    302    FETCH_LOG(
    303        ("FetchInstance::Fetch FetchDriver::Fetch failed(0x%X)", (uint32_t)rv));
    304    return FetchService::NetworkErrorResponse(rv, mArgs);
    305  }
    306 
    307  return mPromises;
    308 }
    309 
    310 bool FetchService::FetchInstance::IsLocalHostFetch() const {
    311  if (!mPrincipal) {
    312    return false;
    313  }
    314  bool res;
    315  nsresult rv = mPrincipal->GetIsLoopbackHost(&res);
    316  if (NS_WARN_IF(NS_FAILED(rv))) {
    317    return false;
    318  }
    319  return res;
    320 }
    321 
    322 void FetchService::FetchInstance::Cancel(bool aForceAbort) {
    323  MOZ_ASSERT(XRE_IsParentProcess());
    324  MOZ_ASSERT(NS_IsMainThread());
    325 
    326  FETCH_LOG(("FetchInstance::Cancel() [%p]", this));
    327 
    328  // If mFetchDriver is not null here, FetchInstance::Fetch() has already
    329  // started, let mFetchDriver::RunAbortAlgorithm() to call
    330  // FetchInstance::OnResponseEnd() to resolve the pending promises.
    331  // Otherwise, resolving the pending promises here.
    332  if (mFetchDriver) {
    333    // if keepalive is active and it is NOT user initiated Abort, then
    334    // do not cancel the request.
    335    if (mRequest->GetKeepalive() && !aForceAbort) {
    336      FETCH_LOG(("Cleaning up the worker for keepalive[%p]", this));
    337 
    338      MOZ_ASSERT(mArgs.is<WorkerFetchArgs>());
    339      if (mArgs.is<WorkerFetchArgs>()) {
    340        // delete the actors for cleanup for worker keep-alive requests.
    341        // Non-worker keepalive requests need actors to be active until request
    342        // completion, because we update request quota per load-group in
    343        // FetchChild::ActorDestroy.
    344        MOZ_ASSERT((mArgs.as<WorkerFetchArgs>().mFetchParentPromise));
    345        if (mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Exists()) {
    346          FETCH_LOG(
    347              ("FetchInstance::Cancel() [%p] mResponseEndPromiseHolder exists",
    348               this));
    349 
    350          mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Disconnect();
    351 
    352          // the parent promise resolution leads to deleting of actors
    353          // mActorDying prevents further access to FetchParent
    354          mActorDying = true;
    355          mArgs.as<WorkerFetchArgs>().mFetchParentPromise->Resolve(true,
    356                                                                   __func__);
    357        }
    358      }
    359      return;
    360    }
    361    mFetchDriver->RunAbortAlgorithm();
    362    return;
    363  }
    364 
    365  MOZ_ASSERT(mPromises);
    366 
    367  mPromises->ResolveResponseAvailablePromise(
    368      InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR), __func__);
    369 
    370  mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__);
    371 
    372  mPromises->ResolveResponseEndPromise(
    373      ResponseEndArgs(FetchDriverObserver::eAborted), __func__);
    374 }
    375 
    376 void FetchService::FetchInstance::OnResponseEnd(
    377    FetchDriverObserver::EndReason aReason,
    378    JS::Handle<JS::Value> aReasonDetails) {
    379  FETCH_LOG(("FetchInstance::OnResponseEnd [%p] %s", this,
    380             aReason == eAborted ? "eAborted" : "eNetworking"));
    381 
    382  if (mRequest->GetKeepalive()) {
    383    nsAutoCString origin;
    384    MOZ_ASSERT(mPrincipal);
    385    mPrincipal->GetOrigin(origin);
    386    RefPtr<FetchService> fetchService = FetchService::GetInstance();
    387    fetchService->DecrementKeepAliveRequestCount(origin);
    388  }
    389 
    390  MOZ_ASSERT(mRequest);
    391  if (mArgsType != FetchArgsType::NavigationPreload) {
    392    FlushConsoleReport();
    393    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    394        __func__,
    395        [endArgs = ResponseEndArgs(aReason), actorID = GetActorID()]() {
    396          FETCH_LOG(("FetchInstance::OnResponseEnd, Runnable"));
    397          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    398          if (actor) {
    399            actor->OnResponseEnd(std::move(endArgs));
    400          }
    401        });
    402    MOZ_ALWAYS_SUCCEEDS(
    403        GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    404  }
    405 
    406  MOZ_ASSERT(mPromises);
    407 
    408  if (mArgs.is<WorkerFetchArgs>() &&
    409      mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Exists()) {
    410    mArgs.as<WorkerFetchArgs>().mResponseEndPromiseHolder.Complete();
    411  }
    412 
    413  if (aReason == eAborted) {
    414    // If ResponseAvailablePromise has not resolved yet, resolved with
    415    // NS_ERROR_DOM_ABORT_ERR response. If the promise is already resolved,
    416    // this will have no effect.
    417    mPromises->ResolveResponseAvailablePromise(
    418        InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR), __func__);
    419 
    420    // If ResponseTimingPromise has not resolved yet, resolved with empty
    421    // ResponseTiming. If the promise is already resolved, this has no effect.
    422    mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__);
    423    // Resolve the ResponseEndPromise
    424    mPromises->ResolveResponseEndPromise(ResponseEndArgs(aReason), __func__);
    425    return;
    426  }
    427 
    428  MOZ_ASSERT(mPromises->IsResponseAvailablePromiseResolved() &&
    429             mPromises->IsResponseTimingPromiseResolved());
    430 
    431  // Resolve the ResponseEndPromise
    432  mPromises->ResolveResponseEndPromise(ResponseEndArgs(aReason), __func__);
    433 
    434  // Remove the FetchInstance from FetchInstanceTable
    435  RefPtr<FetchService> fetchService = FetchService::GetInstance();
    436  MOZ_ASSERT(fetchService);
    437  auto entry = fetchService->mFetchInstanceTable.Lookup(mPromises);
    438  if (entry) {
    439    entry.Remove();
    440    FETCH_LOG(
    441        ("FetchInstance::OnResponseEnd entry of responsePromise[%p] is "
    442         "removed",
    443         mPromises.get()));
    444  }
    445 }
    446 
    447 void FetchService::FetchInstance::OnResponseAvailableInternal(
    448    SafeRefPtr<InternalResponse> aResponse) {
    449  FETCH_LOG(("FetchInstance::OnResponseAvailableInternal [%p]", this));
    450  mResponse = std::move(aResponse);
    451 
    452  nsCOMPtr<nsIInputStream> body;
    453  mResponse->GetUnfilteredBody(getter_AddRefs(body));
    454  FETCH_LOG(
    455      ("FetchInstance::OnResponseAvailableInternal [%p] response body: %p",
    456       this, body.get()));
    457  MOZ_ASSERT(mRequest);
    458 
    459  if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) {
    460    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    461        __func__,
    462        [response = mResponse.clonePtr(), actorID = GetActorID()]() mutable {
    463          FETCH_LOG(("FetchInstance::OnResponseAvailableInternal Runnable"));
    464          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    465          if (actor) {
    466            actor->OnResponseAvailableInternal(std::move(response));
    467          }
    468        });
    469    MOZ_ALWAYS_SUCCEEDS(
    470        GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    471  }
    472 
    473  MOZ_ASSERT(mPromises);
    474 
    475  // Resolve the ResponseAvailablePromise
    476  mPromises->ResolveResponseAvailablePromise(mResponse.clonePtr(), __func__);
    477 }
    478 
    479 bool FetchService::FetchInstance::NeedOnDataAvailable() {
    480  if (mArgs.is<WorkerFetchArgs>()) {
    481    return mArgs.as<WorkerFetchArgs>().mNeedOnDataAvailable;
    482  }
    483 
    484  if (mArgs.is<MainThreadFetchArgs>()) {
    485    return mArgs.as<MainThreadFetchArgs>().mNeedOnDataAvailable;
    486  }
    487 
    488  return false;
    489 }
    490 
    491 void FetchService::FetchInstance::OnDataAvailable() {
    492  FETCH_LOG(("FetchInstance::OnDataAvailable [%p]", this));
    493 
    494  if (!NeedOnDataAvailable()) {
    495    return;
    496  }
    497 
    498  MOZ_ASSERT(mRequest);
    499 
    500  if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) {
    501    nsCOMPtr<nsIRunnable> r =
    502        NS_NewRunnableFunction(__func__, [actorID = GetActorID()]() {
    503          FETCH_LOG(("FetchInstance::OnDataAvailable, Runnable"));
    504          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    505          if (actor) {
    506            actor->OnDataAvailable();
    507          }
    508        });
    509    MOZ_ALWAYS_SUCCEEDS(
    510        GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    511  }
    512 }
    513 
    514 void FetchService::FetchInstance::FlushConsoleReport() {
    515  FETCH_LOG(("FetchInstance::FlushConsoleReport [%p]", this));
    516 
    517  if (mArgsType != FetchArgsType::NavigationPreload && !mActorDying) {
    518    if (!mReporter) {
    519      return;
    520    }
    521    nsTArray<net::ConsoleReportCollected> reports;
    522    mReporter->StealConsoleReports(reports);
    523    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    524        __func__,
    525        [actorID = GetActorID(), consoleReports = std::move(reports)]() {
    526          FETCH_LOG(("FetchInstance::FlushConsolReport, Runnable"));
    527          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    528          if (actor) {
    529            actor->OnFlushConsoleReport(std::move(consoleReports));
    530          }
    531        });
    532    MOZ_ALWAYS_SUCCEEDS(
    533        GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    534  }
    535 }
    536 
    537 void FetchService::FetchInstance::OnReportPerformanceTiming() {
    538  FETCH_LOG(("FetchInstance::OnReportPerformanceTiming [%p]", this));
    539  MOZ_ASSERT(mFetchDriver);
    540  MOZ_ASSERT(mPromises);
    541 
    542  if (mPromises->IsResponseTimingPromiseResolved()) {
    543    return;
    544  }
    545 
    546  ResponseTiming timing;
    547  UniquePtr<PerformanceTimingData> performanceTiming(
    548      mFetchDriver->GetPerformanceTimingData(timing.initiatorType(),
    549                                             timing.entryName()));
    550  // FetchDriver has no corresponding performance timing when fetch() failed.
    551  // Resolve the ResponseTimingPromise with empty timing.
    552  if (!performanceTiming) {
    553    mPromises->ResolveResponseTimingPromise(ResponseTiming(), __func__);
    554    return;
    555  }
    556  timing.timingData() = performanceTiming->ToIPC();
    557  // Force replace initiatorType for ServiceWorkerNavgationPreload.
    558  if (mArgsType == FetchArgsType::NavigationPreload) {
    559    timing.initiatorType() = u"navigation"_ns;
    560  } else if (!mActorDying) {
    561    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    562        __func__, [actorID = GetActorID(), timing = timing]() {
    563          FETCH_LOG(("FetchInstance::OnReportPerformanceTiming, Runnable"));
    564          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    565          if (actor) {
    566            actor->OnReportPerformanceTiming(std::move(timing));
    567          }
    568        });
    569    MOZ_ALWAYS_SUCCEEDS(
    570        GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    571  }
    572 
    573  mPromises->ResolveResponseTimingPromise(std::move(timing), __func__);
    574 }
    575 
    576 void FetchService::FetchInstance::OnNotifyNetworkMonitorAlternateStack(
    577    uint64_t aChannelID) {
    578  FETCH_LOG(("FetchInstance::OnNotifyNetworkMonitorAlternateStack [%p]", this));
    579  MOZ_ASSERT(mFetchDriver);
    580  MOZ_ASSERT(mPromises);
    581 
    582  if (mArgsType != FetchArgsType::WorkerFetch &&
    583      mArgsType != FetchArgsType::MainThreadFetch) {
    584    // Fetch type not supported
    585    return;
    586  }
    587 
    588  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    589      __func__, [actorID = GetActorID(), channelID = aChannelID]() {
    590        FETCH_LOG(
    591            ("FetchInstance::OnNotifyNetworkMonitorAlternateStack, Runnable"));
    592        RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    593        if (actor) {
    594          actor->OnNotifyNetworkMonitorAlternateStack(channelID);
    595        }
    596      });
    597 
    598  MOZ_ALWAYS_SUCCEEDS(
    599      GetBackgroundEventTarget()->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    600 }
    601 
    602 nsID FetchService::FetchInstance::GetActorID() {
    603  if (mArgsType == FetchArgsType::WorkerFetch) {
    604    return mArgs.as<WorkerFetchArgs>().mActorID;
    605  }
    606 
    607  if (mArgsType == FetchArgsType::MainThreadFetch) {
    608    return mArgs.as<MainThreadFetchArgs>().mActorID;
    609  }
    610 
    611  MOZ_ASSERT_UNREACHABLE("GetActorID called for unexpected mArgsType");
    612 
    613  return {};
    614 }
    615 
    616 nsCOMPtr<nsISerialEventTarget>
    617 FetchService::FetchInstance::GetBackgroundEventTarget() {
    618  if (mArgsType == FetchArgsType::WorkerFetch) {
    619    return mArgs.as<WorkerFetchArgs>().mEventTarget;
    620  }
    621 
    622  if (mArgsType == FetchArgsType::MainThreadFetch) {
    623    return mArgs.as<MainThreadFetchArgs>().mEventTarget;
    624  }
    625 
    626  MOZ_ASSERT_UNREACHABLE(
    627      "GetBackgroundEventTarget called for unexpected mArgsType");
    628 
    629  return {};
    630 }
    631 
    632 // FetchService
    633 
    634 NS_IMPL_ISUPPORTS(FetchService, nsIObserver)
    635 
    636 StaticRefPtr<FetchService> gInstance;
    637 
    638 /*static*/
    639 already_AddRefed<FetchService> FetchService::GetInstance() {
    640  MOZ_ASSERT(XRE_IsParentProcess());
    641  MOZ_ASSERT(NS_IsMainThread());
    642 
    643  if (!gInstance) {
    644    gInstance = MakeRefPtr<FetchService>();
    645    nsresult rv = gInstance->RegisterNetworkObserver();
    646    if (NS_WARN_IF(NS_FAILED(rv))) {
    647      gInstance = nullptr;
    648      return nullptr;
    649    }
    650    ClearOnShutdown(&gInstance);
    651  }
    652  RefPtr<FetchService> service = gInstance;
    653  return service.forget();
    654 }
    655 
    656 /*static*/
    657 RefPtr<FetchServicePromises> FetchService::NetworkErrorResponse(
    658    nsresult aRv, const FetchArgs& aArgs) {
    659  if (aArgs.is<WorkerFetchArgs>()) {
    660    const WorkerFetchArgs& args = aArgs.as<WorkerFetchArgs>();
    661    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    662        __func__, [aRv, actorID = args.mActorID]() mutable {
    663          FETCH_LOG(
    664              ("FetchService::PropagateErrorResponse runnable aError: 0x%X",
    665               (uint32_t)aRv));
    666          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    667          if (actor) {
    668            actor->OnResponseAvailableInternal(
    669                InternalResponse::NetworkError(aRv));
    670            actor->OnResponseEnd(
    671                ResponseEndArgs(FetchDriverObserver::eAborted));
    672          }
    673        });
    674    MOZ_ALWAYS_SUCCEEDS(
    675        args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    676  } else if (aArgs.is<MainThreadFetchArgs>()) {
    677    const MainThreadFetchArgs& args = aArgs.as<MainThreadFetchArgs>();
    678    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
    679        __func__, [aRv, actorID = args.mActorID]() mutable {
    680          FETCH_LOG(
    681              ("FetchService::PropagateErrorResponse runnable aError: 0x%X",
    682               (uint32_t)aRv));
    683          RefPtr<FetchParent> actor = FetchParent::GetActorByID(actorID);
    684          if (actor) {
    685            actor->OnResponseAvailableInternal(
    686                InternalResponse::NetworkError(aRv));
    687            actor->OnResponseEnd(
    688                ResponseEndArgs(FetchDriverObserver::eAborted));
    689          }
    690        });
    691    MOZ_ALWAYS_SUCCEEDS(
    692        args.mEventTarget->Dispatch(r, nsIThread::DISPATCH_NORMAL));
    693  }
    694 
    695  RefPtr<FetchServicePromises> promises = MakeRefPtr<FetchServicePromises>();
    696  promises->ResolveResponseAvailablePromise(InternalResponse::NetworkError(aRv),
    697                                            __func__);
    698  promises->ResolveResponseTimingPromise(ResponseTiming(), __func__);
    699  promises->ResolveResponseEndPromise(
    700      ResponseEndArgs(FetchDriverObserver::eAborted), __func__);
    701  return promises;
    702 }
    703 
    704 FetchService::FetchService() {
    705  MOZ_ASSERT(XRE_IsParentProcess());
    706  MOZ_ASSERT(NS_IsMainThread());
    707 }
    708 
    709 FetchService::~FetchService() {
    710  MOZ_ALWAYS_SUCCEEDS(UnregisterNetworkObserver());
    711 }
    712 
    713 nsresult FetchService::RegisterNetworkObserver() {
    714  AssertIsOnMainThread();
    715  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
    716  if (!observerService) {
    717    return NS_ERROR_UNEXPECTED;
    718  }
    719 
    720  nsCOMPtr<nsIIOService> ioService = services::GetIOService();
    721  if (!ioService) {
    722    return NS_ERROR_UNEXPECTED;
    723  }
    724 
    725  nsresult rv = observerService->AddObserver(
    726      this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false);
    727  NS_ENSURE_SUCCESS(rv, rv);
    728 
    729  rv = observerService->AddObserver(this, "xpcom-shutdown", false);
    730  NS_ENSURE_SUCCESS(rv, rv);
    731 
    732  rv = ioService->GetOffline(&mOffline);
    733  NS_ENSURE_SUCCESS(rv, rv);
    734  mObservingNetwork = true;
    735 
    736  return NS_OK;
    737 }
    738 
    739 nsresult FetchService::UnregisterNetworkObserver() {
    740  AssertIsOnMainThread();
    741  nsresult rv;
    742  if (mObservingNetwork) {
    743    nsCOMPtr<nsIObserverService> observerService =
    744        mozilla::services::GetObserverService();
    745    if (observerService) {
    746      rv = observerService->RemoveObserver(this,
    747                                           NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
    748      NS_ENSURE_SUCCESS(rv, rv);
    749      rv = observerService->RemoveObserver(this, "xpcom-shutdown");
    750      NS_ENSURE_SUCCESS(rv, rv);
    751    }
    752    mObservingNetwork = false;
    753  }
    754  return NS_OK;
    755 }
    756 
    757 void FetchService::IncrementKeepAliveRequestCount(const nsACString& aOrigin) {
    758  MOZ_ASSERT(XRE_IsParentProcess());
    759  MOZ_ASSERT(NS_IsMainThread());
    760  FETCH_LOG(("FetchService::IncrementKeepAliveRequestCount [origin=%s]\n",
    761             PromiseFlatCString(aOrigin).get()));
    762  ++mTotalKeepAliveRequests;
    763  uint32_t count = mPendingKeepAliveRequestsPerOrigin.Get(aOrigin) + 1;
    764  mPendingKeepAliveRequestsPerOrigin.InsertOrUpdate(aOrigin, count);
    765 }
    766 
    767 void FetchService::DecrementKeepAliveRequestCount(const nsACString& aOrigin) {
    768  MOZ_ASSERT(XRE_IsParentProcess());
    769  MOZ_ASSERT(NS_IsMainThread());
    770  FETCH_LOG(("FetchService::DecrementKeepAliveRequestCount [origin=%s]\n",
    771             PromiseFlatCString(aOrigin).get()));
    772  MOZ_ASSERT(mTotalKeepAliveRequests > 0);
    773  if (mTotalKeepAliveRequests) {
    774    --mTotalKeepAliveRequests;
    775  }
    776 
    777  uint32_t count = mPendingKeepAliveRequestsPerOrigin.Get(aOrigin);
    778  MOZ_ASSERT(count > 0);
    779  if (count) {
    780    --count;
    781    if (count == 0) {
    782      mPendingKeepAliveRequestsPerOrigin.Remove(aOrigin);
    783    } else {
    784      mPendingKeepAliveRequestsPerOrigin.InsertOrUpdate(aOrigin, count);
    785    }
    786  }
    787 }
    788 
    789 bool FetchService::DoesExceedsKeepaliveResourceLimits(
    790    const nsACString& origin) {
    791  if (mTotalKeepAliveRequests >=
    792      StaticPrefs::dom_fetchKeepalive_total_request_limit()) {
    793    return true;
    794  }
    795 
    796  if (mPendingKeepAliveRequestsPerOrigin.Get(origin) >=
    797      StaticPrefs::dom_fetchKeepalive_request_limit_per_origin()) {
    798    return true;
    799  }
    800 
    801  return false;
    802 }
    803 
    804 NS_IMETHODIMP FetchService::Observe(nsISupports* aSubject, const char* aTopic,
    805                                    const char16_t* aData) {
    806  FETCH_LOG(("FetchService::Observe topic: %s", aTopic));
    807  AssertIsOnMainThread();
    808  MOZ_ASSERT(!strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC) ||
    809             !strcmp(aTopic, "xpcom-shutdown"));
    810 
    811  if (!strcmp(aTopic, "xpcom-shutdown")) {
    812    // Going to shutdown, unregister the network status observer to avoid
    813    // receiving
    814    nsresult rv = UnregisterNetworkObserver();
    815    NS_ENSURE_SUCCESS(rv, rv);
    816    return NS_OK;
    817  }
    818 
    819  if (nsDependentString(aData).EqualsLiteral(NS_IOSERVICE_ONLINE)) {
    820    mOffline = false;
    821  } else {
    822    mOffline = true;
    823    // Network is offline, cancel the running fetch that is not to local server.
    824    mFetchInstanceTable.RemoveIf([](auto& entry) {
    825      bool res = entry.Data()->IsLocalHostFetch();
    826      if (res) {
    827        return false;
    828      }
    829      entry.Data()->Cancel(true);
    830      return true;
    831    });
    832  }
    833  return NS_OK;
    834 }
    835 
    836 RefPtr<FetchServicePromises> FetchService::Fetch(FetchArgs&& aArgs) {
    837  MOZ_ASSERT(XRE_IsParentProcess());
    838  MOZ_ASSERT(NS_IsMainThread());
    839 
    840  FETCH_LOG(("FetchService::Fetch (%s)", aArgs.is<NavigationPreloadArgs>()
    841                                             ? "NavigationPreload"
    842                                             : "WorkerFetch"));
    843  // Create FetchInstance
    844  RefPtr<FetchInstance> fetch = MakeRefPtr<FetchInstance>();
    845 
    846  // Call FetchInstance::Initialize() to get needed information for
    847  // FetchDriver
    848  nsresult rv = fetch->Initialize(std::move(aArgs));
    849  if (NS_WARN_IF(NS_FAILED(rv))) {
    850    return NetworkErrorResponse(rv, fetch->Args());
    851  }
    852 
    853  if (mOffline && !fetch->IsLocalHostFetch()) {
    854    FETCH_LOG(("FetchService::Fetch network offline"));
    855    return NetworkErrorResponse(NS_ERROR_OFFLINE, fetch->Args());
    856  }
    857 
    858  // Call FetchInstance::Fetch() to start an asynchronous fetching.
    859  RefPtr<FetchServicePromises> promises = fetch->Fetch();
    860  MOZ_ASSERT(promises);
    861 
    862  if (!promises->IsResponseAvailablePromiseResolved()) {
    863    // Insert the created FetchInstance into FetchInstanceTable.
    864    if (!mFetchInstanceTable.WithEntryHandle(promises, [&](auto&& entry) {
    865          if (entry.HasEntry()) {
    866            return false;
    867          }
    868          entry.Insert(fetch);
    869          return true;
    870        })) {
    871      FETCH_LOG(
    872          ("FetchService::Fetch entry[%p] already exists", promises.get()));
    873      return NetworkErrorResponse(NS_ERROR_UNEXPECTED, fetch->Args());
    874    }
    875    FETCH_LOG(("FetchService::Fetch entry[%p] of FetchInstance[%p] added",
    876               promises.get(), fetch.get()));
    877  }
    878  return promises;
    879 }
    880 
    881 void FetchService::CancelFetch(const RefPtr<FetchServicePromises>&& aPromises,
    882                               bool aForceAbort) {
    883  MOZ_ASSERT(XRE_IsParentProcess());
    884  MOZ_ASSERT(NS_IsMainThread());
    885  MOZ_ASSERT(aPromises);
    886  FETCH_LOG(("FetchService::CancelFetch aPromises[%p]", aPromises.get()));
    887 
    888  auto entry = mFetchInstanceTable.Lookup(aPromises);
    889  if (entry) {
    890    // Notice any modifications here before entry.Remove() probably should be
    891    // reflected to Observe() offline case.
    892    entry.Data()->Cancel(aForceAbort);
    893    entry.Remove();
    894    FETCH_LOG(
    895        ("FetchService::CancelFetch entry [%p] removed", aPromises.get()));
    896  }
    897 }
    898 
    899 MozPromiseRequestHolder<FetchServiceResponseEndPromise>&
    900 FetchService::GetResponseEndPromiseHolder(
    901    const RefPtr<FetchServicePromises>& aPromises) {
    902  MOZ_ASSERT(XRE_IsParentProcess());
    903  MOZ_ASSERT(NS_IsMainThread());
    904  MOZ_ASSERT(aPromises);
    905  auto entry = mFetchInstanceTable.Lookup(aPromises);
    906  MOZ_ASSERT(entry);
    907  return entry.Data()->GetResponseEndPromiseHolder();
    908 }
    909 
    910 }  // namespace mozilla::dom