tor-browser

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

HttpChannelParent.cpp (79190B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et 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 // HttpLog.h should generally be included first
      8 #include "ErrorList.h"
      9 #include "HttpLog.h"
     10 
     11 #include "mozilla/ConsoleReportCollector.h"
     12 #include "mozilla/dom/BrowsingContext.h"
     13 #include "mozilla/ipc/IPCStreamUtils.h"
     14 #include "mozilla/net/EarlyHintRegistrar.h"
     15 #include "mozilla/net/HttpChannelParent.h"
     16 #include "mozilla/net/CacheEntryWriteHandleParent.h"
     17 #include "mozilla/dom/ContentParent.h"
     18 #include "mozilla/dom/ContentProcessManager.h"
     19 #include "mozilla/dom/Element.h"
     20 #include "mozilla/dom/ServiceWorkerUtils.h"
     21 #include "mozilla/dom/BrowserParent.h"
     22 #include "mozilla/dom/WindowGlobalParent.h"
     23 #include "mozilla/net/NeckoParent.h"
     24 #include "mozilla/net/ExecuteIfOnMainThreadEventTarget.h"
     25 #include "mozilla/net/CookieServiceParent.h"
     26 #include "nsIClassOfService.h"
     27 #include "mozilla/Components.h"
     28 #include "mozilla/InputStreamLengthHelper.h"
     29 #include "mozilla/IntegerPrintfMacros.h"
     30 #include "mozilla/ProfilerLabels.h"
     31 #include "mozilla/ProfilerMarkers.h"
     32 #include "mozilla/StaticPrefs_network.h"
     33 #include "mozilla/StoragePrincipalHelper.h"
     34 #include "HttpBackgroundChannelParent.h"
     35 #include "ParentChannelListener.h"
     36 #include "nsDebug.h"
     37 #include "nsICacheInfoChannel.h"
     38 #include "nsHttpHandler.h"
     39 #include "nsNetCID.h"
     40 #include "nsNetUtil.h"
     41 #include "nsISupportsPriority.h"
     42 #include "mozilla/net/BackgroundChannelRegistrar.h"
     43 #include "nsSerializationHelper.h"
     44 #include "nsISerializable.h"
     45 #include "mozilla/ipc/InputStreamUtils.h"
     46 #include "mozilla/ipc/URIUtils.h"
     47 #include "SerializedLoadContext.h"
     48 #include "nsIAuthPrompt.h"
     49 #include "nsIAuthPrompt2.h"
     50 #include "mozilla/ipc/BackgroundUtils.h"
     51 #include "mozilla/LoadInfo.h"
     52 #include "nsQueryObject.h"
     53 #include "mozilla/BasePrincipal.h"
     54 #include "nsCORSListenerProxy.h"
     55 #include "nsIIPCSerializableInputStream.h"
     56 #include "nsIPrompt.h"
     57 #include "nsIPromptFactory.h"
     58 #include "mozilla/net/ChannelEventQueue.h"
     59 #include "mozilla/net/RedirectChannelRegistrar.h"
     60 #include "nsIWindowWatcher.h"
     61 #include "mozilla/dom/Document.h"
     62 #include "nsISecureBrowserUI.h"
     63 #include "nsStreamUtils.h"
     64 #include "nsStringStream.h"
     65 #include "nsThreadUtils.h"
     66 #include "nsQueryObject.h"
     67 #include "nsIMultiPartChannel.h"
     68 #include "nsIViewSourceChannel.h"
     69 
     70 using namespace mozilla;
     71 
     72 namespace geckoprofiler::markers {
     73 
     74 struct ChannelMarker {
     75  static constexpr Span<const char> MarkerTypeName() {
     76    return MakeStringSpan("ChannelMarker");
     77  }
     78  static void StreamJSONMarkerData(
     79      mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
     80      const mozilla::ProfilerString8View& aURL, uint64_t aChannelId) {
     81    if (aURL.Length() != 0) {
     82      aWriter.StringProperty("url", aURL);
     83    }
     84    aWriter.IntProperty("channelId", static_cast<int64_t>(aChannelId));
     85  }
     86  static MarkerSchema MarkerTypeDisplay() {
     87    using MS = MarkerSchema;
     88    MS schema(MS::Location::MarkerChart, MS::Location::MarkerTable);
     89    schema.SetTableLabel("{marker.data.url}");
     90    schema.AddKeyFormat("url", MS::Format::Url, MS::PayloadFlags::Searchable);
     91    schema.AddStaticLabelValue(
     92        "Description",
     93        "Timestamp capturing various phases of a network channel's lifespan.");
     94    return schema;
     95  }
     96 };
     97 
     98 }  // namespace geckoprofiler::markers
     99 
    100 using mozilla::BasePrincipal;
    101 using namespace mozilla::dom;
    102 using namespace mozilla::ipc;
    103 
    104 namespace mozilla::net {
    105 
    106 HttpChannelParent::HttpChannelParent(dom::BrowserParent* iframeEmbedding,
    107                                     nsILoadContext* aLoadContext,
    108                                     PBOverrideStatus aOverrideStatus)
    109    : mLoadContext(aLoadContext),
    110      mIPCClosed(false),
    111      mPBOverride(aOverrideStatus),
    112      mStatus(NS_OK),
    113      mIgnoreProgress(false),
    114      mHasSuspendedByBackPressure(false),
    115      mCacheNeedFlowControlInitialized(false),
    116      mNeedFlowControl(true),
    117      mSuspendedForFlowControl(false),
    118      mAfterOnStartRequestBegun(false),
    119      mDataSentToChildProcess(false) {
    120  LOG(("Creating HttpChannelParent [this=%p]\n", this));
    121 
    122  // Ensure gHttpHandler is initialized: we need the atom table up and running.
    123  nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer =
    124      do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
    125 
    126  MOZ_ASSERT(gHttpHandler);
    127  mHttpHandler = gHttpHandler;
    128 
    129  mBrowserParent = iframeEmbedding;
    130 
    131  mSendWindowSize = gHttpHandler->SendWindowSize();
    132 
    133  mEventQ =
    134      new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this));
    135 }
    136 
    137 HttpChannelParent::~HttpChannelParent() {
    138  LOG(("Destroying HttpChannelParent [this=%p]\n", this));
    139  CleanupBackgroundChannel();
    140 
    141  MOZ_ASSERT(!mRedirectCallback);
    142  if (NS_WARN_IF(mRedirectCallback)) {
    143    mRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_UNEXPECTED);
    144    mRedirectCallback = nullptr;
    145  }
    146  mEventQ->NotifyReleasingOwner();
    147 }
    148 
    149 void HttpChannelParent::ActorDestroy(ActorDestroyReason why) {
    150  // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
    151  // yet, but child process has crashed.  We must not try to send any more msgs
    152  // to child, or IPDL will kill chrome process, too.
    153  mIPCClosed = true;
    154  CleanupBackgroundChannel();
    155 }
    156 
    157 bool HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) {
    158  LOG(("HttpChannelParent::Init [this=%p]\n", this));
    159  AUTO_PROFILER_LABEL("HttpChannelParent::Init", NETWORK);
    160  switch (aArgs.type()) {
    161    case HttpChannelCreationArgs::THttpChannelOpenArgs: {
    162      const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
    163      return DoAsyncOpen(
    164          a.uri(), a.original(), a.doc(), a.referrerInfo(), a.apiRedirectTo(),
    165          a.topWindowURI(), a.loadFlags(), a.requestHeaders(),
    166          a.requestMethod(), a.uploadStream(), a.uploadStreamHasHeaders(),
    167          a.priority(), a.classOfService(), a.redirectionLimit(), a.allowSTS(),
    168          a.thirdPartyFlags(), a.resumeAt(), a.startPos(), a.entityID(),
    169          a.allowSpdy(), a.allowHttp3(), a.allowAltSvc(), a.beConservative(),
    170          a.bypassProxy(), a.tlsFlags(), a.loadInfo(), a.cacheKey(),
    171          a.requestContextID(), a.preflightArgs(), a.initialRwin(),
    172          a.blockAuthPrompt(), a.allowStaleCacheContent(),
    173          a.preferCacheLoadOverBypass(), a.contentTypeHint(), a.requestMode(),
    174          a.redirectMode(), a.channelId(), a.contentWindowId(),
    175          a.preferredAlternativeTypes(), a.browserId(),
    176          a.launchServiceWorkerStart(), a.launchServiceWorkerEnd(),
    177          a.dispatchFetchEventStart(), a.dispatchFetchEventEnd(),
    178          a.handleFetchEventStart(), a.handleFetchEventEnd(),
    179          a.forceMainDocumentChannel(), a.navigationStartTimeStamp(),
    180          a.earlyHintPreloaderId(), a.classicScriptHintCharset(),
    181          a.documentCharacterSet(), a.isUserAgentHeaderModified(),
    182          a.initiatorType());
    183    }
    184    case HttpChannelCreationArgs::THttpChannelConnectArgs: {
    185      const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
    186      return ConnectChannel(cArgs.registrarId());
    187    }
    188    default:
    189      MOZ_ASSERT_UNREACHABLE("unknown open type");
    190      return false;
    191  }
    192 }
    193 
    194 void HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv) {
    195  LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32
    196       "]\n",
    197       this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv)));
    198  MOZ_ASSERT(NS_IsMainThread());
    199  AUTO_PROFILER_LABEL("HttpChannelParent::TryInvokeAsyncOpen", NETWORK);
    200 
    201  // TryInvokeAsyncOpen is called more than we expected.
    202  // Assert in nightly build but ignore it in release channel.
    203  MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0);
    204  if (NS_WARN_IF(!mAsyncOpenBarrier)) {
    205    return;
    206  }
    207 
    208  if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) {
    209    // Need to wait for more events.
    210    return;
    211  }
    212 
    213  InvokeAsyncOpen(aRv);
    214 }
    215 
    216 void HttpChannelParent::OnBackgroundParentReady(
    217    HttpBackgroundChannelParent* aBgParent) {
    218  LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n",
    219       this, aBgParent));
    220  MOZ_ASSERT(NS_IsMainThread());
    221  MOZ_ASSERT(!mBgParent);
    222 
    223  mBgParent = aBgParent;
    224 
    225  mPromise.ResolveIfExists(true, __func__);
    226 }
    227 
    228 void HttpChannelParent::OnBackgroundParentDestroyed() {
    229  LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this));
    230  MOZ_ASSERT(NS_IsMainThread());
    231 
    232  if (!mPromise.IsEmpty()) {
    233    MOZ_ASSERT(!mBgParent);
    234    mPromise.Reject(NS_ERROR_FAILURE, __func__);
    235    return;
    236  }
    237 
    238  if (!mBgParent) {
    239    return;
    240  }
    241 
    242  // Background channel is closed unexpectly, abort PHttpChannel operation.
    243  mBgParent = nullptr;
    244  Delete();
    245 }
    246 
    247 void HttpChannelParent::CleanupBackgroundChannel() {
    248  LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n",
    249       this, mBgParent.get()));
    250  MOZ_ASSERT(NS_IsMainThread());
    251 
    252  if (mBgParent) {
    253    RefPtr<HttpBackgroundChannelParent> bgParent = std::move(mBgParent);
    254    bgParent->OnChannelClosed();
    255    return;
    256  }
    257 
    258  // The nsHttpChannel may have a reference to this parent, release it
    259  // to avoid circular references.
    260  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
    261  if (httpChannelImpl) {
    262    httpChannelImpl->SetWarningReporter(nullptr);
    263  }
    264 
    265  if (!mPromise.IsEmpty()) {
    266    mRequest.DisconnectIfExists();
    267    mPromise.Reject(NS_ERROR_FAILURE, __func__);
    268 
    269    if (!mChannel) {
    270      return;
    271    }
    272 
    273    // This HttpChannelParent might still have a reference from
    274    // BackgroundChannelRegistrar.
    275    nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
    276        BackgroundChannelRegistrar::GetOrCreate();
    277    MOZ_ASSERT(registrar);
    278 
    279    registrar->DeleteChannel(mChannel->ChannelId());
    280 
    281    // If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure
    282    // is still on going. we need to abort AsyncOpen with failure to destroy
    283    // PHttpChannel actor.
    284    if (mAsyncOpenBarrier) {
    285      TryInvokeAsyncOpen(NS_ERROR_FAILURE);
    286    }
    287  }
    288 }
    289 
    290 base::ProcessId HttpChannelParent::OtherPid() const {
    291  if (mIPCClosed) {
    292    return 0;
    293  }
    294  return PHttpChannelParent::OtherPid();
    295 }
    296 
    297 //-----------------------------------------------------------------------------
    298 // HttpChannelParent::nsISupports
    299 //-----------------------------------------------------------------------------
    300 
    301 NS_IMPL_ADDREF(HttpChannelParent)
    302 NS_IMPL_RELEASE(HttpChannelParent)
    303 NS_INTERFACE_MAP_BEGIN(HttpChannelParent)
    304  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
    305  NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
    306  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
    307  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
    308  NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
    309  NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel)
    310  NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
    311  NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
    312  NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener)
    313  NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannelListener)
    314  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel)
    315  NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent)
    316 NS_INTERFACE_MAP_END
    317 
    318 //-----------------------------------------------------------------------------
    319 // HttpChannelParent::nsIInterfaceRequestor
    320 //-----------------------------------------------------------------------------
    321 
    322 NS_IMETHODIMP
    323 HttpChannelParent::GetInterface(const nsIID& aIID, void** result) {
    324  // A system XHR can be created without reference to a window, hence mTabParent
    325  // may be null.  In that case we want to let the window watcher pick a prompt
    326  // directly.
    327  if (!mBrowserParent && (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
    328                          aIID.Equals(NS_GET_IID(nsIAuthPrompt2)))) {
    329    nsresult rv;
    330    nsCOMPtr<nsIWindowWatcher> wwatch;
    331    wwatch = mozilla::components::WindowWatcher::Service(&rv);
    332    NS_ENSURE_SUCCESS(rv, NS_ERROR_NO_INTERFACE);
    333 
    334    bool hasWindowCreator = false;
    335    (void)wwatch->HasWindowCreator(&hasWindowCreator);
    336    if (!hasWindowCreator) {
    337      return NS_ERROR_NO_INTERFACE;
    338    }
    339 
    340    nsCOMPtr<nsIPromptFactory> factory = do_QueryInterface(wwatch);
    341    if (!factory) {
    342      return NS_ERROR_NO_INTERFACE;
    343    }
    344    rv = factory->GetPrompt(nullptr, aIID, reinterpret_cast<void**>(result));
    345    if (NS_FAILED(rv)) {
    346      return NS_ERROR_NO_INTERFACE;
    347    }
    348    return NS_OK;
    349  }
    350 
    351  // Only support nsILoadContext if child channel's callbacks did too
    352  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
    353    nsCOMPtr<nsILoadContext> copy = mLoadContext;
    354    copy.forget(result);
    355    return NS_OK;
    356  }
    357 
    358  return QueryInterface(aIID, result);
    359 }
    360 
    361 //-----------------------------------------------------------------------------
    362 // HttpChannelParent::PHttpChannelParent
    363 //-----------------------------------------------------------------------------
    364 
    365 void HttpChannelParent::AsyncOpenFailed(nsresult aRv) {
    366  MOZ_ASSERT(NS_IsMainThread());
    367  MOZ_ASSERT(NS_FAILED(aRv));
    368 
    369  // Break the reference cycle among HttpChannelParent,
    370  // ParentChannelListener, and nsHttpChannel to avoid memory leakage.
    371  mChannel = nullptr;
    372  mParentListener = nullptr;
    373 
    374  if (!mIPCClosed) {
    375    (void)SendFailedAsyncOpen(aRv);
    376  }
    377 }
    378 
    379 void HttpChannelParent::InvokeAsyncOpen(nsresult rv) {
    380  LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n", this,
    381       static_cast<uint32_t>(rv)));
    382  MOZ_ASSERT(NS_IsMainThread());
    383 
    384  if (NS_FAILED(rv)) {
    385    AsyncOpenFailed(rv);
    386    return;
    387  }
    388 
    389  rv = mChannel->AsyncOpen(mParentListener);
    390  if (NS_FAILED(rv)) {
    391    AsyncOpenFailed(rv);
    392  }
    393 }
    394 
    395 void HttpChannelParent::InvokeEarlyHintPreloader(
    396    nsresult rv, uint64_t aEarlyHintPreloaderId) {
    397  LOG(("HttpChannelParent::InvokeEarlyHintPreloader [this=%p rv=%" PRIx32 "]\n",
    398       this, static_cast<uint32_t>(rv)));
    399  MOZ_ASSERT(NS_IsMainThread());
    400 
    401  ContentParentId cpId =
    402      static_cast<ContentParent*>(Manager()->Manager())->ChildID();
    403 
    404  RefPtr<EarlyHintRegistrar> ehr = EarlyHintRegistrar::GetOrCreate();
    405  if (NS_SUCCEEDED(rv)) {
    406    rv = ehr->LinkParentChannel(cpId, aEarlyHintPreloaderId, this)
    407             ? NS_OK
    408             : NS_ERROR_FAILURE;
    409  }
    410 
    411  if (NS_FAILED(rv)) {
    412    ehr->DeleteEntry(cpId, aEarlyHintPreloaderId);
    413    AsyncOpenFailed(NS_ERROR_FAILURE);
    414  }
    415 }
    416 
    417 bool HttpChannelParent::DoAsyncOpen(
    418    nsIURI* aURI, nsIURI* aOriginalURI, nsIURI* aDocURI,
    419    nsIReferrerInfo* aReferrerInfo, nsIURI* aAPIRedirectToURI,
    420    nsIURI* aTopWindowURI, const uint32_t& aLoadFlags,
    421    const RequestHeaderTuples& requestHeaders, const nsCString& requestMethod,
    422    const Maybe<IPCStream>& uploadStream, const bool& uploadStreamHasHeaders,
    423    const int16_t& priority, const ClassOfService& classOfService,
    424    const uint8_t& redirectionLimit, const bool& allowSTS,
    425    const uint32_t& thirdPartyFlags, const bool& doResumeAt,
    426    const uint64_t& startPos, const nsCString& entityID, const bool& allowSpdy,
    427    const bool& allowHttp3, const bool& allowAltSvc, const bool& beConservative,
    428    const bool& bypassProxy, const uint32_t& tlsFlags,
    429    const LoadInfoArgs& aLoadInfoArgs, const uint32_t& aCacheKey,
    430    const uint64_t& aRequestContextID,
    431    const Maybe<CorsPreflightArgs>& aCorsPreflightArgs,
    432    const uint32_t& aInitialRwin, const bool& aBlockAuthPrompt,
    433    const bool& aAllowStaleCacheContent, const bool& aPreferCacheLoadOverBypass,
    434    const nsCString& aContentTypeHint, const dom::RequestMode& aRequestMode,
    435    const uint32_t& aRedirectMode, const uint64_t& aChannelId,
    436    const uint64_t& aContentWindowId,
    437    const nsTArray<PreferredAlternativeDataTypeParams>&
    438        aPreferredAlternativeTypes,
    439    const uint64_t& aBrowserId, const TimeStamp& aLaunchServiceWorkerStart,
    440    const TimeStamp& aLaunchServiceWorkerEnd,
    441    const TimeStamp& aDispatchFetchEventStart,
    442    const TimeStamp& aDispatchFetchEventEnd,
    443    const TimeStamp& aHandleFetchEventStart,
    444    const TimeStamp& aHandleFetchEventEnd,
    445    const bool& aForceMainDocumentChannel,
    446    const TimeStamp& aNavigationStartTimeStamp,
    447    const uint64_t& aEarlyHintPreloaderId,
    448    const nsAString& aClassicScriptHintCharset,
    449    const nsAString& aDocumentCharacterSet,
    450    const bool& aIsUserAgentHeaderModified, const nsString& aInitiatorType) {
    451  MOZ_ASSERT(aURI, "aURI should not be NULL");
    452 
    453  if (aEarlyHintPreloaderId) {
    454    // Wait for HttpBackgrounChannel to continue the async open procedure.
    455    mEarlyHintPreloaderId = aEarlyHintPreloaderId;
    456    RefPtr<HttpChannelParent> self = this;
    457    WaitForBgParent(aChannelId)
    458        ->Then(
    459            GetMainThreadSerialEventTarget(), __func__,
    460            [self, aEarlyHintPreloaderId]() {
    461              self->mRequest.Complete();
    462              self->InvokeEarlyHintPreloader(NS_OK, aEarlyHintPreloaderId);
    463            },
    464            [self, aEarlyHintPreloaderId](nsresult aStatus) {
    465              self->mRequest.Complete();
    466              self->InvokeEarlyHintPreloader(aStatus, aEarlyHintPreloaderId);
    467            })
    468        ->Track(mRequest);
    469    return true;
    470  }
    471 
    472  if (!aURI) {
    473    // this check is neccessary to prevent null deref
    474    // in opt builds
    475    return false;
    476  }
    477 
    478  LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64
    479       " browserid=%" PRIx64 "]\n",
    480       this, aURI->GetSpecOrDefault().get(), aChannelId, aBrowserId));
    481 
    482  PROFILER_MARKER("Receive AsyncOpen in Parent", NETWORK,
    483                  MarkerThreadId::MainThread(), ChannelMarker,
    484                  aURI->GetSpecOrDefault(), aChannelId);
    485 
    486  nsresult rv;
    487  nsAutoCString remoteType;
    488  rv = GetRemoteType(remoteType);
    489  if (NS_FAILED(rv)) {
    490    return SendFailedAsyncOpen(rv);
    491  }
    492 
    493  nsCOMPtr<nsILoadInfo> loadInfo;
    494  rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs, remoteType,
    495                                            getter_AddRefs(loadInfo));
    496  if (NS_FAILED(rv)) {
    497    return SendFailedAsyncOpen(rv);
    498  }
    499 
    500  nsCOMPtr<nsIChannel> channel;
    501  rv = mHttpHandler->NewProxiedChannel(aURI, nullptr, 0, nullptr, loadInfo,
    502                                       getter_AddRefs(channel));
    503  if (NS_FAILED(rv)) {
    504    return SendFailedAsyncOpen(rv);
    505  }
    506 
    507  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel, &rv);
    508  if (NS_FAILED(rv)) {
    509    return SendFailedAsyncOpen(rv);
    510  }
    511 
    512  // Set attributes needed to create a FetchEvent from this channel.
    513  httpChannel->SetRequestMode(aRequestMode);
    514  httpChannel->SetRedirectMode(aRedirectMode);
    515 
    516  // Set the channelId allocated in child to the parent instance
    517  httpChannel->SetChannelId(aChannelId);
    518  httpChannel->SetTopLevelContentWindowId(aContentWindowId);
    519  httpChannel->SetBrowserId(aBrowserId);
    520 
    521  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(httpChannel);
    522  if (httpChannelImpl) {
    523    httpChannelImpl->SetWarningReporter(this);
    524  }
    525  if (mPBOverride != kPBOverride_Unset) {
    526    httpChannel->SetPrivate(mPBOverride == kPBOverride_Private);
    527  }
    528 
    529  if (doResumeAt) httpChannel->ResumeAt(startPos, entityID);
    530 
    531  if (aOriginalURI) {
    532    httpChannel->SetOriginalURI(aOriginalURI);
    533  }
    534 
    535  if (aDocURI) {
    536    httpChannel->SetDocumentURI(aDocURI);
    537  }
    538 
    539  if (aReferrerInfo) {
    540    // Referrer header is computed in child no need to recompute here
    541    rv =
    542        httpChannel->SetReferrerInfoInternal(aReferrerInfo, false, false, true);
    543    MOZ_ASSERT(NS_SUCCEEDED(rv));
    544  }
    545 
    546  httpChannel->SetClassicScriptHintCharset(aClassicScriptHintCharset);
    547  httpChannel->SetDocumentCharacterSet(aDocumentCharacterSet);
    548 
    549  if (aAPIRedirectToURI) {
    550    httpChannel->RedirectTo(aAPIRedirectToURI);
    551  }
    552 
    553  if (aTopWindowURI) {
    554    httpChannel->SetTopWindowURI(aTopWindowURI);
    555  }
    556 
    557  if (aLoadFlags != nsIRequest::LOAD_NORMAL) {
    558    httpChannel->SetLoadFlags(aLoadFlags);
    559  }
    560 
    561  if (aForceMainDocumentChannel) {
    562    httpChannel->SetIsMainDocumentChannel(true);
    563  }
    564 
    565  for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
    566    if (requestHeaders[i].mEmpty) {
    567      httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
    568    } else {
    569      httpChannel->SetRequestHeader(requestHeaders[i].mHeader,
    570                                    requestHeaders[i].mValue,
    571                                    requestHeaders[i].mMerge);
    572    }
    573  }
    574 
    575  httpChannel->SetIsUserAgentHeaderModified(aIsUserAgentHeaderModified);
    576 
    577  httpChannel->SetInitiatorType(aInitiatorType);
    578 
    579  RefPtr<ParentChannelListener> parentListener = new ParentChannelListener(
    580      this, mBrowserParent ? mBrowserParent->GetBrowsingContext() : nullptr);
    581 
    582  httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
    583 
    584  if (aCorsPreflightArgs.isSome()) {
    585    const CorsPreflightArgs& args = aCorsPreflightArgs.ref();
    586    httpChannel->SetCorsPreflightParameters(args.unsafeHeaders(), false, false);
    587  }
    588 
    589  nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
    590  if (stream) {
    591    rv = httpChannel->InternalSetUploadStream(stream);
    592    if (NS_FAILED(rv)) {
    593      return SendFailedAsyncOpen(rv);
    594    }
    595 
    596    httpChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
    597  }
    598 
    599  nsCOMPtr<nsICacheInfoChannel> cacheChannel =
    600      do_QueryInterface(static_cast<nsIChannel*>(httpChannel.get()));
    601  if (cacheChannel) {
    602    cacheChannel->SetCacheKey(aCacheKey);
    603    for (const auto& data : aPreferredAlternativeTypes) {
    604      cacheChannel->PreferAlternativeDataType(data.type(), data.contentType(),
    605                                              data.deliverAltData());
    606    }
    607 
    608    cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
    609    cacheChannel->SetPreferCacheLoadOverBypass(aPreferCacheLoadOverBypass);
    610 
    611    // This is to mark that the results are going to the content process.
    612    if (httpChannelImpl) {
    613      httpChannelImpl->SetAltDataForChild(true);
    614    }
    615  }
    616 
    617  httpChannel->SetContentType(aContentTypeHint);
    618 
    619  if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
    620    httpChannel->SetPriority(priority);
    621  }
    622  if (classOfService.Flags() || classOfService.Incremental()) {
    623    httpChannel->SetClassOfService(classOfService);
    624  }
    625  httpChannel->SetRedirectionLimit(redirectionLimit);
    626  httpChannel->SetAllowSTS(allowSTS);
    627  httpChannel->SetThirdPartyFlags(thirdPartyFlags);
    628  httpChannel->SetAllowSpdy(allowSpdy);
    629  httpChannel->SetAllowHttp3(allowHttp3);
    630  httpChannel->SetAllowAltSvc(allowAltSvc);
    631  httpChannel->SetBeConservative(beConservative);
    632  httpChannel->SetTlsFlags(tlsFlags);
    633  httpChannel->SetInitialRwin(aInitialRwin);
    634  httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
    635 
    636  httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
    637  httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
    638  httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
    639  httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
    640  httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
    641  httpChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
    642 
    643  httpChannel->SetNavigationStartTimeStamp(aNavigationStartTimeStamp);
    644  httpChannel->SetRequestContextID(aRequestContextID);
    645 
    646  // Store the strong reference of channel and parent listener object until
    647  // all the initialization procedure is complete without failure, to remove
    648  // cycle reference in fail case and to avoid memory leakage.
    649  mChannel = std::move(httpChannel);
    650  mParentListener = std::move(parentListener);
    651  mChannel->SetNotificationCallbacks(mParentListener);
    652 
    653  MOZ_ASSERT(!mBgParent);
    654  MOZ_ASSERT(mPromise.IsEmpty());
    655  // Wait for HttpBackgroundChannel to continue the async open procedure.
    656  ++mAsyncOpenBarrier;
    657  RefPtr<HttpChannelParent> self = this;
    658  nsCOMPtr<nsISerialEventTarget> eventTarget = GetEventTargetForBgParentWait();
    659  WaitForBgParent(mChannel->ChannelId())
    660      ->Then(
    661          eventTarget, __func__,
    662          [self]() {
    663            self->mRequest.Complete();
    664            self->TryInvokeAsyncOpen(NS_OK);
    665          },
    666          [self](nsresult aStatus) {
    667            self->mRequest.Complete();
    668            self->TryInvokeAsyncOpen(aStatus);
    669          })
    670      ->Track(mRequest);
    671  return true;
    672 }
    673 
    674 RefPtr<GenericNonExclusivePromise> HttpChannelParent::WaitForBgParent(
    675    uint64_t aChannelId) {
    676  LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
    677  MOZ_ASSERT(!mBgParent);
    678 
    679  if (!mChannel && !mEarlyHintPreloaderId) {
    680    return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
    681                                                       __func__);
    682  }
    683 
    684  nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
    685      BackgroundChannelRegistrar::GetOrCreate();
    686  MOZ_ASSERT(registrar);
    687  registrar->LinkHttpChannel(aChannelId, this);
    688 
    689  if (mBgParent) {
    690    return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
    691  }
    692 
    693  return mPromise.Ensure(__func__);
    694 }
    695 
    696 bool HttpChannelParent::ConnectChannel(const uint32_t& registrarId) {
    697  nsresult rv;
    698 
    699  LOG(
    700      ("HttpChannelParent::ConnectChannel: Looking for a registered channel "
    701       "[this=%p, id=%" PRIu32 "]\n",
    702       this, registrarId));
    703  nsCOMPtr<nsIChannel> channel;
    704  rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(channel));
    705  if (NS_FAILED(rv)) {
    706    NS_WARNING("Could not find the http channel to connect its IPC parent");
    707    // This makes the channel delete itself safely.  It's the only thing
    708    // we can do now, since this parent channel cannot be used and there is
    709    // no other way to tell the child side there were something wrong.
    710    Delete();
    711    return true;
    712  }
    713 
    714  LOG(("  found channel %p, rv=%08" PRIx32, channel.get(),
    715       static_cast<uint32_t>(rv)));
    716  mChannel = do_QueryObject(channel);
    717  if (!mChannel) {
    718    LOG(("  but it's not HttpBaseChannel"));
    719    Delete();
    720    return true;
    721  }
    722 
    723  LOG(("  and it is HttpBaseChannel %p", mChannel.get()));
    724 
    725  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
    726  if (httpChannelImpl) {
    727    httpChannelImpl->SetWarningReporter(this);
    728  }
    729 
    730  if (mPBOverride != kPBOverride_Unset) {
    731    // redirected-to channel may not support PB
    732    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
    733    if (pbChannel) {
    734      pbChannel->SetPrivate(mPBOverride == kPBOverride_Private);
    735    }
    736  }
    737 
    738  MOZ_ASSERT(!mBgParent);
    739  MOZ_ASSERT(mPromise.IsEmpty());
    740  // Waiting for background channel
    741  RefPtr<HttpChannelParent> self = this;
    742  nsCOMPtr<nsISerialEventTarget> eventTarget = GetEventTargetForBgParentWait();
    743  WaitForBgParent(mChannel->ChannelId())
    744      ->Then(
    745          eventTarget, __func__, [self]() { self->mRequest.Complete(); },
    746          [self](const nsresult& aResult) {
    747            NS_ERROR("failed to establish the background channel");
    748            self->mRequest.Complete();
    749          })
    750      ->Track(mRequest);
    751  return true;
    752 }
    753 
    754 mozilla::ipc::IPCResult HttpChannelParent::RecvSetPriority(
    755    const int16_t& priority) {
    756  LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%d]\n", this,
    757       priority));
    758  AUTO_PROFILER_LABEL("HttpChannelParent::RecvSetPriority", NETWORK);
    759 
    760  if (mChannel) {
    761    mChannel->SetPriority(priority);
    762  }
    763 
    764  nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
    765      do_QueryInterface(mRedirectChannel);
    766  if (priorityRedirectChannel) priorityRedirectChannel->SetPriority(priority);
    767 
    768  return IPC_OK();
    769 }
    770 
    771 mozilla::ipc::IPCResult HttpChannelParent::RecvSetClassOfService(
    772    const ClassOfService& cos) {
    773  if (mChannel) {
    774    mChannel->SetClassOfService(cos);
    775  }
    776  return IPC_OK();
    777 }
    778 
    779 mozilla::ipc::IPCResult HttpChannelParent::RecvSuspend() {
    780  LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this));
    781 
    782  if (mChannel) {
    783    mChannel->Suspend();
    784  }
    785  return IPC_OK();
    786 }
    787 
    788 mozilla::ipc::IPCResult HttpChannelParent::RecvResume() {
    789  LOG(("HttpChannelParent::RecvResume [this=%p]\n", this));
    790 
    791  if (mChannel) {
    792    mChannel->Resume();
    793  }
    794  return IPC_OK();
    795 }
    796 
    797 mozilla::ipc::IPCResult HttpChannelParent::RecvCancel(
    798    const nsresult& status, const uint32_t& requestBlockingReason,
    799    const nsACString& reason, const mozilla::Maybe<nsCString>& logString) {
    800  LOG(("HttpChannelParent::RecvCancel [this=%p, reason=%s]\n", this,
    801       PromiseFlatCString(reason).get()));
    802 
    803  // logging child cancel reason on the parent side
    804  if (logString.isSome()) {
    805    LOG(("HttpChannelParent::RecvCancel: %s", logString->get()));
    806  }
    807 
    808  // May receive cancel before channel has been constructed!
    809  if (mChannel) {
    810    mChannel->CancelWithReason(status, reason);
    811 
    812    if (MOZ_UNLIKELY(requestBlockingReason !=
    813                     nsILoadInfo::BLOCKING_REASON_NONE)) {
    814      nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
    815      loadInfo->SetRequestBlockingReason(requestBlockingReason);
    816    }
    817 
    818    // Once we receive |Cancel|, child will stop sending RecvBytesRead. Force
    819    // the channel resumed if needed.
    820    if (mSuspendedForFlowControl) {
    821      LOG(("  resume the channel due to e10s backpressure relief by cancel"));
    822      (void)mChannel->Resume();
    823      mSuspendedForFlowControl = false;
    824    }
    825  } else if (!mIPCClosed) {
    826    // Make sure that the child correctly delivers all stream listener
    827    // notifications.
    828    (void)SendFailedAsyncOpen(status);
    829  }
    830 
    831  // We won't need flow control anymore. Toggle the flag to avoid |Suspend|
    832  // since OnDataAvailable could be off-main-thread.
    833  mCacheNeedFlowControlInitialized = true;
    834  mNeedFlowControl = false;
    835 
    836  // If the channel is cancelled before the redirect is completed
    837  // RecvRedirect2Verify will not be called, so we must clear the callback.
    838  if (mRedirectCallback) {
    839    mRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_UNEXPECTED);
    840    mRedirectCallback = nullptr;
    841  }
    842 
    843  return IPC_OK();
    844 }
    845 
    846 mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify(
    847    const nsresult& aResult, const RequestHeaderTuples& changedHeaders,
    848    const uint32_t& aSourceRequestBlockingReason,
    849    const Maybe<ChildLoadInfoForwarderArgs>& aTargetLoadInfoForwarder,
    850    const uint32_t& loadFlags, nsIReferrerInfo* aReferrerInfo,
    851    nsIURI* aAPIRedirectURI,
    852    const Maybe<CorsPreflightArgs>& aCorsPreflightArgs) {
    853  LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
    854       this, static_cast<uint32_t>(aResult)));
    855 
    856  // Result from the child.  If something fails here, we might overwrite a
    857  // success with a further failure.
    858  nsresult result = aResult;
    859 
    860  // Local results.
    861  nsresult rv;
    862 
    863  if (NS_SUCCEEDED(result)) {
    864    nsCOMPtr<nsIHttpChannel> newHttpChannel =
    865        do_QueryInterface(mRedirectChannel);
    866 
    867    if (newHttpChannel) {
    868      if (aAPIRedirectURI) {
    869        rv = newHttpChannel->RedirectTo(aAPIRedirectURI);
    870        MOZ_ASSERT(NS_SUCCEEDED(rv));
    871      }
    872 
    873      for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
    874        if (changedHeaders[i].mEmpty) {
    875          rv = newHttpChannel->SetEmptyRequestHeader(changedHeaders[i].mHeader);
    876        } else {
    877          rv = newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
    878                                                changedHeaders[i].mValue,
    879                                                changedHeaders[i].mMerge);
    880        }
    881        MOZ_ASSERT(NS_SUCCEEDED(rv));
    882      }
    883 
    884      // A successfully redirected channel must have the LOAD_REPLACE flag.
    885      MOZ_ASSERT(loadFlags & nsIChannel::LOAD_REPLACE);
    886      if (loadFlags & nsIChannel::LOAD_REPLACE) {
    887        newHttpChannel->SetLoadFlags(loadFlags);
    888      }
    889 
    890      if (aCorsPreflightArgs.isSome()) {
    891        nsCOMPtr<nsIHttpChannelInternal> newInternalChannel =
    892            do_QueryInterface(newHttpChannel);
    893        MOZ_RELEASE_ASSERT(newInternalChannel);
    894        const CorsPreflightArgs& args = aCorsPreflightArgs.ref();
    895        newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders(),
    896                                                       false, false);
    897      }
    898 
    899      if (aReferrerInfo) {
    900        RefPtr<HttpBaseChannel> baseChannel = do_QueryObject(newHttpChannel);
    901        MOZ_ASSERT(baseChannel);
    902        if (baseChannel) {
    903          // Referrer header is computed in child no need to recompute here
    904          rv = baseChannel->SetReferrerInfoInternal(aReferrerInfo, false, false,
    905                                                    true);
    906          MOZ_ASSERT(NS_SUCCEEDED(rv));
    907        }
    908      }
    909 
    910      if (aTargetLoadInfoForwarder.isSome()) {
    911        nsCOMPtr<nsILoadInfo> newLoadInfo = newHttpChannel->LoadInfo();
    912        rv = MergeChildLoadInfoForwarder(aTargetLoadInfoForwarder.ref(),
    913                                         newLoadInfo);
    914        if (NS_FAILED(rv) && NS_SUCCEEDED(result)) {
    915          result = rv;
    916        }
    917      }
    918    }
    919  }
    920 
    921  // If the redirect is vetoed, reason is set on the source (current) channel's
    922  // load info, so we must carry iver the change.
    923  // The channel may have already been cleaned up, so there is nothing we can
    924  // do.
    925  if (MOZ_UNLIKELY(aSourceRequestBlockingReason !=
    926                   nsILoadInfo::BLOCKING_REASON_NONE) &&
    927      mChannel) {
    928    nsCOMPtr<nsILoadInfo> sourceLoadInfo = mChannel->LoadInfo();
    929    sourceLoadInfo->SetRequestBlockingReason(aSourceRequestBlockingReason);
    930  }
    931 
    932  // Continue the verification procedure if child has veto the redirection.
    933  if (NS_FAILED(result)) {
    934    ContinueRedirect2Verify(result);
    935    return IPC_OK();
    936  }
    937 
    938  // Wait for background channel ready on target channel
    939  nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
    940      RedirectChannelRegistrar::GetOrCreate();
    941  MOZ_ASSERT(redirectReg);
    942 
    943  nsCOMPtr<nsIParentChannel> redirectParentChannel;
    944  rv = redirectReg->GetParentChannel(mRedirectChannelId,
    945                                     getter_AddRefs(redirectParentChannel));
    946  if (!redirectParentChannel) {
    947    ContinueRedirect2Verify(rv);
    948    return IPC_OK();
    949  }
    950 
    951  nsCOMPtr<nsIParentRedirectingChannel> redirectedParent =
    952      do_QueryInterface(redirectParentChannel);
    953  if (!redirectedParent) {
    954    // Continue verification procedure if redirecting to non-Http protocol
    955    ContinueRedirect2Verify(result);
    956    return IPC_OK();
    957  }
    958 
    959  // Ask redirected channel if verification can proceed.
    960  // ContinueRedirect2Verify will be invoked when redirected channel is ready.
    961  redirectedParent->ContinueVerification(this);
    962 
    963  return IPC_OK();
    964 }
    965 
    966 // from nsIParentRedirectingChannel
    967 NS_IMETHODIMP
    968 HttpChannelParent::ContinueVerification(
    969    nsIAsyncVerifyRedirectReadyCallback* aCallback) {
    970  LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n", this,
    971       aCallback));
    972 
    973  MOZ_ASSERT(NS_IsMainThread());
    974  MOZ_ASSERT(aCallback);
    975 
    976  // Continue the verification procedure if background channel is ready.
    977  if (mBgParent) {
    978    aCallback->ReadyToVerify(NS_OK);
    979    return NS_OK;
    980  }
    981 
    982  // ConnectChannel must be received before Redirect2Verify.
    983  MOZ_ASSERT(!mPromise.IsEmpty());
    984 
    985  // Otherwise, wait for the background channel.
    986  nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback;
    987  if (mChannel) {
    988    nsCOMPtr<nsISerialEventTarget> eventTarget =
    989        GetEventTargetForBgParentWait();
    990    WaitForBgParent(mChannel->ChannelId())
    991        ->Then(
    992            eventTarget, __func__,
    993            [callback]() { callback->ReadyToVerify(NS_OK); },
    994            [callback](const nsresult& aResult) {
    995              NS_ERROR("failed to establish the background channel");
    996              callback->ReadyToVerify(aResult);
    997            });
    998  } else {
    999    // mChannel can be null for several reasons (AsyncOpenFailed, etc)
   1000    NS_ERROR("No channel for ContinueVerification");
   1001    GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
   1002        __func__, [callback] { callback->ReadyToVerify(NS_ERROR_FAILURE); }));
   1003  }
   1004  return NS_OK;
   1005 }
   1006 
   1007 void HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult) {
   1008  LOG(
   1009      ("HttpChannelParent::ContinueRedirect2Verify "
   1010       "[this=%p result=%" PRIx32 "]\n",
   1011       this, static_cast<uint32_t>(aResult)));
   1012 
   1013  if (mRedirectCallback) {
   1014    LOG(
   1015        ("HttpChannelParent::ContinueRedirect2Verify call "
   1016         "OnRedirectVerifyCallback"
   1017         " [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n",
   1018         this, static_cast<uint32_t>(aResult), mRedirectCallback.get()));
   1019    mRedirectCallback->OnRedirectVerifyCallback(aResult);
   1020    mRedirectCallback = nullptr;
   1021  } else {
   1022    LOG(
   1023        ("RecvRedirect2Verify[%p]: NO CALLBACKS! | "
   1024         "mRedirectChannelId: %" PRIx64 ", mRedirectChannel: %p",
   1025         this, mRedirectChannelId, mRedirectChannel.get()));
   1026  }
   1027 }
   1028 
   1029 mozilla::ipc::IPCResult HttpChannelParent::RecvDocumentChannelCleanup(
   1030    const bool& clearCacheEntry) {
   1031  CleanupBackgroundChannel();  // Background channel can be closed.
   1032  mChannel = nullptr;          // Reclaim some memory sooner.
   1033  if (clearCacheEntry) {
   1034    mCacheEntry = nullptr;  // Else we'll block other channels reading same URI
   1035  }
   1036  return IPC_OK();
   1037 }
   1038 
   1039 mozilla::ipc::IPCResult HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(
   1040    nsIURI* uri, const mozilla::ipc::PrincipalInfo& requestingPrincipal,
   1041    const OriginAttributes& originAttributes) {
   1042  if (!uri) {
   1043    return IPC_FAIL_NO_REASON(this);
   1044  }
   1045  auto principalOrErr = PrincipalInfoToPrincipal(requestingPrincipal);
   1046  if (NS_WARN_IF(principalOrErr.isErr())) {
   1047    return IPC_FAIL_NO_REASON(this);
   1048  }
   1049  nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
   1050  nsCORSListenerProxy::RemoveFromCorsPreflightCache(uri, principal,
   1051                                                    originAttributes);
   1052  return IPC_OK();
   1053 }
   1054 
   1055 mozilla::ipc::IPCResult HttpChannelParent::RecvSetCookies(
   1056    const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes,
   1057    nsIURI* aHost, const bool& aFromHttp, const bool& aIsThirdParty,
   1058    nsTArray<CookieStruct>&& aCookies) {
   1059  net::PCookieServiceParent* csParent =
   1060      LoneManagedOrNullAsserts(Manager()->ManagedPCookieServiceParent());
   1061  NS_ENSURE_TRUE(csParent, IPC_OK());
   1062 
   1063  auto* cs = static_cast<net::CookieServiceParent*>(csParent);
   1064 
   1065  BrowsingContext* browsingContext = nullptr;
   1066  if (mBrowserParent) {
   1067    browsingContext = mBrowserParent->GetBrowsingContext();
   1068  }
   1069 
   1070  return cs->SetCookies(nsCString(aBaseDomain), aOriginAttributes, aHost,
   1071                        aFromHttp, aIsThirdParty, aCookies, browsingContext);
   1072 }
   1073 
   1074 //-----------------------------------------------------------------------------
   1075 // HttpChannelParent::nsIRequestObserver
   1076 //-----------------------------------------------------------------------------
   1077 
   1078 static ResourceTimingStructArgs GetTimingAttributes(HttpBaseChannel* aChannel) {
   1079  ResourceTimingStructArgs args;
   1080  TimeStamp timeStamp;
   1081  aChannel->GetDomainLookupStart(&timeStamp);
   1082  args.domainLookupStart() = timeStamp;
   1083  aChannel->GetDomainLookupEnd(&timeStamp);
   1084  args.domainLookupEnd() = timeStamp;
   1085  aChannel->GetConnectStart(&timeStamp);
   1086  args.connectStart() = timeStamp;
   1087  aChannel->GetTcpConnectEnd(&timeStamp);
   1088  args.tcpConnectEnd() = timeStamp;
   1089  aChannel->GetSecureConnectionStart(&timeStamp);
   1090  args.secureConnectionStart() = timeStamp;
   1091  aChannel->GetConnectEnd(&timeStamp);
   1092  args.connectEnd() = timeStamp;
   1093  aChannel->GetRequestStart(&timeStamp);
   1094  args.requestStart() = timeStamp;
   1095  aChannel->GetResponseStart(&timeStamp);
   1096  args.responseStart() = timeStamp;
   1097  aChannel->GetResponseEnd(&timeStamp);
   1098  args.responseEnd() = timeStamp;
   1099  aChannel->GetAsyncOpen(&timeStamp);
   1100  args.fetchStart() = timeStamp;
   1101  aChannel->GetRedirectStart(&timeStamp);
   1102  args.redirectStart() = timeStamp;
   1103  aChannel->GetRedirectEnd(&timeStamp);
   1104  args.redirectEnd() = timeStamp;
   1105 
   1106  uint64_t size = 0;
   1107  aChannel->GetTransferSize(&size);
   1108  args.transferSize() = size;
   1109 
   1110  aChannel->GetEncodedBodySize(&size);
   1111  args.encodedBodySize() = size;
   1112 
   1113  aChannel->GetDecodedBodySize(&size);
   1114  args.decodedBodySize() = size;
   1115 
   1116  aChannel->GetCacheReadStart(&timeStamp);
   1117  args.cacheReadStart() = timeStamp;
   1118 
   1119  aChannel->GetCacheReadEnd(&timeStamp);
   1120  args.cacheReadEnd() = timeStamp;
   1121 
   1122  aChannel->GetTransactionPending(&timeStamp);
   1123  args.transactionPending() = timeStamp;
   1124  return args;
   1125 }
   1126 
   1127 NS_IMETHODIMP
   1128 HttpChannelParent::OnStartRequest(nsIRequest* aRequest) {
   1129  nsresult rv;
   1130 
   1131  LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n", this,
   1132       aRequest));
   1133  MOZ_ASSERT(NS_IsMainThread());
   1134 
   1135  Maybe<uint32_t> multiPartID;
   1136  bool isFirstPartOfMultiPart = false;
   1137  bool isLastPartOfMultiPart = false;
   1138  DebugOnly<bool> isMultiPart = false;
   1139 
   1140  RefPtr<HttpBaseChannel> chan = do_QueryObject(aRequest);
   1141  if (!chan) {
   1142    if (nsCOMPtr<nsIMultiPartChannel> multiPartChannel =
   1143            do_QueryInterface(aRequest)) {
   1144      isMultiPart = true;
   1145      nsCOMPtr<nsIChannel> baseChannel;
   1146      multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
   1147      chan = do_QueryObject(baseChannel);
   1148 
   1149      uint32_t partID = 0;
   1150      multiPartChannel->GetPartID(&partID);
   1151      multiPartID = Some(partID);
   1152      multiPartChannel->GetIsFirstPart(&isFirstPartOfMultiPart);
   1153      multiPartChannel->GetIsLastPart(&isLastPartOfMultiPart);
   1154    } else if (nsCOMPtr<nsIViewSourceChannel> viewSourceChannel =
   1155                   do_QueryInterface(aRequest)) {
   1156      chan = do_QueryObject(viewSourceChannel->GetInnerChannel());
   1157    }
   1158  }
   1159  MOZ_ASSERT(multiPartID || !isMultiPart, "Changed multi-part state?");
   1160 
   1161  if (!chan) {
   1162    LOG(("  aRequest is not HttpBaseChannel"));
   1163    NS_ERROR(
   1164        "Expecting only HttpBaseChannel as aRequest in "
   1165        "HttpChannelParent::OnStartRequest");
   1166    return NS_ERROR_UNEXPECTED;
   1167  }
   1168 
   1169  mAfterOnStartRequestBegun = true;
   1170 
   1171  // Todo: re-enable when bug 1589749 is fixed.
   1172  /*MOZ_ASSERT(mChannel == chan,
   1173             "HttpChannelParent getting OnStartRequest from a different "
   1174             "HttpBaseChannel instance");*/
   1175 
   1176  HttpChannelOnStartRequestArgs args;
   1177 
   1178  // Send down any permissions/cookies which are relevant to this URL if we are
   1179  // performing a document load. We can't do that if mIPCClosed is set.
   1180  if (!mIPCClosed) {
   1181    PContentParent* pcp = Manager()->Manager();
   1182    MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed");
   1183    DebugOnly<nsresult> rv =
   1184        static_cast<ContentParent*>(pcp)->AboutToLoadHttpDocumentForChild(
   1185            chan, &args.shouldWaitForOnStartRequestSent());
   1186    MOZ_ASSERT(NS_SUCCEEDED(rv));
   1187  }
   1188 
   1189  args.multiPartID() = multiPartID;
   1190  args.isFirstPartOfMultiPart() = isFirstPartOfMultiPart;
   1191  args.isLastPartOfMultiPart() = isLastPartOfMultiPart;
   1192 
   1193  args.cacheExpirationTime() = nsICacheEntry::NO_EXPIRATION_TIME;
   1194 
   1195  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(chan);
   1196 
   1197  if (httpChannelImpl) {
   1198    httpChannelImpl->IsFromCache(&args.isFromCache());
   1199    httpChannelImpl->GetCacheDisposition(&args.cacheDisposition());
   1200    httpChannelImpl->IsRacing(&args.isRacing());
   1201    httpChannelImpl->GetCacheEntryId(&args.cacheEntryId());
   1202    httpChannelImpl->GetCacheTokenFetchCount(&args.cacheFetchCount());
   1203    httpChannelImpl->GetCacheTokenExpirationTime(&args.cacheExpirationTime());
   1204    httpChannelImpl->GetProtocolVersion(args.protocolVersion());
   1205 
   1206    mDataSentToChildProcess = httpChannelImpl->DataSentToChildProcess();
   1207 
   1208    // If RCWN is enabled and cache wins, we can't use the ODA from socket
   1209    // process.
   1210    if (args.isRacing()) {
   1211      mDataSentToChildProcess =
   1212          httpChannelImpl->DataSentToChildProcess() && !args.isFromCache();
   1213    }
   1214    args.dataFromSocketProcess() = mDataSentToChildProcess;
   1215  }
   1216 
   1217  // Propagate whether or not conversion should occur from the parent-side
   1218  // channel to the child-side channel.  Then disable the parent-side
   1219  // conversion so that it only occurs in the child.
   1220  (void)chan->GetApplyConversion(&args.applyConversion());
   1221  chan->SetApplyConversion(false);
   1222 
   1223  // If we've already applied the conversion (as can happen if we installed
   1224  // a multipart converted), then don't apply it again on the child.
   1225  if (chan->HasAppliedConversion()) {
   1226    args.applyConversion() = false;
   1227  }
   1228 
   1229  chan->GetStatus(&args.channelStatus());
   1230 
   1231  // Keep the cache entry for future use when opening alternative streams.
   1232  // It could be already released by nsHttpChannel at that time.
   1233  nsCOMPtr<nsISupports> cacheEntry;
   1234 
   1235  if (httpChannelImpl) {
   1236    httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry));
   1237    mCacheEntry = do_QueryInterface(cacheEntry);
   1238    args.cacheEntryAvailable() = static_cast<bool>(mCacheEntry);
   1239 
   1240    httpChannelImpl->GetCacheKey(&args.cacheKey());
   1241    httpChannelImpl->GetAlternativeDataType(args.altDataType());
   1242  }
   1243 
   1244  args.altDataLength() = chan->GetAltDataLength();
   1245  args.deliveringAltData() = chan->IsDeliveringAltData();
   1246 
   1247  args.securityInfo() = SecurityInfo();
   1248 
   1249  chan->GetRedirectCount(&args.redirectCount());
   1250  chan->GetHasHTTPSRR(&args.hasHTTPSRR());
   1251 
   1252  chan->GetIsProxyUsed(&args.isProxyUsed());
   1253 
   1254  nsCOMPtr<nsILoadInfo> loadInfo = chan->LoadInfo();
   1255  mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo,
   1256                                                  &args.loadInfoForwarder());
   1257 
   1258  nsHttpResponseHead* responseHead = chan->GetResponseHead();
   1259  bool useResponseHead = !!responseHead;
   1260  nsHttpResponseHead cleanedUpResponseHead;
   1261 
   1262  if (responseHead &&
   1263      (responseHead->HasHeader(nsHttp::Set_Cookie) || multiPartID)) {
   1264    cleanedUpResponseHead = *responseHead;
   1265    cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie);
   1266    if (multiPartID) {
   1267      nsCOMPtr<nsIChannel> multiPartChannel = do_QueryInterface(aRequest);
   1268      // For the multipart channel, use the parsed subtype instead. Note that
   1269      // `chan` is the underlying base channel of the multipart channel in this
   1270      // case, which is different from `multiPartChannel`.
   1271      MOZ_ASSERT(multiPartChannel);
   1272      nsAutoCString contentType;
   1273      multiPartChannel->GetContentType(contentType);
   1274      cleanedUpResponseHead.SetContentType(contentType);
   1275    }
   1276    responseHead = &cleanedUpResponseHead;
   1277  }
   1278 
   1279  if (!responseHead) {
   1280    responseHead = &cleanedUpResponseHead;
   1281  }
   1282 
   1283  if (chan->ChannelBlockedByOpaqueResponse() &&
   1284      chan->CachedOpaqueResponseBlockingPref()) {
   1285    responseHead->ClearHeaders();
   1286  }
   1287 
   1288  chan->GetIsResolvedByTRR(&args.isResolvedByTRR());
   1289  chan->GetAllRedirectsSameOrigin(&args.allRedirectsSameOrigin());
   1290  chan->GetCrossOriginOpenerPolicy(&args.openerPolicy());
   1291  args.selfAddr() = chan->GetSelfAddr();
   1292  args.peerAddr() = chan->GetPeerAddr();
   1293  args.timing() = GetTimingAttributes(mChannel);
   1294  if (mOverrideReferrerInfo) {
   1295    args.overrideReferrerInfo() = ToRefPtr(std::move(mOverrideReferrerInfo));
   1296  }
   1297  args.cookieChanges().SwapElements(mCookieChanges);
   1298 
   1299  nsHttpRequestHead* requestHead = chan->GetRequestHead();
   1300  // !!! We need to lock headers and please don't forget to unlock them !!!
   1301  requestHead->Enter();
   1302 
   1303  nsHttpHeaderArray cleanedUpRequestHeaders;
   1304  bool cleanedUpRequest = false;
   1305  if (requestHead->HasHeader(nsHttp::Cookie)) {
   1306    cleanedUpRequestHeaders = requestHead->Headers();
   1307    cleanedUpRequestHeaders.ClearHeader(nsHttp::Cookie);
   1308    cleanedUpRequest = true;
   1309  }
   1310 
   1311  rv = NS_OK;
   1312 
   1313  nsCOMPtr<nsICacheEntry> altDataSource;
   1314  nsCOMPtr<nsICacheInfoChannel> cacheChannel =
   1315      do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
   1316  if (cacheChannel) {
   1317    for (const auto& pref : cacheChannel->PreferredAlternativeDataTypes()) {
   1318      if (pref.type() == args.altDataType() &&
   1319          pref.deliverAltData() ==
   1320              nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::
   1321                  SERIALIZE) {
   1322        altDataSource = mCacheEntry;
   1323        break;
   1324      }
   1325    }
   1326  }
   1327 
   1328  nsIRequest::TRRMode effectiveMode = nsIRequest::TRR_DEFAULT_MODE;
   1329  mChannel->GetEffectiveTRRMode(&effectiveMode);
   1330  args.effectiveTRRMode() = effectiveMode;
   1331 
   1332  TRRSkippedReason reason = TRRSkippedReason::TRR_UNSET;
   1333  mChannel->GetTrrSkipReason(&reason);
   1334  args.trrSkipReason() = reason;
   1335 
   1336  if (mIPCClosed) {
   1337    rv = NS_ERROR_UNEXPECTED;
   1338  } else {
   1339    nsHttpResponseHead newResponseHead = *responseHead;
   1340    if (!mBgParent->OnStartRequest(
   1341            std::move(newResponseHead), useResponseHead,
   1342            cleanedUpRequest ? cleanedUpRequestHeaders : requestHead->Headers(),
   1343            args, altDataSource, chan->GetOnStartRequestStartTime())) {
   1344      rv = NS_ERROR_UNEXPECTED;
   1345    }
   1346  }
   1347 
   1348  requestHead->Exit();
   1349 
   1350  // Need to wait for the cookies/permissions to content process, which is sent
   1351  // via PContent in AboutToLoadHttpFtpDocumentForChild. For multipart channel,
   1352  // send only one time since the cookies/permissions are the same.
   1353  if (NS_SUCCEEDED(rv) && args.shouldWaitForOnStartRequestSent() &&
   1354      multiPartID.valueOr(0) == 0) {
   1355    LOG(("HttpChannelParent::SendOnStartRequestSent\n"));
   1356    (void)SendOnStartRequestSent();
   1357  }
   1358 
   1359  return rv;
   1360 }
   1361 
   1362 NS_IMETHODIMP
   1363 HttpChannelParent::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
   1364  LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32
   1365       "]\n",
   1366       this, aRequest, static_cast<uint32_t>(aStatusCode)));
   1367  MOZ_ASSERT(NS_IsMainThread());
   1368 
   1369  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
   1370  if (httpChannelImpl) {
   1371    httpChannelImpl->SetWarningReporter(nullptr);
   1372  }
   1373 
   1374  nsHttpHeaderArray* responseTrailer = mChannel->GetResponseTrailers();
   1375 
   1376  nsTArray<ConsoleReportCollected> consoleReports;
   1377 
   1378  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(mChannel);
   1379  TimeStamp onStopRequestStart;
   1380  if (httpChannel) {
   1381    httpChannel->StealConsoleReports(consoleReports);
   1382    onStopRequestStart = httpChannel->GetOnStopRequestStartTime();
   1383  }
   1384 
   1385  // Either IPC channel is closed or background channel
   1386  // is ready to send OnStopRequest.
   1387  MOZ_ASSERT(mIPCClosed || mBgParent);
   1388 
   1389  if (mDataSentToChildProcess) {
   1390    if (mIPCClosed || !mBgParent ||
   1391        !mBgParent->OnConsoleReport(consoleReports)) {
   1392      return NS_ERROR_UNEXPECTED;
   1393    }
   1394    return NS_OK;
   1395  }
   1396 
   1397  // If we're handling a multi-part stream, then send this directly
   1398  // over PHttpChannel to make synchronization easier.
   1399  if (mIPCClosed || !mBgParent ||
   1400      !mBgParent->OnStopRequest(
   1401          aStatusCode, GetTimingAttributes(mChannel),
   1402          responseTrailer ? *responseTrailer : nsHttpHeaderArray(),
   1403          consoleReports, onStopRequestStart)) {
   1404    return NS_ERROR_UNEXPECTED;
   1405  }
   1406 
   1407  if (NeedFlowControl()) {
   1408    bool isLocal = false;
   1409    NetAddr peerAddr = mChannel->GetPeerAddr();
   1410 
   1411 #if defined(XP_UNIX)
   1412    // Unix-domain sockets are always local.
   1413    isLocal = (peerAddr.raw.family == PR_AF_LOCAL);
   1414 #endif
   1415 
   1416    isLocal = isLocal || peerAddr.IsLoopbackAddr();
   1417 
   1418    if (!isLocal) {
   1419      if (!mHasSuspendedByBackPressure) {
   1420        glean::network::back_pressure_suspension_rate
   1421            .EnumGet(
   1422                glean::network::BackPressureSuspensionRateLabel::eNotsuspended)
   1423            .Add();
   1424      } else {
   1425        glean::network::back_pressure_suspension_rate
   1426            .EnumGet(
   1427                glean::network::BackPressureSuspensionRateLabel::eSuspended)
   1428            .Add();
   1429 
   1430        // Only analyze non-local suspended cases, which we are interested in.
   1431        nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
   1432        glean::network::back_pressure_suspension_cp_type.AccumulateSingleSample(
   1433            loadInfo->InternalContentPolicyType());
   1434      }
   1435    } else {
   1436      if (!mHasSuspendedByBackPressure) {
   1437        glean::network::back_pressure_suspension_rate
   1438            .EnumGet(glean::network::BackPressureSuspensionRateLabel::
   1439                         eNotsuspendedlocal)
   1440            .Add();
   1441      } else {
   1442        glean::network::back_pressure_suspension_rate
   1443            .EnumGet(glean::network::BackPressureSuspensionRateLabel::
   1444                         eSuspendedlocal)
   1445            .Add();
   1446      }
   1447    }
   1448  }
   1449  return NS_OK;
   1450 }
   1451 
   1452 //-----------------------------------------------------------------------------
   1453 // HttpChannelParent::nsIMultiPartChannelListener
   1454 //-----------------------------------------------------------------------------
   1455 
   1456 NS_IMETHODIMP
   1457 HttpChannelParent::OnAfterLastPart(nsresult aStatus) {
   1458  LOG(("HttpChannelParent::OnAfterLastPart [this=%p]\n", this));
   1459  MOZ_ASSERT(NS_IsMainThread());
   1460 
   1461  // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
   1462  if (mIPCClosed) {
   1463    return NS_OK;
   1464  }
   1465 
   1466  // If IPC channel is open, background channel should be ready to send
   1467  // OnAfterLastPart.
   1468  MOZ_ASSERT(mBgParent);
   1469 
   1470  if (!mBgParent || !mBgParent->OnAfterLastPart(aStatus)) {
   1471    return NS_ERROR_UNEXPECTED;
   1472  }
   1473 
   1474  return NS_OK;
   1475 }
   1476 
   1477 //-----------------------------------------------------------------------------
   1478 // HttpChannelParent::nsIStreamListener
   1479 //-----------------------------------------------------------------------------
   1480 
   1481 NS_IMETHODIMP
   1482 HttpChannelParent::OnDataAvailable(nsIRequest* aRequest,
   1483                                   nsIInputStream* aInputStream,
   1484                                   uint64_t aOffset, uint32_t aCount) {
   1485  LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64
   1486       " count=%" PRIu32 "]\n",
   1487       this, aRequest, aOffset, aCount));
   1488  MOZ_ASSERT(NS_IsMainThread());
   1489 
   1490  if (mDataSentToChildProcess) {
   1491    uint32_t n;
   1492    return aInputStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &n);
   1493  }
   1494 
   1495  nsresult channelStatus = NS_OK;
   1496  mChannel->GetStatus(&channelStatus);
   1497 
   1498  nsresult transportStatus = NS_NET_STATUS_RECEIVING_FROM;
   1499  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
   1500  TimeStamp onDataAvailableStart = TimeStamp::Now();
   1501  if (httpChannelImpl) {
   1502    if (httpChannelImpl->IsReadingFromCache()) {
   1503      transportStatus = NS_NET_STATUS_READING;
   1504    }
   1505    onDataAvailableStart = httpChannelImpl->GetDataAvailableStartTime();
   1506  }
   1507 
   1508  nsCString data;
   1509  nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
   1510  if (NS_FAILED(rv)) {
   1511    return rv;
   1512  }
   1513 
   1514  // Either IPC channel is closed or background channel
   1515  // is ready to send OnTransportAndData.
   1516  MOZ_ASSERT(mIPCClosed || mBgParent);
   1517 
   1518  if (mIPCClosed || !mBgParent ||
   1519      !mBgParent->OnTransportAndData(channelStatus, transportStatus, aOffset,
   1520                                     aCount, data, onDataAvailableStart)) {
   1521    return NS_ERROR_UNEXPECTED;
   1522  }
   1523 
   1524  int32_t count = static_cast<int32_t>(aCount);
   1525 
   1526  if (NeedFlowControl()) {
   1527    // We're going to run out of sending window size
   1528    if (mSendWindowSize > 0 && mSendWindowSize <= count) {
   1529      MOZ_ASSERT(!mSuspendedForFlowControl);
   1530      LOG(("  suspend the channel due to e10s backpressure"));
   1531      (void)mChannel->Suspend();
   1532      mSuspendedForFlowControl = true;
   1533      mHasSuspendedByBackPressure = true;
   1534    } else if (!mResumedTimestamp.IsNull()) {
   1535      // Calculate the delay when the first packet arrived after resume
   1536      glean::network::back_pressure_suspension_delay_time.AccumulateRawDuration(
   1537          TimeStamp::Now() - mResumedTimestamp);
   1538      mResumedTimestamp = TimeStamp();
   1539    }
   1540    mSendWindowSize -= count;
   1541  }
   1542 
   1543  return NS_OK;
   1544 }
   1545 
   1546 // Get the appropriate event target for background parent operations based on
   1547 // the channel's class of service flags: Urgent channels use
   1548 // ExecuteIfOnMainThreadEventTarget to avoid the async main-thread dispatch
   1549 // overhead when already on the main thread. Non-urgent channels use the regular
   1550 // event queue to prevent head-of-line blocking that would delay other main
   1551 // thread events.
   1552 nsCOMPtr<nsISerialEventTarget>
   1553 HttpChannelParent::GetEventTargetForBgParentWait() {
   1554  uint32_t classOfServiceFlags = 0;
   1555  mChannel->GetClassFlags(&classOfServiceFlags);
   1556  return (classOfServiceFlags & nsIClassOfService::UrgentStart)
   1557             ? ExecuteIfOnMainThreadEventTarget::Get()
   1558             : GetMainThreadSerialEventTarget();
   1559 }
   1560 
   1561 bool HttpChannelParent::NeedFlowControl() {
   1562  if (mCacheNeedFlowControlInitialized) {
   1563    return mNeedFlowControl;
   1564  }
   1565 
   1566  int64_t contentLength = -1;
   1567 
   1568  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
   1569 
   1570  // By design, we won't trigger the flow control if
   1571  // a. pref-out
   1572  // b. the resource is from cache or partial cache
   1573  // c. the resource is small
   1574  // d. data will be sent from socket process to child process directly
   1575  // Note that we served the cached resource first for partical cache, which is
   1576  // ignored here since we only take the first ODA into consideration.
   1577  if (gHttpHandler->SendWindowSize() == 0 || !httpChannelImpl ||
   1578      httpChannelImpl->IsReadingFromCache() ||
   1579      NS_FAILED(httpChannelImpl->GetContentLength(&contentLength)) ||
   1580      contentLength < gHttpHandler->SendWindowSize() ||
   1581      mDataSentToChildProcess) {
   1582    mNeedFlowControl = false;
   1583  }
   1584  mCacheNeedFlowControlInitialized = true;
   1585  return mNeedFlowControl;
   1586 }
   1587 
   1588 mozilla::ipc::IPCResult HttpChannelParent::RecvBytesRead(
   1589    const int32_t& aCount) {
   1590  if (!NeedFlowControl()) {
   1591    return IPC_OK();
   1592  }
   1593 
   1594  LOG(("HttpChannelParent::RecvBytesRead [this=%p count=%" PRId32 "]\n", this,
   1595       aCount));
   1596 
   1597  if (mSendWindowSize <= 0 && mSendWindowSize + aCount > 0) {
   1598    MOZ_ASSERT(mSuspendedForFlowControl);
   1599    LOG(("  resume the channel due to e10s backpressure relief"));
   1600    (void)mChannel->Resume();
   1601    mSuspendedForFlowControl = false;
   1602 
   1603    mResumedTimestamp = TimeStamp::Now();
   1604  }
   1605  mSendWindowSize += aCount;
   1606  return IPC_OK();
   1607 }
   1608 
   1609 mozilla::ipc::IPCResult HttpChannelParent::RecvOpenOriginalCacheInputStream() {
   1610  if (mIPCClosed) {
   1611    return IPC_OK();
   1612  }
   1613  Maybe<IPCStream> ipcStream;
   1614  if (mCacheEntry) {
   1615    nsCOMPtr<nsIInputStream> inputStream;
   1616    nsresult rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(inputStream));
   1617    if (NS_SUCCEEDED(rv)) {
   1618      (void)mozilla::ipc::SerializeIPCStream(inputStream.forget(), ipcStream,
   1619                                             /* aAllowLazy */ false);
   1620    }
   1621  }
   1622 
   1623  (void)SendOriginalCacheInputStreamAvailable(ipcStream);
   1624  return IPC_OK();
   1625 }
   1626 
   1627 //-----------------------------------------------------------------------------
   1628 // HttpChannelParent::nsIProgressEventSink
   1629 //-----------------------------------------------------------------------------
   1630 
   1631 NS_IMETHODIMP
   1632 HttpChannelParent::OnProgress(nsIRequest* aRequest, int64_t aProgress,
   1633                              int64_t aProgressMax) {
   1634  LOG(("HttpChannelParent::OnProgress [this=%p progress=%" PRId64 "max=%" PRId64
   1635       "]\n",
   1636       this, aProgress, aProgressMax));
   1637  MOZ_ASSERT(NS_IsMainThread());
   1638 
   1639  // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
   1640  if (mIPCClosed) {
   1641    return NS_OK;
   1642  }
   1643 
   1644  // If it indicates this precedes OnDataAvailable, child can derive the value
   1645  // in ODA.
   1646  if (mIgnoreProgress) {
   1647    mIgnoreProgress = false;
   1648    return NS_OK;
   1649  }
   1650 
   1651  // If IPC channel is open, background channel should be ready to send
   1652  // OnProgress.
   1653  MOZ_ASSERT(mBgParent);
   1654 
   1655  // Send OnProgress events to the child for data upload progress notifications
   1656  // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
   1657  // LOAD_BACKGROUND set.
   1658  if (!mBgParent || !mBgParent->OnProgress(aProgress, aProgressMax)) {
   1659    return NS_ERROR_UNEXPECTED;
   1660  }
   1661 
   1662  return NS_OK;
   1663 }
   1664 
   1665 NS_IMETHODIMP
   1666 HttpChannelParent::OnStatus(nsIRequest* aRequest, nsresult aStatus,
   1667                            const char16_t* aStatusArg) {
   1668  LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n", this,
   1669       static_cast<uint32_t>(aStatus)));
   1670  MOZ_ASSERT(NS_IsMainThread());
   1671 
   1672  // If IPC channel is closed, there is nothing we can do. Just return NS_OK.
   1673  if (mIPCClosed) {
   1674    return NS_OK;
   1675  }
   1676 
   1677  // If this precedes OnDataAvailable, transportStatus will be derived in ODA.
   1678  if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
   1679      aStatus == NS_NET_STATUS_READING) {
   1680    // The transport status and progress generated by ODA will be coalesced
   1681    // into one IPC message. Therefore, we can ignore the next OnProgress event
   1682    // since it is generated by ODA as well.
   1683    mIgnoreProgress = true;
   1684    return NS_OK;
   1685  }
   1686 
   1687  // If IPC channel is open, background channel should be ready to send
   1688  // OnStatus.
   1689  MOZ_ASSERT(mIPCClosed || mBgParent);
   1690 
   1691  // Otherwise, send to child now
   1692  if (!mBgParent || !mBgParent->OnStatus(aStatus)) {
   1693    return NS_ERROR_UNEXPECTED;
   1694  }
   1695 
   1696  return NS_OK;
   1697 }
   1698 
   1699 //-----------------------------------------------------------------------------
   1700 // HttpChannelParent::nsIParentChannel
   1701 //-----------------------------------------------------------------------------
   1702 
   1703 NS_IMETHODIMP
   1704 HttpChannelParent::SetParentListener(ParentChannelListener* aListener) {
   1705  LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n", this,
   1706       aListener));
   1707  MOZ_ASSERT(aListener);
   1708  MOZ_ASSERT(!mParentListener,
   1709             "SetParentListener should only be called for "
   1710             "new HttpChannelParents after a redirect, when "
   1711             "mParentListener is null.");
   1712  mParentListener = aListener;
   1713  return NS_OK;
   1714 }
   1715 
   1716 NS_IMETHODIMP
   1717 HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
   1718                                            const nsACString& aProvider,
   1719                                            const nsACString& aFullHash) {
   1720  LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this));
   1721  if (!mIPCClosed) {
   1722    MOZ_ASSERT(mBgParent);
   1723    (void)mBgParent->OnSetClassifierMatchedInfo(aList, aProvider, aFullHash);
   1724  }
   1725  return NS_OK;
   1726 }
   1727 
   1728 NS_IMETHODIMP
   1729 HttpChannelParent::SetClassifierMatchedTrackingInfo(
   1730    const nsACString& aLists, const nsACString& aFullHashes) {
   1731  LOG(("HttpChannelParent::SetClassifierMatchedTrackingInfo [this=%p]\n",
   1732       this));
   1733  if (!mIPCClosed) {
   1734    MOZ_ASSERT(mBgParent);
   1735    (void)mBgParent->OnSetClassifierMatchedTrackingInfo(aLists, aFullHashes);
   1736  }
   1737  return NS_OK;
   1738 }
   1739 
   1740 NS_IMETHODIMP
   1741 HttpChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
   1742                                             bool aIsThirdParty) {
   1743  LOG(
   1744      ("HttpChannelParent::NotifyClassificationFlags "
   1745       "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n",
   1746       aClassificationFlags, static_cast<int>(aIsThirdParty), this));
   1747  if (!mIPCClosed) {
   1748    MOZ_ASSERT(mBgParent);
   1749    (void)mBgParent->OnNotifyClassificationFlags(aClassificationFlags,
   1750                                                 aIsThirdParty);
   1751  }
   1752  return NS_OK;
   1753 }
   1754 
   1755 NS_IMETHODIMP
   1756 HttpChannelParent::Delete() {
   1757  if (!mIPCClosed) (void)DoSendDeleteSelf();
   1758 
   1759  return NS_OK;
   1760 }
   1761 
   1762 NS_IMETHODIMP
   1763 HttpChannelParent::GetRemoteType(nsACString& aRemoteType) {
   1764  if (!CanSend()) {
   1765    return NS_ERROR_UNEXPECTED;
   1766  }
   1767 
   1768  dom::PContentParent* pcp = Manager()->Manager();
   1769  aRemoteType = static_cast<dom::ContentParent*>(pcp)->GetRemoteType();
   1770  return NS_OK;
   1771 }
   1772 
   1773 bool HttpChannelParent::IsRedirectDueToAuthRetry(uint32_t redirectFlags) {
   1774  return (redirectFlags & nsIChannelEventSink::REDIRECT_AUTH_RETRY);
   1775 }
   1776 
   1777 //-----------------------------------------------------------------------------
   1778 // HttpChannelParent::nsIParentRedirectingChannel
   1779 //-----------------------------------------------------------------------------
   1780 
   1781 NS_IMETHODIMP
   1782 HttpChannelParent::StartRedirect(nsIChannel* newChannel, uint32_t redirectFlags,
   1783                                 nsIAsyncVerifyRedirectCallback* callback) {
   1784  nsresult rv;
   1785 
   1786  LOG(("HttpChannelParent::StartRedirect [this=%p, newChannel=%p callback=%p]",
   1787       this, newChannel, callback));
   1788 
   1789  // Register the new channel and obtain id for it
   1790  nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
   1791      RedirectChannelRegistrar::GetOrCreate();
   1792  MOZ_ASSERT(registrar);
   1793 
   1794  mRedirectChannelId = nsContentUtils::GenerateLoadIdentifier();
   1795  rv = registrar->RegisterChannel(newChannel, mRedirectChannelId);
   1796  NS_ENSURE_SUCCESS(rv, rv);
   1797 
   1798  LOG(("Registered %p channel under id=%" PRIx64, newChannel,
   1799       mRedirectChannelId));
   1800 
   1801  if (mIPCClosed) {
   1802    return NS_BINDING_ABORTED;
   1803  }
   1804 
   1805  // If this is an internal redirect for service worker interception or
   1806  // internal redirect due to auth retries, then hide it from the child
   1807  // process.  The original e10s interception code was not designed with this
   1808  // in mind and its not necessary to replace the HttpChannelChild/Parent
   1809  // objects in this case.
   1810  if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
   1811    nsCOMPtr<nsIInterceptedChannel> oldIntercepted =
   1812        do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
   1813    nsCOMPtr<nsIInterceptedChannel> newIntercepted =
   1814        do_QueryInterface(newChannel);
   1815 
   1816    // 1. We only want to hide the special internal redirects from
   1817    // nsHttpChannel to InterceptedHttpChannel.
   1818    // 2. We want to allow through internal redirects
   1819    // initiated from the InterceptedHttpChannel even if they are to another
   1820    // InterceptedHttpChannel, except the interception reset, since
   1821    // corresponding HttpChannelChild/Parent objects can be reused for reset
   1822    // case.
   1823    // 3. If this is an internal redirect due to auth retry then we will
   1824    // hide it from the child process
   1825 
   1826    if ((!oldIntercepted && newIntercepted) ||
   1827        (oldIntercepted && !newIntercepted && oldIntercepted->IsReset()) ||
   1828        (IsRedirectDueToAuthRetry(redirectFlags))) {
   1829      // We need to move across the reserved and initial client information
   1830      // to the new channel.  Normally this would be handled by the child
   1831      // ClientChannelHelper, but that is not notified of this redirect since
   1832      // we're not propagating it back to the child process.
   1833      nsCOMPtr<nsILoadInfo> oldLoadInfo = mChannel->LoadInfo();
   1834 
   1835      nsCOMPtr<nsILoadInfo> newLoadInfo = newChannel->LoadInfo();
   1836 
   1837      Maybe<ClientInfo> reservedClientInfo(
   1838          oldLoadInfo->GetReservedClientInfo());
   1839      if (reservedClientInfo.isSome()) {
   1840        newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref());
   1841      }
   1842 
   1843      Maybe<ClientInfo> initialClientInfo(oldLoadInfo->GetInitialClientInfo());
   1844      if (initialClientInfo.isSome()) {
   1845        newLoadInfo->SetInitialClientInfo(initialClientInfo.ref());
   1846      }
   1847 
   1848      // If this is ServiceWorker fallback redirect, info HttpChannelChild to
   1849      // detach StreamFilters. Otherwise StreamFilters will be attached twice
   1850      // on the same HttpChannelChild when opening the new nsHttpChannel.
   1851      if (oldIntercepted) {
   1852        (void)DetachStreamFilters();
   1853      }
   1854 
   1855      // Re-link the HttpChannelParent to the new channel.
   1856      nsCOMPtr<nsIChannel> linkedChannel;
   1857      rv = NS_LinkRedirectChannels(mRedirectChannelId, this,
   1858                                   getter_AddRefs(linkedChannel));
   1859      NS_ENSURE_SUCCESS(rv, rv);
   1860      MOZ_ASSERT(linkedChannel == newChannel);
   1861 
   1862      // We immediately store the channel as our nested mChannel.
   1863      // None of the redirect IPC messaging takes place.
   1864      mChannel = do_QueryObject(newChannel);
   1865 
   1866      callback->OnRedirectVerifyCallback(NS_OK);
   1867      return NS_OK;
   1868    }
   1869  }
   1870 
   1871  // Sending down the original URI, because that is the URI we have
   1872  // to construct the channel from - this is the URI we've been actually
   1873  // redirected to.  URI of the channel may be an inner channel URI.
   1874  // URI of the channel will be reconstructed by the protocol handler
   1875  // on the child process, no need to send it then.
   1876  nsCOMPtr<nsIURI> newOriginalURI;
   1877  newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
   1878 
   1879  uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL;
   1880  MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadFlags(&newLoadFlags));
   1881 
   1882  nsCOMPtr<nsITransportSecurityInfo> securityInfo(SecurityInfo());
   1883 
   1884  // If the channel is a HTTP channel, we also want to inform the child
   1885  // about the parent's channelId attribute, so that both parent and child
   1886  // share the same ID. Useful for monitoring channel activity in devtools.
   1887  uint64_t channelId = 0;
   1888  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
   1889  if (httpChannel) {
   1890    rv = httpChannel->GetChannelId(&channelId);
   1891    NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED);
   1892  }
   1893 
   1894  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
   1895 
   1896  ParentLoadInfoForwarderArgs loadInfoForwarderArg;
   1897  mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo,
   1898                                                  &loadInfoForwarderArg);
   1899 
   1900  nsHttpResponseHead* responseHead = mChannel->GetResponseHead();
   1901 
   1902  nsHttpResponseHead cleanedUpResponseHead;
   1903  if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) {
   1904    cleanedUpResponseHead = *responseHead;
   1905    cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie);
   1906    responseHead = &cleanedUpResponseHead;
   1907  }
   1908 
   1909  if (!responseHead) {
   1910    responseHead = &cleanedUpResponseHead;
   1911  }
   1912 
   1913  if (!mIPCClosed) {
   1914    cleanedUpResponseHead = *responseHead;
   1915    if (!SendRedirect1Begin(mRedirectChannelId, newOriginalURI, newLoadFlags,
   1916                            redirectFlags, loadInfoForwarderArg,
   1917                            std::move(cleanedUpResponseHead), securityInfo,
   1918                            channelId, mChannel->GetPeerAddr(),
   1919                            GetTimingAttributes(mChannel))) {
   1920      return NS_BINDING_ABORTED;
   1921    }
   1922  }
   1923 
   1924  // Result is handled in RecvRedirect2Verify above
   1925 
   1926  mRedirectChannel = newChannel;
   1927  mRedirectCallback = callback;
   1928  return NS_OK;
   1929 }
   1930 
   1931 NS_IMETHODIMP
   1932 HttpChannelParent::CompleteRedirect(nsresult status) {
   1933  LOG(("HttpChannelParent::CompleteRedirect [this=%p status=0x%X]\n", this,
   1934       static_cast<uint32_t>(status)));
   1935 
   1936  // If this was an internal redirect for a service worker interception then
   1937  // we will not have a redirecting channel here.  Hide this redirect from
   1938  // the child.
   1939  if (!mRedirectChannel) {
   1940    return NS_OK;
   1941  }
   1942 
   1943  if (!mIPCClosed) {
   1944    // TODO: check return value: assume child dead if failed
   1945    if (NS_SUCCEEDED(status)) {
   1946      (void)SendRedirect3Complete();
   1947    } else {
   1948      (void)SendRedirectFailed(status);
   1949    }
   1950  }
   1951 
   1952  mRedirectChannel = nullptr;
   1953  return NS_OK;
   1954 }
   1955 
   1956 NS_IMPL_ADDREF(CacheEntryWriteHandleParent)
   1957 NS_IMPL_RELEASE(CacheEntryWriteHandleParent)
   1958 NS_INTERFACE_MAP_BEGIN(CacheEntryWriteHandleParent)
   1959  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1960  NS_INTERFACE_MAP_ENTRY(nsICacheEntryWriteHandle)
   1961 NS_INTERFACE_MAP_END
   1962 
   1963 CacheEntryWriteHandleParent::CacheEntryWriteHandleParent(
   1964    nsICacheEntry* aCacheEntry)
   1965    : mCacheEntry(aCacheEntry) {}
   1966 
   1967 NS_IMETHODIMP
   1968 CacheEntryWriteHandleParent::OpenAlternativeOutputStream(
   1969    const nsACString& type, int64_t predictedSize,
   1970    nsIAsyncOutputStream** _retval) {
   1971  if (!mCacheEntry) {
   1972    return NS_ERROR_NOT_AVAILABLE;
   1973  }
   1974 
   1975  nsresult rv =
   1976      mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval);
   1977  if (NS_SUCCEEDED(rv)) {
   1978    mCacheEntry->SetMetaDataElement("alt-data-from-child", "1");
   1979  }
   1980  return rv;
   1981 }
   1982 
   1983 CacheEntryWriteHandleParent* HttpChannelParent::AllocCacheEntryWriteHandle() {
   1984  return new CacheEntryWriteHandleParent(mCacheEntry);
   1985 }
   1986 
   1987 nsresult HttpChannelParent::OpenAlternativeOutputStream(
   1988    const nsACString& type, int64_t predictedSize,
   1989    nsIAsyncOutputStream** _retval) {
   1990  // We need to make sure the child does not call SendDocumentChannelCleanup()
   1991  // before opening the altOutputStream, because that clears mCacheEntry.
   1992  if (!mCacheEntry) {
   1993    return NS_ERROR_NOT_AVAILABLE;
   1994  }
   1995  nsresult rv =
   1996      mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval);
   1997  if (NS_SUCCEEDED(rv)) {
   1998    mCacheEntry->SetMetaDataElement("alt-data-from-child", "1");
   1999  }
   2000  return rv;
   2001 }
   2002 
   2003 already_AddRefed<nsITransportSecurityInfo> HttpChannelParent::SecurityInfo() {
   2004  if (!mChannel) {
   2005    return nullptr;
   2006  }
   2007  nsCOMPtr<nsITransportSecurityInfo> securityInfo;
   2008  mChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
   2009  return securityInfo.forget();
   2010 }
   2011 
   2012 bool HttpChannelParent::DoSendDeleteSelf() {
   2013  mIPCClosed = true;
   2014  bool rv = SendDeleteSelf();
   2015 
   2016  CleanupBackgroundChannel();
   2017 
   2018  return rv;
   2019 }
   2020 
   2021 mozilla::ipc::IPCResult HttpChannelParent::RecvDeletingChannel() {
   2022  // We need to ensure that the parent channel will not be sending any more IPC
   2023  // messages after this, as the child is going away. DoSendDeleteSelf will
   2024  // set mIPCClosed = true;
   2025  if (!DoSendDeleteSelf()) {
   2026    return IPC_FAIL_NO_REASON(this);
   2027  }
   2028  return IPC_OK();
   2029 }
   2030 
   2031 //-----------------------------------------------------------------------------
   2032 // HttpChannelSecurityWarningReporter
   2033 //-----------------------------------------------------------------------------
   2034 
   2035 nsresult HttpChannelParent::ReportSecurityMessage(
   2036    const nsAString& aMessageTag, const nsAString& aMessageCategory) {
   2037  if (mIPCClosed || NS_WARN_IF(!SendReportSecurityMessage(
   2038                        nsString(aMessageTag), nsString(aMessageCategory)))) {
   2039    return NS_ERROR_UNEXPECTED;
   2040  }
   2041  return NS_OK;
   2042 }
   2043 
   2044 //-----------------------------------------------------------------------------
   2045 // nsIAsyncVerifyRedirectReadyCallback
   2046 //-----------------------------------------------------------------------------
   2047 
   2048 NS_IMETHODIMP
   2049 HttpChannelParent::ReadyToVerify(nsresult aResult) {
   2050  LOG(("HttpChannelParent::ReadyToVerify [this=%p result=%" PRIx32 "]\n", this,
   2051       static_cast<uint32_t>(aResult)));
   2052  MOZ_ASSERT(NS_IsMainThread());
   2053 
   2054  ContinueRedirect2Verify(aResult);
   2055 
   2056  return NS_OK;
   2057 }
   2058 
   2059 void HttpChannelParent::DoSendSetPriority(int16_t aValue) {
   2060  if (!mIPCClosed) {
   2061    (void)SendSetPriority(aValue);
   2062  }
   2063 }
   2064 
   2065 void HttpChannelParent::DoSendReportLNAToConsole(
   2066    const NetAddr& aPeerAddr, const nsACString& aMessageType,
   2067    const nsACString& aPromptAction, const nsACString& aTopLevelSite) {
   2068  if (!mIPCClosed) {
   2069    (void)SendReportLNAToConsole(aPeerAddr, nsCString(aMessageType),
   2070                                 nsCString(aPromptAction),
   2071                                 nsCString(aTopLevelSite));
   2072  }
   2073 }
   2074 
   2075 nsresult HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage,
   2076                                                  const nsACString& aCategory,
   2077                                                  bool aIsWarning) {
   2078  if (mIPCClosed ||
   2079      NS_WARN_IF(!SendLogBlockedCORSRequest(
   2080          nsString(aMessage), nsCString(aCategory), aIsWarning))) {
   2081    return NS_ERROR_UNEXPECTED;
   2082  }
   2083  return NS_OK;
   2084 }
   2085 
   2086 nsresult HttpChannelParent::LogMimeTypeMismatch(const nsACString& aMessageName,
   2087                                                bool aWarning,
   2088                                                const nsAString& aURL,
   2089                                                const nsAString& aContentType) {
   2090  if (mIPCClosed || NS_WARN_IF(!SendLogMimeTypeMismatch(
   2091                        nsCString(aMessageName), aWarning, nsString(aURL),
   2092                        nsString(aContentType)))) {
   2093    return NS_ERROR_UNEXPECTED;
   2094  }
   2095  return NS_OK;
   2096 }
   2097 
   2098 //-----------------------------------------------------------------------------
   2099 // nsIChannelEventSink
   2100 //-----------------------------------------------------------------------------
   2101 
   2102 NS_IMETHODIMP
   2103 HttpChannelParent::AsyncOnChannelRedirect(
   2104    nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aRedirectFlags,
   2105    nsIAsyncVerifyRedirectCallback* aCallback) {
   2106  LOG(
   2107      ("HttpChannelParent::AsyncOnChannelRedirect [this=%p, old=%p, "
   2108       "new=%p, flags=%u]",
   2109       this, aOldChannel, aNewChannel, aRedirectFlags));
   2110 
   2111  return StartRedirect(aNewChannel, aRedirectFlags, aCallback);
   2112 }
   2113 
   2114 //-----------------------------------------------------------------------------
   2115 // nsIRedirectResultListener
   2116 //-----------------------------------------------------------------------------
   2117 
   2118 NS_IMETHODIMP
   2119 HttpChannelParent::OnRedirectResult(nsresult status) {
   2120  LOG(("HttpChannelParent::OnRedirectResult [this=%p, status=0x%X]", this,
   2121       static_cast<uint32_t>(status)));
   2122 
   2123  nsresult rv = NS_OK;
   2124 
   2125  nsCOMPtr<nsIParentChannel> redirectChannel;
   2126  if (mRedirectChannelId) {
   2127    nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
   2128        RedirectChannelRegistrar::GetOrCreate();
   2129    MOZ_ASSERT(registrar);
   2130 
   2131    rv = registrar->GetParentChannel(mRedirectChannelId,
   2132                                     getter_AddRefs(redirectChannel));
   2133    if (NS_FAILED(rv) || !redirectChannel) {
   2134      // Redirect might get canceled before we got AsyncOnChannelRedirect
   2135      LOG(("Registered parent channel not found under id=%" PRIx64,
   2136           mRedirectChannelId));
   2137 
   2138      nsCOMPtr<nsIChannel> newChannel;
   2139      rv = registrar->GetRegisteredChannel(mRedirectChannelId,
   2140                                           getter_AddRefs(newChannel));
   2141      MOZ_ASSERT(newChannel, "Already registered channel not found");
   2142 
   2143      if (NS_SUCCEEDED(rv)) {
   2144        newChannel->Cancel(NS_BINDING_ABORTED);
   2145      }
   2146    }
   2147 
   2148    // Release all previously registered channels, they are no longer need to be
   2149    // kept in the registrar from this moment.
   2150    registrar->DeregisterChannels(mRedirectChannelId);
   2151 
   2152    mRedirectChannelId = 0;
   2153  }
   2154 
   2155  if (!redirectChannel) {
   2156    if (NS_FAILED(rv)) {
   2157      status = rv;
   2158    } else {
   2159      status = NS_ERROR_NULL_POINTER;
   2160    }
   2161  }
   2162 
   2163  CompleteRedirect(status);
   2164 
   2165  if (NS_SUCCEEDED(status)) {
   2166    if (!SameCOMIdentity(redirectChannel,
   2167                         static_cast<nsIParentRedirectingChannel*>(this))) {
   2168      Delete();
   2169      mParentListener->SetListenerAfterRedirect(redirectChannel);
   2170      redirectChannel->SetParentListener(mParentListener);
   2171    }
   2172  } else if (redirectChannel) {
   2173    // Delete the redirect target channel: continue using old channel
   2174    redirectChannel->Delete();
   2175  }
   2176 
   2177  return NS_OK;
   2178 }
   2179 
   2180 void HttpChannelParent::OverrideReferrerInfoDuringBeginConnect(
   2181    nsIReferrerInfo* aReferrerInfo) {
   2182  MOZ_ASSERT(aReferrerInfo);
   2183  MOZ_ASSERT(!mAfterOnStartRequestBegun);
   2184 
   2185  mOverrideReferrerInfo = aReferrerInfo;
   2186 }
   2187 
   2188 auto HttpChannelParent::AttachStreamFilter(
   2189    Endpoint<extensions::PStreamFilterParent>&& aParentEndpoint,
   2190    Endpoint<extensions::PStreamFilterChild>&& aChildEndpoint)
   2191    -> RefPtr<ChildEndpointPromise> {
   2192  LOG(("HttpChannelParent::AttachStreamFilter [this=%p]", this));
   2193  MOZ_ASSERT(!mAfterOnStartRequestBegun);
   2194 
   2195  if (mIPCClosed) {
   2196    return ChildEndpointPromise::CreateAndReject(false, __func__);
   2197  }
   2198 
   2199  // If IPC channel is open, background channel should be ready to send
   2200  // SendAttachStreamFilter.
   2201  MOZ_ASSERT(mBgParent);
   2202  return InvokeAsync(mBgParent->GetBackgroundTarget(), mBgParent.get(),
   2203                     __func__, &HttpBackgroundChannelParent::AttachStreamFilter,
   2204                     std::move(aParentEndpoint), std::move(aChildEndpoint));
   2205 }
   2206 
   2207 auto HttpChannelParent::DetachStreamFilters() -> RefPtr<GenericPromise> {
   2208  LOG(("HttpChannelParent::DeattachStreamFilter [this=%p]", this));
   2209  MOZ_ASSERT(!mAfterOnStartRequestBegun);
   2210 
   2211  if (NS_WARN_IF(mIPCClosed)) {
   2212    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   2213  }
   2214 
   2215  MOZ_ASSERT(mBgParent);
   2216  return InvokeAsync(mBgParent->GetBackgroundTarget(), mBgParent.get(),
   2217                     __func__,
   2218                     &HttpBackgroundChannelParent::DetachStreamFilters);
   2219 }
   2220 
   2221 void HttpChannelParent::SetHttpChannelFromEarlyHintPreloader(
   2222    HttpBaseChannel* aChannel) {
   2223  MOZ_ASSERT(aChannel);
   2224  if (mChannel) {
   2225    MOZ_ASSERT(false, "SetHttpChannel called with mChannel aready set");
   2226    return;
   2227  }
   2228 
   2229  mChannel = aChannel;
   2230 }
   2231 
   2232 void HttpChannelParent::SetCookieChanges(nsTArray<CookieChange>&& aChanges) {
   2233  LOG(("HttpChannelParent::SetCookie [this=%p]", this));
   2234  MOZ_ASSERT(!mAfterOnStartRequestBegun);
   2235  MOZ_ASSERT(mCookieChanges.IsEmpty());
   2236 
   2237  // The loadGroup of the channel in the parent process could be null in the
   2238  // XPCShell content process test, see test_cookiejars_wrap.js. In this case,
   2239  // we cannot explicitly set the loadGroup for the parent channel because it's
   2240  // created from the content process. To workaround this, we add a testing pref
   2241  // to skip this check.
   2242  if (!StaticPrefs::
   2243          network_cookie_skip_browsing_context_check_in_parent_for_testing() &&
   2244      mChannel->IsBrowsingContextDiscarded()) {
   2245    return;
   2246  }
   2247  mCookieChanges.AppendElements(aChanges);
   2248 }
   2249 
   2250 }  // namespace mozilla::net