tor-browser

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

FetchDriver.cpp (69771B)


      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 "mozilla/dom/FetchDriver.h"
      8 
      9 #include "Fetch.h"
     10 #include "FetchLog.h"
     11 #include "FetchUtil.h"
     12 #include "InternalRequest.h"
     13 #include "InternalResponse.h"
     14 #include "js/Value.h"
     15 #include "mozilla/DebugOnly.h"
     16 #include "mozilla/PreloaderBase.h"
     17 #include "mozilla/StaticPrefs_browser.h"
     18 #include "mozilla/StaticPrefs_javascript.h"
     19 #include "mozilla/StaticPrefs_network.h"
     20 #include "mozilla/StaticPrefs_privacy.h"
     21 #include "mozilla/TaskQueue.h"
     22 #include "mozilla/dom/BlobURLProtocolHandler.h"
     23 #include "mozilla/dom/Document.h"
     24 #include "mozilla/dom/FetchPriority.h"
     25 #include "mozilla/dom/File.h"
     26 #include "mozilla/dom/PerformanceStorage.h"
     27 #include "mozilla/dom/PerformanceTiming.h"
     28 #include "mozilla/dom/ReferrerInfo.h"
     29 #include "mozilla/dom/ServiceWorkerInterceptController.h"
     30 #include "mozilla/dom/UserActivation.h"
     31 #include "mozilla/dom/WorkerCommon.h"
     32 #include "mozilla/ipc/PBackgroundSharedTypes.h"
     33 #include "mozilla/net/ContentRange.h"
     34 #include "mozilla/net/InterceptionInfo.h"
     35 #include "mozilla/net/NeckoChannelParams.h"
     36 #include "nsContentPolicyUtils.h"
     37 #include "nsDataChannel.h"
     38 #include "nsDataHandler.h"
     39 #include "nsHttpChannel.h"
     40 #include "nsIAsyncVerifyRedirectCallback.h"
     41 #include "nsIBaseChannel.h"
     42 #include "nsICookieJarSettings.h"
     43 #include "nsIFile.h"
     44 #include "nsIFileChannel.h"
     45 #include "nsIHttpChannel.h"
     46 #include "nsIHttpChannelInternal.h"
     47 #include "nsIInputStream.h"
     48 #include "nsIInterceptionInfo.h"
     49 #include "nsIInterfaceRequestorUtils.h"
     50 #include "nsIOutputStream.h"
     51 #include "nsIPipe.h"
     52 #include "nsIRedirectHistoryEntry.h"
     53 #include "nsISupportsPriority.h"
     54 #include "nsIThreadRetargetableRequest.h"
     55 #include "nsIUploadChannel2.h"
     56 #include "nsNetUtil.h"
     57 #include "nsPrintfCString.h"
     58 #include "nsProxyRelease.h"
     59 #include "nsStreamUtils.h"
     60 #include "nsStringStream.h"
     61 
     62 namespace mozilla::dom {
     63 
     64 namespace {
     65 
     66 void GetBlobURISpecFromChannel(nsIRequest* aRequest, nsCString& aBlobURISpec) {
     67  MOZ_ASSERT(aRequest);
     68 
     69  aBlobURISpec.SetIsVoid(true);
     70 
     71  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
     72  if (!channel) {
     73    return;
     74  }
     75 
     76  nsCOMPtr<nsIURI> uri;
     77  nsresult rv = NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
     78  if (NS_FAILED(rv)) {
     79    return;
     80  }
     81 
     82  if (!dom::IsBlobURI(uri)) {
     83    return;
     84  }
     85 
     86  uri->GetSpec(aBlobURISpec);
     87 }
     88 
     89 bool ShouldCheckSRI(const InternalRequest& aRequest,
     90                    const InternalResponse& aResponse) {
     91  return !aRequest.GetIntegrity().IsEmpty() &&
     92         aResponse.Type() != ResponseType::Error;
     93 }
     94 
     95 }  // anonymous namespace
     96 
     97 //-----------------------------------------------------------------------------
     98 // AlternativeDataStreamListener
     99 //-----------------------------------------------------------------------------
    100 class AlternativeDataStreamListener final
    101    : public nsIThreadRetargetableStreamListener {
    102 public:
    103  NS_DECL_THREADSAFE_ISUPPORTS
    104  NS_DECL_NSIREQUESTOBSERVER
    105  NS_DECL_NSISTREAMLISTENER
    106  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
    107 
    108  // The status of AlternativeDataStreamListener
    109  // LOADING: is the initial status, loading the alternative data
    110  // COMPLETED: Alternative data loading is completed
    111  // CANCELED: Alternative data loading is canceled, this would make
    112  //           AlternativeDataStreamListener ignore all channel callbacks
    113  // FALLBACK: fallback the channel callbacks to FetchDriver
    114  // Depends on different situaions, the status transition could be followings
    115  // 1. LOADING->COMPLETED
    116  //    This is the normal status transition for alternative data loading
    117  //
    118  // 2. LOADING->CANCELED
    119  //    LOADING->COMPLETED->CANCELED
    120  //    Alternative data loading could be canceled when cacheId from alternative
    121  //    data channel does not match with from main data channel(The cacheID
    122  //    checking is in FetchDriver::OnStartRequest).
    123  //    Notice the alternative data loading could finish before the cacheID
    124  //    checking, so the statust transition could be
    125  //    LOADING->COMPLETED->CANCELED
    126  //
    127  // 3. LOADING->FALLBACK
    128  //    For the case that alternative data loading could not be initialized,
    129  //    i.e. alternative data does not exist or no preferred alternative data
    130  //    type is requested. Once the status becomes FALLBACK,
    131  //    AlternativeDataStreamListener transits the channel callback request to
    132  //    FetchDriver, and the status should not go back to LOADING, COMPLETED, or
    133  //    CANCELED anymore.
    134  enum eStatus { LOADING = 0, COMPLETED, CANCELED, FALLBACK };
    135 
    136  AlternativeDataStreamListener(FetchDriver* aFetchDriver, nsIChannel* aChannel,
    137                                const nsACString& aAlternativeDataType);
    138  eStatus Status();
    139  void Cancel();
    140  uint64_t GetAlternativeDataCacheEntryId();
    141  const nsACString& GetAlternativeDataType() const;
    142  already_AddRefed<nsICacheInfoChannel> GetCacheInfoChannel();
    143  already_AddRefed<nsIInputStream> GetAlternativeInputStream();
    144 
    145 private:
    146  ~AlternativeDataStreamListener() = default;
    147 
    148  // This creates a strong reference cycle with FetchDriver and its
    149  // mAltDataListener. We need to clear at least one reference of them once the
    150  // data loading finishes.
    151  RefPtr<FetchDriver> mFetchDriver;
    152  nsCString mAlternativeDataType;
    153  nsCOMPtr<nsIInputStream> mPipeAlternativeInputStream;
    154  nsCOMPtr<nsIOutputStream> mPipeAlternativeOutputStream;
    155  uint64_t mAlternativeDataCacheEntryId;
    156  nsCOMPtr<nsICacheInfoChannel> mCacheInfoChannel;
    157  nsCOMPtr<nsIChannel> mChannel;
    158  Atomic<eStatus> mStatus;
    159 };
    160 
    161 NS_IMPL_ISUPPORTS(AlternativeDataStreamListener, nsIStreamListener,
    162                  nsIThreadRetargetableStreamListener)
    163 
    164 AlternativeDataStreamListener::AlternativeDataStreamListener(
    165    FetchDriver* aFetchDriver, nsIChannel* aChannel,
    166    const nsACString& aAlternativeDataType)
    167    : mFetchDriver(aFetchDriver),
    168      mAlternativeDataType(aAlternativeDataType),
    169      mAlternativeDataCacheEntryId(0),
    170      mChannel(aChannel),
    171      mStatus(AlternativeDataStreamListener::LOADING) {
    172  MOZ_DIAGNOSTIC_ASSERT(mFetchDriver);
    173  MOZ_DIAGNOSTIC_ASSERT(mChannel);
    174 }
    175 
    176 AlternativeDataStreamListener::eStatus AlternativeDataStreamListener::Status() {
    177  return mStatus;
    178 }
    179 
    180 void AlternativeDataStreamListener::Cancel() {
    181  mAlternativeDataCacheEntryId = 0;
    182  mCacheInfoChannel = nullptr;
    183  mPipeAlternativeOutputStream = nullptr;
    184  mPipeAlternativeInputStream = nullptr;
    185  if (mChannel && mStatus != AlternativeDataStreamListener::FALLBACK) {
    186    // if mStatus is fallback, we need to keep channel to forward request back
    187    // to FetchDriver
    188    mChannel->CancelWithReason(NS_BINDING_ABORTED,
    189                               "AlternativeDataStreamListener::Cancel"_ns);
    190    mChannel = nullptr;
    191  }
    192  mStatus = AlternativeDataStreamListener::CANCELED;
    193 }
    194 
    195 uint64_t AlternativeDataStreamListener::GetAlternativeDataCacheEntryId() {
    196  return mAlternativeDataCacheEntryId;
    197 }
    198 
    199 const nsACString& AlternativeDataStreamListener::GetAlternativeDataType()
    200    const {
    201  return mAlternativeDataType;
    202 }
    203 
    204 already_AddRefed<nsIInputStream>
    205 AlternativeDataStreamListener::GetAlternativeInputStream() {
    206  nsCOMPtr<nsIInputStream> inputStream = mPipeAlternativeInputStream;
    207  return inputStream.forget();
    208 }
    209 
    210 already_AddRefed<nsICacheInfoChannel>
    211 AlternativeDataStreamListener::GetCacheInfoChannel() {
    212  nsCOMPtr<nsICacheInfoChannel> channel = mCacheInfoChannel;
    213  return channel.forget();
    214 }
    215 
    216 NS_IMETHODIMP
    217 AlternativeDataStreamListener::OnStartRequest(nsIRequest* aRequest) {
    218  AssertIsOnMainThread();
    219  MOZ_ASSERT(!mAlternativeDataType.IsEmpty());
    220  // Checking the alternative data type is the same between we asked and the
    221  // saved in the channel.
    222  nsAutoCString alternativeDataType;
    223  nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(aRequest);
    224  mStatus = AlternativeDataStreamListener::LOADING;
    225  if (cic && NS_SUCCEEDED(cic->GetAlternativeDataType(alternativeDataType)) &&
    226      mAlternativeDataType.Equals(alternativeDataType) &&
    227      NS_SUCCEEDED(cic->GetCacheEntryId(&mAlternativeDataCacheEntryId))) {
    228    MOZ_DIAGNOSTIC_ASSERT(!mPipeAlternativeInputStream);
    229    MOZ_DIAGNOSTIC_ASSERT(!mPipeAlternativeOutputStream);
    230    NS_NewPipe(getter_AddRefs(mPipeAlternativeInputStream),
    231               getter_AddRefs(mPipeAlternativeOutputStream),
    232               0 /* default segment size */, UINT32_MAX /* infinite pipe */,
    233               true /* non-blocking input, otherwise you deadlock */,
    234               false /* blocking output, since the pipe is 'in'finite */);
    235 
    236    MOZ_DIAGNOSTIC_ASSERT(!mCacheInfoChannel);
    237    mCacheInfoChannel = cic;
    238 
    239    // call FetchDriver::HttpFetch to load main body
    240    MOZ_ASSERT(mFetchDriver);
    241    return mFetchDriver->HttpFetch();
    242  }
    243  // Needn't load alternative data, since alternative data does not exist.
    244  // Set status to FALLBACK to reuse the opened channel to load main body,
    245  // then call FetchDriver::OnStartRequest to continue the work. Unfortunately
    246  // can't change the stream listener to mFetchDriver, need to keep
    247  // AlternativeDataStreamListener alive to redirect OnDataAvailable and
    248  // OnStopRequest to mFetchDriver.
    249  MOZ_ASSERT(alternativeDataType.IsEmpty());
    250  mStatus = AlternativeDataStreamListener::FALLBACK;
    251  mAlternativeDataCacheEntryId = 0;
    252  MOZ_ASSERT(mFetchDriver);
    253  return mFetchDriver->OnStartRequest(aRequest);
    254 }
    255 
    256 NS_IMETHODIMP
    257 AlternativeDataStreamListener::OnDataAvailable(nsIRequest* aRequest,
    258                                               nsIInputStream* aInputStream,
    259                                               uint64_t aOffset,
    260                                               uint32_t aCount) {
    261  FETCH_LOG(
    262      ("FetchDriver::OnDataAvailable this=%p, request=%p", this, aRequest));
    263  if (mStatus == AlternativeDataStreamListener::LOADING) {
    264    MOZ_ASSERT(mPipeAlternativeOutputStream);
    265    uint32_t read = 0;
    266    return aInputStream->ReadSegments(
    267        NS_CopySegmentToStream, mPipeAlternativeOutputStream, aCount, &read);
    268  }
    269  if (mStatus == AlternativeDataStreamListener::FALLBACK) {
    270    MOZ_ASSERT(mFetchDriver);
    271    return mFetchDriver->OnDataAvailable(aRequest, aInputStream, aOffset,
    272                                         aCount);
    273  }
    274  return NS_OK;
    275 }
    276 
    277 NS_IMETHODIMP
    278 AlternativeDataStreamListener::OnStopRequest(nsIRequest* aRequest,
    279                                             nsresult aStatusCode) {
    280  AssertIsOnMainThread();
    281 
    282  // Alternative data loading is going to finish, breaking the reference cycle
    283  // here by taking the ownership to a loacl variable.
    284  RefPtr<FetchDriver> fetchDriver = std::move(mFetchDriver);
    285 
    286  if (mStatus == AlternativeDataStreamListener::CANCELED) {
    287    // do nothing
    288    return NS_OK;
    289  }
    290 
    291  if (mStatus == AlternativeDataStreamListener::FALLBACK) {
    292    MOZ_ASSERT(fetchDriver);
    293    return fetchDriver->OnStopRequest(aRequest, aStatusCode);
    294  }
    295 
    296  MOZ_DIAGNOSTIC_ASSERT(mStatus == AlternativeDataStreamListener::LOADING);
    297 
    298  MOZ_ASSERT(!mAlternativeDataType.IsEmpty() && mPipeAlternativeOutputStream &&
    299             mPipeAlternativeInputStream);
    300 
    301  mPipeAlternativeOutputStream->Close();
    302  mPipeAlternativeOutputStream = nullptr;
    303 
    304  // Cleanup the states for alternative data if needed.
    305  if (NS_FAILED(aStatusCode)) {
    306    mAlternativeDataCacheEntryId = 0;
    307    mCacheInfoChannel = nullptr;
    308    mPipeAlternativeInputStream = nullptr;
    309  }
    310  mStatus = AlternativeDataStreamListener::COMPLETED;
    311  // alternative data loading finish, call FetchDriver::FinishOnStopRequest to
    312  // continue the final step for the case FetchDriver::OnStopRequest is called
    313  // earlier than AlternativeDataStreamListener::OnStopRequest
    314  MOZ_ASSERT(fetchDriver);
    315  fetchDriver->FinishOnStopRequest(this);
    316  return NS_OK;
    317 }
    318 
    319 NS_IMETHODIMP
    320 AlternativeDataStreamListener::CheckListenerChain() { return NS_OK; }
    321 
    322 NS_IMETHODIMP
    323 AlternativeDataStreamListener::OnDataFinished(nsresult aStatus) {
    324  return NS_OK;
    325 }
    326 
    327 //-----------------------------------------------------------------------------
    328 // FetchDriver
    329 //-----------------------------------------------------------------------------
    330 
    331 NS_IMPL_ISUPPORTS(FetchDriver, nsIStreamListener, nsIChannelEventSink,
    332                  nsIInterfaceRequestor, nsIThreadRetargetableStreamListener,
    333                  nsINetworkInterceptController)
    334 
    335 FetchDriver::FetchDriver(SafeRefPtr<InternalRequest> aRequest,
    336                         nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup,
    337                         nsIEventTarget* aMainThreadEventTarget,
    338                         nsICookieJarSettings* aCookieJarSettings,
    339                         PerformanceStorage* aPerformanceStorage,
    340                         net::ClassificationFlags aTrackingFlags)
    341    : mPrincipal(aPrincipal),
    342      mLoadGroup(aLoadGroup),
    343      mRequest(std::move(aRequest)),
    344      mODAMutex("FetchDriver::mODAMutex"),
    345      mMainThreadEventTarget(aMainThreadEventTarget),
    346      mCookieJarSettings(aCookieJarSettings),
    347      mPerformanceStorage(aPerformanceStorage),
    348      mNeedToObserveOnDataAvailable(false),
    349      mTrackingFlags(aTrackingFlags),
    350      mIsOn3PCBExceptionList(false),
    351      mOnStopRequestCalled(false)
    352 #ifdef DEBUG
    353      ,
    354      mResponseAvailableCalled(false),
    355      mFetchCalled(false)
    356 #endif
    357 {
    358  AssertIsOnMainThread();
    359 
    360  MOZ_ASSERT(mRequest);
    361  MOZ_ASSERT(aPrincipal);
    362  MOZ_ASSERT(aMainThreadEventTarget);
    363 
    364  mIsTrackingFetch = net::UrlClassifierCommon::IsTrackingClassificationFlag(
    365      mTrackingFlags.thirdPartyFlags, false);
    366 }
    367 
    368 FetchDriver::~FetchDriver() {
    369  AssertIsOnMainThread();
    370 
    371  // We assert this since even on failures, we should call
    372  // FailWithNetworkError().
    373  MOZ_ASSERT(mResponseAvailableCalled);
    374 }
    375 
    376 already_AddRefed<PreloaderBase> FetchDriver::FindPreload(nsIURI* aURI) {
    377  // Decide if we allow reuse of an existing <link rel=preload as=fetch>
    378  // response for this request.  First examine this fetch requets itself if it
    379  // is 'pure' enough to use the response and then try to find a preload.
    380 
    381  if (!mDocument) {
    382    // Preloads are mapped on the document, no document, no preload.
    383    return nullptr;
    384  }
    385  CORSMode cors;
    386  switch (mRequest->Mode()) {
    387    case RequestMode::No_cors:
    388      cors = CORSMode::CORS_NONE;
    389      break;
    390    case RequestMode::Cors:
    391      cors = mRequest->GetCredentialsMode() == RequestCredentials::Include
    392                 ? CORSMode::CORS_USE_CREDENTIALS
    393                 : CORSMode::CORS_ANONYMOUS;
    394      break;
    395    default:
    396      // Can't be satisfied by a preload because preload cannot define any of
    397      // remaining modes.
    398      return nullptr;
    399  }
    400  if (!mRequest->Headers()->HasOnlySimpleHeaders()) {
    401    // Preload can't set any headers.
    402    return nullptr;
    403  }
    404  if (!mRequest->GetIntegrity().IsEmpty()) {
    405    // There is currently no support for SRI checking in the fetch preloader.
    406    return nullptr;
    407  }
    408  if (mRequest->GetCacheMode() != RequestCache::Default) {
    409    // Preload can only go with the default caching mode.
    410    return nullptr;
    411  }
    412  if (mRequest->SkipServiceWorker()) {
    413    // Preload can't be forbidden interception.
    414    return nullptr;
    415  }
    416  if (mRequest->GetRedirectMode() != RequestRedirect::Follow) {
    417    // Preload always follows redirects.
    418    return nullptr;
    419  }
    420  nsAutoCString method;
    421  mRequest->GetMethod(method);
    422  if (!method.EqualsLiteral("GET")) {
    423    // Preload can only do GET, this also eliminates the case we do upload, so
    424    // no need to check if the request has any body to send out.
    425    return nullptr;
    426  }
    427 
    428  // OK, this request can be satisfied by a preloaded response, try to find one.
    429 
    430  auto preloadKey = PreloadHashKey::CreateAsFetch(aURI, cors);
    431  return mDocument->Preloads().LookupPreload(preloadKey);
    432 }
    433 
    434 void FetchDriver::UpdateReferrerInfoFromNewChannel(nsIChannel* aChannel) {
    435  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
    436  if (!httpChannel) {
    437    return;
    438  }
    439 
    440  nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo();
    441  if (!referrerInfo) {
    442    return;
    443  }
    444 
    445  nsAutoCString computedReferrerSpec;
    446  mRequest->SetReferrerPolicy(referrerInfo->ReferrerPolicy());
    447  (void)referrerInfo->GetComputedReferrerSpec(computedReferrerSpec);
    448  mRequest->SetReferrer(computedReferrerSpec);
    449 }
    450 
    451 nsresult FetchDriver::Fetch(AbortSignalImpl* aSignalImpl,
    452                            FetchDriverObserver* aObserver) {
    453  AssertIsOnMainThread();
    454 #ifdef DEBUG
    455  MOZ_ASSERT(!mFetchCalled);
    456  mFetchCalled = true;
    457 #endif
    458 
    459  mObserver = aObserver;
    460 
    461  // FIXME(nsm): Deal with HSTS.
    462 
    463  MOZ_RELEASE_ASSERT(!mRequest->IsSynchronous(),
    464                     "Synchronous fetch not supported");
    465 
    466  UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo(
    467      new mozilla::ipc::PrincipalInfo());
    468  nsresult rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo.get());
    469  if (NS_WARN_IF(NS_FAILED(rv))) {
    470    return rv;
    471  }
    472 
    473  mRequest->SetPrincipalInfo(std::move(principalInfo));
    474 
    475  // If the signal is aborted, it's time to inform the observer and terminate
    476  // the operation.
    477  if (aSignalImpl) {
    478    if (aSignalImpl->Aborted()) {
    479      FetchDriverAbortActions(aSignalImpl);
    480      return NS_OK;
    481    }
    482 
    483    Follow(aSignalImpl);
    484  }
    485 
    486  rv = HttpFetch(mRequest->GetPreferredAlternativeDataType());
    487  if (NS_FAILED(rv)) {
    488    FailWithNetworkError(rv);
    489  }
    490 
    491  // Any failure is handled by FailWithNetworkError notifying the aObserver.
    492  return NS_OK;
    493 }
    494 
    495 // This function implements the "HTTP Fetch" algorithm from the Fetch spec.
    496 // Functionality is often split between here, the CORS listener proxy and the
    497 // Necko HTTP implementation.
    498 nsresult FetchDriver::HttpFetch(
    499    const nsACString& aPreferredAlternativeDataType) {
    500  MOZ_ASSERT(NS_IsMainThread());
    501 
    502  // Step 1. "Let response be null."
    503  mResponse = nullptr;
    504  mOnStopRequestCalled = false;
    505  nsresult rv;
    506 
    507  nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
    508  NS_ENSURE_SUCCESS(rv, rv);
    509 
    510  nsAutoCString url;
    511  mRequest->GetURL(url);
    512  nsCOMPtr<nsIURI> uri;
    513  rv = NS_NewURI(getter_AddRefs(uri), url);
    514  NS_ENSURE_SUCCESS(rv, rv);
    515 
    516  // Unsafe requests aren't allowed with when using no-core mode.
    517  if (mRequest->Mode() == RequestMode::No_cors && mRequest->UnsafeRequest() &&
    518      (!mRequest->HasSimpleMethod() ||
    519       !mRequest->Headers()->HasOnlySimpleHeaders())) {
    520    MOZ_ASSERT(false, "The API should have caught this");
    521    return NS_ERROR_DOM_BAD_URI;
    522  }
    523 
    524  // non-GET requests aren't allowed for blob.
    525  if (IsBlobURI(uri)) {
    526    nsAutoCString method;
    527    mRequest->GetMethod(method);
    528    if (!method.EqualsLiteral("GET")) {
    529      return NS_ERROR_DOM_NETWORK_ERR;
    530    }
    531  }
    532 
    533  RefPtr<PreloaderBase> fetchPreload = FindPreload(uri);
    534  if (fetchPreload) {
    535    fetchPreload->RemoveSelf(mDocument);
    536    fetchPreload->NotifyUsage(mDocument, PreloaderBase::LoadBackground::Keep);
    537 
    538    rv = fetchPreload->AsyncConsume(this);
    539    if (NS_SUCCEEDED(rv)) {
    540      mFromPreload = true;
    541 
    542      mChannel = fetchPreload->Channel();
    543      MOZ_ASSERT(mChannel);
    544      mChannel->SetNotificationCallbacks(this);
    545 
    546      // Copied from AsyncOnChannelRedirect.
    547      for (const auto& redirect : fetchPreload->Redirects()) {
    548        if (redirect.Flags() & nsIChannelEventSink::REDIRECT_INTERNAL) {
    549          mRequest->SetURLForInternalRedirect(redirect.Flags(), redirect.Spec(),
    550                                              redirect.Fragment());
    551        } else {
    552          mRequest->AddURL(redirect.Spec(), redirect.Fragment());
    553        }
    554      }
    555 
    556      return NS_OK;
    557    }
    558 
    559    // The preload failed to be consumed.  Behave like there were no preload.
    560    fetchPreload = nullptr;
    561  }
    562 
    563  // Step 2 deals with letting ServiceWorkers intercept requests. This is
    564  // handled by Necko after the channel is opened.
    565  // FIXME(nsm): Bug 1119026: The channel's skip service worker flag should be
    566  // set based on the Request's flag.
    567 
    568  // Step 3.1 "If the CORS preflight flag is set and one of these conditions is
    569  // true..." is handled by the CORS proxy.
    570  //
    571  // Step 3.2 "Set request's skip service worker flag." This isn't required
    572  // since Necko will fall back to the network if the ServiceWorker does not
    573  // respond with a valid Response.
    574  //
    575  // NS_StartCORSPreflight() will automatically kick off the original request
    576  // if it succeeds, so we need to have everything setup for the original
    577  // request too.
    578 
    579  // Step 3.3 "Let credentials flag be set if one of
    580  //  - request's credentials mode is "include"
    581  //  - request's credentials mode is "same-origin" and either the CORS flag
    582  //    is unset or response tainting is "opaque"
    583  // is true, and unset otherwise."
    584 
    585  // Set skip serviceworker flag.
    586  // While the spec also gates on the client being a ServiceWorker, we can't
    587  // infer that here. Instead we rely on callers to set the flag correctly.
    588  const nsLoadFlags bypassFlag = mRequest->SkipServiceWorker()
    589                                     ? nsIChannel::LOAD_BYPASS_SERVICE_WORKER
    590                                     : 0;
    591 
    592  nsSecurityFlags secFlags = 0;
    593  if (mRequest->Mode() == RequestMode::Cors) {
    594    secFlags |= nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
    595  } else if (mRequest->Mode() == RequestMode::Same_origin ||
    596             mRequest->Mode() == RequestMode::Navigate) {
    597    secFlags |= nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT;
    598  } else if (mRequest->Mode() == RequestMode::No_cors) {
    599    secFlags |= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
    600  } else {
    601    MOZ_ASSERT_UNREACHABLE("Unexpected request mode!");
    602    return NS_ERROR_UNEXPECTED;
    603  }
    604 
    605  if (mRequest->GetRedirectMode() != RequestRedirect::Follow) {
    606    secFlags |= nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS;
    607  }
    608 
    609  // This handles the use credentials flag in "HTTP
    610  // network or cache fetch" in the spec and decides whether to transmit
    611  // cookies and other identifying information.
    612  if (mRequest->GetCredentialsMode() == RequestCredentials::Include) {
    613    secFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
    614  } else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
    615    secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
    616  } else if (mRequest->GetCredentialsMode() ==
    617             RequestCredentials::Same_origin) {
    618    secFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
    619  } else {
    620    MOZ_ASSERT_UNREACHABLE("Unexpected credentials mode!");
    621    return NS_ERROR_UNEXPECTED;
    622  }
    623 
    624  // From here on we create a channel and set its properties with the
    625  // information from the InternalRequest. This is an implementation detail.
    626  MOZ_ASSERT(mLoadGroup);
    627  nsCOMPtr<nsIChannel> chan;
    628 
    629  nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | bypassFlag;
    630  if (mDocument) {
    631    MOZ_ASSERT(mDocument->NodePrincipal() == mPrincipal);
    632    MOZ_ASSERT(mDocument->CookieJarSettings() == mCookieJarSettings);
    633    rv = NS_NewChannel(getter_AddRefs(chan), uri, mDocument, secFlags,
    634                       mRequest->ContentPolicyType(),
    635                       nullptr,             /* aPerformanceStorage */
    636                       mLoadGroup, nullptr, /* aCallbacks */
    637                       loadFlags, ios);
    638  } else if (mClientInfo.isSome()) {
    639    rv = NS_NewChannel(getter_AddRefs(chan), uri, mPrincipal, mClientInfo.ref(),
    640                       mController, secFlags, mRequest->ContentPolicyType(),
    641                       mCookieJarSettings, mPerformanceStorage, mLoadGroup,
    642                       nullptr, /* aCallbacks */
    643                       loadFlags, ios);
    644  } else {
    645    nsCOMPtr<nsIPrincipal> principal = mPrincipal;
    646    if (principal->IsSystemPrincipal() &&
    647        mRequest->GetTriggeringPrincipalOverride()) {
    648      rv = NS_NewChannelWithTriggeringPrincipal(
    649          getter_AddRefs(chan), uri, mPrincipal,
    650          mRequest->GetTriggeringPrincipalOverride(), secFlags,
    651          mRequest->ContentPolicyType(), mCookieJarSettings,
    652          mPerformanceStorage, mLoadGroup, nullptr, /* aCallbacks */
    653          loadFlags, ios);
    654    } else {
    655      rv = NS_NewChannel(getter_AddRefs(chan), uri, mPrincipal, secFlags,
    656                         mRequest->ContentPolicyType(), mCookieJarSettings,
    657                         mPerformanceStorage, mLoadGroup,
    658                         nullptr, /* aCallbacks */
    659                         loadFlags, ios);
    660    }
    661  }
    662  NS_ENSURE_SUCCESS(rv, rv);
    663 
    664  if (mCSPEventListener) {
    665    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    666    rv = loadInfo->SetCspEventListener(mCSPEventListener);
    667    NS_ENSURE_SUCCESS(rv, rv);
    668  }
    669 
    670  {
    671    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    672    rv = loadInfo->SetLoadingEmbedderPolicy(mRequest->GetEmbedderPolicy());
    673    NS_ENSURE_SUCCESS(rv, rv);
    674  }
    675 
    676  if (mAssociatedBrowsingContextID) {
    677    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    678    rv = loadInfo->SetWorkerAssociatedBrowsingContextID(
    679        mAssociatedBrowsingContextID);
    680    NS_ENSURE_SUCCESS(rv, rv);
    681  }
    682 
    683  if (mIsThirdPartyContext.isSome()) {
    684    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    685    rv = loadInfo->SetIsInThirdPartyContext(mIsThirdPartyContext.ref());
    686    NS_ENSURE_SUCCESS(rv, rv);
    687  }
    688 
    689  if (mIsOn3PCBExceptionList) {
    690    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    691    rv = loadInfo->SetIsOn3PCBExceptionList(mIsOn3PCBExceptionList);
    692    NS_ENSURE_SUCCESS(rv, rv);
    693  }
    694 
    695  nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    696  rv = loadInfo->SetTriggeringFirstPartyClassificationFlags(
    697      mTrackingFlags.firstPartyFlags);
    698  NS_ENSURE_SUCCESS(rv, rv);
    699  rv = loadInfo->SetTriggeringThirdPartyClassificationFlags(
    700      mTrackingFlags.thirdPartyFlags);
    701  NS_ENSURE_SUCCESS(rv, rv);
    702 
    703  // If the fetch is created by FetchEvent.request or NavigationPreload request,
    704  // corresponding InterceptedHttpChannel information need to propagate to the
    705  // channel of the fetch.
    706  if (mRequest->GetInterceptionTriggeringPrincipalInfo()) {
    707    auto principalOrErr = mozilla::ipc::PrincipalInfoToPrincipal(
    708        *(mRequest->GetInterceptionTriggeringPrincipalInfo().get()));
    709    if (!principalOrErr.isErr()) {
    710      nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
    711 
    712      nsTArray<nsCOMPtr<nsIRedirectHistoryEntry>> redirectChain;
    713      if (!mRequest->InterceptionRedirectChain().IsEmpty()) {
    714        for (const RedirectHistoryEntryInfo& entryInfo :
    715             mRequest->InterceptionRedirectChain()) {
    716          nsCOMPtr<nsIRedirectHistoryEntry> entry =
    717              mozilla::ipc::RHEntryInfoToRHEntry(entryInfo);
    718          redirectChain.AppendElement(entry);
    719        }
    720      }
    721 
    722      nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    723      MOZ_ASSERT(loadInfo);
    724      loadInfo->SetInterceptionInfo(new mozilla::net::InterceptionInfo(
    725          principal, mRequest->InterceptionContentPolicyType(), redirectChain,
    726          mRequest->InterceptionFromThirdParty()));
    727    }
    728  }
    729 
    730  if (mDocument && mDocument->GetEmbedderElement() &&
    731      mDocument->GetEmbedderElement()->IsAnyOfHTMLElements(nsGkAtoms::object,
    732                                                           nsGkAtoms::embed)) {
    733    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    734    rv = loadInfo->SetIsFromObjectOrEmbed(true);
    735    NS_ENSURE_SUCCESS(rv, rv);
    736  }
    737 
    738  // Insert ourselves into the notification callbacks chain so we can set
    739  // headers on redirects.
    740 #ifdef DEBUG
    741  {
    742    nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
    743    chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
    744    MOZ_ASSERT(!notificationCallbacks);
    745  }
    746 #endif
    747  chan->SetNotificationCallbacks(this);
    748 
    749  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(chan));
    750  // Mark channel as urgent-start if the Fetch is triggered by user input
    751  // events.
    752  if (cos && UserActivation::IsHandlingUserInput()) {
    753    cos->AddClassFlags(nsIClassOfService::UrgentStart);
    754  }
    755 
    756  // Step 3.5 begins "HTTP network or cache fetch".
    757  // HTTP network or cache fetch
    758  // ---------------------------
    759  // Step 1 "Let HTTPRequest..." The channel is the HTTPRequest.
    760  nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
    761  if (httpChan) {
    762    // Copy the method.
    763    nsAutoCString method;
    764    mRequest->GetMethod(method);
    765    rv = httpChan->SetRequestMethod(method);
    766    NS_ENSURE_SUCCESS(rv, rv);
    767 
    768    // Set the same headers.
    769    SetRequestHeaders(httpChan, false, false);
    770 
    771    // Step 5 of https://fetch.spec.whatwg.org/#main-fetch
    772    // If request's referrer policy is the empty string and request's client is
    773    // non-null, then set request's referrer policy to request's client's
    774    // associated referrer policy.
    775    // Basically, "client" is not in our implementation, we use
    776    // EnvironmentReferrerPolicy of the worker or document context
    777    ReferrerPolicy referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
    778    if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
    779      mRequest->SetReferrerPolicy(referrerPolicy);
    780    }
    781    // Step 6 of https://fetch.spec.whatwg.org/#main-fetch
    782    // If request’s referrer policy is the empty string,
    783    // then set request’s referrer policy to the user-set default policy.
    784    if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
    785      nsCOMPtr<nsILoadInfo> loadInfo = httpChan->LoadInfo();
    786      bool isPrivate = loadInfo->GetOriginAttributes().IsPrivateBrowsing();
    787      referrerPolicy =
    788          ReferrerInfo::GetDefaultReferrerPolicy(httpChan, uri, isPrivate);
    789      mRequest->SetReferrerPolicy(referrerPolicy);
    790    }
    791 
    792    rv = FetchUtil::SetRequestReferrer(mPrincipal, mDocument, httpChan,
    793                                       *mRequest);
    794    NS_ENSURE_SUCCESS(rv, rv);
    795 
    796    // Bug 1120722 - Authorization will be handled later.
    797    // Auth may require prompting, we don't support it yet.
    798    // The next patch in this same bug prevents this from aborting the request.
    799    // Credentials checks for CORS are handled by nsCORSListenerProxy,
    800 
    801    nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
    802 
    803    rv = internalChan->SetRequestMode(mRequest->Mode());
    804    MOZ_ASSERT(NS_SUCCEEDED(rv));
    805    // Conversion between enumerations is safe due to static asserts in
    806    // dom/workers/ServiceWorkerManager.cpp
    807    rv = internalChan->SetRedirectMode(
    808        static_cast<uint32_t>(mRequest->GetRedirectMode()));
    809    MOZ_ASSERT(NS_SUCCEEDED(rv));
    810    mRequest->MaybeSkipCacheIfPerformingRevalidation();
    811    rv = internalChan->SetFetchCacheMode(
    812        static_cast<uint32_t>(mRequest->GetCacheMode()));
    813    MOZ_ASSERT(NS_SUCCEEDED(rv));
    814    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    815    rv = loadInfo->SetIntegrityMetadata(mRequest->GetIntegrity());
    816    MOZ_ASSERT(NS_SUCCEEDED(rv));
    817 
    818    // Set the initiator type
    819    nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
    820    if (timedChannel) {
    821      timedChannel->SetInitiatorType(u"fetch"_ns);
    822    }
    823  }
    824 
    825  // Step 5. Proxy authentication will be handled by Necko.
    826 
    827  // Continue setting up 'HTTPRequest'. Content-Type and body data.
    828  nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(chan);
    829  if (uploadChan) {
    830    nsAutoCString contentType;
    831    ErrorResult result;
    832    mRequest->Headers()->GetFirst("content-type"_ns, contentType, result);
    833    // We don't actually expect "result" to have failed here: that only happens
    834    // for invalid header names.  But if for some reason it did, just propagate
    835    // it out.
    836    if (result.Failed()) {
    837      return result.StealNSResult();
    838    }
    839 
    840    // Now contentType is the header that was set in mRequest->Headers(), or a
    841    // void string if no header was set.
    842 #ifdef DEBUG
    843    bool hasContentTypeHeader =
    844        mRequest->Headers()->Has("content-type"_ns, result);
    845    MOZ_ASSERT(!result.Failed());
    846    MOZ_ASSERT_IF(!hasContentTypeHeader, contentType.IsVoid());
    847 #endif  // DEBUG
    848 
    849    int64_t bodyLength;
    850    nsCOMPtr<nsIInputStream> bodyStream;
    851    mRequest->GetBody(getter_AddRefs(bodyStream), &bodyLength);
    852    if (bodyStream) {
    853      nsAutoCString method;
    854      mRequest->GetMethod(method);
    855      rv = uploadChan->ExplicitSetUploadStream(bodyStream, contentType,
    856                                               bodyLength, method,
    857                                               false /* aStreamHasHeaders */);
    858      NS_ENSURE_SUCCESS(rv, rv);
    859    }
    860  }
    861 
    862  // If preflight is required, start a "CORS preflight fetch"
    863  // https://fetch.spec.whatwg.org/#cors-preflight-fetch-0. All the
    864  // implementation is handled by the http channel calling into
    865  // nsCORSListenerProxy. We just inform it which unsafe headers are included
    866  // in the request.
    867  if (mRequest->Mode() == RequestMode::Cors) {
    868    AutoTArray<nsCString, 5> unsafeHeaders;
    869    mRequest->Headers()->GetUnsafeHeaders(unsafeHeaders);
    870    nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
    871    loadInfo->SetCorsPreflightInfo(unsafeHeaders, false);
    872  }
    873 
    874  if (mIsTrackingFetch && StaticPrefs::network_http_tailing_enabled() && cos) {
    875    cos->AddClassFlags(nsIClassOfService::Throttleable |
    876                       nsIClassOfService::Tail);
    877  }
    878 
    879  const auto fetchPriority = ToFetchPriority(mRequest->GetPriorityMode());
    880  if (cos) {
    881    cos->SetFetchPriorityDOM(fetchPriority);
    882  }
    883 
    884  if (nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(chan)) {
    885    if (mIsTrackingFetch &&
    886        StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
    887      p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
    888    } else if (StaticPrefs::network_fetchpriority_enabled()) {
    889      // According to step 15 of https://fetch.spec.whatwg.org/#concept-fetch
    890      // request’s priority, initiator, destination, and render-blocking are
    891      // used in an implementation-defined manner to set the internal priority.
    892      // See corresponding preferences in StaticPrefList.yaml for more context.
    893      const int32_t supportsPriorityDelta = [this, &fetchPriority]() {
    894        auto destination = mRequest->GetInterceptionTriggeringPrincipalInfo()
    895                               ? mRequest->InterceptionDestination()
    896                               : mRequest->Destination();
    897        switch (destination) {
    898          case RequestDestination::Font:
    899            return FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_font,
    900                                                 fetchPriority);
    901          case RequestDestination::Style:
    902            return FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_style,
    903                                                 fetchPriority);
    904          case RequestDestination::Script:
    905          case RequestDestination::Audioworklet:
    906          case RequestDestination::Paintworklet:
    907          case RequestDestination::Sharedworker:
    908          case RequestDestination::Worker:
    909          case RequestDestination::Xslt:
    910          case RequestDestination::Json:
    911            return FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_script,
    912                                                 fetchPriority);
    913          case RequestDestination::Image:
    914            return FETCH_PRIORITY_ADJUSTMENT_FOR(images, fetchPriority);
    915          case RequestDestination::Audio:
    916          case RequestDestination::Track:
    917          case RequestDestination::Video:
    918            return FETCH_PRIORITY_ADJUSTMENT_FOR(media, fetchPriority);
    919          case RequestDestination::Document:
    920          case RequestDestination::Embed:
    921          case RequestDestination::Frame:
    922          case RequestDestination::Iframe:
    923          case RequestDestination::Manifest:
    924          case RequestDestination::Object:
    925          case RequestDestination::Report:
    926          case RequestDestination::_empty:
    927            return FETCH_PRIORITY_ADJUSTMENT_FOR(global_fetch_api,
    928                                                 fetchPriority);
    929        };
    930        MOZ_ASSERT_UNREACHABLE("Unknown destination");
    931        return 0;
    932      }();
    933      p->SetPriority(mRequest->InternalPriority());
    934      p->AdjustPriority(supportsPriorityDelta);
    935    }
    936  }
    937 
    938  NotifyNetworkMonitorAlternateStack(chan, std::move(mOriginStack));
    939  if (mObserver && httpChan) {
    940    mObserver->OnNotifyNetworkMonitorAlternateStack(httpChan->ChannelId());
    941  }
    942 
    943  // Should set a Content-Range header for blob scheme, and also slice the
    944  // blob appropriately, so we process the Range header here for later use.
    945  if (IsBlobURI(uri)) {
    946    ErrorResult result;
    947    nsAutoCString range;
    948    mRequest->Headers()->Get("Range"_ns, range, result);
    949    MOZ_ASSERT(!result.Failed());
    950    if (!range.IsVoid()) {
    951      rv = NS_SetChannelContentRangeForBlobURI(chan, uri, range);
    952      if (NS_FAILED(rv)) {
    953        return rv;
    954      }
    955    }
    956  }
    957 
    958  // if the preferred alternative data type in InternalRequest is not empty, set
    959  // the data type on the created channel and also create a
    960  // AlternativeDataStreamListener to be the stream listener of the channel.
    961  if (!aPreferredAlternativeDataType.IsEmpty()) {
    962    nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(chan);
    963    if (cic) {
    964      cic->PreferAlternativeDataType(
    965          aPreferredAlternativeDataType, ""_ns,
    966          nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::ASYNC);
    967      MOZ_ASSERT(!mAltDataListener);
    968      mAltDataListener = new AlternativeDataStreamListener(
    969          this, chan, aPreferredAlternativeDataType);
    970      rv = chan->AsyncOpen(mAltDataListener);
    971    } else {
    972      rv = chan->AsyncOpen(this);
    973    }
    974  } else {
    975    // Integrity check cannot be done on alt-data yet.
    976    if (mRequest->GetIntegrity().IsEmpty()) {
    977      nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(chan);
    978      if (cic && StaticPrefs::javascript_options_wasm_caching() &&
    979          !mRequest->SkipWasmCaching()) {
    980        cic->PreferAlternativeDataType(
    981            FetchUtil::GetWasmAltDataType(),
    982            nsLiteralCString(WASM_CONTENT_TYPE),
    983            nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::
    984                SERIALIZE);
    985      }
    986    }
    987 
    988    rv = chan->AsyncOpen(this);
    989  }
    990 
    991  if (NS_FAILED(rv)) {
    992    return rv;
    993  }
    994 
    995  // Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
    996 
    997  mChannel = chan;
    998  return NS_OK;
    999 }
   1000 
   1001 SafeRefPtr<InternalResponse> FetchDriver::BeginAndGetFilteredResponse(
   1002    SafeRefPtr<InternalResponse> aResponse, bool aFoundOpaqueRedirect) {
   1003  MOZ_ASSERT(aResponse);
   1004  AutoTArray<nsCString, 4> reqURLList;
   1005  mRequest->GetURLListWithoutFragment(reqURLList);
   1006  MOZ_ASSERT(!reqURLList.IsEmpty());
   1007  aResponse->SetURLList(reqURLList);
   1008  SafeRefPtr<InternalResponse> filteredResponse;
   1009  if (aFoundOpaqueRedirect) {
   1010    filteredResponse = aResponse->OpaqueRedirectResponse();
   1011  } else {
   1012    switch (mRequest->GetResponseTainting()) {
   1013      case LoadTainting::Basic:
   1014        filteredResponse = aResponse->BasicResponse();
   1015        break;
   1016      case LoadTainting::CORS:
   1017        filteredResponse = aResponse->CORSResponse();
   1018        break;
   1019      case LoadTainting::Opaque: {
   1020        filteredResponse = aResponse->OpaqueResponse();
   1021        nsresult rv = filteredResponse->GeneratePaddingInfo();
   1022        if (NS_WARN_IF(NS_FAILED(rv))) {
   1023          return nullptr;
   1024        }
   1025        break;
   1026      }
   1027      default:
   1028        MOZ_CRASH("Unexpected case");
   1029    }
   1030  }
   1031 
   1032  MOZ_ASSERT(filteredResponse);
   1033  MOZ_ASSERT(mObserver);
   1034  MOZ_ASSERT(filteredResponse);
   1035  if (!ShouldCheckSRI(*mRequest, *filteredResponse)) {
   1036    // Need to keep mObserver alive.
   1037    RefPtr<FetchDriverObserver> observer = mObserver;
   1038    observer->OnResponseAvailable(filteredResponse.clonePtr());
   1039 #ifdef DEBUG
   1040    mResponseAvailableCalled = true;
   1041 #endif
   1042  }
   1043 
   1044  return filteredResponse;
   1045 }
   1046 
   1047 void FetchDriver::FailWithNetworkError(nsresult rv) {
   1048  AssertIsOnMainThread();
   1049  if (mObserver) {
   1050    // Need to keep mObserver alive.
   1051    RefPtr<FetchDriverObserver> observer = mObserver;
   1052    observer->OnResponseAvailable(InternalResponse::NetworkError(rv));
   1053 #ifdef DEBUG
   1054    mResponseAvailableCalled = true;
   1055 #endif
   1056  }
   1057 
   1058  // mObserver could be null after OnResponseAvailable().
   1059  if (mObserver) {
   1060    mObserver->OnReportPerformanceTiming();
   1061    mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking,
   1062                             JS::UndefinedHandleValue);
   1063    mObserver = nullptr;
   1064  }
   1065 
   1066  mChannel = nullptr;
   1067  Unfollow();
   1068 }
   1069 
   1070 NS_IMETHODIMP
   1071 FetchDriver::OnStartRequest(nsIRequest* aRequest) {
   1072  FETCH_LOG(
   1073      ("FetchDriver::OnStartRequest this=%p, request=%p", this, aRequest));
   1074  AssertIsOnMainThread();
   1075 
   1076  // Note, this can be called multiple times if we are doing an opaqueredirect.
   1077  // In that case we will get a simulated OnStartRequest() and then the real
   1078  // channel will call in with an errored OnStartRequest().
   1079 
   1080  if (mFromPreload && mAborted) {
   1081    aRequest->CancelWithReason(NS_BINDING_ABORTED,
   1082                               "FetchDriver::OnStartRequest aborted"_ns);
   1083    return NS_BINDING_ABORTED;
   1084  }
   1085 
   1086  if (!mChannel) {
   1087    MOZ_ASSERT(!mObserver);
   1088    return NS_BINDING_ABORTED;
   1089  }
   1090 
   1091  nsresult rv;
   1092  aRequest->GetStatus(&rv);
   1093  if (NS_FAILED(rv)) {
   1094    FailWithNetworkError(rv);
   1095    return rv;
   1096  }
   1097 
   1098  // We should only get to the following code once.
   1099  MOZ_ASSERT(!mPipeOutputStream);
   1100 
   1101  if (!mObserver) {
   1102    MOZ_ASSERT(false, "We should have mObserver here.");
   1103    FailWithNetworkError(NS_ERROR_UNEXPECTED);
   1104    return NS_ERROR_UNEXPECTED;
   1105  }
   1106 
   1107  mNeedToObserveOnDataAvailable = mObserver->NeedOnDataAvailable();
   1108 
   1109  SafeRefPtr<InternalResponse> response;
   1110  nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   1111  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   1112 
   1113  // On a successful redirect we perform the following substeps of HTTP Fetch,
   1114  // step 5, "redirect status", step 11.
   1115 
   1116  bool foundOpaqueRedirect = false;
   1117 
   1118  nsAutoCString contentType(VoidCString());
   1119 
   1120  int64_t contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
   1121  rv = channel->GetContentLength(&contentLength);
   1122  MOZ_ASSERT_IF(NS_FAILED(rv),
   1123                contentLength == InternalResponse::UNKNOWN_BODY_SIZE);
   1124 
   1125  if (httpChannel) {
   1126    channel->GetContentType(contentType);
   1127 
   1128    uint32_t responseStatus = 0;
   1129    rv = httpChannel->GetResponseStatus(&responseStatus);
   1130    if (NS_FAILED(rv)) {
   1131      FailWithNetworkError(rv);
   1132      return rv;
   1133    }
   1134 
   1135    if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) {
   1136      if (mRequest->GetRedirectMode() == RequestRedirect::Error) {
   1137        FailWithNetworkError(NS_BINDING_ABORTED);
   1138        return NS_BINDING_FAILED;
   1139      }
   1140      if (mRequest->GetRedirectMode() == RequestRedirect::Manual) {
   1141        foundOpaqueRedirect = true;
   1142      }
   1143    }
   1144 
   1145    nsAutoCString statusText;
   1146    rv = httpChannel->GetResponseStatusText(statusText);
   1147    MOZ_ASSERT(NS_SUCCEEDED(rv));
   1148 
   1149    response = MakeSafeRefPtr<InternalResponse>(responseStatus, statusText,
   1150                                                mRequest->GetCredentialsMode());
   1151 
   1152    UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo(
   1153        new mozilla::ipc::PrincipalInfo());
   1154    nsresult rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo.get());
   1155    if (NS_WARN_IF(NS_FAILED(rv))) {
   1156      return rv;
   1157    }
   1158 
   1159    response->SetPrincipalInfo(std::move(principalInfo));
   1160 
   1161    response->Headers()->FillResponseHeaders(httpChannel);
   1162 
   1163    // If Content-Encoding or Transfer-Encoding headers are set, then the actual
   1164    // Content-Length (which refer to the decoded data) is obscured behind the
   1165    // encodings.
   1166    ErrorResult result;
   1167    if (response->Headers()->Has("content-encoding"_ns, result) ||
   1168        response->Headers()->Has("transfer-encoding"_ns, result)) {
   1169      // We cannot trust the content-length when content-encoding or
   1170      // transfer-encoding are set.  There are many servers which just
   1171      // get this wrong.
   1172      contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
   1173    }
   1174    MOZ_ASSERT(!result.Failed());
   1175  } else {
   1176    // Should set a Content-Range header for blob scheme
   1177    // (https://fetch.spec.whatwg.org/#scheme-fetch)
   1178    nsAutoCString contentRange(VoidCString());
   1179    nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(mChannel);
   1180    if (baseChan) {
   1181      RefPtr<mozilla::net::ContentRange> range = baseChan->ContentRange();
   1182      if (range) {
   1183        range->AsHeader(contentRange);
   1184      }
   1185    }
   1186 
   1187    response = MakeSafeRefPtr<InternalResponse>(
   1188        contentRange.IsVoid() ? 200 : 206,
   1189        contentRange.IsVoid() ? "OK"_ns : "Partial Content"_ns,
   1190        mRequest->GetCredentialsMode());
   1191 
   1192    IgnoredErrorResult result;
   1193    if (!contentRange.IsVoid()) {
   1194      response->Headers()->Append("Content-Range"_ns, contentRange, result);
   1195      MOZ_ASSERT(!result.Failed());
   1196    }
   1197 
   1198    if (baseChan) {
   1199      RefPtr<CMimeType> fullMimeType(baseChan->FullMimeType());
   1200      if (fullMimeType) {
   1201        fullMimeType->Serialize(contentType);
   1202      }
   1203    }
   1204    if (contentType.IsVoid()) {
   1205      channel->GetContentType(contentType);
   1206      if (!contentType.IsEmpty()) {
   1207        nsAutoCString contentCharset;
   1208        channel->GetContentCharset(contentCharset);
   1209        if (NS_SUCCEEDED(rv) && !contentCharset.IsEmpty()) {
   1210          contentType += ";charset="_ns + contentCharset;
   1211        }
   1212      }
   1213    }
   1214 
   1215    response->Headers()->Append("Content-Type"_ns, contentType, result);
   1216    MOZ_ASSERT(!result.Failed());
   1217 
   1218    if (contentLength >= 0) {
   1219      nsAutoCString contentLenStr;
   1220      contentLenStr.AppendInt(contentLength);
   1221 
   1222      IgnoredErrorResult result;
   1223      response->Headers()->Append("Content-Length"_ns, contentLenStr, result);
   1224      MOZ_ASSERT(!result.Failed());
   1225    }
   1226  }
   1227 
   1228  nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(aRequest);
   1229  if (cic) {
   1230    if (mAltDataListener) {
   1231      // Skip the case that mAltDataListener->Status() equals to FALLBACK, that
   1232      // means the opened channel for alternative data loading is reused for
   1233      // loading the main data.
   1234      if (mAltDataListener->Status() !=
   1235          AlternativeDataStreamListener::FALLBACK) {
   1236        // Verify the cache ID is the same with from alternative data cache.
   1237        // If the cache ID is different, droping the alternative data loading,
   1238        // otherwise setup the response's alternative body and cacheInfoChannel.
   1239        uint64_t cacheEntryId = 0;
   1240        if (NS_SUCCEEDED(cic->GetCacheEntryId(&cacheEntryId)) &&
   1241            cacheEntryId !=
   1242                mAltDataListener->GetAlternativeDataCacheEntryId()) {
   1243          mAltDataListener->Cancel();
   1244        } else {
   1245          // AlternativeDataStreamListener::OnStartRequest had already been
   1246          // called, the alternative data input stream and cacheInfo channel
   1247          // must be created.
   1248          nsCOMPtr<nsICacheInfoChannel> cacheInfo =
   1249              mAltDataListener->GetCacheInfoChannel();
   1250          nsCOMPtr<nsIInputStream> altInputStream =
   1251              mAltDataListener->GetAlternativeInputStream();
   1252          MOZ_ASSERT(altInputStream && cacheInfo);
   1253          response->SetAlternativeBody(altInputStream);
   1254          nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
   1255              new nsMainThreadPtrHolder<nsICacheInfoChannel>(
   1256                  "nsICacheInfoChannel", cacheInfo, false));
   1257          response->SetCacheInfoChannel(handle);
   1258        }
   1259      } else if (!mAltDataListener->GetAlternativeDataType().IsEmpty()) {
   1260        // If the status is FALLBACK and the
   1261        // mAltDataListener::mAlternativeDataType is not empty, that means the
   1262        // data need to be saved into cache, setup the response's
   1263        // nsICacheInfoChannel for caching the data after loading.
   1264        nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
   1265            new nsMainThreadPtrHolder<nsICacheInfoChannel>(
   1266                "nsICacheInfoChannel", cic, false));
   1267        response->SetCacheInfoChannel(handle);
   1268      }
   1269    } else if (!cic->PreferredAlternativeDataTypes().IsEmpty()) {
   1270      MOZ_ASSERT(cic->PreferredAlternativeDataTypes().Length() == 1);
   1271      MOZ_ASSERT(cic->PreferredAlternativeDataTypes()[0].type().Equals(
   1272          FetchUtil::GetWasmAltDataType()));
   1273      MOZ_ASSERT(
   1274          cic->PreferredAlternativeDataTypes()[0].contentType().EqualsLiteral(
   1275              WASM_CONTENT_TYPE));
   1276 
   1277      if (contentType.EqualsLiteral(WASM_CONTENT_TYPE)) {
   1278        // We want to attach the CacheInfoChannel to the response object such
   1279        // that we can track its origin when the Response object is manipulated
   1280        // by JavaScript code. This is important for WebAssembly, which uses
   1281        // fetch to query its sources in JavaScript and transfer the Response
   1282        // object to other function responsible for storing the alternate data
   1283        // using the CacheInfoChannel.
   1284        nsMainThreadPtrHandle<nsICacheInfoChannel> handle(
   1285            new nsMainThreadPtrHolder<nsICacheInfoChannel>(
   1286                "nsICacheInfoChannel", cic, false));
   1287        response->SetCacheInfoChannel(handle);
   1288      }
   1289    }
   1290  }
   1291 
   1292  // Fetch spec Main Fetch step 21: ignore body for head/connect methods.
   1293  nsAutoCString method;
   1294  mRequest->GetMethod(method);
   1295  if (!(method.EqualsLiteral("HEAD") || method.EqualsLiteral("CONNECT"))) {
   1296    // We open a pipe so that we can immediately set the pipe's read end as the
   1297    // response's body. Setting the segment size to UINT32_MAX means that the
   1298    // pipe has infinite space. The nsIChannel will continue to buffer data in
   1299    // xpcom events even if we block on a fixed size pipe.  It might be possible
   1300    // to suspend the channel and then resume when there is space available, but
   1301    // for now use an infinite pipe to avoid blocking.
   1302    nsCOMPtr<nsIInputStream> pipeInputStream;
   1303    NS_NewPipe(getter_AddRefs(pipeInputStream),
   1304               getter_AddRefs(mPipeOutputStream), 0, /* default segment size */
   1305               UINT32_MAX /* infinite pipe */,
   1306               true /* non-blocking input, otherwise you deadlock */,
   1307               false /* blocking output, since the pipe is 'in'finite */);
   1308    response->SetBody(pipeInputStream, contentLength);
   1309  }
   1310 
   1311  // If the request is a file channel, then remember the local path to
   1312  // that file so we can later create File blobs rather than plain ones.
   1313  nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aRequest);
   1314  if (fc) {
   1315    nsCOMPtr<nsIFile> file;
   1316    rv = fc->GetFile(getter_AddRefs(file));
   1317    if (!NS_WARN_IF(NS_FAILED(rv))) {
   1318      nsAutoString path;
   1319      file->GetPath(path);
   1320      response->SetBodyLocalPath(path);
   1321    }
   1322  } else {
   1323    // If the request is a blob URI, then remember that URI so that we
   1324    // can later just use that blob instance instead of cloning it.
   1325    nsCString blobURISpec;
   1326    GetBlobURISpecFromChannel(aRequest, blobURISpec);
   1327    if (!blobURISpec.IsVoid()) {
   1328      response->SetBodyBlobURISpec(blobURISpec);
   1329    }
   1330  }
   1331 
   1332  response->InitChannelInfo(channel);
   1333 
   1334  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
   1335  // Propagate any tainting from the channel back to our response here.  This
   1336  // step is not reflected in the spec because the spec is written such that
   1337  // FetchEvent.respondWith() just passes the already-tainted Response back to
   1338  // the outer fetch().  In gecko, however, we serialize the Response through
   1339  // the channel and must regenerate the tainting from the channel in the
   1340  // interception case.
   1341  mRequest->MaybeIncreaseResponseTainting(loadInfo->GetTainting());
   1342 
   1343  // Resolves fetch() promise which may trigger code running in a worker.  Make
   1344  // sure the Response is fully initialized before calling this.
   1345  mResponse =
   1346      BeginAndGetFilteredResponse(std::move(response), foundOpaqueRedirect);
   1347  if (NS_WARN_IF(!mResponse)) {
   1348    // Fail to generate a paddingInfo for opaque response.
   1349    MOZ_DIAGNOSTIC_ASSERT(mRequest->GetResponseTainting() ==
   1350                              LoadTainting::Opaque &&
   1351                          !foundOpaqueRedirect);
   1352    FailWithNetworkError(NS_ERROR_UNEXPECTED);
   1353    return NS_ERROR_UNEXPECTED;
   1354  }
   1355 
   1356  // From "Main Fetch" step 19: SRI-part1.
   1357  if (ShouldCheckSRI(*mRequest, *mResponse) && mSRIMetadata.IsEmpty()) {
   1358    nsIConsoleReportCollector* reporter = nullptr;
   1359    if (mObserver) {
   1360      reporter = mObserver->GetReporter();
   1361    }
   1362 
   1363    nsAutoCString sourceUri;
   1364    if (mDocument && mDocument->GetDocumentURI()) {
   1365      mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
   1366    } else if (!mWorkerScript.IsEmpty()) {
   1367      sourceUri.Assign(mWorkerScript);
   1368    }
   1369    SRICheck::IntegrityMetadata(mRequest->GetIntegrity(), sourceUri, reporter,
   1370                                &mSRIMetadata);
   1371    mSRIDataVerifier =
   1372        MakeUnique<SRICheckDataVerifier>(mSRIMetadata, channel, reporter);
   1373 
   1374    // Do not retarget off main thread when using SRI API.
   1375    return NS_OK;
   1376  }
   1377 
   1378  // Only retarget if not already retargeted
   1379  nsCOMPtr<nsISerialEventTarget> target;
   1380  nsCOMPtr<nsIThreadRetargetableRequest> req = do_QueryInterface(aRequest);
   1381  if (req) {
   1382    rv = req->GetDeliveryTarget(getter_AddRefs(target));
   1383    if (NS_SUCCEEDED(rv) && target && !target->IsOnCurrentThread()) {
   1384      FETCH_LOG(
   1385          ("FetchDriver::OnStartRequest this=%p, request=%p already retargeted",
   1386           this, aRequest));
   1387      return NS_OK;
   1388    }
   1389  }
   1390 
   1391  nsCOMPtr<nsIEventTarget> sts =
   1392      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
   1393  if (NS_WARN_IF(NS_FAILED(rv))) {
   1394    FailWithNetworkError(rv);
   1395    // Cancel request.
   1396    return rv;
   1397  }
   1398 
   1399  FETCH_LOG(("FetchDriver retargeting: request %p", aRequest));
   1400  // Try to retarget off main thread.
   1401  if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
   1402    RefPtr<TaskQueue> queue =
   1403        TaskQueue::Create(sts.forget(), "FetchDriver STS Delivery Queue");
   1404    (void)NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(queue)));
   1405  }
   1406  return NS_OK;
   1407 }
   1408 
   1409 namespace {
   1410 
   1411 // Runnable to call the observer OnDataAvailable on the main-thread.
   1412 class DataAvailableRunnable final : public Runnable {
   1413  RefPtr<FetchDriverObserver> mObserver;
   1414 
   1415 public:
   1416  explicit DataAvailableRunnable(FetchDriverObserver* aObserver)
   1417      : Runnable("dom::DataAvailableRunnable"), mObserver(aObserver) {
   1418    MOZ_ASSERT(aObserver);
   1419  }
   1420 
   1421  NS_IMETHOD
   1422  Run() override {
   1423    mObserver->OnDataAvailable();
   1424    mObserver = nullptr;
   1425    return NS_OK;
   1426  }
   1427 };
   1428 
   1429 struct SRIVerifierAndOutputHolder {
   1430  SRIVerifierAndOutputHolder(SRICheckDataVerifier* aVerifier,
   1431                             nsIOutputStream* aOutputStream)
   1432      : mVerifier(aVerifier), mOutputStream(aOutputStream) {}
   1433 
   1434  SRICheckDataVerifier* mVerifier;
   1435  nsIOutputStream* mOutputStream;
   1436 
   1437 private:
   1438  SRIVerifierAndOutputHolder() = delete;
   1439 };
   1440 
   1441 // Just like NS_CopySegmentToStream, but also sends the data into an
   1442 // SRICheckDataVerifier.
   1443 nsresult CopySegmentToStreamAndSRI(nsIInputStream* aInStr, void* aClosure,
   1444                                   const char* aBuffer, uint32_t aOffset,
   1445                                   uint32_t aCount, uint32_t* aCountWritten) {
   1446  auto holder = static_cast<SRIVerifierAndOutputHolder*>(aClosure);
   1447  MOZ_DIAGNOSTIC_ASSERT(holder && holder->mVerifier && holder->mOutputStream,
   1448                        "Bogus holder");
   1449  nsresult rv = holder->mVerifier->Update(
   1450      aCount, reinterpret_cast<const uint8_t*>(aBuffer));
   1451  NS_ENSURE_SUCCESS(rv, rv);
   1452 
   1453  // The rest is just like NS_CopySegmentToStream.
   1454  *aCountWritten = 0;
   1455  while (aCount) {
   1456    uint32_t n = 0;
   1457    rv = holder->mOutputStream->Write(aBuffer, aCount, &n);
   1458    if (NS_FAILED(rv)) {
   1459      return rv;
   1460    }
   1461    aBuffer += n;
   1462    aCount -= n;
   1463    *aCountWritten += n;
   1464  }
   1465  return NS_OK;
   1466 }
   1467 
   1468 }  // anonymous namespace
   1469 
   1470 NS_IMETHODIMP
   1471 FetchDriver::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
   1472                             uint64_t aOffset, uint32_t aCount) {
   1473  // NB: This can be called on any thread!  But we're guaranteed that it is
   1474  // called between OnStartRequest and OnStopRequest, so we don't need to worry
   1475  // about races for the members accessed in OnStartRequest, OnStopRequest,
   1476  // FailWithNetworkError and member functions accessed before opening the
   1477  // channel. However, we have a possibility of a race from
   1478  // FetchDriverAbortActions
   1479 
   1480  if (!mPipeOutputStream) {
   1481    // We ignore the body for HEAD/CONNECT requests.
   1482    // nsIStreamListener mandates reading from the stream before returning.
   1483    uint32_t totalRead;
   1484    nsresult rv = aInputStream->ReadSegments(NS_DiscardSegment, nullptr, aCount,
   1485                                             &totalRead);
   1486    NS_ENSURE_SUCCESS(rv, rv);
   1487    return NS_OK;
   1488  }
   1489 
   1490  if (mNeedToObserveOnDataAvailable) {
   1491    mNeedToObserveOnDataAvailable = false;
   1492    RefPtr<FetchDriverObserver> observer;
   1493    {
   1494      MutexAutoLock lock(mODAMutex);
   1495      // Need to keep mObserver alive.
   1496      observer = mObserver;
   1497    }
   1498    if (observer) {
   1499      if (NS_IsMainThread()) {
   1500        observer->OnDataAvailable();
   1501      } else {
   1502        RefPtr<Runnable> runnable = new DataAvailableRunnable(observer);
   1503        nsresult rv = mMainThreadEventTarget->Dispatch(runnable.forget(),
   1504                                                       NS_DISPATCH_NORMAL);
   1505        if (NS_WARN_IF(NS_FAILED(rv))) {
   1506          return rv;
   1507        }
   1508      }
   1509    }
   1510  }
   1511 
   1512  if (!mResponse) {
   1513    MOZ_ASSERT(false);
   1514    return NS_ERROR_UNEXPECTED;
   1515  }
   1516 
   1517  // Needs to be initialized to 0 because in some cases nsStringInputStream may
   1518  // not write to aRead.
   1519  uint32_t aRead = 0;
   1520  MOZ_ASSERT(mPipeOutputStream);
   1521 
   1522  // From "Main Fetch" step 19: SRI-part2.
   1523  // Note: Avoid checking the hidden opaque body.
   1524  nsresult rv;
   1525  if (mResponse->Type() != ResponseType::Opaque &&
   1526      ShouldCheckSRI(*mRequest, *mResponse)) {
   1527    MOZ_ASSERT(mSRIDataVerifier);
   1528 
   1529    SRIVerifierAndOutputHolder holder(mSRIDataVerifier.get(),
   1530                                      mPipeOutputStream);
   1531    rv = aInputStream->ReadSegments(CopySegmentToStreamAndSRI, &holder, aCount,
   1532                                    &aRead);
   1533  } else {
   1534    rv = aInputStream->ReadSegments(NS_CopySegmentToStream, mPipeOutputStream,
   1535                                    aCount, &aRead);
   1536  }
   1537 
   1538  // If no data was read, it's possible the output stream is closed but the
   1539  // ReadSegments call followed its contract of returning NS_OK despite write
   1540  // errors.  Unfortunately, nsIOutputStream has an ill-conceived contract when
   1541  // taken together with ReadSegments' contract, because the pipe will just
   1542  // NS_OK if we try and invoke its Write* functions ourselves with a 0 count.
   1543  // So we must just assume the pipe is broken.
   1544  if (aRead == 0 && aCount != 0) {
   1545    return NS_BASE_STREAM_CLOSED;
   1546  }
   1547  return rv;
   1548 }
   1549 
   1550 NS_IMETHODIMP
   1551 FetchDriver::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
   1552  FETCH_LOG(("FetchDriver::OnStopRequest this=%p, request=%p", this, aRequest));
   1553  AssertIsOnMainThread();
   1554 
   1555  MOZ_DIAGNOSTIC_ASSERT(!mOnStopRequestCalled);
   1556  mOnStopRequestCalled = true;
   1557 
   1558  // main data loading is going to finish, breaking the reference cycle.
   1559  RefPtr<AlternativeDataStreamListener> altDataListener =
   1560      std::move(mAltDataListener);
   1561 
   1562  // For PFetch and ServiceWorker navigationPreload, resource timing should be
   1563  // reported before the body stream closing.
   1564  if (mObserver) {
   1565    mObserver->OnReportPerformanceTiming();
   1566  }
   1567 
   1568  // We need to check mObserver, which is nulled by FailWithNetworkError(),
   1569  // because in the case of "error" redirect mode, aStatusCode may be NS_OK but
   1570  // mResponse will definitely be null so we must not take the else branch.
   1571  if (NS_FAILED(aStatusCode) || !mObserver) {
   1572    nsCOMPtr<nsIAsyncOutputStream> outputStream =
   1573        do_QueryInterface(mPipeOutputStream);
   1574    if (outputStream) {
   1575      outputStream->CloseWithStatus(NS_FAILED(aStatusCode) ? aStatusCode
   1576                                                           : NS_BINDING_FAILED);
   1577    }
   1578    if (altDataListener) {
   1579      altDataListener->Cancel();
   1580    }
   1581 
   1582    // We proceed as usual here, since we've already created a successful
   1583    // response from OnStartRequest.
   1584  } else {
   1585    MOZ_ASSERT(mResponse);
   1586    MOZ_ASSERT(!mResponse->IsError());
   1587 
   1588    // From "Main Fetch" step 19: SRI-part3.
   1589    if (ShouldCheckSRI(*mRequest, *mResponse)) {
   1590      MOZ_ASSERT(mSRIDataVerifier);
   1591 
   1592      nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   1593 
   1594      nsIConsoleReportCollector* reporter = nullptr;
   1595      if (mObserver) {
   1596        reporter = mObserver->GetReporter();
   1597      }
   1598 
   1599      nsresult rv = mSRIDataVerifier->Verify(mSRIMetadata, channel, reporter);
   1600      if (NS_FAILED(rv)) {
   1601        if (altDataListener) {
   1602          altDataListener->Cancel();
   1603        }
   1604        FailWithNetworkError(rv);
   1605        // Cancel request.
   1606        return rv;
   1607      }
   1608    }
   1609 
   1610    if (mPipeOutputStream) {
   1611      mPipeOutputStream->Close();
   1612    }
   1613  }
   1614 
   1615  FinishOnStopRequest(altDataListener);
   1616  return NS_OK;
   1617 }
   1618 
   1619 void FetchDriver::FinishOnStopRequest(
   1620    AlternativeDataStreamListener* aAltDataListener) {
   1621  AssertIsOnMainThread();
   1622  // OnStopRequest is not called from channel, that means the main data loading
   1623  // does not finish yet. Reaching here since alternative data loading finishes.
   1624  if (!mOnStopRequestCalled) {
   1625    return;
   1626  }
   1627 
   1628  MOZ_DIAGNOSTIC_ASSERT(!mAltDataListener);
   1629  // Wait for alternative data loading finish if we needed it.
   1630  if (aAltDataListener &&
   1631      aAltDataListener->Status() == AlternativeDataStreamListener::LOADING) {
   1632    // For LOADING case, channel holds the reference of altDataListener, no need
   1633    // to restore it to mAltDataListener.
   1634    return;
   1635  }
   1636 
   1637  if (mObserver) {
   1638    // From "Main Fetch" step 19.1, 19.2: Process response.
   1639    if (ShouldCheckSRI(*mRequest, *mResponse)) {
   1640      MOZ_ASSERT(mResponse);
   1641      // Need to keep mObserver alive.
   1642      RefPtr<FetchDriverObserver> observer = mObserver;
   1643      observer->OnResponseAvailable(mResponse.clonePtr());
   1644 #ifdef DEBUG
   1645      mResponseAvailableCalled = true;
   1646 #endif
   1647    }
   1648  }
   1649 
   1650  if (mObserver) {
   1651    mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking,
   1652                             JS::UndefinedHandleValue);
   1653    mObserver = nullptr;
   1654  }
   1655 
   1656  mChannel = nullptr;
   1657  Unfollow();
   1658 }
   1659 
   1660 NS_IMETHODIMP
   1661 FetchDriver::ShouldPrepareForIntercept(nsIURI* aURI, nsIChannel* aChannel,
   1662                                       bool* aShouldIntercept) {
   1663  MOZ_ASSERT(aChannel);
   1664 
   1665  if (mInterceptController) {
   1666    MOZ_ASSERT(XRE_IsParentProcess());
   1667    return mInterceptController->ShouldPrepareForIntercept(aURI, aChannel,
   1668                                                           aShouldIntercept);
   1669  }
   1670 
   1671  nsCOMPtr<nsINetworkInterceptController> controller;
   1672  NS_QueryNotificationCallbacks(nullptr, mLoadGroup,
   1673                                NS_GET_IID(nsINetworkInterceptController),
   1674                                getter_AddRefs(controller));
   1675  if (controller) {
   1676    return controller->ShouldPrepareForIntercept(aURI, aChannel,
   1677                                                 aShouldIntercept);
   1678  }
   1679 
   1680  *aShouldIntercept = false;
   1681  return NS_OK;
   1682 }
   1683 
   1684 NS_IMETHODIMP
   1685 FetchDriver::ChannelIntercepted(nsIInterceptedChannel* aChannel) {
   1686  if (mInterceptController) {
   1687    MOZ_ASSERT(XRE_IsParentProcess());
   1688    return mInterceptController->ChannelIntercepted(aChannel);
   1689  }
   1690 
   1691  nsCOMPtr<nsINetworkInterceptController> controller;
   1692  NS_QueryNotificationCallbacks(nullptr, mLoadGroup,
   1693                                NS_GET_IID(nsINetworkInterceptController),
   1694                                getter_AddRefs(controller));
   1695  if (controller) {
   1696    return controller->ChannelIntercepted(aChannel);
   1697  }
   1698 
   1699  return NS_OK;
   1700 }
   1701 
   1702 void FetchDriver::EnableNetworkInterceptControl() {
   1703  MOZ_ASSERT(XRE_IsParentProcess());
   1704  MOZ_ASSERT(NS_IsMainThread());
   1705  MOZ_ASSERT(!mInterceptController);
   1706  mInterceptController = new ServiceWorkerInterceptController();
   1707 }
   1708 
   1709 NS_IMETHODIMP
   1710 FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
   1711                                    nsIChannel* aNewChannel, uint32_t aFlags,
   1712                                    nsIAsyncVerifyRedirectCallback* aCallback) {
   1713  nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(aOldChannel);
   1714  nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(aNewChannel);
   1715  if (oldHttpChannel && newHttpChannel) {
   1716    nsAutoCString method;
   1717    mRequest->GetMethod(method);
   1718 
   1719    // Fetch 4.4.11
   1720    bool rewriteToGET = false;
   1721    (void)oldHttpChannel->ShouldStripRequestBodyHeader(method, &rewriteToGET);
   1722 
   1723    // we need to strip Authentication headers for cross-origin requests
   1724    // Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch
   1725    bool skipAuthHeader =
   1726        NS_ShouldRemoveAuthHeaderOnRedirect(aOldChannel, aNewChannel, aFlags);
   1727 
   1728    SetRequestHeaders(newHttpChannel, rewriteToGET, skipAuthHeader);
   1729  }
   1730 
   1731  // "HTTP-redirect fetch": step 14 "Append locationURL to request's URL list."
   1732  // However, ignore internal redirects here.  We don't want to flip
   1733  // Response.redirected to true if an internal redirect occurs.  These
   1734  // should be transparent to script.
   1735  nsCOMPtr<nsIURI> uri;
   1736  MOZ_ALWAYS_SUCCEEDS(NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(uri)));
   1737 
   1738  nsCOMPtr<nsIURI> uriClone;
   1739  nsresult rv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
   1740  if (NS_WARN_IF(NS_FAILED(rv))) {
   1741    return rv;
   1742  }
   1743  nsCString spec;
   1744  rv = uriClone->GetSpec(spec);
   1745  if (NS_WARN_IF(NS_FAILED(rv))) {
   1746    return rv;
   1747  }
   1748  nsCString fragment;
   1749  rv = uri->GetRef(fragment);
   1750  if (NS_WARN_IF(NS_FAILED(rv))) {
   1751    return rv;
   1752  }
   1753 
   1754  if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
   1755    mRequest->AddURL(spec, fragment);
   1756  } else {
   1757    // Overwrite the URL only when the request is redirected by a service
   1758    // worker.
   1759    mRequest->SetURLForInternalRedirect(aFlags, spec, fragment);
   1760  }
   1761 
   1762  // In redirect, httpChannel already took referrer-policy into account, so
   1763  // updates request’s associated referrer policy from channel.
   1764  UpdateReferrerInfoFromNewChannel(aNewChannel);
   1765 
   1766  aCallback->OnRedirectVerifyCallback(NS_OK);
   1767  return NS_OK;
   1768 }
   1769 
   1770 NS_IMETHODIMP
   1771 FetchDriver::CheckListenerChain() { return NS_OK; }
   1772 
   1773 NS_IMETHODIMP
   1774 FetchDriver::OnDataFinished(nsresult) { return NS_OK; }
   1775 
   1776 NS_IMETHODIMP
   1777 FetchDriver::GetInterface(const nsIID& aIID, void** aResult) {
   1778  if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
   1779    *aResult = static_cast<nsIChannelEventSink*>(this);
   1780    NS_ADDREF_THIS();
   1781    return NS_OK;
   1782  }
   1783  if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
   1784    *aResult = static_cast<nsIStreamListener*>(this);
   1785    NS_ADDREF_THIS();
   1786    return NS_OK;
   1787  }
   1788  if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
   1789    *aResult = static_cast<nsIRequestObserver*>(this);
   1790    NS_ADDREF_THIS();
   1791    return NS_OK;
   1792  }
   1793 
   1794  return QueryInterface(aIID, aResult);
   1795 }
   1796 
   1797 void FetchDriver::SetDocument(Document* aDocument) {
   1798  // Cannot set document after Fetch() has been called.
   1799  MOZ_ASSERT(!mFetchCalled);
   1800  mDocument = aDocument;
   1801 }
   1802 
   1803 void FetchDriver::SetCSPEventListener(nsICSPEventListener* aCSPEventListener) {
   1804  MOZ_ASSERT(!mFetchCalled);
   1805  mCSPEventListener = aCSPEventListener;
   1806 }
   1807 
   1808 void FetchDriver::SetClientInfo(const ClientInfo& aClientInfo) {
   1809  MOZ_ASSERT(!mFetchCalled);
   1810  mClientInfo.emplace(aClientInfo);
   1811 }
   1812 
   1813 void FetchDriver::SetController(
   1814    const Maybe<ServiceWorkerDescriptor>& aController) {
   1815  MOZ_ASSERT(!mFetchCalled);
   1816  mController = aController;
   1817 }
   1818 
   1819 PerformanceTimingData* FetchDriver::GetPerformanceTimingData(
   1820    nsAString& aInitiatorType, nsAString& aEntryName) {
   1821  MOZ_ASSERT(XRE_IsParentProcess());
   1822  if (!mChannel) {
   1823    return nullptr;
   1824  }
   1825 
   1826  nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
   1827  if (!timedChannel) {
   1828    return nullptr;
   1829  }
   1830  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
   1831  if (!httpChannel) {
   1832    return nullptr;
   1833  }
   1834  return dom::PerformanceTimingData::Create(timedChannel, httpChannel, 0,
   1835                                            aInitiatorType, aEntryName);
   1836 }
   1837 
   1838 void FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel,
   1839                                    bool aStripRequestBodyHeader,
   1840                                    bool aStripAuthHeader) const {
   1841  MOZ_ASSERT(aChannel);
   1842 
   1843  // nsIHttpChannel has a set of pre-configured headers (Accept,
   1844  // Accept-Languages, ...) and we don't want to merge the Request's headers
   1845  // with them. This array is used to know if the current header has been aleady
   1846  // set, if yes, we ask necko to merge it with the previous one, otherwise, we
   1847  // don't want the merge.
   1848  nsTArray<nsCString> headersSet;
   1849 
   1850  AutoTArray<InternalHeaders::Entry, 5> headers;
   1851  mRequest->Headers()->GetEntries(headers);
   1852  for (uint32_t i = 0; i < headers.Length(); ++i) {
   1853    if (aStripRequestBodyHeader &&
   1854        (headers[i].mName.LowerCaseEqualsASCII("content-type") ||
   1855         headers[i].mName.LowerCaseEqualsASCII("content-encoding") ||
   1856         headers[i].mName.LowerCaseEqualsASCII("content-language") ||
   1857         headers[i].mName.LowerCaseEqualsASCII("content-location"))) {
   1858      continue;
   1859    }
   1860 
   1861    if (aStripAuthHeader &&
   1862        headers[i].mName.LowerCaseEqualsASCII("authorization")) {
   1863      continue;
   1864    }
   1865 
   1866    bool alreadySet = headersSet.Contains(headers[i].mName);
   1867    if (!alreadySet) {
   1868      headersSet.AppendElement(headers[i].mName);
   1869    }
   1870 
   1871    if (headers[i].mValue.IsEmpty()) {
   1872      DebugOnly<nsresult> rv =
   1873          aChannel->SetEmptyRequestHeader(headers[i].mName);
   1874      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1875    } else {
   1876      DebugOnly<nsresult> rv = aChannel->SetRequestHeader(
   1877          headers[i].mName, headers[i].mValue, alreadySet /* merge */);
   1878      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1879    }
   1880  }
   1881 }
   1882 
   1883 void FetchDriver::RunAbortAlgorithm() { FetchDriverAbortActions(Signal()); }
   1884 
   1885 void FetchDriver::FetchDriverAbortActions(AbortSignalImpl* aSignalImpl) {
   1886  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
   1887  RefPtr<FetchDriverObserver> observer;
   1888  {
   1889    MutexAutoLock lock(mODAMutex);
   1890    observer = std::move(mObserver);
   1891  }
   1892 
   1893  if (observer) {
   1894 #ifdef DEBUG
   1895    mResponseAvailableCalled = true;
   1896 #endif
   1897    JS::Rooted<JS::Value> reason(RootingCx());
   1898    if (aSignalImpl) {
   1899      reason.set(aSignalImpl->RawReason());
   1900    }
   1901    observer->OnResponseEnd(FetchDriverObserver::eAborted, reason);
   1902  }
   1903 
   1904  if (mChannel) {
   1905    mChannel->CancelWithReason(NS_BINDING_ABORTED,
   1906                               "FetchDriver::RunAbortAlgorithm"_ns);
   1907    mChannel = nullptr;
   1908  }
   1909 
   1910  mAborted = true;
   1911 }
   1912 
   1913 }  // namespace mozilla::dom