tor-browser

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

Fetch.cpp (60786B)


      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 "Fetch.h"
      8 
      9 #include "BodyExtractor.h"
     10 #include "FetchChild.h"
     11 #include "FetchObserver.h"
     12 #include "FetchUtil.h"
     13 #include "InternalRequest.h"
     14 #include "InternalResponse.h"
     15 #include "ThirdPartyUtil.h"
     16 #include "js/RootingAPI.h"
     17 #include "js/Value.h"
     18 #include "mozilla/CycleCollectedJSContext.h"
     19 #include "mozilla/ErrorResult.h"
     20 #include "mozilla/StaticPrefs_dom.h"
     21 #include "mozilla/dom/BindingDeclarations.h"
     22 #include "mozilla/dom/BodyConsumer.h"
     23 #include "mozilla/dom/DOMException.h"
     24 #include "mozilla/dom/Document.h"
     25 #include "mozilla/dom/Exceptions.h"
     26 #include "mozilla/dom/FetchDriver.h"
     27 #include "mozilla/dom/File.h"
     28 #include "mozilla/dom/FormData.h"
     29 #include "mozilla/dom/Headers.h"
     30 #include "mozilla/dom/MimeType.h"
     31 #include "mozilla/dom/Promise.h"
     32 #include "mozilla/dom/PromiseWorkerProxy.h"
     33 #include "mozilla/dom/ReadableStreamDefaultReader.h"
     34 #include "mozilla/dom/RemoteWorkerChild.h"
     35 #include "mozilla/dom/Request.h"
     36 #include "mozilla/dom/Response.h"
     37 #include "mozilla/dom/ScriptSettings.h"
     38 #include "mozilla/dom/URLSearchParams.h"
     39 #include "mozilla/dom/WorkerCommon.h"
     40 #include "mozilla/dom/WorkerRef.h"
     41 #include "mozilla/dom/WorkerRunnable.h"
     42 #include "mozilla/dom/WorkerScope.h"
     43 #include "mozilla/ipc/BackgroundChild.h"
     44 #include "mozilla/ipc/IPCStreamUtils.h"
     45 #include "mozilla/ipc/PBackgroundChild.h"
     46 #include "mozilla/ipc/PBackgroundSharedTypes.h"
     47 #include "mozilla/net/CookieJarSettings.h"
     48 #include "nsDOMString.h"
     49 #include "nsIClassifiedChannel.h"
     50 #include "nsIGlobalObject.h"
     51 #include "nsJSUtils.h"
     52 #include "nsNetUtil.h"
     53 #include "nsProxyRelease.h"
     54 #include "nsReadableUtils.h"
     55 #include "nsStreamUtils.h"
     56 #include "nsStringStream.h"
     57 
     58 namespace mozilla::dom {
     59 
     60 namespace {
     61 
     62 // Step 17.2.1.2 and 17.2.2 of
     63 // https://fetch.spec.whatwg.org/#concept-http-network-fetch
     64 // If stream is readable, then error stream with ...
     65 void AbortStream(JSContext* aCx, ReadableStream* aReadableStream,
     66                 ErrorResult& aRv, JS::Handle<JS::Value> aReasonDetails) {
     67  if (aReadableStream->State() != ReadableStream::ReaderState::Readable) {
     68    return;
     69  }
     70 
     71  JS::Rooted<JS::Value> value(aCx, aReasonDetails);
     72 
     73  if (aReasonDetails.isUndefined()) {
     74    RefPtr<DOMException> e = DOMException::Create(NS_ERROR_DOM_ABORT_ERR);
     75    if (!GetOrCreateDOMReflector(aCx, e, &value)) {
     76      return;
     77    }
     78  }
     79 
     80  aReadableStream->ErrorNative(aCx, value, aRv);
     81 }
     82 
     83 }  // namespace
     84 
     85 class AbortSignalMainThread final : public AbortSignalImpl {
     86 public:
     87  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     88  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbortSignalMainThread)
     89 
     90  explicit AbortSignalMainThread(SignalAborted aAborted)
     91      : AbortSignalImpl(aAborted, JS::UndefinedHandleValue) {
     92    mozilla::HoldJSObjects(this);
     93  }
     94 
     95 private:
     96  ~AbortSignalMainThread() { mozilla::DropJSObjects(this); };
     97 };
     98 
     99 NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread)
    100 
    101 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AbortSignalMainThread)
    102  AbortSignalImpl::Unlink(static_cast<AbortSignalImpl*>(tmp));
    103 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    104 
    105 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbortSignalMainThread)
    106  AbortSignalImpl::Traverse(static_cast<AbortSignalImpl*>(tmp), cb);
    107 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    108 
    109 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AbortSignalMainThread)
    110  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReason)
    111 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    112 
    113 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignalMainThread)
    114  NS_INTERFACE_MAP_ENTRY(nsISupports)
    115 NS_INTERFACE_MAP_END
    116 
    117 NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortSignalMainThread)
    118 NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortSignalMainThread)
    119 
    120 class AbortSignalProxy;
    121 
    122 // This runnable propagates changes from the AbortSignalImpl on workers to the
    123 // AbortSignalImpl on main-thread.
    124 class AbortSignalProxyRunnable final : public Runnable {
    125  RefPtr<AbortSignalProxy> mProxy;
    126 
    127 public:
    128  explicit AbortSignalProxyRunnable(AbortSignalProxy* aProxy)
    129      : Runnable("dom::AbortSignalProxyRunnable"), mProxy(aProxy) {}
    130 
    131  NS_IMETHOD Run() override;
    132 };
    133 
    134 // This class orchestrates the proxying of AbortSignal operations between the
    135 // main thread and a worker thread.
    136 class AbortSignalProxy final : public AbortFollower {
    137  // This is created and released on the main-thread.
    138  RefPtr<AbortSignalImpl> mSignalImplMainThread;
    139 
    140  // The main-thread event target for runnable dispatching.
    141  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
    142 
    143  // This value is used only when creating mSignalImplMainThread on the main
    144  // thread, to create it in already-aborted state if necessary.  It does *not*
    145  // reflect the instantaneous is-aborted status of the worker thread's
    146  // AbortSignal.
    147  const SignalAborted mAborted;
    148 
    149 public:
    150  NS_DECL_THREADSAFE_ISUPPORTS
    151 
    152  AbortSignalProxy(AbortSignalImpl* aSignalImpl,
    153                   nsIEventTarget* aMainThreadEventTarget)
    154      : mMainThreadEventTarget(aMainThreadEventTarget),
    155        mAborted(aSignalImpl->Aborted() ? SignalAborted::Yes
    156                                        : SignalAborted::No) {
    157    MOZ_ASSERT(!NS_IsMainThread());
    158    MOZ_ASSERT(mMainThreadEventTarget);
    159    Follow(aSignalImpl);
    160  }
    161 
    162  // AbortFollower
    163  void RunAbortAlgorithm() override;
    164 
    165  AbortSignalImpl* GetOrCreateSignalImplForMainThread() {
    166    MOZ_ASSERT(NS_IsMainThread());
    167    if (!mSignalImplMainThread) {
    168      mSignalImplMainThread = new AbortSignalMainThread(mAborted);
    169    }
    170    return mSignalImplMainThread;
    171  }
    172 
    173  AbortSignalImpl* GetSignalImplForTargetThread() {
    174    MOZ_ASSERT(!NS_IsMainThread());
    175    return Signal();
    176  }
    177 
    178  nsIEventTarget* MainThreadEventTarget() { return mMainThreadEventTarget; }
    179 
    180  void Shutdown() {
    181    MOZ_ASSERT(!NS_IsMainThread());
    182    Unfollow();
    183  }
    184 
    185 private:
    186  ~AbortSignalProxy() {
    187    NS_ProxyRelease("AbortSignalProxy::mSignalImplMainThread",
    188                    mMainThreadEventTarget, mSignalImplMainThread.forget());
    189  }
    190 };
    191 
    192 NS_IMPL_ISUPPORTS0(AbortSignalProxy)
    193 
    194 NS_IMETHODIMP AbortSignalProxyRunnable::Run() {
    195  MOZ_ASSERT(NS_IsMainThread());
    196  AbortSignalImpl* signalImpl = mProxy->GetOrCreateSignalImplForMainThread();
    197  signalImpl->SignalAbort(JS::UndefinedHandleValue);
    198  return NS_OK;
    199 }
    200 
    201 void AbortSignalProxy::RunAbortAlgorithm() {
    202  MOZ_ASSERT(!NS_IsMainThread());
    203  RefPtr<AbortSignalProxyRunnable> runnable =
    204      new AbortSignalProxyRunnable(this);
    205  MainThreadEventTarget()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
    206 }
    207 
    208 class WorkerFetchResolver final : public FetchDriverObserver {
    209  // Thread-safe:
    210  RefPtr<PromiseWorkerProxy> mPromiseProxy;
    211  RefPtr<AbortSignalProxy> mSignalProxy;
    212 
    213  // Touched only on the worker thread.
    214  RefPtr<FetchObserver> mFetchObserver;
    215  RefPtr<WeakWorkerRef> mWorkerRef;
    216  bool mIsShutdown;
    217 
    218  Atomic<bool> mNeedOnDataAvailable;
    219 
    220 public:
    221  // Returns null if worker is shutting down.
    222  static already_AddRefed<WorkerFetchResolver> Create(
    223      WorkerPrivate* aWorkerPrivate, Promise* aPromise,
    224      AbortSignalImpl* aSignalImpl, FetchObserver* aObserver) {
    225    MOZ_ASSERT(aWorkerPrivate);
    226    aWorkerPrivate->AssertIsOnWorkerThread();
    227    RefPtr<PromiseWorkerProxy> proxy =
    228        PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
    229    if (!proxy) {
    230      return nullptr;
    231    }
    232 
    233    RefPtr<AbortSignalProxy> signalProxy;
    234    if (aSignalImpl) {
    235      signalProxy = new AbortSignalProxy(
    236          aSignalImpl, aWorkerPrivate->MainThreadEventTarget());
    237    }
    238 
    239    RefPtr<WorkerFetchResolver> r =
    240        new WorkerFetchResolver(proxy, signalProxy, aObserver);
    241 
    242    RefPtr<WeakWorkerRef> workerRef = WeakWorkerRef::Create(
    243        aWorkerPrivate, [r]() { r->Shutdown(r->mWorkerRef->GetPrivate()); });
    244    if (NS_WARN_IF(!workerRef)) {
    245      return nullptr;
    246    }
    247 
    248    r->mWorkerRef = std::move(workerRef);
    249 
    250    return r.forget();
    251  }
    252 
    253  AbortSignalImpl* GetAbortSignalForMainThread() {
    254    MOZ_ASSERT(NS_IsMainThread());
    255 
    256    if (!mSignalProxy) {
    257      return nullptr;
    258    }
    259 
    260    return mSignalProxy->GetOrCreateSignalImplForMainThread();
    261  }
    262 
    263  AbortSignalImpl* GetAbortSignalForTargetThread() {
    264    mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
    265 
    266    if (!mSignalProxy) {
    267      return nullptr;
    268    }
    269 
    270    return mSignalProxy->GetSignalImplForTargetThread();
    271  }
    272 
    273  PromiseWorkerProxy* PromiseProxy() const {
    274    MOZ_ASSERT(NS_IsMainThread());
    275    return mPromiseProxy;
    276  }
    277 
    278  Promise* WorkerPromise(WorkerPrivate* aWorkerPrivate) const {
    279    MOZ_ASSERT(aWorkerPrivate);
    280    aWorkerPrivate->AssertIsOnWorkerThread();
    281    MOZ_ASSERT(!mIsShutdown);
    282 
    283    return mPromiseProxy->GetWorkerPromise();
    284  }
    285 
    286  FetchObserver* GetFetchObserver(WorkerPrivate* aWorkerPrivate) const {
    287    MOZ_ASSERT(aWorkerPrivate);
    288    aWorkerPrivate->AssertIsOnWorkerThread();
    289 
    290    return mFetchObserver;
    291  }
    292 
    293  void OnResponseAvailableInternal(
    294      SafeRefPtr<InternalResponse> aResponse) override;
    295 
    296  void OnResponseEnd(FetchDriverObserver::EndReason aReason,
    297                     JS::Handle<JS::Value> aReasonDetails) override;
    298 
    299  bool NeedOnDataAvailable() override;
    300 
    301  void OnDataAvailable() override;
    302 
    303  void Shutdown(WorkerPrivate* aWorkerPrivate) {
    304    MOZ_ASSERT(aWorkerPrivate);
    305    aWorkerPrivate->AssertIsOnWorkerThread();
    306 
    307    mIsShutdown = true;
    308    mPromiseProxy->CleanUp();
    309 
    310    mNeedOnDataAvailable = false;
    311    mFetchObserver = nullptr;
    312 
    313    if (mSignalProxy) {
    314      mSignalProxy->Shutdown();
    315    }
    316 
    317    mWorkerRef = nullptr;
    318  }
    319 
    320  bool IsShutdown(WorkerPrivate* aWorkerPrivate) const {
    321    MOZ_ASSERT(aWorkerPrivate);
    322    aWorkerPrivate->AssertIsOnWorkerThread();
    323    return mIsShutdown;
    324  }
    325 
    326 private:
    327  WorkerFetchResolver(PromiseWorkerProxy* aProxy,
    328                      AbortSignalProxy* aSignalProxy, FetchObserver* aObserver)
    329      : mPromiseProxy(aProxy),
    330        mSignalProxy(aSignalProxy),
    331        mFetchObserver(aObserver),
    332        mIsShutdown(false),
    333        mNeedOnDataAvailable(!!aObserver) {
    334    MOZ_ASSERT(!NS_IsMainThread());
    335    MOZ_ASSERT(mPromiseProxy);
    336  }
    337 
    338  ~WorkerFetchResolver() = default;
    339 
    340  virtual void FlushConsoleReport() override;
    341 };
    342 
    343 void FetchDriverObserver::OnResponseAvailable(
    344    SafeRefPtr<InternalResponse> aResponse) {
    345  MOZ_ASSERT(!mGotResponseAvailable);
    346  mGotResponseAvailable = true;
    347  OnResponseAvailableInternal(std::move(aResponse));
    348 }
    349 
    350 class MainThreadFetchResolver final : public FetchDriverObserver {
    351  RefPtr<Promise> mPromise;
    352  RefPtr<Response> mResponse;
    353  RefPtr<FetchObserver> mFetchObserver;
    354  RefPtr<AbortSignalImpl> mSignalImpl;
    355  const bool mMozErrors;
    356 
    357  nsCOMPtr<nsILoadGroup> mLoadGroup;
    358 
    359  NS_DECL_OWNINGTHREAD
    360 public:
    361  MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver,
    362                          AbortSignalImpl* aSignalImpl, bool aMozErrors)
    363      : mPromise(aPromise),
    364        mFetchObserver(aObserver),
    365        mSignalImpl(aSignalImpl),
    366        mMozErrors(aMozErrors) {}
    367 
    368  void OnResponseAvailableInternal(
    369      SafeRefPtr<InternalResponse> aResponse) override;
    370 
    371  void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
    372 
    373  void OnResponseEnd(FetchDriverObserver::EndReason aReason,
    374                     JS::Handle<JS::Value> aReasonDetails) override {
    375    if (aReason == eAborted) {
    376      if (!aReasonDetails.isUndefined()) {
    377        mPromise->MaybeReject(aReasonDetails);
    378      } else {
    379        mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
    380      }
    381    }
    382 
    383    mFetchObserver = nullptr;
    384 
    385    FlushConsoleReport();
    386  }
    387 
    388  bool NeedOnDataAvailable() override;
    389 
    390  void OnDataAvailable() override;
    391 
    392 private:
    393  ~MainThreadFetchResolver();
    394 
    395  void FlushConsoleReport() override {
    396    mReporter->FlushConsoleReports(mLoadGroup);
    397  }
    398 };
    399 
    400 class MainThreadFetchRunnable : public Runnable {
    401  RefPtr<WorkerFetchResolver> mResolver;
    402  const ClientInfo mClientInfo;
    403  const Maybe<ServiceWorkerDescriptor> mController;
    404  nsCOMPtr<nsICSPEventListener> mCSPEventListener;
    405  SafeRefPtr<InternalRequest> mRequest;
    406  UniquePtr<SerializedStackHolder> mOriginStack;
    407 
    408 public:
    409  MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
    410                          const ClientInfo& aClientInfo,
    411                          const Maybe<ServiceWorkerDescriptor>& aController,
    412                          nsICSPEventListener* aCSPEventListener,
    413                          SafeRefPtr<InternalRequest> aRequest,
    414                          UniquePtr<SerializedStackHolder>&& aOriginStack)
    415      : Runnable("dom::MainThreadFetchRunnable"),
    416        mResolver(aResolver),
    417        mClientInfo(aClientInfo),
    418        mController(aController),
    419        mCSPEventListener(aCSPEventListener),
    420        mRequest(std::move(aRequest)),
    421        mOriginStack(std::move(aOriginStack)) {
    422    MOZ_ASSERT(mResolver);
    423  }
    424 
    425  NS_IMETHOD
    426  Run() override {
    427    AssertIsOnMainThread();
    428    RefPtr<FetchDriver> fetch;
    429    RefPtr<PromiseWorkerProxy> proxy = mResolver->PromiseProxy();
    430 
    431    {
    432      // Acquire the proxy mutex while getting data from the WorkerPrivate...
    433      MutexAutoLock lock(proxy->Lock());
    434      if (proxy->CleanedUp()) {
    435        NS_WARNING("Aborting Fetch because worker already shut down");
    436        return NS_OK;
    437      }
    438 
    439      WorkerPrivate* workerPrivate = proxy->GetWorkerPrivate();
    440      MOZ_ASSERT(workerPrivate);
    441      nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
    442      MOZ_ASSERT(principal);
    443      nsCOMPtr<nsILoadGroup> loadGroup = workerPrivate->GetLoadGroup();
    444      MOZ_ASSERT(loadGroup);
    445      // We don't track if a worker is spawned from a tracking script for now,
    446      // so pass false as the last argument to FetchDriver().
    447      fetch = new FetchDriver(mRequest.clonePtr(), principal, loadGroup,
    448                              workerPrivate->MainThreadEventTarget(),
    449                              workerPrivate->CookieJarSettings(),
    450                              workerPrivate->GetPerformanceStorage(),
    451                              net::ClassificationFlags({0, 0}));
    452      nsAutoCString spec;
    453      if (proxy->GetWorkerPrivate()->GetBaseURI()) {
    454        proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
    455      }
    456      fetch->SetWorkerScript(spec);
    457 
    458      fetch->SetClientInfo(mClientInfo);
    459      fetch->SetController(mController);
    460      fetch->SetCSPEventListener(mCSPEventListener);
    461    }
    462 
    463    fetch->SetOriginStack(std::move(mOriginStack));
    464 
    465    RefPtr<AbortSignalImpl> signalImpl =
    466        mResolver->GetAbortSignalForMainThread();
    467 
    468    // ...but release it before calling Fetch, because mResolver's callback can
    469    // be called synchronously and they want the mutex, too.
    470    return fetch->Fetch(signalImpl, mResolver);
    471  }
    472 };
    473 
    474 already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
    475                                       const RequestOrUTF8String& aInput,
    476                                       const RequestInit& aInit,
    477                                       CallerType aCallerType,
    478                                       ErrorResult& aRv) {
    479  RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
    480  if (NS_WARN_IF(aRv.Failed())) {
    481    return nullptr;
    482  }
    483 
    484  MOZ_ASSERT(aGlobal);
    485 
    486  // Double check that we have chrome privileges if the Request's content
    487  // policy type has been overridden.
    488  MOZ_ASSERT_IF(aInput.IsRequest() &&
    489                    aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
    490                aCallerType == CallerType::System);
    491 
    492  AutoJSAPI jsapi;
    493  if (!jsapi.Init(aGlobal)) {
    494    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    495    return nullptr;
    496  }
    497 
    498  JSContext* cx = jsapi.cx();
    499  JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
    500  GlobalObject global(cx, jsGlobal);
    501 
    502  SafeRefPtr<Request> request =
    503      Request::Constructor(global, aInput, aInit, aRv);
    504  if (aRv.Failed()) {
    505    return nullptr;
    506  }
    507 
    508  SafeRefPtr<InternalRequest> internalRequest = request->GetInternalRequest();
    509 
    510  // Restore information of InterceptedHttpChannel if they are passed with the
    511  // Request. Since Request::Constructor would not copy these members.
    512  if (aInput.IsRequest()) {
    513    RefPtr<Request> inputReq = &aInput.GetAsRequest();
    514    SafeRefPtr<InternalRequest> inputInReq = inputReq->GetInternalRequest();
    515    if (inputInReq->GetInterceptionTriggeringPrincipalInfo()) {
    516      internalRequest->SetInterceptionContentPolicyType(
    517          inputInReq->InterceptionContentPolicyType());
    518      internalRequest->SetInterceptionTriggeringPrincipalInfo(
    519          MakeUnique<mozilla::ipc::PrincipalInfo>(
    520              *(inputInReq->GetInterceptionTriggeringPrincipalInfo().get())));
    521      if (!inputInReq->InterceptionRedirectChain().IsEmpty()) {
    522        internalRequest->SetInterceptionRedirectChain(
    523            inputInReq->InterceptionRedirectChain());
    524      }
    525      internalRequest->SetInterceptionFromThirdParty(
    526          inputInReq->InterceptionFromThirdParty());
    527    }
    528  }
    529 
    530  RefPtr<AbortSignalImpl> signalImpl = request->GetSignalImpl();
    531 
    532  if (signalImpl && signalImpl->Aborted()) {
    533    // Already aborted signal rejects immediately.
    534    JS::Rooted<JS::Value> reason(cx, signalImpl->RawReason());
    535    if (reason.get().isUndefined()) {
    536      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
    537      return nullptr;
    538    }
    539 
    540    p->MaybeReject(reason);
    541    return p.forget();
    542  }
    543 
    544  JS::Realm* realm = JS::GetCurrentRealmOrNull(cx);
    545  if (realm && JS::GetDebuggerObservesWasm(realm)) {
    546    internalRequest->SetSkipWasmCaching();
    547  }
    548 
    549  RefPtr<FetchObserver> observer;
    550  if (aInit.mObserve.WasPassed()) {
    551    observer = new FetchObserver(aGlobal, signalImpl);
    552    aInit.mObserve.Value().HandleEvent(*observer);
    553  }
    554 
    555  if (NS_IsMainThread() && !internalRequest->GetKeepalive()) {
    556    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
    557    nsCOMPtr<Document> doc;
    558    nsCOMPtr<nsILoadGroup> loadGroup;
    559    nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
    560    nsIPrincipal* principal;
    561    net::ClassificationFlags trackingFlags = {0, 0};
    562    if (window) {
    563      doc = window->GetExtantDoc();
    564      if (!doc) {
    565        aRv.Throw(NS_ERROR_FAILURE);
    566        return nullptr;
    567      }
    568      principal = doc->NodePrincipal();
    569      loadGroup = doc->GetDocumentLoadGroup();
    570      cookieJarSettings = doc->CookieJarSettings();
    571 
    572      trackingFlags = doc->GetScriptTrackingFlags();
    573    } else {
    574      principal = aGlobal->PrincipalOrNull();
    575      if (NS_WARN_IF(!principal)) {
    576        aRv.Throw(NS_ERROR_FAILURE);
    577        return nullptr;
    578      }
    579 
    580      cookieJarSettings = mozilla::net::CookieJarSettings::Create(principal);
    581    }
    582 
    583    if (!loadGroup) {
    584      nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
    585      if (NS_WARN_IF(NS_FAILED(rv))) {
    586        aRv.Throw(rv);
    587        return nullptr;
    588      }
    589    }
    590 
    591    RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(
    592        p, observer, signalImpl, request->MozErrors());
    593    RefPtr<FetchDriver> fetch =
    594        new FetchDriver(std::move(internalRequest), principal, loadGroup,
    595                        aGlobal->SerialEventTarget(), cookieJarSettings,
    596                        nullptr,  // PerformanceStorage
    597                        trackingFlags);
    598    fetch->SetDocument(doc);
    599    resolver->SetLoadGroup(loadGroup);
    600    aRv = fetch->Fetch(signalImpl, resolver);
    601    if (NS_WARN_IF(aRv.Failed())) {
    602      return nullptr;
    603    }
    604  } else if (NS_IsMainThread() && internalRequest->GetKeepalive()) {
    605    // keepalive is set to true, route the request through PFetch
    606    // We plan to route all main-thread fetch request through PFetch.
    607    // See Bug 1897129.
    608 
    609    uint64_t bodyLength =
    610        internalRequest->BodyLength() > 0 ? internalRequest->BodyLength() : 0;
    611 
    612    nsCOMPtr<nsILoadGroup> loadGroup =
    613        FetchUtil::GetLoadGroupFromGlobal(aGlobal);
    614 
    615    if (loadGroup && !FetchUtil::IncrementPendingKeepaliveRequestSize(
    616                         loadGroup, bodyLength)) {
    617      p->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
    618      return p.forget();
    619    };
    620 
    621    if (!loadGroup) {
    622      // if there is no load group for this request ensure that the request
    623      // size does not exceed FETCH_KEEPALIVE_MAX_SIZE
    624      if (bodyLength > FETCH_KEEPALIVE_MAX_SIZE) {
    625        p->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
    626        return p.forget();
    627      }
    628    }
    629 
    630    RefPtr<FetchChild> actor =
    631        FetchChild::CreateForMainThread(p, signalImpl, observer);
    632    if (!actor) {
    633      NS_WARNING("Could not start keepalive request.");
    634      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    635      return nullptr;
    636    }
    637 
    638    Maybe<ClientInfo> clientInfo(aGlobal->GetClientInfo());
    639    if (clientInfo.isNothing()) {
    640      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    641      return nullptr;
    642    }
    643 
    644    auto* backgroundChild =
    645        mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
    646    (void)NS_WARN_IF(!backgroundChild->SendPFetchConstructor(actor));
    647 
    648    FetchOpArgs ipcArgs;
    649 
    650    ipcArgs.request() = IPCInternalRequest();
    651    internalRequest->ToIPCInternalRequest(&(ipcArgs.request()),
    652                                          backgroundChild);
    653 
    654    ipcArgs.clientInfo() = clientInfo.ref().ToIPC();
    655    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
    656    nsCOMPtr<Document> doc;
    657    nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
    658    nsIPrincipal* principal;
    659    // we don't check if we this request is invoked from a tracking script
    660    // we might add this capability in future.
    661    // See Bug 1892406
    662    if (window) {
    663      doc = window->GetExtantDoc();
    664      if (!doc) {
    665        aRv.Throw(NS_ERROR_FAILURE);
    666        return nullptr;
    667      }
    668      principal = doc->NodePrincipal();
    669      cookieJarSettings = doc->CookieJarSettings();
    670      // fetch the thirdparty context from the document
    671 
    672      ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
    673      if (!thirdPartyUtil) {
    674        return nullptr;
    675      }
    676      if (thirdPartyUtil) {
    677        bool thirdParty = false;
    678        (void)thirdPartyUtil->IsThirdPartyWindow(window->GetOuterWindow(),
    679                                                 nullptr, &thirdParty);
    680        ipcArgs.isThirdPartyContext() = thirdParty;
    681      }
    682    } else {
    683      principal = aGlobal->PrincipalOrNull();
    684      if (NS_WARN_IF(!principal)) {
    685        aRv.Throw(NS_ERROR_FAILURE);
    686        return nullptr;
    687      }
    688      cookieJarSettings = mozilla::net::CookieJarSettings::Create(principal);
    689    }
    690 
    691    if (cookieJarSettings) {
    692      net::CookieJarSettingsArgs csArgs;
    693      net::CookieJarSettings::Cast(cookieJarSettings)->Serialize(csArgs);
    694      ipcArgs.cookieJarSettings() = Some(csArgs);
    695    }
    696 
    697    nsresult rv = PrincipalToPrincipalInfo(principal, &ipcArgs.principalInfo());
    698    NS_ENSURE_SUCCESS(rv, nullptr);
    699 
    700    ipcArgs.hasCSPEventListener() = false;
    701    ipcArgs.isWorkerRequest() = false;
    702 
    703    if (window && window->GetBrowsingContext()) {
    704      ipcArgs.associatedBrowsingContextID() =
    705          window->GetBrowsingContext()->Id();
    706    }
    707 
    708    UniquePtr<SerializedStackHolder> stack = GetCurrentStackForNetMonitor(cx);
    709    if (stack) {
    710      actor->SetOriginStack(std::move(stack));
    711    }
    712 
    713    actor->DoFetchOp(ipcArgs);
    714 
    715    return p.forget();
    716  } else {
    717    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
    718    MOZ_ASSERT(worker);
    719 
    720    if (worker->IsServiceWorker()) {
    721      internalRequest->SetSkipServiceWorker();
    722    }
    723 
    724    // PFetch gives no benefit for the fetch in the parent process.
    725    // Dispatch fetch to the parent process main thread directly for that case.
    726    // For child process, dispatch fetch op to the parent.
    727    if (StaticPrefs::dom_workers_pFetch_enabled() && !XRE_IsParentProcess()) {
    728      if (internalRequest->GetKeepalive()) {
    729        uint64_t bodyLength = internalRequest->BodyLength() > 0
    730                                  ? internalRequest->BodyLength()
    731                                  : 0;
    732 
    733        // We differ from the fetch spec and main thread fetch here.
    734        // We do not limit the keepalive size per loadgroup(but instead per
    735        // request). This is due to the fact that loadgroup is not accessible on
    736        // the worker thread and we dont want to introduce async to introduce
    737        // this check.
    738        if (bodyLength > FETCH_KEEPALIVE_MAX_SIZE) {
    739          p->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
    740          return p.forget();
    741        }
    742      }
    743 
    744      RefPtr<FetchChild> actor =
    745          FetchChild::CreateForWorker(worker, p, signalImpl, observer);
    746      if (!actor) {
    747        NS_WARNING("Could not keep the worker alive.");
    748        aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
    749        return nullptr;
    750      }
    751 
    752      Maybe<ClientInfo> clientInfo(worker->GlobalScope()->GetClientInfo());
    753      if (clientInfo.isNothing()) {
    754        aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    755        return nullptr;
    756      }
    757 
    758      auto* backgroundChild =
    759          mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
    760      (void)NS_WARN_IF(!backgroundChild->SendPFetchConstructor(actor));
    761 
    762      FetchOpArgs ipcArgs;
    763      ipcArgs.request() = IPCInternalRequest();
    764      internalRequest->ToIPCInternalRequest(&(ipcArgs.request()),
    765                                            backgroundChild);
    766 
    767      ipcArgs.principalInfo() = worker->GetPrincipalInfo();
    768      ipcArgs.clientInfo() = clientInfo.ref().ToIPC();
    769      if (worker->GetBaseURI()) {
    770        worker->GetBaseURI()->GetAsciiSpec(ipcArgs.workerScript());
    771      }
    772      if (worker->GlobalScope()->GetController().isSome()) {
    773        ipcArgs.controller() =
    774            Some(worker->GlobalScope()->GetController().ref().ToIPC());
    775      }
    776      if (worker->CookieJarSettings()) {
    777        ipcArgs.cookieJarSettings() = Some(worker->CookieJarSettingsArgs());
    778      }
    779      if (worker->CSPEventListener()) {
    780        ipcArgs.hasCSPEventListener() = true;
    781        actor->SetCSPEventListener(worker->CSPEventListener());
    782      } else {
    783        ipcArgs.hasCSPEventListener() = false;
    784      }
    785 
    786      ipcArgs.associatedBrowsingContextID() =
    787          worker->AssociatedBrowsingContextID();
    788 
    789      if (worker->IsWatchedByDevTools()) {
    790        UniquePtr<SerializedStackHolder> stack;
    791        stack = GetCurrentStackForNetMonitor(cx);
    792        actor->SetOriginStack(std::move(stack));
    793      }
    794 
    795      ipcArgs.isThirdPartyContext() = worker->IsThirdPartyContext();
    796 
    797      ipcArgs.isOn3PCBExceptionList() = worker->IsOn3PCBExceptionList();
    798 
    799      ipcArgs.isWorkerRequest() = true;
    800 
    801      actor->DoFetchOp(ipcArgs);
    802 
    803      return p.forget();
    804    }
    805    // Dispatch worker fetch to the main thread
    806    // We do not check if keepalive flag is set for ChromeWorkers
    807    // See Bug 1898664
    808    RefPtr<WorkerFetchResolver> resolver =
    809        WorkerFetchResolver::Create(worker, p, signalImpl, observer);
    810    if (!resolver) {
    811      NS_WARNING("Could not keep the worker alive.");
    812      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
    813      return nullptr;
    814    }
    815 
    816    Maybe<ClientInfo> clientInfo(worker->GlobalScope()->GetClientInfo());
    817    if (clientInfo.isNothing()) {
    818      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    819      return nullptr;
    820    }
    821 
    822    UniquePtr<SerializedStackHolder> stack;
    823    if (worker->IsWatchedByDevTools()) {
    824      stack = GetCurrentStackForNetMonitor(cx);
    825    }
    826 
    827    RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(
    828        resolver, clientInfo.ref(), worker->GlobalScope()->GetController(),
    829        worker->CSPEventListener(), std::move(internalRequest),
    830        std::move(stack));
    831    worker->DispatchToMainThread(run.forget());
    832  }
    833 
    834  return p.forget();
    835 }
    836 
    837 class ResolveFetchPromise : public Runnable {
    838 public:
    839  ResolveFetchPromise(Promise* aPromise, Response* aResponse)
    840      : Runnable("ResolveFetchPromise"),
    841        mPromise(aPromise),
    842        mResponse(aResponse) {}
    843 
    844  NS_IMETHOD Run() override {
    845    mPromise->MaybeResolve(mResponse);
    846    return NS_OK;
    847  }
    848  RefPtr<Promise> mPromise;
    849  RefPtr<Response> mResponse;
    850 };
    851 
    852 void MainThreadFetchResolver::OnResponseAvailableInternal(
    853    SafeRefPtr<InternalResponse> aResponse) {
    854  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
    855  AssertIsOnMainThread();
    856 
    857  if (aResponse->Type() != ResponseType::Error) {
    858    nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
    859    nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(go);
    860 
    861    // Notify the document when a fetch completes successfully. This is
    862    // used by the password manager as a hint to observe DOM mutations.
    863    // Call this prior to setting state to Complete so we can set up the
    864    // observer before mutations occurs.
    865    Document* doc = inner ? inner->GetExtantDoc() : nullptr;
    866    if (doc) {
    867      doc->NotifyFetchOrXHRSuccess();
    868    }
    869 
    870    if (mFetchObserver) {
    871      mFetchObserver->SetState(FetchState::Complete);
    872    }
    873 
    874    mResponse = new Response(go, std::move(aResponse), mSignalImpl);
    875    // response headers received from the network should be immutable
    876    // all response header settings must be done before this point
    877    // see Bug 1574174
    878    ErrorResult result;
    879    mResponse->Headers_()->SetGuard(HeadersGuardEnum::Immutable, result);
    880    MOZ_ASSERT(!result.Failed());
    881 
    882    BrowsingContext* bc = inner ? inner->GetBrowsingContext() : nullptr;
    883    bc = bc ? bc->Top() : nullptr;
    884    if (bc && bc->IsLoading()) {
    885      bc->AddDeprioritizedLoadRunner(
    886          new ResolveFetchPromise(mPromise, mResponse));
    887    } else {
    888      mPromise->MaybeResolve(mResponse);
    889    }
    890  } else {
    891    if (mFetchObserver) {
    892      mFetchObserver->SetState(FetchState::Errored);
    893    }
    894 
    895    if (mMozErrors) {
    896      mPromise->MaybeReject(aResponse->GetErrorCode());
    897      return;
    898    }
    899 
    900    mPromise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
    901  }
    902 }
    903 
    904 bool MainThreadFetchResolver::NeedOnDataAvailable() {
    905  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
    906  return !!mFetchObserver;
    907 }
    908 
    909 void MainThreadFetchResolver::OnDataAvailable() {
    910  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
    911  AssertIsOnMainThread();
    912 
    913  if (!mFetchObserver) {
    914    return;
    915  }
    916 
    917  if (mFetchObserver->State() == FetchState::Requesting) {
    918    mFetchObserver->SetState(FetchState::Responding);
    919  }
    920 }
    921 
    922 MainThreadFetchResolver::~MainThreadFetchResolver() {
    923  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
    924 }
    925 
    926 class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable {
    927  RefPtr<WorkerFetchResolver> mResolver;
    928  // Passed from main thread to worker thread after being initialized.
    929  SafeRefPtr<InternalResponse> mInternalResponse;
    930 
    931 public:
    932  WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
    933                              WorkerFetchResolver* aResolver,
    934                              SafeRefPtr<InternalResponse> aResponse)
    935      : MainThreadWorkerRunnable("WorkerFetchResponseRunnable"),
    936        mResolver(aResolver),
    937        mInternalResponse(std::move(aResponse)) {
    938    MOZ_ASSERT(mResolver);
    939  }
    940 
    941  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
    942    MOZ_ASSERT(aWorkerPrivate);
    943    aWorkerPrivate->AssertIsOnWorkerThread();
    944    if (mResolver->IsShutdown(aWorkerPrivate)) {
    945      return true;
    946    }
    947 
    948    RefPtr<Promise> promise = mResolver->WorkerPromise(aWorkerPrivate);
    949    // Once Worker had already started shutdown, workerPromise would be nullptr
    950    if (!promise) {
    951      return true;
    952    }
    953    RefPtr<FetchObserver> fetchObserver =
    954        mResolver->GetFetchObserver(aWorkerPrivate);
    955 
    956    if (mInternalResponse->Type() != ResponseType::Error) {
    957      if (fetchObserver) {
    958        fetchObserver->SetState(FetchState::Complete);
    959      }
    960 
    961      RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
    962      RefPtr<Response> response =
    963          new Response(global, mInternalResponse.clonePtr(),
    964                       mResolver->GetAbortSignalForTargetThread());
    965 
    966      // response headers received from the network should be immutable,
    967      // all response header settings must be done before this point
    968      // see Bug 1574174
    969      ErrorResult result;
    970      response->Headers_()->SetGuard(HeadersGuardEnum::Immutable, result);
    971      MOZ_ASSERT(!result.Failed());
    972 
    973      promise->MaybeResolve(response);
    974    } else {
    975      if (fetchObserver) {
    976        fetchObserver->SetState(FetchState::Errored);
    977      }
    978 
    979      promise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
    980    }
    981    return true;
    982  }
    983 };
    984 
    985 class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable {
    986  RefPtr<WorkerFetchResolver> mResolver;
    987 
    988 public:
    989  WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
    990                              WorkerFetchResolver* aResolver)
    991      : MainThreadWorkerRunnable("WorkerDataAvailableRunnable"),
    992        mResolver(aResolver) {}
    993 
    994  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
    995    MOZ_ASSERT(aWorkerPrivate);
    996    aWorkerPrivate->AssertIsOnWorkerThread();
    997 
    998    RefPtr<FetchObserver> fetchObserver =
    999        mResolver->GetFetchObserver(aWorkerPrivate);
   1000 
   1001    if (fetchObserver && fetchObserver->State() == FetchState::Requesting) {
   1002      fetchObserver->SetState(FetchState::Responding);
   1003    }
   1004 
   1005    return true;
   1006  }
   1007 };
   1008 
   1009 class WorkerFetchResponseEndBase {
   1010 protected:
   1011  RefPtr<WorkerFetchResolver> mResolver;
   1012 
   1013 public:
   1014  explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
   1015      : mResolver(aResolver) {
   1016    MOZ_ASSERT(aResolver);
   1017  }
   1018 
   1019  void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) {
   1020    mResolver->Shutdown(aWorkerPrivate);
   1021  }
   1022 };
   1023 
   1024 class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable,
   1025                                             public WorkerFetchResponseEndBase {
   1026  FetchDriverObserver::EndReason mReason;
   1027 
   1028 public:
   1029  WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
   1030                                 WorkerFetchResolver* aResolver,
   1031                                 FetchDriverObserver::EndReason aReason)
   1032      : MainThreadWorkerRunnable("WorkerFetchResponseEndRunnable"),
   1033        WorkerFetchResponseEndBase(aResolver),
   1034        mReason(aReason) {}
   1035 
   1036  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
   1037    if (mResolver->IsShutdown(aWorkerPrivate)) {
   1038      return true;
   1039    }
   1040 
   1041    if (mReason == FetchDriverObserver::eAborted) {
   1042      mResolver->WorkerPromise(aWorkerPrivate)
   1043          ->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
   1044    }
   1045 
   1046    WorkerRunInternal(aWorkerPrivate);
   1047    return true;
   1048  }
   1049 
   1050  nsresult Cancel() override { return Run(); }
   1051 };
   1052 
   1053 class WorkerFetchResponseEndControlRunnable final
   1054    : public MainThreadWorkerControlRunnable,
   1055      public WorkerFetchResponseEndBase {
   1056 public:
   1057  WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
   1058                                        WorkerFetchResolver* aResolver)
   1059      : MainThreadWorkerControlRunnable(
   1060            "WorkerFetchResponseEndControlRunnable"),
   1061        WorkerFetchResponseEndBase(aResolver) {}
   1062 
   1063  bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
   1064    WorkerRunInternal(aWorkerPrivate);
   1065    return true;
   1066  }
   1067 
   1068  // Control runnable cancel already calls Run().
   1069 };
   1070 
   1071 void WorkerFetchResolver::OnResponseAvailableInternal(
   1072    SafeRefPtr<InternalResponse> aResponse) {
   1073  AssertIsOnMainThread();
   1074 
   1075  MutexAutoLock lock(mPromiseProxy->Lock());
   1076  if (mPromiseProxy->CleanedUp()) {
   1077    return;
   1078  }
   1079 
   1080  RefPtr<WorkerFetchResponseRunnable> r = new WorkerFetchResponseRunnable(
   1081      mPromiseProxy->GetWorkerPrivate(), this, std::move(aResponse));
   1082 
   1083  if (!r->Dispatch(mPromiseProxy->GetWorkerPrivate())) {
   1084    NS_WARNING("Could not dispatch fetch response");
   1085  }
   1086 }
   1087 
   1088 bool WorkerFetchResolver::NeedOnDataAvailable() {
   1089  AssertIsOnMainThread();
   1090  return mNeedOnDataAvailable;
   1091 }
   1092 
   1093 void WorkerFetchResolver::OnDataAvailable() {
   1094  AssertIsOnMainThread();
   1095 
   1096  MutexAutoLock lock(mPromiseProxy->Lock());
   1097  if (mPromiseProxy->CleanedUp()) {
   1098    return;
   1099  }
   1100 
   1101  RefPtr<WorkerDataAvailableRunnable> r =
   1102      new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
   1103  (void)r->Dispatch(mPromiseProxy->GetWorkerPrivate());
   1104 }
   1105 
   1106 void WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason,
   1107                                        JS::Handle<JS::Value> aReasonDetails) {
   1108  AssertIsOnMainThread();
   1109  MutexAutoLock lock(mPromiseProxy->Lock());
   1110  if (mPromiseProxy->CleanedUp()) {
   1111    return;
   1112  }
   1113 
   1114  FlushConsoleReport();
   1115 
   1116  (void)aReasonDetails;
   1117 
   1118  RefPtr<WorkerFetchResponseEndRunnable> r = new WorkerFetchResponseEndRunnable(
   1119      mPromiseProxy->GetWorkerPrivate(), this, aReason);
   1120 
   1121  if (!r->Dispatch(mPromiseProxy->GetWorkerPrivate())) {
   1122    RefPtr<WorkerFetchResponseEndControlRunnable> cr =
   1123        new WorkerFetchResponseEndControlRunnable(
   1124            mPromiseProxy->GetWorkerPrivate(), this);
   1125    // This can fail if the worker thread is canceled or killed causing
   1126    // the PromiseWorkerProxy to give up its WorkerRef immediately,
   1127    // allowing the worker thread to become Dead.
   1128    if (!cr->Dispatch(mPromiseProxy->GetWorkerPrivate())) {
   1129      NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
   1130    }
   1131  }
   1132 }
   1133 
   1134 void WorkerFetchResolver::FlushConsoleReport() {
   1135  AssertIsOnMainThread();
   1136  MOZ_ASSERT(mPromiseProxy);
   1137 
   1138  if (!mReporter) {
   1139    return;
   1140  }
   1141 
   1142  WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
   1143  if (!worker) {
   1144    mReporter->FlushReportsToConsole(0);
   1145    return;
   1146  }
   1147 
   1148  if (worker->IsServiceWorker()) {
   1149    // Flush to service worker
   1150    mReporter->FlushReportsToConsoleForServiceWorkerScope(
   1151        worker->ServiceWorkerScope());
   1152    return;
   1153  }
   1154 
   1155  if (worker->IsSharedWorker()) {
   1156    // Flush to shared worker
   1157    worker->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter);
   1158    return;
   1159  }
   1160 
   1161  // Flush to dedicated worker
   1162  mReporter->FlushConsoleReports(worker->GetLoadGroup());
   1163 }
   1164 
   1165 nsresult ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
   1166                                   nsIInputStream** aStream,
   1167                                   nsCString& aContentTypeWithCharset,
   1168                                   uint64_t& aContentLength) {
   1169  MOZ_ASSERT(aStream);
   1170  nsAutoCString charset;
   1171  aContentTypeWithCharset.SetIsVoid(true);
   1172 
   1173  if (aBodyInit.IsArrayBuffer()) {
   1174    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
   1175    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1176                            charset);
   1177  }
   1178 
   1179  if (aBodyInit.IsArrayBufferView()) {
   1180    BodyExtractor<const ArrayBufferView> body(
   1181        &aBodyInit.GetAsArrayBufferView());
   1182    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1183                            charset);
   1184  }
   1185 
   1186  if (aBodyInit.IsBlob()) {
   1187    Blob& blob = aBodyInit.GetAsBlob();
   1188    BodyExtractor<const Blob> body(&blob);
   1189    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1190                            charset);
   1191  }
   1192 
   1193  if (aBodyInit.IsFormData()) {
   1194    FormData& formData = aBodyInit.GetAsFormData();
   1195    BodyExtractor<const FormData> body(&formData);
   1196    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1197                            charset);
   1198  }
   1199 
   1200  if (aBodyInit.IsUSVString()) {
   1201    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
   1202    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1203                            charset);
   1204  }
   1205 
   1206  if (aBodyInit.IsURLSearchParams()) {
   1207    URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
   1208    BodyExtractor<const URLSearchParams> body(&usp);
   1209    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1210                            charset);
   1211  }
   1212 
   1213  MOZ_ASSERT_UNREACHABLE("Should never reach here");
   1214  return NS_ERROR_FAILURE;
   1215 }
   1216 
   1217 nsresult ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
   1218                                   nsIInputStream** aStream,
   1219                                   nsCString& aContentTypeWithCharset,
   1220                                   uint64_t& aContentLength) {
   1221  MOZ_ASSERT(aStream);
   1222  MOZ_ASSERT(!*aStream);
   1223 
   1224  nsAutoCString charset;
   1225  aContentTypeWithCharset.SetIsVoid(true);
   1226 
   1227  if (aBodyInit.IsArrayBuffer()) {
   1228    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
   1229    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1230                            charset);
   1231  }
   1232 
   1233  if (aBodyInit.IsArrayBufferView()) {
   1234    BodyExtractor<const ArrayBufferView> body(
   1235        &aBodyInit.GetAsArrayBufferView());
   1236    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1237                            charset);
   1238  }
   1239 
   1240  if (aBodyInit.IsBlob()) {
   1241    BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
   1242    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1243                            charset);
   1244  }
   1245 
   1246  if (aBodyInit.IsFormData()) {
   1247    BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
   1248    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1249                            charset);
   1250  }
   1251 
   1252  if (aBodyInit.IsUSVString()) {
   1253    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
   1254    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1255                            charset);
   1256  }
   1257 
   1258  if (aBodyInit.IsURLSearchParams()) {
   1259    BodyExtractor<const URLSearchParams> body(
   1260        &aBodyInit.GetAsURLSearchParams());
   1261    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1262                            charset);
   1263  }
   1264 
   1265  MOZ_ASSERT_UNREACHABLE("Should never reach here");
   1266  return NS_ERROR_FAILURE;
   1267 }
   1268 
   1269 nsresult ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
   1270                                   nsIInputStream** aStream,
   1271                                   nsCString& aContentTypeWithCharset,
   1272                                   uint64_t& aContentLength) {
   1273  MOZ_ASSERT(aStream);
   1274  MOZ_ASSERT(!*aStream);
   1275 
   1276  // ReadableStreams should be handled by
   1277  // BodyExtractorReadableStream::GetAsStream.
   1278  MOZ_ASSERT(!aBodyInit.IsReadableStream());
   1279 
   1280  nsAutoCString charset;
   1281  aContentTypeWithCharset.SetIsVoid(true);
   1282 
   1283  if (aBodyInit.IsArrayBuffer()) {
   1284    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
   1285    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1286                            charset);
   1287  }
   1288 
   1289  if (aBodyInit.IsArrayBufferView()) {
   1290    BodyExtractor<const ArrayBufferView> body(
   1291        &aBodyInit.GetAsArrayBufferView());
   1292    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1293                            charset);
   1294  }
   1295 
   1296  if (aBodyInit.IsBlob()) {
   1297    BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
   1298    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1299                            charset);
   1300  }
   1301 
   1302  if (aBodyInit.IsFormData()) {
   1303    BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
   1304    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1305                            charset);
   1306  }
   1307 
   1308  if (aBodyInit.IsUSVString()) {
   1309    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
   1310    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1311                            charset);
   1312  }
   1313 
   1314  if (aBodyInit.IsURLSearchParams()) {
   1315    BodyExtractor<const URLSearchParams> body(
   1316        &aBodyInit.GetAsURLSearchParams());
   1317    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
   1318                            charset);
   1319  }
   1320 
   1321  MOZ_ASSERT_UNREACHABLE("Should never reach here");
   1322  return NS_ERROR_FAILURE;
   1323 }
   1324 
   1325 NS_IMPL_CYCLE_COLLECTION(FetchBodyBase, mReadableStreamBody)
   1326 
   1327 NS_IMPL_CYCLE_COLLECTING_ADDREF(FetchBodyBase)
   1328 NS_IMPL_CYCLE_COLLECTING_RELEASE(FetchBodyBase)
   1329 
   1330 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchBodyBase)
   1331  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1332 NS_INTERFACE_MAP_END
   1333 
   1334 template <class Derived>
   1335 FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
   1336    : mOwner(aOwner), mBodyUsed(false) {
   1337  MOZ_ASSERT(aOwner);
   1338 
   1339  if (!NS_IsMainThread()) {
   1340    WorkerPrivate* wp = GetCurrentThreadWorkerPrivate();
   1341    MOZ_ASSERT(wp);
   1342    mMainThreadEventTarget = wp->MainThreadEventTarget();
   1343  } else {
   1344    mMainThreadEventTarget = GetMainThreadSerialEventTarget();
   1345  }
   1346 
   1347  MOZ_ASSERT(mMainThreadEventTarget);
   1348 }
   1349 
   1350 template FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
   1351 
   1352 template FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
   1353 
   1354 template <class Derived>
   1355 FetchBody<Derived>::~FetchBody() {
   1356  Unfollow();
   1357 }
   1358 
   1359 template FetchBody<Request>::~FetchBody();
   1360 
   1361 template FetchBody<Response>::~FetchBody();
   1362 
   1363 template <class Derived>
   1364 bool FetchBody<Derived>::BodyUsed() const {
   1365  if (mBodyUsed) {
   1366    return true;
   1367  }
   1368 
   1369  // If this stream is disturbed, return true.
   1370  if (mReadableStreamBody) {
   1371    return mReadableStreamBody->Disturbed();
   1372  }
   1373 
   1374  return false;
   1375 }
   1376 
   1377 template bool FetchBody<Request>::BodyUsed() const;
   1378 
   1379 template bool FetchBody<Response>::BodyUsed() const;
   1380 
   1381 template <class Derived>
   1382 void FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv) {
   1383  MOZ_ASSERT(aCx);
   1384  MOZ_ASSERT(mOwner->SerialEventTarget()->IsOnCurrentThread());
   1385 
   1386  MOZ_DIAGNOSTIC_ASSERT(!BodyUsed(), "Consuming already used body?");
   1387  if (BodyUsed()) {
   1388    return;
   1389  }
   1390 
   1391  mBodyUsed = true;
   1392 
   1393  // If we already have a ReadableStreamBody and it has been created by DOM, we
   1394  // have to lock it now because it can have been shared with other objects.
   1395  if (mReadableStreamBody) {
   1396    if (mFetchStreamReader) {
   1397      // Having FetchStreamReader means there's no nsIInputStream underlying it
   1398      MOZ_ASSERT(!mReadableStreamBody->MaybeGetInputStreamIfUnread());
   1399      mFetchStreamReader->StartConsuming(aCx, mReadableStreamBody, aRv);
   1400      return;
   1401    }
   1402    // We should have nsIInputStream at this point as long as it's still
   1403    // readable
   1404    MOZ_ASSERT_IF(
   1405        mReadableStreamBody->State() == ReadableStream::ReaderState::Readable,
   1406        mReadableStreamBody->MaybeGetInputStreamIfUnread());
   1407    LockStream(aCx, mReadableStreamBody, aRv);
   1408  }
   1409 }
   1410 
   1411 template void FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
   1412 
   1413 template void FetchBody<Response>::SetBodyUsed(JSContext* aCx,
   1414                                               ErrorResult& aRv);
   1415 
   1416 template <class Derived>
   1417 already_AddRefed<Promise> FetchBody<Derived>::ConsumeBody(
   1418    JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv) {
   1419  aRv.MightThrowJSException();
   1420 
   1421  RefPtr<AbortSignalImpl> signalImpl =
   1422      DerivedClass()->GetSignalImplToConsumeBody();
   1423 
   1424  if (signalImpl && signalImpl->Aborted()) {
   1425    JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
   1426 
   1427    if (abortReason.get().isUndefined()) {
   1428      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
   1429      return nullptr;
   1430    }
   1431 
   1432    nsCOMPtr<nsIGlobalObject> go = DerivedClass()->GetParentObject();
   1433 
   1434    RefPtr<Promise> promise = Promise::Create(go, aRv);
   1435    promise->MaybeReject(abortReason);
   1436    return promise.forget();
   1437  }
   1438 
   1439  if (BodyUsed()) {
   1440    aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
   1441    return nullptr;
   1442  }
   1443 
   1444  nsAutoCString mimeType;
   1445  nsAutoCString mixedCaseMimeType;
   1446  DerivedClass()->GetMimeType(mimeType, mixedCaseMimeType);
   1447 
   1448  // Null bodies are a special-case in the fetch spec.  The Body mix-in can only
   1449  // be "disturbed" or "locked" if its associated "body" is non-null.
   1450  // Additionally, the Body min-in's "consume body" algorithm explicitly creates
   1451  // a fresh empty ReadableStream object in step 2.  This means that `bodyUsed`
   1452  // will never return true for a null body.
   1453  //
   1454  // To this end, we create a fresh (empty) body every time a request is made
   1455  // and consume its body here, without marking this FetchBody consumed via
   1456  // SetBodyUsed.
   1457  nsCOMPtr<nsIInputStream> bodyStream;
   1458  DerivedClass()->GetBody(getter_AddRefs(bodyStream));
   1459  if (!bodyStream) {
   1460    RefPtr<EmptyBody> emptyBody =
   1461        EmptyBody::Create(DerivedClass()->GetParentObject(),
   1462                          DerivedClass()->GetPrincipalInfo().get(), signalImpl,
   1463                          mimeType, mixedCaseMimeType, aRv);
   1464    if (NS_WARN_IF(aRv.Failed())) {
   1465      return nullptr;
   1466    }
   1467 
   1468    return emptyBody->ConsumeBody(aCx, aType, aRv);
   1469  }
   1470 
   1471  SetBodyUsed(aCx, aRv);
   1472  if (NS_WARN_IF(aRv.Failed())) {
   1473    return nullptr;
   1474  }
   1475 
   1476  nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
   1477 
   1478  MutableBlobStorage::MutableBlobStorageType blobStorageType =
   1479      MutableBlobStorage::eOnlyInMemory;
   1480  const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo =
   1481      DerivedClass()->GetPrincipalInfo();
   1482  // We support temporary file for blobs only if the principal is known and
   1483  // it's system or content not in private Browsing.
   1484  if (principalInfo &&
   1485      (principalInfo->type() ==
   1486           mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo ||
   1487       (principalInfo->type() ==
   1488            mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
   1489        !principalInfo->get_ContentPrincipalInfo()
   1490             .attrs()
   1491             .IsPrivateBrowsing()))) {
   1492    blobStorageType = MutableBlobStorage::eCouldBeInTemporaryFile;
   1493  }
   1494 
   1495  RefPtr<Promise> promise = BodyConsumer::Create(
   1496      global, mMainThreadEventTarget, bodyStream, signalImpl, aType,
   1497      BodyBlobURISpec(), BodyLocalPath(), mimeType, mixedCaseMimeType,
   1498      blobStorageType, aRv);
   1499  if (NS_WARN_IF(aRv.Failed())) {
   1500    return nullptr;
   1501  }
   1502 
   1503  return promise.forget();
   1504 }
   1505 
   1506 template already_AddRefed<Promise> FetchBody<Request>::ConsumeBody(
   1507    JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
   1508 
   1509 template already_AddRefed<Promise> FetchBody<Response>::ConsumeBody(
   1510    JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
   1511 
   1512 template already_AddRefed<Promise> FetchBody<EmptyBody>::ConsumeBody(
   1513    JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
   1514 
   1515 template <class Derived>
   1516 void FetchBody<Derived>::GetMimeType(nsACString& aMimeType,
   1517                                     nsACString& aMixedCaseMimeType) {
   1518  // Implements "extract a MIME type" from
   1519  // https://fetch.spec.whatwg.org/#concept-header-extract-mime-type
   1520  MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
   1521 
   1522  ErrorResult result;
   1523  nsAutoCString contentTypeValue;
   1524  DerivedClass()->GetInternalHeaders()->Get("Content-Type"_ns, contentTypeValue,
   1525                                            result);
   1526  MOZ_ALWAYS_TRUE(!result.Failed());
   1527 
   1528  if (contentTypeValue.IsVoid()) {
   1529    return;
   1530  }
   1531 
   1532  nsTArray<nsTDependentSubstring<char>> values =
   1533      CMimeType::SplitMimetype(contentTypeValue);
   1534 
   1535  nsAutoCString charset;
   1536  nsAutoCString essence;
   1537  RefPtr<CMimeType> mimeType;
   1538 
   1539  for (const auto& value : values) {
   1540    RefPtr<CMimeType> temporaryMimeType = CMimeType::Parse(value);
   1541 
   1542    if (!temporaryMimeType) {
   1543      continue;
   1544    }
   1545 
   1546    nsAutoCString temporaryEssence;
   1547    temporaryMimeType->GetEssence(temporaryEssence);
   1548 
   1549    if (temporaryEssence.EqualsLiteral("*/*")) {
   1550      continue;
   1551    }
   1552 
   1553    mimeType = temporaryMimeType;
   1554 
   1555    if (!temporaryEssence.Equals(essence)) {
   1556      charset.Truncate();
   1557      mimeType->GetParameterValue("charset"_ns, charset, false, false);
   1558 
   1559      essence = temporaryEssence;
   1560    } else {
   1561      nsAutoCString newCharset;
   1562      if (!mimeType->GetParameterValue("charset"_ns, newCharset, false,
   1563                                       false) &&
   1564          !charset.IsEmpty()) {
   1565        mimeType->SetParameterValue("charset"_ns, charset);
   1566      } else if (!newCharset.IsEmpty()) {
   1567        charset = newCharset;
   1568      }
   1569    }
   1570  }
   1571 
   1572  if (mimeType) {
   1573    mimeType->Serialize(aMixedCaseMimeType);
   1574    aMimeType = aMixedCaseMimeType;
   1575    ToLowerCase(aMimeType);
   1576  }
   1577 }
   1578 
   1579 template void FetchBody<Request>::GetMimeType(nsACString& aMimeType,
   1580                                              nsACString& aMixedCaseMimeType);
   1581 template void FetchBody<Response>::GetMimeType(nsACString& aMimeType,
   1582                                               nsACString& aMixedCaseMimeType);
   1583 
   1584 template <class Derived>
   1585 const nsACString& FetchBody<Derived>::BodyBlobURISpec() const {
   1586  return DerivedClass()->BodyBlobURISpec();
   1587 }
   1588 
   1589 template const nsACString& FetchBody<Request>::BodyBlobURISpec() const;
   1590 
   1591 template const nsACString& FetchBody<Response>::BodyBlobURISpec() const;
   1592 
   1593 template const nsACString& FetchBody<EmptyBody>::BodyBlobURISpec() const;
   1594 
   1595 template <class Derived>
   1596 const nsAString& FetchBody<Derived>::BodyLocalPath() const {
   1597  return DerivedClass()->BodyLocalPath();
   1598 }
   1599 
   1600 template const nsAString& FetchBody<Request>::BodyLocalPath() const;
   1601 
   1602 template const nsAString& FetchBody<Response>::BodyLocalPath() const;
   1603 
   1604 template const nsAString& FetchBody<EmptyBody>::BodyLocalPath() const;
   1605 
   1606 template <class Derived>
   1607 void FetchBody<Derived>::SetReadableStreamBody(JSContext* aCx,
   1608                                               ReadableStream* aBody) {
   1609  MOZ_ASSERT(!mReadableStreamBody);
   1610  MOZ_ASSERT(aBody);
   1611  mReadableStreamBody = aBody;
   1612 
   1613  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
   1614  if (!signalImpl) {
   1615    return;
   1616  }
   1617 
   1618  bool aborted = signalImpl->Aborted();
   1619  if (aborted) {
   1620    IgnoredErrorResult result;
   1621    JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
   1622    AbortStream(aCx, mReadableStreamBody, result, abortReason);
   1623    if (NS_WARN_IF(result.Failed())) {
   1624      return;
   1625    }
   1626  } else if (!IsFollowing()) {
   1627    Follow(signalImpl);
   1628  }
   1629 }
   1630 
   1631 template void FetchBody<Request>::SetReadableStreamBody(JSContext* aCx,
   1632                                                        ReadableStream* aBody);
   1633 
   1634 template void FetchBody<Response>::SetReadableStreamBody(JSContext* aCx,
   1635                                                         ReadableStream* aBody);
   1636 
   1637 template <class Derived>
   1638 already_AddRefed<ReadableStream> FetchBody<Derived>::GetBody(JSContext* aCx,
   1639                                                             ErrorResult& aRv) {
   1640  if (mReadableStreamBody) {
   1641    return do_AddRef(mReadableStreamBody);
   1642  }
   1643 
   1644  nsCOMPtr<nsIInputStream> inputStream;
   1645  DerivedClass()->GetBody(getter_AddRefs(inputStream));
   1646 
   1647  if (!inputStream) {
   1648    return nullptr;
   1649  }
   1650 
   1651  // The spec immediately creates ReadableStream on Response/Request constructor
   1652  // via https://fetch.spec.whatwg.org/#concept-bodyinit-extract, but Gecko
   1653  // creates nsIInputStream there instead and creates ReadableStream only when
   1654  // .body is accessed. Thus we only follow step 4 of it here.
   1655  //
   1656  // Step 4: Otherwise, set stream to a new ReadableStream object, and set up
   1657  // stream with byte reading support.
   1658  auto algorithms =
   1659      MakeRefPtr<NonAsyncInputToReadableStreamAlgorithms>(*inputStream);
   1660  RefPtr<ReadableStream> body = ReadableStream::CreateByteNative(
   1661      aCx, DerivedClass()->GetParentObject(), *algorithms, Nothing(), aRv);
   1662  if (aRv.Failed()) {
   1663    return nullptr;
   1664  }
   1665  mReadableStreamBody = body;
   1666 
   1667  // If the body has been already consumed, we lock the stream.
   1668  if (BodyUsed()) {
   1669    LockStream(aCx, body, aRv);
   1670    if (NS_WARN_IF(aRv.Failed())) {
   1671      return nullptr;
   1672    }
   1673  }
   1674 
   1675  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
   1676  if (signalImpl) {
   1677    if (signalImpl->Aborted()) {
   1678      JS::Rooted<JS::Value> abortReason(aCx, signalImpl->RawReason());
   1679      AbortStream(aCx, body, aRv, abortReason);
   1680      if (NS_WARN_IF(aRv.Failed())) {
   1681        return nullptr;
   1682      }
   1683    } else if (!IsFollowing()) {
   1684      Follow(signalImpl);
   1685    }
   1686  }
   1687 
   1688  return body.forget();
   1689 }
   1690 
   1691 template already_AddRefed<ReadableStream> FetchBody<Request>::GetBody(
   1692    JSContext* aCx, ErrorResult& aRv);
   1693 
   1694 template already_AddRefed<ReadableStream> FetchBody<Response>::GetBody(
   1695    JSContext* aCx, ErrorResult& aRv);
   1696 
   1697 template <class Derived>
   1698 void FetchBody<Derived>::LockStream(JSContext* aCx, ReadableStream* aStream,
   1699                                    ErrorResult& aRv) {
   1700  // This is native stream, creating a reader will not execute any JS code.
   1701  RefPtr<ReadableStreamDefaultReader> reader = aStream->GetReader(aRv);
   1702  if (aRv.Failed()) {
   1703    return;
   1704  }
   1705 }
   1706 
   1707 template void FetchBody<Request>::LockStream(JSContext* aCx,
   1708                                             ReadableStream* aStream,
   1709                                             ErrorResult& aRv);
   1710 
   1711 template void FetchBody<Response>::LockStream(JSContext* aCx,
   1712                                              ReadableStream* aStream,
   1713                                              ErrorResult& aRv);
   1714 
   1715 template <class Derived>
   1716 void FetchBody<Derived>::MaybeTeeReadableStreamBody(
   1717    JSContext* aCx, ReadableStream** aBodyOut,
   1718    FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
   1719    ErrorResult& aRv) {
   1720  MOZ_DIAGNOSTIC_ASSERT(aStreamReader);
   1721  MOZ_DIAGNOSTIC_ASSERT(aInputStream);
   1722  MOZ_DIAGNOSTIC_ASSERT(!BodyUsed());
   1723 
   1724  *aBodyOut = nullptr;
   1725  *aStreamReader = nullptr;
   1726  *aInputStream = nullptr;
   1727 
   1728  if (!mReadableStreamBody) {
   1729    return;
   1730  }
   1731 
   1732  // If this is a ReadableStream with an native source, this has been
   1733  // generated by a Fetch. In this case, Fetch will be able to recreate it
   1734  // again when GetBody() is called.
   1735  if (mReadableStreamBody->MaybeGetInputStreamIfUnread()) {
   1736    *aBodyOut = nullptr;
   1737    return;
   1738  }
   1739 
   1740  nsTArray<RefPtr<ReadableStream>> branches;
   1741  MOZ_KnownLive(mReadableStreamBody)->Tee(aCx, branches, aRv);
   1742  if (aRv.Failed()) {
   1743    return;
   1744  }
   1745 
   1746  mReadableStreamBody = branches[0];
   1747  branches[1].forget(aBodyOut);
   1748 
   1749  aRv = FetchStreamReader::Create(aCx, mOwner, aStreamReader, aInputStream);
   1750  if (NS_WARN_IF(aRv.Failed())) {
   1751    return;
   1752  }
   1753 }
   1754 
   1755 template void FetchBody<Request>::MaybeTeeReadableStreamBody(
   1756    JSContext* aCx, ReadableStream** aBodyOut,
   1757    FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
   1758    ErrorResult& aRv);
   1759 
   1760 template void FetchBody<Response>::MaybeTeeReadableStreamBody(
   1761    JSContext* aCx, ReadableStream** aBodyOut,
   1762    FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
   1763    ErrorResult& aRv);
   1764 
   1765 template <class Derived>
   1766 void FetchBody<Derived>::RunAbortAlgorithm() {
   1767  if (!mReadableStreamBody) {
   1768    return;
   1769  }
   1770 
   1771  AutoJSAPI jsapi;
   1772  if (!jsapi.Init(mOwner)) {
   1773    return;
   1774  }
   1775 
   1776  JSContext* cx = jsapi.cx();
   1777 
   1778  RefPtr<ReadableStream> body(mReadableStreamBody);
   1779  IgnoredErrorResult result;
   1780 
   1781  JS::Rooted<JS::Value> abortReason(cx);
   1782 
   1783  AbortSignalImpl* signalImpl = Signal();
   1784  if (signalImpl) {
   1785    abortReason.set(signalImpl->RawReason());
   1786  }
   1787 
   1788  AbortStream(cx, body, result, abortReason);
   1789 }
   1790 
   1791 template void FetchBody<Request>::RunAbortAlgorithm();
   1792 
   1793 template void FetchBody<Response>::RunAbortAlgorithm();
   1794 
   1795 NS_IMPL_ADDREF_INHERITED(EmptyBody, FetchBody<EmptyBody>)
   1796 NS_IMPL_RELEASE_INHERITED(EmptyBody, FetchBody<EmptyBody>)
   1797 
   1798 NS_IMPL_CYCLE_COLLECTION_CLASS(EmptyBody)
   1799 
   1800 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(EmptyBody, FetchBody<EmptyBody>)
   1801  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
   1802  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAbortSignalImpl)
   1803  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
   1804 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1805 
   1806 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EmptyBody,
   1807                                                  FetchBody<EmptyBody>)
   1808  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   1809  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAbortSignalImpl)
   1810  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
   1811 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1812 
   1813 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(EmptyBody, FetchBody<EmptyBody>)
   1814 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1815 
   1816 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EmptyBody)
   1817 NS_INTERFACE_MAP_END_INHERITING(FetchBody<EmptyBody>)
   1818 
   1819 EmptyBody::EmptyBody(nsIGlobalObject* aGlobal,
   1820                     mozilla::ipc::PrincipalInfo* aPrincipalInfo,
   1821                     AbortSignalImpl* aAbortSignalImpl,
   1822                     const nsACString& aMimeType,
   1823                     const nsACString& aMixedCaseMimeType,
   1824                     already_AddRefed<nsIInputStream> aBodyStream)
   1825    : FetchBody<EmptyBody>(aGlobal),
   1826      mAbortSignalImpl(aAbortSignalImpl),
   1827      mMimeType(aMimeType),
   1828      mMixedCaseMimeType(aMixedCaseMimeType),
   1829      mBodyStream(std::move(aBodyStream)) {
   1830  if (aPrincipalInfo) {
   1831    mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*aPrincipalInfo);
   1832  }
   1833 }
   1834 
   1835 EmptyBody::~EmptyBody() = default;
   1836 
   1837 /* static */
   1838 already_AddRefed<EmptyBody> EmptyBody::Create(
   1839    nsIGlobalObject* aGlobal, mozilla::ipc::PrincipalInfo* aPrincipalInfo,
   1840    AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
   1841    const nsACString& aMixedCaseMimeType, ErrorResult& aRv) {
   1842  nsCOMPtr<nsIInputStream> bodyStream;
   1843  aRv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), ""_ns);
   1844  if (NS_WARN_IF(aRv.Failed())) {
   1845    return nullptr;
   1846  }
   1847 
   1848  RefPtr<EmptyBody> emptyBody =
   1849      new EmptyBody(aGlobal, aPrincipalInfo, aAbortSignalImpl, aMimeType,
   1850                    aMixedCaseMimeType, bodyStream.forget());
   1851  return emptyBody.forget();
   1852 }
   1853 
   1854 void EmptyBody::GetBody(nsIInputStream** aStream, int64_t* aBodyLength) {
   1855  MOZ_ASSERT(aStream);
   1856 
   1857  if (aBodyLength) {
   1858    *aBodyLength = 0;
   1859  }
   1860 
   1861  nsCOMPtr<nsIInputStream> bodyStream = mBodyStream;
   1862  bodyStream.forget(aStream);
   1863 }
   1864 
   1865 }  // namespace mozilla::dom