tor-browser

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

TRRServiceChannel.cpp (48814B)


      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 
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "TRRServiceChannel.h"
      9 
     10 #include "HttpLog.h"
     11 #include "AltServiceChild.h"
     12 #include "mozilla/glean/NetwerkMetrics.h"
     13 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     14 #include "mozilla/ScopeExit.h"
     15 #include "mozilla/StaticPrefs_network.h"
     16 #include "nsDNSPrefetch.h"
     17 #include "nsEscape.h"
     18 #include "nsHttpTransaction.h"
     19 #include "nsICancelable.h"
     20 #include "nsICachingChannel.h"
     21 #include "nsIProtocolProxyService2.h"
     22 #include "nsIOService.h"
     23 #include "nsISeekableStream.h"
     24 #include "nsURLHelper.h"
     25 #include "ProxyConfigLookup.h"
     26 #include "TRRLoadInfo.h"
     27 #include "ReferrerInfo.h"
     28 #include "TRR.h"
     29 #include "TRRService.h"
     30 
     31 namespace mozilla::net {
     32 
     33 NS_IMPL_ADDREF(TRRServiceChannel)
     34 
     35 // Because nsSupportsWeakReference isn't thread-safe we must ensure that
     36 // TRRServiceChannel is destroyed on the target thread. Any Release() called
     37 // on a different thread is dispatched to the target thread.
     38 bool TRRServiceChannel::DispatchRelease() {
     39  if (mCurrentEventTarget->IsOnCurrentThread()) {
     40    return false;
     41  }
     42 
     43  mCurrentEventTarget->Dispatch(
     44      NewNonOwningRunnableMethod("net::TRRServiceChannel::Release", this,
     45                                 &TRRServiceChannel::Release),
     46      NS_DISPATCH_NORMAL);
     47 
     48  return true;
     49 }
     50 
     51 NS_IMETHODIMP_(MozExternalRefCountType)
     52 TRRServiceChannel::Release() {
     53  nsrefcnt count = mRefCnt - 1;
     54  if (DispatchRelease()) {
     55    // Redispatched to the target thread.
     56    return count;
     57  }
     58 
     59  MOZ_ASSERT(0 != mRefCnt, "dup release");
     60  count = --mRefCnt;
     61  NS_LOG_RELEASE(this, count, "TRRServiceChannel");
     62 
     63  if (0 == count) {
     64    mRefCnt = 1;
     65    delete (this);
     66    return 0;
     67  }
     68 
     69  return count;
     70 }
     71 
     72 NS_INTERFACE_MAP_BEGIN(TRRServiceChannel)
     73  NS_INTERFACE_MAP_ENTRY(nsIRequest)
     74  NS_INTERFACE_MAP_ENTRY(nsIChannel)
     75  NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
     76  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
     77  NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     78  NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
     79  NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
     80  NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
     81  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     82  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     83  NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
     84  NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
     85  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     86  NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
     87  NS_INTERFACE_MAP_ENTRY_CONCRETE(TRRServiceChannel)
     88 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
     89 
     90 TRRServiceChannel::TRRServiceChannel()
     91    : HttpAsyncAborter<TRRServiceChannel>(this),
     92      mProxyRequest(nullptr, "TRRServiceChannel::mProxyRequest"),
     93      mCurrentEventTarget(GetCurrentSerialEventTarget()) {
     94  LOG(("TRRServiceChannel ctor [this=%p]\n", this));
     95 }
     96 
     97 TRRServiceChannel::~TRRServiceChannel() {
     98  LOG(("TRRServiceChannel dtor [this=%p]\n", this));
     99 }
    100 
    101 NS_IMETHODIMP TRRServiceChannel::SetCanceledReason(const nsACString& aReason) {
    102  return SetCanceledReasonImpl(aReason);
    103 }
    104 
    105 NS_IMETHODIMP TRRServiceChannel::GetCanceledReason(nsACString& aReason) {
    106  return GetCanceledReasonImpl(aReason);
    107 }
    108 
    109 NS_IMETHODIMP
    110 TRRServiceChannel::CancelWithReason(nsresult aStatus,
    111                                    const nsACString& aReason) {
    112  return CancelWithReasonImpl(aStatus, aReason);
    113 }
    114 
    115 NS_IMETHODIMP
    116 TRRServiceChannel::Cancel(nsresult status) {
    117  LOG(("TRRServiceChannel::Cancel [this=%p status=%" PRIx32 "]\n", this,
    118       static_cast<uint32_t>(status)));
    119  if (mCanceled) {
    120    LOG(("  ignoring; already canceled\n"));
    121    return NS_OK;
    122  }
    123 
    124  mCanceled = true;
    125  mStatus = status;
    126 
    127  nsCOMPtr<nsICancelable> proxyRequest;
    128  {
    129    auto req = mProxyRequest.Lock();
    130    proxyRequest.swap(*req);
    131  }
    132 
    133  if (proxyRequest) {
    134    NS_DispatchToMainThread(
    135        NS_NewRunnableFunction(
    136            "CancelProxyRequest",
    137            [proxyRequest, status]() { proxyRequest->Cancel(status); }),
    138        NS_DISPATCH_NORMAL);
    139  }
    140 
    141  CancelNetworkRequest(status);
    142  return NS_OK;
    143 }
    144 
    145 void TRRServiceChannel::CancelNetworkRequest(nsresult aStatus) {
    146  if (mTransaction) {
    147    nsresult rv = gHttpHandler->CancelTransaction(mTransaction, aStatus);
    148    if (NS_FAILED(rv)) {
    149      LOG(("failed to cancel the transaction\n"));
    150    }
    151  }
    152  if (mTransactionPump) mTransactionPump->Cancel(aStatus);
    153 }
    154 
    155 NS_IMETHODIMP
    156 TRRServiceChannel::Suspend() {
    157  LOG(("TRRServiceChannel::SuspendInternal [this=%p]\n", this));
    158 
    159  if (mTransactionPump) {
    160    return mTransactionPump->Suspend();
    161  }
    162 
    163  return NS_OK;
    164 }
    165 
    166 NS_IMETHODIMP
    167 TRRServiceChannel::Resume() {
    168  LOG(("TRRServiceChannel::Resume [this=%p]\n", this));
    169 
    170  if (mTransactionPump) {
    171    return mTransactionPump->Resume();
    172  }
    173 
    174  return NS_OK;
    175 }
    176 
    177 NS_IMETHODIMP
    178 TRRServiceChannel::GetSecurityInfo(nsITransportSecurityInfo** securityInfo) {
    179  NS_ENSURE_ARG_POINTER(securityInfo);
    180  *securityInfo = do_AddRef(mSecurityInfo).take();
    181  return NS_OK;
    182 }
    183 
    184 NS_IMETHODIMP
    185 TRRServiceChannel::AsyncOpen(nsIStreamListener* aListener) {
    186  NS_ENSURE_ARG_POINTER(aListener);
    187  NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS);
    188  NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED);
    189 
    190  if (mCanceled) {
    191    ReleaseListeners();
    192    return mStatus;
    193  }
    194 
    195  // HttpBaseChannel::MaybeWaitForUploadStreamNormalization can only be used on
    196  // main thread, so we can only return an error here.
    197 #ifdef NIGHTLY_BUILD
    198  MOZ_ASSERT(!LoadPendingUploadStreamNormalization());
    199 #endif
    200  if (LoadPendingUploadStreamNormalization()) {
    201    return NS_ERROR_FAILURE;
    202  }
    203 
    204  if (!gHttpHandler->Active()) {
    205    LOG(("  after HTTP shutdown..."));
    206    ReleaseListeners();
    207    return NS_ERROR_NOT_AVAILABLE;
    208  }
    209 
    210  nsresult rv = NS_CheckPortSafety(mURI);
    211  if (NS_FAILED(rv)) {
    212    ReleaseListeners();
    213    return rv;
    214  }
    215 
    216  StoreIsPending(true);
    217  StoreWasOpened(true);
    218 
    219  mListener = aListener;
    220 
    221  mAsyncOpenTime = TimeStamp::Now();
    222 
    223  rv = MaybeResolveProxyAndBeginConnect();
    224  if (NS_FAILED(rv)) {
    225    (void)AsyncAbort(rv);
    226  }
    227 
    228  return NS_OK;
    229 }
    230 
    231 nsresult TRRServiceChannel::MaybeResolveProxyAndBeginConnect() {
    232  nsresult rv;
    233 
    234  // The common case for HTTP channels is to begin proxy resolution and return
    235  // at this point. The only time we know mProxyInfo already is if we're
    236  // proxying a non-http protocol like ftp. We don't need to discover proxy
    237  // settings if we are never going to make a network connection.
    238  // If mConnectionInfo is already supplied, we don't need to do proxy
    239  // resolution again.
    240  if (!mProxyInfo && !mConnectionInfo &&
    241      !(mLoadFlags & (nsICachingChannel::LOAD_ONLY_FROM_CACHE |
    242                      nsICachingChannel::LOAD_NO_NETWORK_IO)) &&
    243      NS_SUCCEEDED(ResolveProxy())) {
    244    return NS_OK;
    245  }
    246 
    247  rv = BeginConnect();
    248  if (NS_FAILED(rv)) {
    249    (void)AsyncAbort(rv);
    250  }
    251 
    252  return NS_OK;
    253 }
    254 
    255 nsresult TRRServiceChannel::ResolveProxy() {
    256  LOG(("TRRServiceChannel::ResolveProxy [this=%p]\n", this));
    257  if (!NS_IsMainThread()) {
    258    return NS_DispatchToMainThread(
    259        NewRunnableMethod("TRRServiceChannel::ResolveProxy", this,
    260                          &TRRServiceChannel::ResolveProxy),
    261        NS_DISPATCH_NORMAL);
    262  }
    263 
    264  MOZ_ASSERT(NS_IsMainThread());
    265 
    266  // TODO: bug 1625171. Consider moving proxy resolution to socket process.
    267  RefPtr<TRRServiceChannel> self = this;
    268  nsCOMPtr<nsICancelable> proxyRequest;
    269  nsresult rv = ProxyConfigLookup::Create(
    270      [self](nsIProxyInfo* aProxyInfo, nsresult aStatus) {
    271        self->OnProxyAvailable(nullptr, nullptr, aProxyInfo, aStatus);
    272      },
    273      mURI, mProxyResolveFlags, getter_AddRefs(proxyRequest));
    274 
    275  if (NS_FAILED(rv)) {
    276    if (!mCurrentEventTarget->IsOnCurrentThread()) {
    277      return mCurrentEventTarget->Dispatch(
    278          NewRunnableMethod<nsresult>("TRRServiceChannel::AsyncAbort", this,
    279                                      &TRRServiceChannel::AsyncAbort, rv),
    280          NS_DISPATCH_NORMAL);
    281    }
    282  }
    283 
    284  {
    285    auto req = mProxyRequest.Lock();
    286    // We only set mProxyRequest if the channel hasn't already been cancelled
    287    // on another thread.
    288    if (!mCanceled) {
    289      *req = proxyRequest.forget();
    290    }
    291  }
    292 
    293  // If the channel has been cancelled, we go ahead and cancel the proxy
    294  // request right here.
    295  if (proxyRequest) {
    296    proxyRequest->Cancel(mStatus);
    297  }
    298 
    299  return rv;
    300 }
    301 
    302 NS_IMETHODIMP
    303 TRRServiceChannel::OnProxyAvailable(nsICancelable* request, nsIChannel* channel,
    304                                    nsIProxyInfo* pi, nsresult status) {
    305  LOG(("TRRServiceChannel::OnProxyAvailable [this=%p pi=%p status=%" PRIx32
    306       " mStatus=%" PRIx32 "]\n",
    307       this, pi, static_cast<uint32_t>(status),
    308       static_cast<uint32_t>(static_cast<nsresult>(mStatus))));
    309 
    310  if (!mCurrentEventTarget->IsOnCurrentThread()) {
    311    RefPtr<TRRServiceChannel> self = this;
    312    nsCOMPtr<nsIProxyInfo> info = pi;
    313    return mCurrentEventTarget->Dispatch(
    314        NS_NewRunnableFunction("TRRServiceChannel::OnProxyAvailable",
    315                               [self, info, status]() {
    316                                 self->OnProxyAvailable(nullptr, nullptr, info,
    317                                                        status);
    318                               }),
    319        NS_DISPATCH_NORMAL);
    320  }
    321 
    322  MOZ_ASSERT(mCurrentEventTarget->IsOnCurrentThread());
    323 
    324  {
    325    auto proxyRequest = mProxyRequest.Lock();
    326    *proxyRequest = nullptr;
    327  }
    328 
    329  nsresult rv;
    330 
    331  // If status is a failure code, then it means that we failed to resolve
    332  // proxy info.  That is a non-fatal error assuming it wasn't because the
    333  // request was canceled.  We just failover to DIRECT when proxy resolution
    334  // fails (failure can mean that the PAC URL could not be loaded).
    335 
    336  if (NS_SUCCEEDED(status)) mProxyInfo = pi;
    337 
    338  if (!gHttpHandler->Active()) {
    339    LOG(
    340        ("nsHttpChannel::OnProxyAvailable [this=%p] "
    341         "Handler no longer active.\n",
    342         this));
    343    rv = NS_ERROR_NOT_AVAILABLE;
    344  } else {
    345    rv = BeginConnect();
    346  }
    347 
    348  if (NS_FAILED(rv)) {
    349    (void)AsyncAbort(rv);
    350  }
    351  return rv;
    352 }
    353 
    354 nsresult TRRServiceChannel::BeginConnect() {
    355  LOG(("TRRServiceChannel::BeginConnect [this=%p]\n", this));
    356  nsresult rv;
    357 
    358  // Construct connection info object
    359  nsAutoCString host;
    360  nsAutoCString scheme;
    361  int32_t port = -1;
    362  bool isHttps = mURI->SchemeIs("https");
    363 
    364  rv = mURI->GetScheme(scheme);
    365  if (NS_SUCCEEDED(rv)) rv = mURI->GetAsciiHost(host);
    366  if (NS_SUCCEEDED(rv)) rv = mURI->GetPort(&port);
    367  if (NS_SUCCEEDED(rv)) rv = mURI->GetAsciiSpec(mSpec);
    368  if (NS_FAILED(rv)) {
    369    return rv;
    370  }
    371 
    372  // Just a warning here because some nsIURIs do not implement this method.
    373  (void)NS_WARN_IF(NS_FAILED(mURI->GetUsername(mUsername)));
    374 
    375  // Reject the URL if it doesn't specify a host
    376  if (host.IsEmpty()) {
    377    rv = NS_ERROR_MALFORMED_URI;
    378    return rv;
    379  }
    380  LOG(("host=%s port=%d\n", host.get(), port));
    381  LOG(("uri=%s\n", mSpec.get()));
    382 
    383  nsCOMPtr<nsProxyInfo> proxyInfo;
    384  if (mConnectionInfo) {
    385    proxyInfo = mConnectionInfo->ProxyInfo();
    386  } else if (mProxyInfo) {
    387    proxyInfo = do_QueryInterface(mProxyInfo);
    388  }
    389 
    390  mRequestHead.SetHTTPS(isHttps);
    391  mRequestHead.SetOrigin(scheme, host, port);
    392 
    393  gHttpHandler->MaybeAddAltSvcForTesting(mURI, mUsername, mPrivateBrowsing,
    394                                         mCallbacks, OriginAttributes());
    395 
    396  RefPtr<nsHttpConnectionInfo> connInfo = new nsHttpConnectionInfo(
    397      host, port, ""_ns, mUsername, proxyInfo, OriginAttributes(), isHttps);
    398  // TODO: Bug 1622778 for using AltService in socket process.
    399  StoreAllowAltSvc(XRE_IsParentProcess() && LoadAllowAltSvc());
    400  bool http2Allowed = !gHttpHandler->IsHttp2Excluded(connInfo);
    401  bool http3Allowed = Http3Allowed();
    402  if (!http3Allowed) {
    403    mCaps |= NS_HTTP_DISALLOW_HTTP3;
    404  }
    405 
    406  RefPtr<AltSvcMapping> mapping;
    407  if (LoadAllowAltSvc() &&  // per channel
    408      (http2Allowed || http3Allowed) && !(mLoadFlags & LOAD_FRESH_CONNECTION) &&
    409      AltSvcMapping::AcceptableProxy(proxyInfo) &&
    410      (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) &&
    411      (mapping = gHttpHandler->GetAltServiceMapping(
    412           scheme, host, port, mPrivateBrowsing, OriginAttributes(),
    413           http2Allowed, http3Allowed))) {
    414    LOG(("TRRServiceChannel %p Alt Service Mapping Found %s://%s:%d [%s]\n",
    415         this, scheme.get(), mapping->AlternateHost().get(),
    416         mapping->AlternatePort(), mapping->HashKey().get()));
    417 
    418    if (!(mLoadFlags & LOAD_ANONYMOUS) && !mPrivateBrowsing) {
    419      nsAutoCString altUsedLine(mapping->AlternateHost());
    420      bool defaultPort =
    421          mapping->AlternatePort() ==
    422          (isHttps ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT);
    423      if (!defaultPort) {
    424        altUsedLine.AppendLiteral(":");
    425        altUsedLine.AppendInt(mapping->AlternatePort());
    426      }
    427      rv = mRequestHead.SetHeader(nsHttp::Alternate_Service_Used, altUsedLine);
    428      MOZ_ASSERT(NS_SUCCEEDED(rv));
    429    }
    430 
    431    LOG(("TRRServiceChannel %p Using connection info from altsvc mapping",
    432         this));
    433    mapping->GetConnectionInfo(getter_AddRefs(mConnectionInfo), proxyInfo,
    434                               OriginAttributes());
    435    glean::http::transaction_use_altsvc
    436        .EnumGet(glean::http::TransactionUseAltsvcLabel::eTrue)
    437        .Add();
    438  } else if (mConnectionInfo) {
    439    LOG(("TRRServiceChannel %p Using channel supplied connection info", this));
    440  } else {
    441    LOG(("TRRServiceChannel %p Using default connection info", this));
    442 
    443    mConnectionInfo = connInfo;
    444    glean::http::transaction_use_altsvc
    445        .EnumGet(glean::http::TransactionUseAltsvcLabel::eFalse)
    446        .Add();
    447  }
    448 
    449  // Need to re-ask the handler, since mConnectionInfo may not be the connInfo
    450  // we used earlier
    451  if (gHttpHandler->IsHttp2Excluded(mConnectionInfo)) {
    452    StoreAllowSpdy(0);
    453    mCaps |= NS_HTTP_DISALLOW_SPDY;
    454    mConnectionInfo->SetNoSpdy(true);
    455  }
    456 
    457  // if this somehow fails we can go on without it
    458  (void)gHttpHandler->AddConnectionHeader(&mRequestHead, mCaps);
    459 
    460  // Adjust mCaps according to our request headers:
    461  //  - If "Connection: close" is set as a request header, then do not bother
    462  //    trying to establish a keep-alive connection.
    463  if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close")) {
    464    mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE);
    465  }
    466 
    467  // TRR requests should never be blocked.
    468  mCaps |= (NS_HTTP_LOAD_UNBLOCKED | NS_HTTP_URGENT_START);
    469  SetPriority(nsISupportsPriority::PRIORITY_HIGHEST);
    470 
    471  if (mCanceled) {
    472    return mStatus;
    473  }
    474 
    475  MaybeStartDNSPrefetch();
    476 
    477  rv = ContinueOnBeforeConnect();
    478  if (NS_FAILED(rv)) {
    479    return rv;
    480  }
    481 
    482  return NS_OK;
    483 }
    484 
    485 nsresult TRRServiceChannel::ContinueOnBeforeConnect() {
    486  LOG(("TRRServiceChannel::ContinueOnBeforeConnect [this=%p]\n", this));
    487 
    488  // ensure that we are using a valid hostname
    489  if (!net_IsValidDNSHost(nsDependentCString(mConnectionInfo->Origin()))) {
    490    return NS_ERROR_UNKNOWN_HOST;
    491  }
    492 
    493  if (LoadIsTRRServiceChannel()) {
    494    mCaps |= NS_HTTP_LARGE_KEEPALIVE;
    495    DisallowHTTPSRR(mCaps);
    496  }
    497 
    498  mCaps |= NS_HTTP_TRR_FLAGS_FROM_MODE(nsIRequest::GetTRRMode());
    499 
    500  // Finalize ConnectionInfo flags before SpeculativeConnect
    501  mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
    502  mConnectionInfo->SetPrivate(mPrivateBrowsing);
    503  mConnectionInfo->SetNoSpdy(mCaps & NS_HTTP_DISALLOW_SPDY);
    504  mConnectionInfo->SetBeConservative((mCaps & NS_HTTP_BE_CONSERVATIVE) ||
    505                                     LoadBeConservative());
    506  mConnectionInfo->SetTlsFlags(mTlsFlags);
    507  mConnectionInfo->SetIsTrrServiceChannel(LoadIsTRRServiceChannel());
    508  mConnectionInfo->SetTRRMode(nsIRequest::GetTRRMode());
    509  mConnectionInfo->SetIPv4Disabled(mCaps & NS_HTTP_DISABLE_IPV4);
    510  mConnectionInfo->SetIPv6Disabled(mCaps & NS_HTTP_DISABLE_IPV6);
    511 
    512  if (mLoadFlags & LOAD_FRESH_CONNECTION) {
    513    glean::networking::trr_connection_cycle_count.Get(TRRService::ProviderKey())
    514        .Add(1);
    515    nsresult rv =
    516        gHttpHandler->ConnMgr()->DoSingleConnectionCleanup(mConnectionInfo);
    517    LOG(
    518        ("TRRServiceChannel::BeginConnect "
    519         "DoSingleConnectionCleanup succeeded=%d %08x [this=%p]",
    520         NS_SUCCEEDED(rv), static_cast<uint32_t>(rv), this));
    521  }
    522 
    523  return Connect();
    524 }
    525 
    526 nsresult TRRServiceChannel::Connect() {
    527  LOG(("TRRServiceChannel::Connect [this=%p]\n", this));
    528 
    529  nsresult rv = SetupTransaction();
    530  if (NS_FAILED(rv)) {
    531    return rv;
    532  }
    533 
    534  rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
    535  if (NS_FAILED(rv)) {
    536    return rv;
    537  }
    538 
    539  return mTransaction->AsyncRead(this, getter_AddRefs(mTransactionPump));
    540 }
    541 
    542 nsresult TRRServiceChannel::SetupTransaction() {
    543  LOG((
    544      "TRRServiceChannel::SetupTransaction "
    545      "[this=%p, cos=%lu, inc=%d, prio=%d]\n",
    546      this, mClassOfService.Flags(), mClassOfService.Incremental(), mPriority));
    547 
    548  NS_ENSURE_TRUE(!mTransaction, NS_ERROR_ALREADY_INITIALIZED);
    549 
    550  nsresult rv;
    551 
    552  if (!LoadAllowSpdy()) {
    553    mCaps |= NS_HTTP_DISALLOW_SPDY;
    554  }
    555  // Check a proxy info from mConnectionInfo. TRR channel may use a proxy that
    556  // is set in mConnectionInfo but acutally the channel do not have mProxyInfo
    557  // set. This can happend when network.trr.async_connInfo is true.
    558  bool useNonDirectProxy = mConnectionInfo->ProxyInfo()
    559                               ? !mConnectionInfo->ProxyInfo()->IsDirect()
    560                               : false;
    561  if (!Http3Allowed() || useNonDirectProxy) {
    562    mCaps |= NS_HTTP_DISALLOW_HTTP3;
    563  }
    564  if (LoadBeConservative()) {
    565    mCaps |= NS_HTTP_BE_CONSERVATIVE;
    566  }
    567 
    568  // Use the URI path if not proxying (transparent proxying such as proxy
    569  // CONNECT does not count here). Also figure out what HTTP version to use.
    570  nsAutoCString buf, path;
    571  nsCString* requestURI;
    572 
    573  // This is the normal e2e H1 path syntax "/index.html"
    574  rv = mURI->GetPathQueryRef(path);
    575  if (NS_FAILED(rv)) {
    576    return rv;
    577  }
    578 
    579  // path may contain UTF-8 characters, so ensure that they're escaped.
    580  if (NS_EscapeURL(path.get(), path.Length(), esc_OnlyNonASCII | esc_Spaces,
    581                   buf)) {
    582    requestURI = &buf;
    583  } else {
    584    requestURI = &path;
    585  }
    586 
    587  // trim off the #ref portion if any...
    588  int32_t ref1 = requestURI->FindChar('#');
    589  if (ref1 != kNotFound) {
    590    requestURI->SetLength(ref1);
    591  }
    592 
    593  if (mConnectionInfo->UsingConnect() || !mConnectionInfo->UsingHttpProxy()) {
    594    mRequestHead.SetVersion(gHttpHandler->HttpVersion());
    595  } else {
    596    mRequestHead.SetPath(*requestURI);
    597 
    598    // RequestURI should be the absolute uri H1 proxy syntax
    599    // "http://foo/index.html" so we will overwrite the relative version in
    600    // requestURI
    601    rv = mURI->GetUserPass(buf);
    602    if (NS_FAILED(rv)) return rv;
    603    if (!buf.IsEmpty() && ((strncmp(mSpec.get(), "http:", 5) == 0) ||
    604                           strncmp(mSpec.get(), "https:", 6) == 0)) {
    605      nsCOMPtr<nsIURI> tempURI = nsIOService::CreateExposableURI(mURI);
    606      rv = tempURI->GetAsciiSpec(path);
    607      if (NS_FAILED(rv)) return rv;
    608      requestURI = &path;
    609    } else {
    610      requestURI = &mSpec;
    611    }
    612 
    613    // trim off the #ref portion if any...
    614    int32_t ref2 = requestURI->FindChar('#');
    615    if (ref2 != kNotFound) {
    616      requestURI->SetLength(ref2);
    617    }
    618 
    619    mRequestHead.SetVersion(gHttpHandler->ProxyHttpVersion());
    620  }
    621 
    622  mRequestHead.SetRequestURI(*requestURI);
    623 
    624  // Force setting no-cache header for TRRServiceChannel.
    625  // We need to send 'Pragma:no-cache' to inhibit proxy caching even if
    626  // no proxy is configured since we might be talking with a transparent
    627  // proxy, i.e. one that operates at the network level.  See bug #14772.
    628  rv = mRequestHead.SetHeaderOnce(nsHttp::Pragma, "no-cache", true);
    629  MOZ_ASSERT(NS_SUCCEEDED(rv));
    630  // If we're configured to speak HTTP/1.1 then also send 'Cache-control:
    631  // no-cache'
    632  if (mRequestHead.Version() >= HttpVersion::v1_1) {
    633    rv = mRequestHead.SetHeaderOnce(nsHttp::Cache_Control, "no-cache", true);
    634    MOZ_ASSERT(NS_SUCCEEDED(rv));
    635  }
    636 
    637  // create wrapper for this channel's notification callbacks
    638  nsCOMPtr<nsIInterfaceRequestor> callbacks;
    639  NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
    640                                         getter_AddRefs(callbacks));
    641 
    642  // create the transaction object
    643  mTransaction = new nsHttpTransaction();
    644  LOG1(("TRRServiceChannel %p created nsHttpTransaction %p\n", this,
    645        mTransaction.get()));
    646 
    647  // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
    648  if (mLoadFlags & LOAD_ANONYMOUS) mCaps |= NS_HTTP_LOAD_ANONYMOUS;
    649 
    650  EnsureRequestContext();
    651 
    652  struct LNAPerms perms{};
    653 
    654  rv = mTransaction->Init(
    655      mCaps, mConnectionInfo, &mRequestHead, mUploadStream, mReqContentLength,
    656      LoadUploadStreamHasHeaders(), mCurrentEventTarget, callbacks, this,
    657      mBrowserId, HttpTrafficCategory::eInvalid, mRequestContext,
    658      mClassOfService, mInitialRwin, LoadResponseTimeoutEnabled(), mChannelId,
    659      nullptr, nsILoadInfo::IPAddressSpace::Unknown, perms);
    660 
    661  if (NS_FAILED(rv)) {
    662    mTransaction = nullptr;
    663    return rv;
    664  }
    665 
    666  return rv;
    667 }
    668 
    669 void TRRServiceChannel::MaybeStartDNSPrefetch() {
    670  if (mConnectionInfo->UsingHttpProxy() ||
    671      (mLoadFlags & (nsICachingChannel::LOAD_NO_NETWORK_IO |
    672                     nsICachingChannel::LOAD_ONLY_FROM_CACHE))) {
    673    return;
    674  }
    675 
    676  LOG(
    677      ("TRRServiceChannel::MaybeStartDNSPrefetch [this=%p] "
    678       "prefetching%s\n",
    679       this, mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : ""));
    680 
    681  OriginAttributes originAttributes;
    682  mDNSPrefetch = new nsDNSPrefetch(mURI, originAttributes,
    683                                   nsIRequest::GetTRRMode(), this, true);
    684  nsIDNSService::DNSFlags dnsFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
    685  if (mCaps & NS_HTTP_REFRESH_DNS) {
    686    dnsFlags |= nsIDNSService::RESOLVE_BYPASS_CACHE;
    687  }
    688  nsresult rv = mDNSPrefetch->PrefetchHigh(dnsFlags);
    689  NS_ENSURE_SUCCESS_VOID(rv);
    690 }
    691 
    692 NS_IMETHODIMP
    693 TRRServiceChannel::OnTransportStatus(nsITransport* trans, nsresult status,
    694                                     int64_t progress, int64_t progressMax) {
    695  return NS_OK;
    696 }
    697 
    698 nsresult TRRServiceChannel::CallOnStartRequest() {
    699  LOG(("TRRServiceChannel::CallOnStartRequest [this=%p]", this));
    700 
    701  if (LoadOnStartRequestCalled()) {
    702    LOG(("CallOnStartRequest already invoked before"));
    703    return mStatus;
    704  }
    705 
    706  nsresult rv = NS_OK;
    707  StoreTracingEnabled(false);
    708 
    709  // Ensure mListener->OnStartRequest will be invoked before exiting
    710  // this function.
    711  auto onStartGuard = MakeScopeExit([&] {
    712    LOG(
    713        ("  calling mListener->OnStartRequest by ScopeExit [this=%p, "
    714         "listener=%p]\n",
    715         this, mListener.get()));
    716    MOZ_ASSERT(!LoadOnStartRequestCalled());
    717 
    718    if (mListener) {
    719      nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
    720      StoreOnStartRequestCalled(true);
    721      deleteProtector->OnStartRequest(this);
    722    }
    723    StoreOnStartRequestCalled(true);
    724  });
    725 
    726  if (mResponseHead && !mResponseHead->HasContentCharset()) {
    727    mResponseHead->SetContentCharset(mContentCharsetHint);
    728  }
    729 
    730  LOG(("  calling mListener->OnStartRequest [this=%p, listener=%p]\n", this,
    731       mListener.get()));
    732 
    733  // About to call OnStartRequest, dismiss the guard object.
    734  onStartGuard.release();
    735 
    736  if (mListener) {
    737    MOZ_ASSERT(!LoadOnStartRequestCalled(),
    738               "We should not call OsStartRequest twice");
    739    nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
    740    StoreOnStartRequestCalled(true);
    741    rv = deleteProtector->OnStartRequest(this);
    742    if (NS_FAILED(rv)) return rv;
    743  } else {
    744    NS_WARNING("OnStartRequest skipped because of null listener");
    745    StoreOnStartRequestCalled(true);
    746  }
    747 
    748  if (!mResponseHead) {
    749    return NS_OK;
    750  }
    751 
    752  nsAutoCString contentEncoding;
    753  rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
    754  if (NS_FAILED(rv) || contentEncoding.IsEmpty()) {
    755    return NS_OK;
    756  }
    757 
    758  // DoApplyContentConversions can only be called on the main thread.
    759  if (NS_IsMainThread()) {
    760    nsCOMPtr<nsIStreamListener> listener;
    761    rv =
    762        DoApplyContentConversions(mListener, getter_AddRefs(listener), nullptr);
    763    if (NS_FAILED(rv)) {
    764      return rv;
    765    }
    766 
    767    AfterApplyContentConversions(rv, listener);
    768    return NS_OK;
    769  }
    770 
    771  Suspend();
    772 
    773  RefPtr<TRRServiceChannel> self = this;
    774  rv = NS_DispatchToMainThread(
    775      NS_NewRunnableFunction("TRRServiceChannel::DoApplyContentConversions",
    776                             [self]() {
    777                               nsCOMPtr<nsIStreamListener> listener;
    778                               nsresult rv = self->DoApplyContentConversions(
    779                                   self->mListener, getter_AddRefs(listener),
    780                                   nullptr);
    781                               self->AfterApplyContentConversions(rv, listener);
    782                             }),
    783      NS_DISPATCH_NORMAL);
    784  if (NS_FAILED(rv)) {
    785    Resume();
    786    return rv;
    787  }
    788 
    789  return NS_OK;
    790 }
    791 
    792 void TRRServiceChannel::AfterApplyContentConversions(
    793    nsresult aResult, nsIStreamListener* aListener) {
    794  LOG(("TRRServiceChannel::AfterApplyContentConversions [this=%p]", this));
    795  if (!mCurrentEventTarget->IsOnCurrentThread()) {
    796    RefPtr<TRRServiceChannel> self = this;
    797    nsCOMPtr<nsIStreamListener> listener = aListener;
    798    self->mCurrentEventTarget->Dispatch(
    799        NS_NewRunnableFunction(
    800            "TRRServiceChannel::AfterApplyContentConversions",
    801            [self, aResult, listener]() {
    802              self->Resume();
    803              self->AfterApplyContentConversions(aResult, listener);
    804            }),
    805        NS_DISPATCH_NORMAL);
    806    return;
    807  }
    808 
    809  if (mCanceled) {
    810    return;
    811  }
    812 
    813  if (NS_FAILED(aResult)) {
    814    (void)AsyncAbort(aResult);
    815    return;
    816  }
    817 
    818  if (aListener) {
    819    mListener = aListener;
    820    mCompressListener = aListener;
    821    StoreHasAppliedConversion(true);
    822  }
    823 }
    824 
    825 void TRRServiceChannel::ProcessAltService(
    826    nsHttpConnectionInfo* aTransConnInfo) {
    827  // e.g. Alt-Svc: h2=":443"; ma=60
    828  // e.g. Alt-Svc: h2="otherhost:443"
    829  // Alt-Svc       = 1#( alternative *( OWS ";" OWS parameter ) )
    830  // alternative   = protocol-id "=" alt-authority
    831  // protocol-id   = token ; percent-encoded ALPN protocol identifier
    832  // alt-authority = quoted-string ;  containing [ uri-host ] ":" port
    833 
    834  if (!LoadAllowAltSvc()) {  // per channel opt out
    835    return;
    836  }
    837 
    838  if (!gHttpHandler->AllowAltSvc() || (mCaps & NS_HTTP_DISALLOW_SPDY)) {
    839    return;
    840  }
    841 
    842  nsCString scheme;
    843  mURI->GetScheme(scheme);
    844  bool isHttp = scheme.EqualsLiteral("http");
    845  if (!isHttp && !scheme.EqualsLiteral("https")) {
    846    return;
    847  }
    848 
    849  nsCString altSvc;
    850  (void)mResponseHead->GetHeader(nsHttp::Alternate_Service, altSvc);
    851  if (altSvc.IsEmpty()) {
    852    return;
    853  }
    854 
    855  if (!nsHttp::IsReasonableHeaderValue(altSvc)) {
    856    LOG(("Alt-Svc Response Header seems unreasonable - skipping\n"));
    857    return;
    858  }
    859 
    860  nsCString originHost;
    861  int32_t originPort = 80;
    862  mURI->GetPort(&originPort);
    863  if (NS_FAILED(mURI->GetAsciiHost(originHost))) {
    864    return;
    865  }
    866 
    867  nsCOMPtr<nsIInterfaceRequestor> callbacks;
    868  nsCOMPtr<nsProxyInfo> proxyInfo;
    869  NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
    870                                         getter_AddRefs(callbacks));
    871  if (mProxyInfo) {
    872    proxyInfo = do_QueryInterface(mProxyInfo);
    873  }
    874 
    875  RefPtr<nsHttpConnectionInfo> connectionInfo = aTransConnInfo;
    876  auto processHeaderTask = [altSvc, scheme, originHost, originPort,
    877                            userName(mUsername),
    878                            privateBrowsing(mPrivateBrowsing), callbacks,
    879                            proxyInfo, caps(mCaps), connectionInfo]() {
    880    if (XRE_IsSocketProcess()) {
    881      AltServiceChild::ProcessHeader(altSvc, scheme, originHost, originPort,
    882                                     userName, privateBrowsing, callbacks,
    883                                     proxyInfo, caps & NS_HTTP_DISALLOW_SPDY,
    884                                     OriginAttributes(), connectionInfo);
    885      return;
    886    }
    887 
    888    AltSvcMapping::ProcessHeader(altSvc, scheme, originHost, originPort,
    889                                 userName, privateBrowsing, callbacks,
    890                                 proxyInfo, caps & NS_HTTP_DISALLOW_SPDY,
    891                                 OriginAttributes(), connectionInfo);
    892  };
    893 
    894  if (NS_IsMainThread()) {
    895    processHeaderTask();
    896    return;
    897  }
    898 
    899  NS_DispatchToMainThread(NS_NewRunnableFunction(
    900      "TRRServiceChannel::ProcessAltService", std::move(processHeaderTask)));
    901 }
    902 
    903 NS_IMETHODIMP
    904 TRRServiceChannel::OnStartRequest(nsIRequest* request) {
    905  LOG(("TRRServiceChannel::OnStartRequest [this=%p request=%p status=%" PRIx32
    906       "]\n",
    907       this, request, static_cast<uint32_t>(static_cast<nsresult>(mStatus))));
    908 
    909  if (!(mCanceled || NS_FAILED(mStatus))) {
    910    // capture the request's status, so our consumers will know ASAP of any
    911    // connection failures, etc - bug 93581
    912    nsresult status;
    913    request->GetStatus(&status);
    914    mStatus = status;
    915  }
    916 
    917  MOZ_ASSERT(request == mTransactionPump, "Unexpected request");
    918 
    919  StoreAfterOnStartRequestBegun(true);
    920  if (mTransaction) {
    921    if (!mSecurityInfo) {
    922      // grab the security info from the connection object; the transaction
    923      // is guaranteed to own a reference to the connection.
    924      mSecurityInfo = mTransaction->SecurityInfo();
    925    }
    926  }
    927 
    928  if (NS_SUCCEEDED(mStatus) && mTransaction) {
    929    // mTransactionPump doesn't hit OnInputStreamReady and call this until
    930    // all of the response headers have been acquired, so we can take
    931    // ownership of them from the transaction.
    932    RefPtr<nsHttpConnectionInfo> connInfo;
    933    mResponseHead =
    934        mTransaction->TakeResponseHeadAndConnInfo(getter_AddRefs(connInfo));
    935    if (mResponseHead) {
    936      uint32_t httpStatus = mResponseHead->Status();
    937      if (mTransaction->ProxyConnectFailed()) {
    938        LOG(("TRRServiceChannel proxy connect failed httpStatus: %d",
    939             httpStatus));
    940        MOZ_ASSERT(mConnectionInfo->UsingConnect(),
    941                   "proxy connect failed but not using CONNECT?");
    942        nsresult rv = HttpProxyResponseToErrorCode(httpStatus);
    943        mTransaction->DontReuseConnection();
    944        Cancel(rv);
    945        return CallOnStartRequest();
    946      }
    947 
    948      if ((httpStatus < 500) && (httpStatus != 421) && (httpStatus != 407)) {
    949        ProcessAltService(connInfo);
    950      }
    951 
    952      if (httpStatus == 300 || httpStatus == 301 || httpStatus == 302 ||
    953          httpStatus == 303 || httpStatus == 307 || httpStatus == 308) {
    954        nsresult rv = SyncProcessRedirection(httpStatus);
    955        if (NS_SUCCEEDED(rv)) {
    956          return rv;
    957        }
    958 
    959        mStatus = rv;
    960        DoNotifyListener();
    961        return rv;
    962      }
    963    } else {
    964      NS_WARNING("No response head in OnStartRequest");
    965    }
    966  }
    967 
    968  // avoid crashing if mListener happens to be null...
    969  if (!mListener) {
    970    MOZ_ASSERT_UNREACHABLE("mListener is null");
    971    return NS_OK;
    972  }
    973 
    974  return CallOnStartRequest();
    975 }
    976 
    977 nsresult TRRServiceChannel::SyncProcessRedirection(uint32_t aHttpStatus) {
    978  nsAutoCString location;
    979 
    980  // if a location header was not given, then we can't perform the redirect,
    981  // so just carry on as though this were a normal response.
    982  if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Location, location))) {
    983    return NS_ERROR_FAILURE;
    984  }
    985 
    986  // make sure non-ASCII characters in the location header are escaped.
    987  nsAutoCString locationBuf;
    988  if (NS_EscapeURL(location.get(), -1, esc_OnlyNonASCII | esc_Spaces,
    989                   locationBuf)) {
    990    location = locationBuf;
    991  }
    992 
    993  LOG(("redirecting to: %s [redirection-limit=%u]\n", location.get(),
    994       uint32_t(mRedirectionLimit)));
    995 
    996  nsCOMPtr<nsIURI> redirectURI;
    997  nsresult rv = NS_NewURI(getter_AddRefs(redirectURI), location);
    998 
    999  if (NS_FAILED(rv)) {
   1000    LOG(("Invalid URI for redirect: Location: %s\n", location.get()));
   1001    return NS_ERROR_CORRUPTED_CONTENT;
   1002  }
   1003 
   1004  // move the reference of the old location to the new one if the new
   1005  // one has none.
   1006  PropagateReferenceIfNeeded(mURI, redirectURI);
   1007 
   1008  bool rewriteToGET =
   1009      ShouldRewriteRedirectToGET(aHttpStatus, mRequestHead.ParsedMethod());
   1010 
   1011  // Let's not rewrite the method to GET for TRR requests.
   1012  if (rewriteToGET) {
   1013    return NS_ERROR_FAILURE;
   1014  }
   1015 
   1016  // If the method is not safe (such as POST, PUT, DELETE, ...)
   1017  if (!mRequestHead.IsSafeMethod()) {
   1018    LOG(("TRRServiceChannel: unsafe redirect to:%s\n", location.get()));
   1019  }
   1020 
   1021  uint32_t redirectFlags;
   1022  if (nsHttp::IsPermanentRedirect(aHttpStatus)) {
   1023    redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
   1024  } else {
   1025    redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
   1026  }
   1027 
   1028  nsCOMPtr<nsIChannel> newChannel;
   1029  nsCOMPtr<nsILoadInfo> redirectLoadInfo =
   1030      static_cast<TRRLoadInfo*>(mLoadInfo.get())->Clone();
   1031  rv = gHttpHandler->CreateTRRServiceChannel(redirectURI, nullptr, 0, nullptr,
   1032                                             redirectLoadInfo,
   1033                                             getter_AddRefs(newChannel));
   1034  if (NS_FAILED(rv)) {
   1035    return rv;
   1036  }
   1037 
   1038  rv = SetupReplacementChannel(redirectURI, newChannel, !rewriteToGET,
   1039                               redirectFlags);
   1040  if (NS_FAILED(rv)) {
   1041    return rv;
   1042  }
   1043 
   1044  // Make sure to do this after we received redirect veto answer,
   1045  // i.e. after all sinks had been notified
   1046  newChannel->SetOriginalURI(mOriginalURI);
   1047 
   1048  rv = newChannel->AsyncOpen(mListener);
   1049  LOG(("  new channel AsyncOpen returned %" PRIX32, static_cast<uint32_t>(rv)));
   1050 
   1051  // close down this channel
   1052  Cancel(NS_BINDING_REDIRECTED);
   1053 
   1054  ReleaseListeners();
   1055 
   1056  return NS_OK;
   1057 }
   1058 
   1059 nsresult TRRServiceChannel::SetupReplacementChannel(nsIURI* aNewURI,
   1060                                                    nsIChannel* aNewChannel,
   1061                                                    bool aPreserveMethod,
   1062                                                    uint32_t aRedirectFlags) {
   1063  LOG(
   1064      ("TRRServiceChannel::SetupReplacementChannel "
   1065       "[this=%p newChannel=%p preserveMethod=%d]",
   1066       this, aNewChannel, aPreserveMethod));
   1067 
   1068  nsresult rv = HttpBaseChannel::SetupReplacementChannel(
   1069      aNewURI, aNewChannel, aPreserveMethod, aRedirectFlags);
   1070  if (NS_FAILED(rv)) {
   1071    return rv;
   1072  }
   1073 
   1074  rv = CheckRedirectLimit(aNewURI, aRedirectFlags);
   1075  NS_ENSURE_SUCCESS(rv, rv);
   1076 
   1077  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
   1078  if (!httpChannel) {
   1079    MOZ_ASSERT(false);
   1080    return NS_ERROR_FAILURE;
   1081  }
   1082 
   1083  // convey the ApplyConversion flag (bug 91862)
   1084  nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(httpChannel);
   1085  if (encodedChannel) {
   1086    encodedChannel->SetApplyConversion(LoadApplyConversion());
   1087  }
   1088 
   1089  if (mContentTypeHint.IsEmpty()) {
   1090    return NS_OK;
   1091  }
   1092 
   1093  // Make sure we set content-type on the old channel properly.
   1094  MOZ_ASSERT(mContentTypeHint.Equals("application/dns-message"));
   1095 
   1096  // Apply TRR specific settings. Note that we already know mContentTypeHint is
   1097  // "application/dns-message" here.
   1098  return TRR::SetupTRRServiceChannelInternal(
   1099      httpChannel,
   1100      mRequestHead.ParsedMethod() == nsHttpRequestHead::kMethod_Get,
   1101      mContentTypeHint);
   1102 }
   1103 
   1104 NS_IMETHODIMP
   1105 TRRServiceChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* input,
   1106                                   uint64_t offset, uint32_t count) {
   1107  LOG(("TRRServiceChannel::OnDataAvailable [this=%p request=%p offset=%" PRIu64
   1108       " count=%" PRIu32 "]\n",
   1109       this, request, offset, count));
   1110 
   1111  // don't send out OnDataAvailable notifications if we've been canceled.
   1112  if (mCanceled) return mStatus;
   1113 
   1114  MOZ_ASSERT(mResponseHead, "No response head in ODA!!");
   1115 
   1116  if (mListener) {
   1117    return mListener->OnDataAvailable(this, input, offset, count);
   1118  }
   1119 
   1120  return NS_ERROR_ABORT;
   1121 }
   1122 
   1123 static void TelemetryReport(nsITimedChannel* aTimedChannel,
   1124                            uint64_t aRequestSize, uint64_t aTransferSize) {
   1125  TimeStamp asyncOpen;
   1126  nsresult rv = aTimedChannel->GetAsyncOpen(&asyncOpen);
   1127  if (NS_FAILED(rv)) {
   1128    return;
   1129  }
   1130 
   1131  TimeStamp domainLookupStart;
   1132  rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart);
   1133  if (NS_FAILED(rv)) {
   1134    return;
   1135  }
   1136 
   1137  TimeStamp domainLookupEnd;
   1138  rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd);
   1139  if (NS_FAILED(rv)) {
   1140    return;
   1141  }
   1142 
   1143  TimeStamp connectStart;
   1144  rv = aTimedChannel->GetConnectStart(&connectStart);
   1145  if (NS_FAILED(rv)) {
   1146    return;
   1147  }
   1148 
   1149  TimeStamp secureConnectionStart;
   1150  rv = aTimedChannel->GetSecureConnectionStart(&secureConnectionStart);
   1151  if (NS_FAILED(rv)) {
   1152    return;
   1153  }
   1154 
   1155  TimeStamp connectEnd;
   1156  rv = aTimedChannel->GetConnectEnd(&connectEnd);
   1157  if (NS_FAILED(rv)) {
   1158    return;
   1159  }
   1160 
   1161  TimeStamp requestStart;
   1162  rv = aTimedChannel->GetRequestStart(&requestStart);
   1163  if (NS_FAILED(rv)) {
   1164    return;
   1165  }
   1166 
   1167  TimeStamp responseStart;
   1168  rv = aTimedChannel->GetResponseStart(&responseStart);
   1169  if (NS_FAILED(rv)) {
   1170    return;
   1171  }
   1172 
   1173  TimeStamp responseEnd;
   1174  rv = aTimedChannel->GetResponseEnd(&responseEnd);
   1175  if (NS_FAILED(rv)) {
   1176    return;
   1177  }
   1178 
   1179  const nsCString& key = TRRService::ProviderKey();
   1180  if (!domainLookupStart.IsNull()) {
   1181    mozilla::glean::networking::trr_dns_start.Get(key).AccumulateRawDuration(
   1182        domainLookupStart - asyncOpen);
   1183    if (!domainLookupEnd.IsNull()) {
   1184      mozilla::glean::networking::trr_dns_end.Get(key).AccumulateRawDuration(
   1185          domainLookupEnd - domainLookupStart);
   1186    }
   1187  }
   1188  if (!connectEnd.IsNull()) {
   1189    if (!connectStart.IsNull()) {
   1190      mozilla::glean::networking::trr_tcp_connection.Get(key)
   1191          .AccumulateRawDuration(connectEnd - connectStart);
   1192    }
   1193    if (!secureConnectionStart.IsNull()) {
   1194      mozilla::glean::networking::trr_tls_handshake.Get(key)
   1195          .AccumulateRawDuration(connectEnd - secureConnectionStart);
   1196    }
   1197  }
   1198  if (!requestStart.IsNull() && !responseEnd.IsNull()) {
   1199    mozilla::glean::networking::trr_open_to_first_sent.Get(key)
   1200        .AccumulateRawDuration(requestStart - asyncOpen);
   1201    mozilla::glean::networking::trr_first_sent_to_last_received.Get(key)
   1202        .AccumulateRawDuration(responseEnd - requestStart);
   1203    mozilla::glean::networking::trr_complete_load.Get(key)
   1204        .AccumulateRawDuration(responseEnd - asyncOpen);
   1205    if (!responseStart.IsNull()) {
   1206      mozilla::glean::networking::trr_open_to_first_received.Get(key)
   1207          .AccumulateRawDuration(responseStart - asyncOpen);
   1208    }
   1209  }
   1210  glean::networking::trr_request_size.Get(key).Accumulate(aRequestSize);
   1211  glean::networking::trr_response_size.Get(key).Accumulate(aTransferSize);
   1212 }
   1213 
   1214 NS_IMETHODIMP
   1215 TRRServiceChannel::OnStopRequest(nsIRequest* request, nsresult status) {
   1216  LOG(("TRRServiceChannel::OnStopRequest [this=%p request=%p status=%" PRIx32
   1217       "]\n",
   1218       this, request, static_cast<uint32_t>(status)));
   1219 
   1220  if (mCanceled || NS_FAILED(mStatus)) status = mStatus;
   1221 
   1222  mTransactionTimings = mTransaction->Timings();
   1223  mRequestSize = mTransaction->GetRequestSize();
   1224  mTransferSize = mTransaction->GetTransferSize();
   1225  mTransaction = nullptr;
   1226  mTransactionPump = nullptr;
   1227 
   1228  if (mListener) {
   1229    LOG(("TRRServiceChannel %p calling OnStopRequest\n", this));
   1230    MOZ_ASSERT(LoadOnStartRequestCalled(),
   1231               "OnStartRequest should be called before OnStopRequest");
   1232    MOZ_ASSERT(!LoadOnStopRequestCalled(),
   1233               "We should not call OnStopRequest twice");
   1234    StoreOnStopRequestCalled(true);
   1235    mListener->OnStopRequest(this, status);
   1236  }
   1237  StoreOnStopRequestCalled(true);
   1238 
   1239  mDNSPrefetch = nullptr;
   1240 
   1241  if (mLoadGroup) {
   1242    mLoadGroup->RemoveRequest(this, nullptr, status);
   1243  }
   1244 
   1245  ReleaseListeners();
   1246  TelemetryReport(this, mRequestSize, mTransferSize);
   1247  return NS_OK;
   1248 }
   1249 
   1250 NS_IMETHODIMP
   1251 TRRServiceChannel::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec,
   1252                                    nsresult status) {
   1253  LOG(
   1254      ("TRRServiceChannel::OnLookupComplete [this=%p] prefetch complete%s: "
   1255       "%s status[0x%" PRIx32 "]\n",
   1256       this, mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : "",
   1257       NS_SUCCEEDED(status) ? "success" : "failure",
   1258       static_cast<uint32_t>(status)));
   1259 
   1260  // We no longer need the dns prefetch object. Note: mDNSPrefetch could be
   1261  // validly null if OnStopRequest has already been called.
   1262  // We only need the domainLookup timestamps when not loading from cache
   1263  if (mDNSPrefetch && mDNSPrefetch->TimingsValid() && mTransaction) {
   1264    TimeStamp connectStart = mTransaction->GetConnectStart();
   1265    TimeStamp requestStart = mTransaction->GetRequestStart();
   1266    // We only set the domainLookup timestamps if we're not using a
   1267    // persistent connection.
   1268    if (requestStart.IsNull() && connectStart.IsNull()) {
   1269      mTransaction->SetDomainLookupStart(mDNSPrefetch->StartTimestamp());
   1270      mTransaction->SetDomainLookupEnd(mDNSPrefetch->EndTimestamp());
   1271    }
   1272  }
   1273  mDNSPrefetch = nullptr;
   1274 
   1275  // Unset DNS cache refresh if it was requested,
   1276  if (mCaps & NS_HTTP_REFRESH_DNS) {
   1277    mCaps &= ~NS_HTTP_REFRESH_DNS;
   1278    if (mTransaction) {
   1279      mTransaction->SetDNSWasRefreshed();
   1280    }
   1281  }
   1282 
   1283  return NS_OK;
   1284 }
   1285 
   1286 NS_IMETHODIMP
   1287 TRRServiceChannel::LogBlockedCORSRequest(const nsAString& aMessage,
   1288                                         const nsACString& aCategory,
   1289                                         bool aIsWarning) {
   1290  return NS_ERROR_NOT_IMPLEMENTED;
   1291 }
   1292 
   1293 NS_IMETHODIMP
   1294 TRRServiceChannel::LogMimeTypeMismatch(const nsACString& aMessageName,
   1295                                       bool aWarning, const nsAString& aURL,
   1296                                       const nsAString& aContentType) {
   1297  return NS_ERROR_NOT_IMPLEMENTED;
   1298 }
   1299 
   1300 NS_IMETHODIMP
   1301 TRRServiceChannel::GetIsAuthChannel(bool* aIsAuthChannel) {
   1302  return NS_ERROR_NOT_IMPLEMENTED;
   1303 }
   1304 
   1305 NS_IMETHODIMP
   1306 TRRServiceChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
   1307  mCallbacks = aCallbacks;
   1308  return NS_OK;
   1309 }
   1310 
   1311 NS_IMETHODIMP
   1312 TRRServiceChannel::SetPriority(int32_t value) {
   1313  return NS_ERROR_NOT_IMPLEMENTED;
   1314 }
   1315 
   1316 void TRRServiceChannel::OnClassOfServiceUpdated() {
   1317  LOG(("TRRServiceChannel::OnClassOfServiceUpdated this=%p, cos=%lu inc=%d",
   1318       this, mClassOfService.Flags(), mClassOfService.Incremental()));
   1319 
   1320  if (mTransaction) {
   1321    gHttpHandler->UpdateClassOfServiceOnTransaction(mTransaction,
   1322                                                    mClassOfService);
   1323  }
   1324 }
   1325 
   1326 NS_IMETHODIMP
   1327 TRRServiceChannel::SetClassFlags(uint32_t inFlags) {
   1328  uint32_t previous = mClassOfService.Flags();
   1329  mClassOfService.SetFlags(inFlags);
   1330  if (previous != mClassOfService.Flags()) {
   1331    OnClassOfServiceUpdated();
   1332  }
   1333  return NS_OK;
   1334 }
   1335 
   1336 NS_IMETHODIMP
   1337 TRRServiceChannel::SetIncremental(bool inFlag) {
   1338  bool previous = mClassOfService.Incremental();
   1339  mClassOfService.SetIncremental(inFlag);
   1340  if (previous != mClassOfService.Incremental()) {
   1341    OnClassOfServiceUpdated();
   1342  }
   1343  return NS_OK;
   1344 }
   1345 
   1346 NS_IMETHODIMP
   1347 TRRServiceChannel::SetClassOfService(ClassOfService cos) {
   1348  ClassOfService previous = mClassOfService;
   1349  mClassOfService = cos;
   1350  if (previous != mClassOfService) {
   1351    OnClassOfServiceUpdated();
   1352  }
   1353  return NS_OK;
   1354 }
   1355 
   1356 NS_IMETHODIMP
   1357 TRRServiceChannel::AddClassFlags(uint32_t inFlags) {
   1358  uint32_t previous = mClassOfService.Flags();
   1359  mClassOfService.SetFlags(inFlags | mClassOfService.Flags());
   1360  if (previous != mClassOfService.Flags()) {
   1361    OnClassOfServiceUpdated();
   1362  }
   1363  return NS_OK;
   1364 }
   1365 
   1366 NS_IMETHODIMP
   1367 TRRServiceChannel::ClearClassFlags(uint32_t inFlags) {
   1368  uint32_t previous = mClassOfService.Flags();
   1369  mClassOfService.SetFlags(~inFlags & mClassOfService.Flags());
   1370  if (previous != mClassOfService.Flags()) {
   1371    OnClassOfServiceUpdated();
   1372  }
   1373  return NS_OK;
   1374 }
   1375 
   1376 NS_IMETHODIMP
   1377 TRRServiceChannel::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID) {
   1378  return NS_ERROR_NOT_IMPLEMENTED;
   1379 }
   1380 
   1381 void TRRServiceChannel::DoAsyncAbort(nsresult aStatus) {
   1382  (void)AsyncAbort(aStatus);
   1383 }
   1384 
   1385 NS_IMETHODIMP
   1386 TRRServiceChannel::GetProxyInfo(nsIProxyInfo** result) {
   1387  if (!mConnectionInfo) {
   1388    *result = do_AddRef(mProxyInfo).take();
   1389  } else {
   1390    *result = do_AddRef(mConnectionInfo->ProxyInfo()).take();
   1391  }
   1392  return NS_OK;
   1393 }
   1394 
   1395 NS_IMETHODIMP TRRServiceChannel::GetHttpProxyConnectResponseCode(
   1396    int32_t* aResponseCode) {
   1397  NS_ENSURE_ARG_POINTER(aResponseCode);
   1398 
   1399  *aResponseCode = -1;
   1400  return NS_OK;
   1401 }
   1402 
   1403 NS_IMETHODIMP
   1404 TRRServiceChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
   1405  return HttpBaseChannel::GetLoadFlags(aLoadFlags);
   1406 }
   1407 
   1408 NS_IMETHODIMP
   1409 TRRServiceChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
   1410  if (aLoadFlags & (nsICachingChannel::LOAD_ONLY_FROM_CACHE | LOAD_FROM_CACHE |
   1411                    nsICachingChannel::LOAD_NO_NETWORK_IO)) {
   1412    MOZ_ASSERT(false, "Wrong load flags!");
   1413    return NS_ERROR_FAILURE;
   1414  }
   1415 
   1416  return HttpBaseChannel::SetLoadFlags(aLoadFlags);
   1417 }
   1418 
   1419 NS_IMETHODIMP
   1420 TRRServiceChannel::GetURI(nsIURI** aURI) {
   1421  return HttpBaseChannel::GetURI(aURI);
   1422 }
   1423 
   1424 NS_IMETHODIMP
   1425 TRRServiceChannel::GetNotificationCallbacks(
   1426    nsIInterfaceRequestor** aCallbacks) {
   1427  return HttpBaseChannel::GetNotificationCallbacks(aCallbacks);
   1428 }
   1429 
   1430 NS_IMETHODIMP
   1431 TRRServiceChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
   1432  return HttpBaseChannel::GetLoadGroup(aLoadGroup);
   1433 }
   1434 
   1435 NS_IMETHODIMP
   1436 TRRServiceChannel::GetRequestMethod(nsACString& aMethod) {
   1437  return HttpBaseChannel::GetRequestMethod(aMethod);
   1438 }
   1439 
   1440 void TRRServiceChannel::DoNotifyListener() {
   1441  LOG(("TRRServiceChannel::DoNotifyListener this=%p", this));
   1442 
   1443  // In case nsHttpChannel::OnStartRequest wasn't called (e.g. due to flag
   1444  // LOAD_ONLY_IF_MODIFIED) we want to set AfterOnStartRequestBegun to true
   1445  // before notifying listener.
   1446  if (!LoadAfterOnStartRequestBegun()) {
   1447    StoreAfterOnStartRequestBegun(true);
   1448  }
   1449 
   1450  if (mListener && !LoadOnStartRequestCalled()) {
   1451    nsCOMPtr<nsIStreamListener> listener = mListener;
   1452    StoreOnStartRequestCalled(true);
   1453    listener->OnStartRequest(this);
   1454  }
   1455  StoreOnStartRequestCalled(true);
   1456 
   1457  // Make sure IsPending is set to false. At this moment we are done from
   1458  // the point of view of our consumer and we have to report our self
   1459  // as not-pending.
   1460  StoreIsPending(false);
   1461 
   1462  if (mListener && !LoadOnStopRequestCalled()) {
   1463    nsCOMPtr<nsIStreamListener> listener = mListener;
   1464    StoreOnStopRequestCalled(true);
   1465    listener->OnStopRequest(this, mStatus);
   1466  }
   1467  StoreOnStopRequestCalled(true);
   1468 
   1469  // We have to make sure to drop the references to listeners and callbacks
   1470  // no longer needed.
   1471  ReleaseListeners();
   1472 
   1473  DoNotifyListenerCleanup();
   1474 }
   1475 
   1476 void TRRServiceChannel::DoNotifyListenerCleanup() {}
   1477 
   1478 NS_IMETHODIMP
   1479 TRRServiceChannel::GetDomainLookupStart(TimeStamp* _retval) {
   1480  if (mTransaction) {
   1481    *_retval = mTransaction->GetDomainLookupStart();
   1482  } else {
   1483    *_retval = mTransactionTimings.domainLookupStart;
   1484  }
   1485  return NS_OK;
   1486 }
   1487 
   1488 NS_IMETHODIMP
   1489 TRRServiceChannel::GetDomainLookupEnd(TimeStamp* _retval) {
   1490  if (mTransaction) {
   1491    *_retval = mTransaction->GetDomainLookupEnd();
   1492  } else {
   1493    *_retval = mTransactionTimings.domainLookupEnd;
   1494  }
   1495  return NS_OK;
   1496 }
   1497 
   1498 NS_IMETHODIMP
   1499 TRRServiceChannel::GetConnectStart(TimeStamp* _retval) {
   1500  if (mTransaction) {
   1501    *_retval = mTransaction->GetConnectStart();
   1502  } else {
   1503    *_retval = mTransactionTimings.connectStart;
   1504  }
   1505  return NS_OK;
   1506 }
   1507 
   1508 NS_IMETHODIMP
   1509 TRRServiceChannel::GetTcpConnectEnd(TimeStamp* _retval) {
   1510  if (mTransaction) {
   1511    *_retval = mTransaction->GetTcpConnectEnd();
   1512  } else {
   1513    *_retval = mTransactionTimings.tcpConnectEnd;
   1514  }
   1515  return NS_OK;
   1516 }
   1517 
   1518 NS_IMETHODIMP
   1519 TRRServiceChannel::GetSecureConnectionStart(TimeStamp* _retval) {
   1520  if (mTransaction) {
   1521    *_retval = mTransaction->GetSecureConnectionStart();
   1522  } else {
   1523    *_retval = mTransactionTimings.secureConnectionStart;
   1524  }
   1525  return NS_OK;
   1526 }
   1527 
   1528 NS_IMETHODIMP
   1529 TRRServiceChannel::GetConnectEnd(TimeStamp* _retval) {
   1530  if (mTransaction) {
   1531    *_retval = mTransaction->GetConnectEnd();
   1532  } else {
   1533    *_retval = mTransactionTimings.connectEnd;
   1534  }
   1535  return NS_OK;
   1536 }
   1537 
   1538 NS_IMETHODIMP
   1539 TRRServiceChannel::GetRequestStart(TimeStamp* _retval) {
   1540  if (mTransaction) {
   1541    *_retval = mTransaction->GetRequestStart();
   1542  } else {
   1543    *_retval = mTransactionTimings.requestStart;
   1544  }
   1545  return NS_OK;
   1546 }
   1547 
   1548 NS_IMETHODIMP
   1549 TRRServiceChannel::GetResponseStart(TimeStamp* _retval) {
   1550  if (mTransaction) {
   1551    *_retval = mTransaction->GetResponseStart();
   1552  } else {
   1553    *_retval = mTransactionTimings.responseStart;
   1554  }
   1555  return NS_OK;
   1556 }
   1557 
   1558 NS_IMETHODIMP
   1559 TRRServiceChannel::GetResponseEnd(TimeStamp* _retval) {
   1560  if (mTransaction) {
   1561    *_retval = mTransaction->GetResponseEnd();
   1562  } else {
   1563    *_retval = mTransactionTimings.responseEnd;
   1564  }
   1565  return NS_OK;
   1566 }
   1567 
   1568 NS_IMETHODIMP TRRServiceChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
   1569  return NS_OK;
   1570 }
   1571 
   1572 NS_IMETHODIMP
   1573 TRRServiceChannel::TimingAllowCheck(nsIPrincipal* aOrigin, bool* aResult) {
   1574  NS_ENSURE_ARG_POINTER(aResult);
   1575  *aResult = true;
   1576  return NS_OK;
   1577 }
   1578 
   1579 bool TRRServiceChannel::SameOriginWithOriginalUri(nsIURI* aURI) { return true; }
   1580 
   1581 }  // namespace mozilla::net