tor-browser

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

nsHttpConnection.cpp (92034B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=4 sw=2 sts=2 et cin: */
      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 "HttpLog.h"
      9 
     10 // Log on level :5, instead of default :4.
     11 #undef LOG
     12 #define LOG(args) LOG5(args)
     13 #undef LOG_ENABLED
     14 #define LOG_ENABLED() LOG5_ENABLED()
     15 
     16 #include "ASpdySession.h"
     17 #include "NSSErrorsService.h"
     18 #include "TLSTransportLayer.h"
     19 #include "mozilla/ChaosMode.h"
     20 #include "mozilla/glean/NetwerkMetrics.h"
     21 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     22 #include "mozilla/StaticPrefs_network.h"
     23 #include "mozpkix/pkixnss.h"
     24 #include "nsCRT.h"
     25 #include "nsHttpConnection.h"
     26 #include "nsHttpHandler.h"
     27 #include "nsHttpRequestHead.h"
     28 #include "nsHttpResponseHead.h"
     29 #include "nsIClassOfService.h"
     30 #include "nsIOService.h"
     31 #include "nsISocketTransport.h"
     32 #include "nsISupportsPriority.h"
     33 #include "nsITLSSocketControl.h"
     34 #include "nsITransportSecurityInfo.h"
     35 #include "nsPreloadedStream.h"
     36 #include "nsProxyRelease.h"
     37 #include "nsQueryObject.h"
     38 #include "nsSocketTransport2.h"
     39 #include "nsSocketTransportService2.h"
     40 #include "nsStringStream.h"
     41 #include "sslerr.h"
     42 #include "sslt.h"
     43 
     44 namespace mozilla::net {
     45 extern const nsCString& TRRProviderKey();
     46 }
     47 
     48 namespace mozilla::net {
     49 
     50 //-----------------------------------------------------------------------------
     51 // nsHttpConnection <public>
     52 //-----------------------------------------------------------------------------
     53 
     54 nsHttpConnection::nsHttpConnection() : mHttpHandler(gHttpHandler) {
     55  LOG(("Creating nsHttpConnection @%p\n", this));
     56 
     57  // the default timeout is for when this connection has not yet processed a
     58  // transaction
     59  static const PRIntervalTime k5Sec = PR_SecondsToInterval(5);
     60  mIdleTimeout = (k5Sec < gHttpHandler->IdleTimeout())
     61                     ? k5Sec
     62                     : gHttpHandler->IdleTimeout();
     63 }
     64 
     65 nsHttpConnection::~nsHttpConnection() {
     66  LOG(("Destroying nsHttpConnection @%p\n", this));
     67 
     68  if (!mEverUsedSpdy) {
     69    LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n", this,
     70         mHttp1xTransactionCount));
     71    glean::http::request_per_conn.AccumulateSingleSample(
     72        mHttp1xTransactionCount);
     73    nsHttpConnectionInfo* ci = nullptr;
     74    if (mTransaction) {
     75      ci = mTransaction->ConnectionInfo();
     76    }
     77    if (!ci) {
     78      ci = mConnInfo;
     79    }
     80 
     81    MOZ_ASSERT(ci);
     82    if (ci->GetIsTrrServiceChannel() && mHttp1xTransactionCount) {
     83      mozilla::glean::networking::trr_request_count_per_conn
     84          .Get(nsPrintfCString("%s_h1", ci->Origin()))
     85          .Add(static_cast<int32_t>(mHttp1xTransactionCount));
     86    }
     87  }
     88 
     89  if (mTotalBytesRead) {
     90    uint32_t totalKBRead = static_cast<uint32_t>(mTotalBytesRead >> 10);
     91    LOG(("nsHttpConnection %p read %dkb on connection spdy=%d\n", this,
     92         totalKBRead, mEverUsedSpdy));
     93    if (mEverUsedSpdy) {
     94      glean::spdy::kbread_per_conn.Accumulate(totalKBRead);
     95    } else {
     96      glean::http::kbread_per_conn2.Accumulate(totalKBRead);
     97    }
     98  }
     99 
    100  if (mForceSendTimer) {
    101    mForceSendTimer->Cancel();
    102    mForceSendTimer = nullptr;
    103  }
    104 
    105  auto ReleaseSocketTransport =
    106      [socketTransport(std::move(mSocketTransport))]() mutable {
    107        socketTransport = nullptr;
    108      };
    109  if (OnSocketThread()) {
    110    ReleaseSocketTransport();
    111  } else {
    112    gSocketTransportService->Dispatch(NS_NewRunnableFunction(
    113        "nsHttpConnection::~nsHttpConnection", ReleaseSocketTransport));
    114  }
    115 }
    116 
    117 nsresult nsHttpConnection::Init(
    118    nsHttpConnectionInfo* info, uint16_t maxHangTime,
    119    nsISocketTransport* transport, nsIAsyncInputStream* instream,
    120    nsIAsyncOutputStream* outstream, bool connectedTransport, nsresult status,
    121    nsIInterfaceRequestor* callbacks, PRIntervalTime rtt, bool forWebSocket) {
    122  LOG1(("nsHttpConnection::Init this=%p sockettransport=%p forWebSocket=%d",
    123        this, transport, forWebSocket));
    124  NS_ENSURE_ARG_POINTER(info);
    125  NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
    126  MOZ_ASSERT(NS_SUCCEEDED(status) || !connectedTransport);
    127 
    128  mConnectedTransport = connectedTransport;
    129  mConnInfo = info;
    130  MOZ_ASSERT(mConnInfo);
    131 
    132  mLastWriteTime = mLastReadTime = PR_IntervalNow();
    133  mRtt = rtt;
    134  mMaxHangTime = PR_SecondsToInterval(maxHangTime);
    135 
    136  mSocketTransport = transport;
    137  mSocketIn = instream;
    138  mSocketOut = outstream;
    139  mForWebSocket = forWebSocket;
    140 
    141  // See explanation for non-strictness of this operation in
    142  // SetSecurityCallbacks.
    143  mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
    144      "nsHttpConnection::mCallbacks", callbacks, false);
    145 
    146  mErrorBeforeConnect = status;
    147  if (NS_SUCCEEDED(mErrorBeforeConnect)) {
    148    mSocketTransport->SetEventSink(this, nullptr);
    149    mSocketTransport->SetSecurityCallbacks(this);
    150    ChangeConnectionState(ConnectionState::INITED);
    151  } else {
    152    SetCloseReason(ToCloseReason(mErrorBeforeConnect));
    153  }
    154 
    155  mTlsHandshaker = new TlsHandshaker(mConnInfo, this);
    156  return NS_OK;
    157 }
    158 
    159 nsresult nsHttpConnection::TryTakeSubTransactions(
    160    nsTArray<RefPtr<nsAHttpTransaction> >& list) {
    161  nsresult rv = mTransaction->TakeSubTransactions(list);
    162 
    163  if (rv == NS_ERROR_ALREADY_OPENED) {
    164    // Has the interface for TakeSubTransactions() changed?
    165    LOG(
    166        ("TakeSubTransactions somehow called after "
    167         "nsAHttpTransaction began processing\n"));
    168    MOZ_ASSERT(false,
    169               "TakeSubTransactions somehow called after "
    170               "nsAHttpTransaction began processing");
    171    mTransaction->Close(NS_ERROR_ABORT);
    172    return rv;
    173  }
    174 
    175  if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
    176    // Has the interface for TakeSubTransactions() changed?
    177    LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
    178    MOZ_ASSERT(false,
    179               "unexpected result from "
    180               "nsAHttpTransaction::TakeSubTransactions()");
    181    mTransaction->Close(NS_ERROR_ABORT);
    182    return rv;
    183  }
    184 
    185  return rv;
    186 }
    187 
    188 void nsHttpConnection::ResetTransaction(RefPtr<nsAHttpTransaction>&& trans,
    189                                        bool aForH2Proxy) {
    190  MOZ_ASSERT(trans);
    191  mSpdySession->SetConnection(trans->Connection());
    192  trans->SetConnection(nullptr);
    193  trans->DoNotRemoveAltSvc();
    194  if (!aForH2Proxy) {
    195    // Only do this when this is for websocket or webtransport over HTTP/2.
    196    trans->SetResettingForTunnelConn(true);
    197  }
    198  if (trans->IsForFallback()) {
    199    trans->InvokeCallback();
    200    trans->Close(NS_OK);
    201  } else {
    202    trans->Close(NS_ERROR_NET_RESET);
    203  }
    204 }
    205 
    206 nsresult nsHttpConnection::MoveTransactionsToSpdy(
    207    nsresult status, nsTArray<RefPtr<nsAHttpTransaction> >& list) {
    208  if (NS_FAILED(status)) {  // includes NS_ERROR_NOT_IMPLEMENTED
    209    MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
    210 
    211    // If this transaction is used to drive websocket or webtransport, we reset
    212    // it to put it in the pending queue. Once we know if the server supports
    213    // websocket or not, the pending queue will be processed.
    214    nsHttpTransaction* trans = mTransaction->QueryHttpTransaction();
    215    if (trans && (trans->IsWebsocketUpgrade() || trans->IsForWebTransport())) {
    216      LOG(
    217          ("nsHttpConnection resetting transaction for websocket or "
    218           "webtransport upgrade"));
    219      // websocket upgrade needs NonSticky for transaction reset
    220      mTransaction->MakeNonSticky();
    221      ResetTransaction(std::move(mTransaction));
    222      mTransaction = nullptr;
    223      return NS_OK;
    224    }
    225 
    226    // This is ok - treat mTransaction as a single real request.
    227    // Wrap the old http transaction into the new spdy session
    228    // as the first stream.
    229    LOG(
    230        ("nsHttpConnection::MoveTransactionsToSpdy moves single transaction %p "
    231         "into SpdySession %p\n",
    232         mTransaction.get(), mSpdySession.get()));
    233    nsresult rv = AddTransaction(mTransaction, mPriority);
    234    if (NS_FAILED(rv)) {
    235      return rv;
    236    }
    237  } else {
    238    int32_t count = list.Length();
    239 
    240    LOG(
    241        ("nsHttpConnection::MoveTransactionsToSpdy moving transaction list "
    242         "len=%d "
    243         "into SpdySession %p\n",
    244         count, mSpdySession.get()));
    245 
    246    if (!count) {
    247      mTransaction->Close(NS_ERROR_ABORT);
    248      return NS_ERROR_ABORT;
    249    }
    250 
    251    for (int32_t index = 0; index < count; ++index) {
    252      RefPtr<nsAHttpTransaction> transaction = list[index];
    253      nsHttpTransaction* trans = transaction->QueryHttpTransaction();
    254      if (trans &&
    255          (trans->IsWebsocketUpgrade() || trans->IsForWebTransport())) {
    256        LOG(
    257            ("nsHttpConnection resetting a transaction for websocket or "
    258             "webtransport upgrade"));
    259        // websocket upgrade needs NonSticky for transaction reset
    260        transaction->MakeNonSticky();
    261        ResetTransaction(std::move(transaction));
    262        transaction = nullptr;
    263        continue;
    264      }
    265      nsresult rv = AddTransaction(list[index], mPriority);
    266      if (NS_FAILED(rv)) {
    267        return rv;
    268      }
    269    }
    270  }
    271 
    272  return NS_OK;
    273 }
    274 
    275 void nsHttpConnection::Start0RTTSpdy(SpdyVersion spdyVersion) {
    276  LOG(("nsHttpConnection::Start0RTTSpdy [this=%p]", this));
    277 
    278  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    279 
    280  mDid0RTTSpdy = true;
    281  mUsingSpdyVersion = spdyVersion;
    282  mEverUsedSpdy = true;
    283  mSpdySession =
    284      ASpdySession::NewSpdySession(spdyVersion, mSocketTransport, true);
    285 
    286  if (mTransaction) {
    287    nsTArray<RefPtr<nsAHttpTransaction> > list;
    288    nsresult rv = TryTakeSubTransactions(list);
    289    if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
    290      LOG(
    291          ("nsHttpConnection::Start0RTTSpdy [this=%p] failed taking "
    292           "subtransactions rv=%" PRIx32,
    293           this, static_cast<uint32_t>(rv)));
    294      return;
    295    }
    296 
    297    rv = MoveTransactionsToSpdy(rv, list);
    298    if (NS_FAILED(rv)) {
    299      LOG(
    300          ("nsHttpConnection::Start0RTTSpdy [this=%p] failed moving "
    301           "transactions rv=%" PRIx32,
    302           this, static_cast<uint32_t>(rv)));
    303      return;
    304    }
    305  }
    306 
    307  mTransaction = mSpdySession;
    308 }
    309 
    310 void nsHttpConnection::StartSpdy(nsITLSSocketControl* sslControl,
    311                                 SpdyVersion spdyVersion) {
    312  LOG(("nsHttpConnection::StartSpdy [this=%p, mDid0RTTSpdy=%d]\n", this,
    313       mDid0RTTSpdy));
    314 
    315  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    316  MOZ_ASSERT(!mSpdySession || mDid0RTTSpdy);
    317 
    318  mUsingSpdyVersion = spdyVersion;
    319  mEverUsedSpdy = true;
    320  if (sslControl) {
    321    sslControl->SetDenyClientCert(true);
    322  }
    323 
    324  if (!mDid0RTTSpdy) {
    325    mSpdySession =
    326        ASpdySession::NewSpdySession(spdyVersion, mSocketTransport, false);
    327  }
    328 
    329  if (!mReportedSpdy) {
    330    mReportedSpdy = true;
    331    // See bug 1797729.
    332    // It's possible that we already have a HTTP/3 connection that can be
    333    // coleased with this connection. We should avoid coalescing with the
    334    // existing HTTP/3 connection if the transaction doesn't allow to use
    335    // HTTP/3.
    336    gHttpHandler->ConnMgr()->ReportSpdyConnection(this, true,
    337                                                  mTransactionDisallowHttp3);
    338  }
    339 
    340  // Setting the connection as reused allows some transactions that fail
    341  // with NS_ERROR_NET_RESET to be restarted and SPDY uses that code
    342  // to handle clean rejections (such as those that arrived after
    343  // a server goaway was generated).
    344  mIsReused = true;
    345 
    346  // If mTransaction is a muxed object it might represent
    347  // several requests. If so, we need to unpack that and
    348  // pack them all into a new spdy session.
    349 
    350  nsTArray<RefPtr<nsAHttpTransaction> > list;
    351  nsresult status = NS_OK;
    352  if (!mDid0RTTSpdy && mTransaction) {
    353    status = TryTakeSubTransactions(list);
    354 
    355    if (NS_FAILED(status) && status != NS_ERROR_NOT_IMPLEMENTED) {
    356      return;
    357    }
    358  }
    359 
    360  if (NeedSpdyTunnel()) {
    361    LOG3(
    362        ("nsHttpConnection::StartSpdy %p Connecting To a HTTP/2 "
    363         "Proxy and Need Connect",
    364         this));
    365    SetTunnelSetupDone();
    366  }
    367 
    368  nsresult rv = NS_OK;
    369  bool spdyProxy = mConnInfo->UsingHttpsProxy() && mConnInfo->UsingConnect() &&
    370                   !mHasTLSTransportLayer;
    371  if (spdyProxy) {
    372    RefPtr<nsHttpConnectionInfo> wildCardProxyCi;
    373    rv = mConnInfo->CreateWildCard(getter_AddRefs(wildCardProxyCi));
    374    MOZ_ASSERT(NS_SUCCEEDED(rv));
    375    gHttpHandler->ConnMgr()->MoveToWildCardConnEntry(mConnInfo, wildCardProxyCi,
    376                                                     this);
    377    mConnInfo = wildCardProxyCi;
    378    MOZ_ASSERT(mConnInfo);
    379  }
    380 
    381  if (!mDid0RTTSpdy && mTransaction) {
    382    if (spdyProxy) {
    383      if (NS_FAILED(status)) {
    384        // proxy upgrade needs Restartable for transaction reset
    385        // note that using NonSticky here won't work because it breaks
    386        // netwerk/test/unit/test_websocket_server.js - h1 ws with h2 proxy
    387        mTransaction->MakeRestartable();
    388        ResetTransaction(std::move(mTransaction), true);
    389        mTransaction = nullptr;
    390      } else {
    391        for (auto trans : list) {
    392          if (!mSpdySession->Connection()) {
    393            mSpdySession->SetConnection(trans->Connection());
    394          }
    395          trans->SetConnection(nullptr);
    396          trans->DoNotRemoveAltSvc();
    397          trans->Close(NS_ERROR_NET_RESET);
    398        }
    399      }
    400    } else {
    401      rv = MoveTransactionsToSpdy(status, list);
    402      if (NS_FAILED(rv)) {
    403        return;
    404      }
    405    }
    406  }
    407 
    408  // Disable TCP Keepalives - use SPDY ping instead.
    409  rv = DisableTCPKeepalives();
    410  if (NS_FAILED(rv)) {
    411    LOG(
    412        ("nsHttpConnection::StartSpdy [%p] DisableTCPKeepalives failed "
    413         "rv[0x%" PRIx32 "]",
    414         this, static_cast<uint32_t>(rv)));
    415  }
    416 
    417  mIdleTimeout = gHttpHandler->SpdyTimeout() * mDefaultTimeoutFactor;
    418 
    419  mTransaction = mSpdySession;
    420 
    421  if (mDontReuse) {
    422    mSpdySession->DontReuse();
    423  }
    424 }
    425 
    426 void nsHttpConnection::PostProcessNPNSetup(bool handshakeSucceeded,
    427                                           bool hasSecurityInfo,
    428                                           bool earlyDataUsed) {
    429  if (mTransaction) {
    430    mTransaction->OnTransportStatus(mSocketTransport,
    431                                    NS_NET_STATUS_TLS_HANDSHAKE_ENDED, 0);
    432  }
    433 
    434  // this is happening after the bootstrap was originally written to. so update
    435  // it.
    436  if (mTransaction && mTransaction->QueryNullTransaction() &&
    437      (mBootstrappedTimings.secureConnectionStart.IsNull() ||
    438       mBootstrappedTimings.tcpConnectEnd.IsNull())) {
    439    mBootstrappedTimings.secureConnectionStart =
    440        mTransaction->QueryNullTransaction()->GetSecureConnectionStart();
    441    mBootstrappedTimings.tcpConnectEnd =
    442        mTransaction->QueryNullTransaction()->GetTcpConnectEnd();
    443  }
    444 
    445  if (hasSecurityInfo) {
    446    mBootstrappedTimings.connectEnd = TimeStamp::Now();
    447  }
    448 
    449  if (earlyDataUsed) {
    450    // Didn't get 0RTT OK, back out of the "attempting 0RTT" state
    451    LOG(("nsHttpConnection::PostProcessNPNSetup [this=%p] 0rtt failed", this));
    452    if (mTransaction && NS_FAILED(mTransaction->Finish0RTT(true, true))) {
    453      mTransaction->Close(NS_ERROR_NET_RESET);
    454    }
    455    mContentBytesWritten0RTT = 0;
    456    if (mDid0RTTSpdy) {
    457      Reset0RttForSpdy();
    458    }
    459  }
    460 
    461  if (hasSecurityInfo) {
    462    // Telemetry for tls failure rate with and without esni;
    463    bool echConfigUsed = false;
    464    mSocketTransport->GetEchConfigUsed(&echConfigUsed);
    465    glean::http::EchconfigSuccessRateLabel label =
    466        echConfigUsed
    467            ? (handshakeSucceeded
    468                   ? glean::http::EchconfigSuccessRateLabel::eEchconfigsucceeded
    469                   : glean::http::EchconfigSuccessRateLabel::eEchconfigfailed)
    470            : (handshakeSucceeded ? glean::http::EchconfigSuccessRateLabel::
    471                                        eNoechconfigsucceeded
    472                                  : glean::http::EchconfigSuccessRateLabel::
    473                                        eNoechconfigfailed);
    474    glean::http::echconfig_success_rate.EnumGet(label).Add();
    475  }
    476 }
    477 
    478 void nsHttpConnection::Reset0RttForSpdy() {
    479  // Reset the work done by Start0RTTSpdy
    480  mUsingSpdyVersion = SpdyVersion::NONE;
    481  mTransaction = nullptr;
    482  mSpdySession = nullptr;
    483  // We have to reset this here, just in case we end up starting spdy again,
    484  // so it can actually do everything it needs to do.
    485  mDid0RTTSpdy = false;
    486 }
    487 
    488 // called on the socket thread
    489 nsresult nsHttpConnection::Activate(nsAHttpTransaction* trans, uint32_t caps,
    490                                    int32_t pri) {
    491  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    492  LOG1(("nsHttpConnection::Activate [this=%p trans=%p caps=%x]\n", this, trans,
    493        caps));
    494 
    495  if (!mExperienced && !trans->IsNullTransaction()) {
    496    mHasFirstHttpTransaction = true;
    497    if (mTlsHandshaker->NPNComplete()) {
    498      mExperienced = true;
    499    }
    500    if (mBootstrappedTimingsSet) {
    501      mBootstrappedTimingsSet = false;
    502      nsHttpTransaction* hTrans = trans->QueryHttpTransaction();
    503      if (hTrans) {
    504        hTrans->BootstrapTimings(mBootstrappedTimings);
    505        SetUrgentStartPreferred(hTrans->GetClassOfService().Flags() &
    506                                nsIClassOfService::UrgentStart);
    507      }
    508    }
    509    mBootstrappedTimings = TimingStruct();
    510  }
    511 
    512  if (caps & NS_HTTP_LARGE_KEEPALIVE) {
    513    mDefaultTimeoutFactor = StaticPrefs::network_http_largeKeepaliveFactor();
    514  }
    515 
    516  mTransactionCaps = caps;
    517  mPriority = pri;
    518 
    519  if (mHasFirstHttpTransaction && mExperienced) {
    520    mHasFirstHttpTransaction = false;
    521    mExperienceState |= ConnectionExperienceState::Experienced;
    522  }
    523 
    524  if (mTransaction && (mUsingSpdyVersion != SpdyVersion::NONE)) {
    525    return AddTransaction(trans, pri);
    526  }
    527 
    528  NS_ENSURE_ARG_POINTER(trans);
    529  NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS);
    530 
    531  // reset the read timers to wash away any idle time
    532  mLastWriteTime = mLastReadTime = PR_IntervalNow();
    533 
    534  // Connection failures are Activated() just like regular transacions.
    535  // If we don't have a confirmation of a connected socket then test it
    536  // with a write() to get relevant error code.
    537  if (NS_FAILED(mErrorBeforeConnect)) {
    538    mSocketOutCondition = mErrorBeforeConnect;
    539    mTransaction = trans;
    540    CloseTransaction(mTransaction, mSocketOutCondition);
    541    return mSocketOutCondition;
    542  }
    543 
    544  if (!mConnectedTransport) {
    545    uint32_t count;
    546    mSocketOutCondition = NS_ERROR_FAILURE;
    547    if (mSocketOut) {
    548      mSocketOutCondition = mSocketOut->Write("", 0, &count);
    549    }
    550    if (NS_FAILED(mSocketOutCondition) &&
    551        mSocketOutCondition != NS_BASE_STREAM_WOULD_BLOCK) {
    552      LOG(("nsHttpConnection::Activate [this=%p] Bad Socket %" PRIx32 "\n",
    553           this, static_cast<uint32_t>(mSocketOutCondition)));
    554      mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
    555      mTransaction = trans;
    556      CloseTransaction(mTransaction, mSocketOutCondition);
    557      return mSocketOutCondition;
    558    }
    559  }
    560 
    561  // take ownership of the transaction
    562  mTransaction = trans;
    563 
    564  // check if this is LNA failure
    565  // XXX - This check should be made earlier, possibly in the
    566  // DnsAndConnectSocket code to avoid unnecessary operations
    567  // See Bug 1968908
    568  nsHttpTransaction* httpTrans = mTransaction->QueryHttpTransaction();
    569 
    570  if (httpTrans && httpTrans->Connection() && !mConnInfo->UsingProxy()) {
    571    NetAddr peerAddr;
    572    httpTrans->Connection()->GetPeerAddr(&peerAddr);
    573    if (!httpTrans->AllowedToConnectToIpAddressSpace(
    574            peerAddr.GetIpAddressSpace())) {
    575      mSocketOutCondition = NS_ERROR_LOCAL_NETWORK_ACCESS_DENIED;
    576      CloseTransaction(mTransaction, mSocketOutCondition);
    577      return mSocketOutCondition;
    578    }
    579  }
    580 
    581  // Update security callbacks
    582  nsCOMPtr<nsIInterfaceRequestor> callbacks;
    583  trans->GetSecurityCallbacks(getter_AddRefs(callbacks));
    584  SetSecurityCallbacks(callbacks);
    585  mTlsHandshaker->SetupSSL(mInSpdyTunnel, mForcePlainText);
    586  if (mTlsHandshaker->NPNComplete()) {
    587    // For non-HTTPS connection, change the state to TRANSFERING directly.
    588    ChangeConnectionState(ConnectionState::TRANSFERING);
    589  } else {
    590    ChangeConnectionState(ConnectionState::TLS_HANDSHAKING);
    591  }
    592 
    593  nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
    594  if (NS_SUCCEEDED(mSocketTransport->GetTlsSocketControl(
    595          getter_AddRefs(tlsSocketControl))) &&
    596      tlsSocketControl) {
    597    tlsSocketControl->SetBrowserId(mTransaction->BrowserId());
    598  }
    599 
    600  MOZ_ASSERT(!mIdleMonitoring, "Activating a connection with an Idle Monitor");
    601  mIdleMonitoring = false;
    602 
    603  // set mKeepAlive according to what will be requested
    604  mKeepAliveMask = mKeepAlive = (caps & NS_HTTP_ALLOW_KEEPALIVE);
    605 
    606  mTransactionDisallowHttp3 |= (caps & NS_HTTP_DISALLOW_HTTP3);
    607 
    608  // need to handle HTTP CONNECT tunnels if this is the first time if
    609  // we are tunneling through a proxy
    610  nsresult rv = CheckTunnelIsNeeded(mTransaction);
    611  if (NS_FAILED(rv)) goto failed_activation;
    612 
    613  // Clear the per activation counter
    614  mCurrentBytesRead = 0;
    615 
    616  // The overflow state is not needed between activations
    617  mInputOverflow = nullptr;
    618 
    619  mResponseTimeoutEnabled = gHttpHandler->ResponseTimeoutEnabled() &&
    620                            mTransaction->ResponseTimeout() > 0 &&
    621                            mTransaction->ResponseTimeoutEnabled();
    622 
    623  rv = StartShortLivedTCPKeepalives();
    624  if (NS_FAILED(rv)) {
    625    LOG(
    626        ("nsHttpConnection::Activate [%p] "
    627         "StartShortLivedTCPKeepalives failed rv[0x%" PRIx32 "]",
    628         this, static_cast<uint32_t>(rv)));
    629  }
    630 
    631  trans->OnActivated();
    632 
    633  rv = OnOutputStreamReady(mSocketOut);
    634 
    635  if (NS_SUCCEEDED(rv) && mContinueHandshakeDone) {
    636    mContinueHandshakeDone();
    637  }
    638  mContinueHandshakeDone = nullptr;
    639 
    640 failed_activation:
    641  if (NS_FAILED(rv)) {
    642    mTransaction = nullptr;
    643  }
    644 
    645  return rv;
    646 }
    647 
    648 nsresult nsHttpConnection::AddTransaction(nsAHttpTransaction* httpTransaction,
    649                                          int32_t priority) {
    650  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    651  MOZ_ASSERT(mSpdySession && (mUsingSpdyVersion != SpdyVersion::NONE),
    652             "AddTransaction to live http connection without spdy/quic");
    653 
    654  // If this is a wild card nshttpconnection (i.e. a spdy proxy) then
    655  // it is important to start the stream using the specific connection
    656  // info of the transaction to ensure it is routed on the right tunnel
    657  nsHttpTransaction* httpTrans = httpTransaction->QueryHttpTransaction();
    658  nsHttpConnectionInfo* transCI = httpTransaction->ConnectionInfo();
    659  if (httpTrans && !transCI->UsingProxy()) {
    660    // this is a httptransaction object, being dispatched into a H2 session
    661    // ensure it does not violate local network access.
    662    NetAddr peerAddr;
    663    if (NS_SUCCEEDED(GetPeerAddr(&peerAddr)) &&
    664        !httpTrans->AllowedToConnectToIpAddressSpace(
    665            peerAddr.GetIpAddressSpace())) {
    666      mSocketOutCondition = NS_ERROR_LOCAL_NETWORK_ACCESS_DENIED;
    667      CloseTransaction(httpTransaction, mSocketOutCondition);
    668      httpTransaction->Close(mSocketOutCondition);
    669      return mSocketOutCondition;
    670    }
    671  }
    672 
    673  bool needTunnel = transCI->UsingHttpsProxy();
    674  needTunnel = needTunnel && !mHasTLSTransportLayer;
    675  needTunnel = needTunnel && transCI->UsingConnect();
    676  needTunnel = needTunnel && httpTransaction->QueryHttpTransaction();
    677 
    678  // Let the transaction know that the tunnel is already established and we
    679  // don't need to setup the tunnel again.
    680  if (transCI->UsingConnect() && mEverUsedSpdy && mHasTLSTransportLayer) {
    681    httpTransaction->OnProxyConnectComplete(200);
    682  }
    683 
    684  LOG(("nsHttpConnection::AddTransaction [this=%p] for %s%s", this,
    685       mSpdySession ? "SPDY" : "QUIC", needTunnel ? " over tunnel" : ""));
    686 
    687  if (mSpdySession) {
    688    if (!mSpdySession->AddStream(httpTransaction, priority, mCallbacks)) {
    689      MOZ_ASSERT(false);  // this cannot happen!
    690      httpTransaction->Close(NS_ERROR_ABORT);
    691      return NS_ERROR_FAILURE;
    692    }
    693  }
    694 
    695  (void)ResumeSend();
    696  return NS_OK;
    697 }
    698 
    699 nsresult nsHttpConnection::CreateTunnelStream(
    700    nsAHttpTransaction* httpTransaction, HttpConnectionBase** aHttpConnection,
    701    bool aIsExtendedCONNECT) {
    702  if (!mSpdySession) {
    703    return NS_ERROR_UNEXPECTED;
    704  }
    705 
    706  auto result = mSpdySession->CreateTunnelStream(httpTransaction, mCallbacks,
    707                                                 mRtt, aIsExtendedCONNECT);
    708  if (result.isErr()) {
    709    return result.unwrapErr();
    710  }
    711  RefPtr<nsHttpConnection> conn = result.unwrap();
    712 
    713  // We need to store the refrence of the Http2Session in the tunneled
    714  // connection, so when nsHttpConnection::DontReuse is called the Http2Session
    715  // can't be reused.
    716  if (aIsExtendedCONNECT) {
    717    LOG(
    718        ("nsHttpConnection::CreateTunnelStream %p Set h2 session %p to "
    719         "tunneled conn %p",
    720         this, mSpdySession.get(), conn.get()));
    721    conn->mExtendedCONNECTHttp2Session = mSpdySession;
    722  }
    723  conn.forget(aHttpConnection);
    724  return NS_OK;
    725 }
    726 
    727 void nsHttpConnection::Close(nsresult reason, bool aIsShutdown) {
    728  LOG(("nsHttpConnection::Close [this=%p reason=%" PRIx32
    729       " mExperienceState=%x]\n",
    730       this, static_cast<uint32_t>(reason),
    731       static_cast<uint32_t>(mExperienceState)));
    732 
    733  if (mConnectionState != ConnectionState::CLOSED) {
    734    RecordConnectionCloseTelemetry(reason);
    735    ChangeConnectionState(ConnectionState::CLOSED);
    736  }
    737 
    738  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    739  mTlsHandshaker->NotifyClose();
    740  mContinueHandshakeDone = nullptr;
    741  mExtendedCONNECTHttp2Session = nullptr;
    742  // Ensure TCP keepalive timer is stopped.
    743  if (mTCPKeepaliveTransitionTimer) {
    744    mTCPKeepaliveTransitionTimer->Cancel();
    745    mTCPKeepaliveTransitionTimer = nullptr;
    746  }
    747  if (mForceSendTimer) {
    748    mForceSendTimer->Cancel();
    749    mForceSendTimer = nullptr;
    750  }
    751 
    752  if (!mTrafficCategory.IsEmpty()) {
    753    HttpTrafficAnalyzer* hta = gHttpHandler->GetHttpTrafficAnalyzer();
    754    if (hta) {
    755      hta->IncrementHttpConnection(std::move(mTrafficCategory));
    756      MOZ_ASSERT(mTrafficCategory.IsEmpty());
    757    }
    758  }
    759 
    760  nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
    761  GetTLSSocketControl(getter_AddRefs(tlsSocketControl));
    762  if (tlsSocketControl) {
    763    tlsSocketControl->SetHandshakeCallbackListener(nullptr);
    764  }
    765 
    766  if (NS_FAILED(reason)) {
    767    if (mIdleMonitoring) EndIdleMonitoring();
    768 
    769    // The connection and security errors clear out alt-svc mappings
    770    // in case any previously validated ones are now invalid
    771    if (((reason == NS_ERROR_NET_RESET) ||
    772         (NS_ERROR_GET_MODULE(reason) == NS_ERROR_MODULE_SECURITY)) &&
    773        mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
    774      gHttpHandler->ClearHostMapping(mConnInfo);
    775    }
    776    if (mTlsHandshaker->EarlyDataWasAvailable() &&
    777        PossibleZeroRTTRetryError(reason)) {
    778      gHttpHandler->Exclude0RttTcp(mConnInfo);
    779    }
    780 
    781    if (mSocketTransport) {
    782      mSocketTransport->SetEventSink(nullptr, nullptr);
    783 
    784      // If there are bytes sitting in the input queue then read them
    785      // into a junk buffer to avoid generating a tcp rst by closing a
    786      // socket with data pending. TLS is a classic case of this where
    787      // a Alert record might be superfulous to a clean HTTP/SPDY shutdown.
    788      // Never block to do this and limit it to a small amount of data.
    789      // During shutdown just be fast!
    790      if (mSocketIn && !aIsShutdown && !mInSpdyTunnel) {
    791        char buffer[4000];
    792        uint32_t count, total = 0;
    793        nsresult rv;
    794        do {
    795          rv = mSocketIn->Read(buffer, 4000, &count);
    796          if (NS_SUCCEEDED(rv)) total += count;
    797        } while (NS_SUCCEEDED(rv) && count > 0 && total < 64000);
    798        LOG(("nsHttpConnection::Close drained %d bytes\n", total));
    799      }
    800 
    801      mSocketTransport->SetSecurityCallbacks(nullptr);
    802      mSocketTransport->Close(reason);
    803      if (mSocketOut) mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
    804    }
    805    mKeepAlive = false;
    806  }
    807 
    808  if (mConnInfo->GetIsTrrServiceChannel() && !mLastTRRResponseTime.IsNull() &&
    809      NS_SUCCEEDED(reason) && !aIsShutdown) {
    810    // Record telemetry keyed by TRR provider.
    811    glean::network::trr_idle_close_time_h1.Get(TRRProviderKey())
    812        .AccumulateRawDuration(TimeStamp::Now() - mLastTRRResponseTime);
    813  }
    814 }
    815 
    816 void nsHttpConnection::MarkAsDontReuse() {
    817  LOG(("nsHttpConnection::MarkAsDontReuse %p\n", this));
    818  mKeepAliveMask = false;
    819  mKeepAlive = false;
    820  mDontReuse = true;
    821  mIdleTimeout = 0;
    822 }
    823 
    824 void nsHttpConnection::DontReuse() {
    825  LOG(("nsHttpConnection::DontReuse %p spdysession=%p\n", this,
    826       mSpdySession.get()));
    827  MarkAsDontReuse();
    828  if (mSpdySession) {
    829    mSpdySession->DontReuse();
    830  } else if (mExtendedCONNECTHttp2Session) {
    831    LOG(("nsHttpConnection::DontReuse %p mExtendedCONNECTHttp2Session=%p\n",
    832         this, mExtendedCONNECTHttp2Session.get()));
    833    mExtendedCONNECTHttp2Session->DontReuse();
    834  }
    835 }
    836 
    837 bool nsHttpConnection::TestJoinConnection(const nsACString& hostname,
    838                                          int32_t port) {
    839  if (mSpdySession && CanDirectlyActivate()) {
    840    return mSpdySession->TestJoinConnection(hostname, port);
    841  }
    842 
    843  return false;
    844 }
    845 
    846 bool nsHttpConnection::JoinConnection(const nsACString& hostname,
    847                                      int32_t port) {
    848  if (mSpdySession && CanDirectlyActivate()) {
    849    return mSpdySession->JoinConnection(hostname, port);
    850  }
    851 
    852  return false;
    853 }
    854 
    855 bool nsHttpConnection::CanReuse() {
    856  if (mDontReuse || !mRemainingConnectionUses) {
    857    return false;
    858  }
    859 
    860  if ((mTransaction ? (mTransaction->IsDone() ? 0U : 1U) : 0U) >=
    861      mRemainingConnectionUses) {
    862    return false;
    863  }
    864 
    865  bool canReuse;
    866  if (mSpdySession) {
    867    canReuse = mSpdySession->CanReuse();
    868  } else {
    869    canReuse = IsKeepAlive();
    870  }
    871 
    872  canReuse = canReuse && (IdleTime() < mIdleTimeout) && IsAlive();
    873 
    874  // An idle persistent connection should not have data waiting to be read
    875  // before a request is sent. Data here is likely a 408 timeout response
    876  // which we would deal with later on through the restart logic, but that
    877  // path is more expensive than just closing the socket now.
    878 
    879  uint64_t dataSize;
    880  if (canReuse && mSocketIn && (mUsingSpdyVersion == SpdyVersion::NONE) &&
    881      mHttp1xTransactionCount &&
    882      NS_SUCCEEDED(mSocketIn->Available(&dataSize)) && dataSize) {
    883    LOG(
    884        ("nsHttpConnection::CanReuse %p %s"
    885         "Socket not reusable because read data pending (%" PRIu64 ") on it.\n",
    886         this, mConnInfo->Origin(), dataSize));
    887    canReuse = false;
    888  }
    889  return canReuse;
    890 }
    891 
    892 bool nsHttpConnection::CanDirectlyActivate() {
    893  // return true if a new transaction can be addded to ths connection at any
    894  // time through Activate(). In practice this means this is a healthy SPDY
    895  // connection with room for more concurrent streams.
    896 
    897  return UsingSpdy() && CanReuse() && mSpdySession &&
    898         mSpdySession->RoomForMoreStreams();
    899 }
    900 
    901 PRIntervalTime nsHttpConnection::IdleTime() {
    902  return mSpdySession ? mSpdySession->IdleTime()
    903                      : (PR_IntervalNow() - mLastReadTime);
    904 }
    905 
    906 // returns the number of seconds left before the allowable idle period
    907 // expires, or 0 if the period has already expied.
    908 uint32_t nsHttpConnection::TimeToLive() {
    909  LOG(("nsHttpConnection::TTL: %p %s idle %d timeout %d\n", this,
    910       mConnInfo->Origin(), IdleTime(), mIdleTimeout));
    911 
    912  if (IdleTime() >= mIdleTimeout) {
    913    return 0;
    914  }
    915 
    916  uint32_t timeToLive = PR_IntervalToSeconds(mIdleTimeout - IdleTime());
    917 
    918  // a positive amount of time can be rounded to 0. Because 0 is used
    919  // as the expiration signal, round all values from 0 to 1 up to 1.
    920  if (!timeToLive) {
    921    timeToLive = 1;
    922  }
    923  return timeToLive;
    924 }
    925 
    926 bool nsHttpConnection::IsAlive() {
    927  if (!mSocketTransport || !mConnectedTransport) return false;
    928 
    929  // SocketTransport::IsAlive can run the SSL state machine, so make sure
    930  // the NPN options are set before that happens.
    931  mTlsHandshaker->SetupSSL(mInSpdyTunnel, mForcePlainText);
    932 
    933  bool alive;
    934  nsresult rv = mSocketTransport->IsAlive(&alive);
    935  if (NS_FAILED(rv)) alive = false;
    936 
    937  return alive;
    938 }
    939 
    940 void nsHttpConnection::SetUrgentStartPreferred(bool urgent) {
    941  if (mExperienced && !mUrgentStartPreferredKnown) {
    942    // Set only according the first ever dispatched non-null transaction
    943    mUrgentStartPreferredKnown = true;
    944    mUrgentStartPreferred = urgent;
    945    LOG(("nsHttpConnection::SetUrgentStartPreferred [this=%p urgent=%d]", this,
    946         urgent));
    947  }
    948 }
    949 
    950 //----------------------------------------------------------------------------
    951 // nsHttpConnection::nsAHttpConnection compatible methods
    952 //----------------------------------------------------------------------------
    953 
    954 nsresult nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction* trans,
    955                                              nsHttpRequestHead* requestHead,
    956                                              nsHttpResponseHead* responseHead,
    957                                              bool* reset) {
    958  LOG(
    959      ("nsHttpConnection::OnHeadersAvailable [this=%p trans=%p "
    960       "response-head=%p]\n",
    961       this, trans, responseHead));
    962 
    963  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    964  NS_ENSURE_ARG_POINTER(trans);
    965  MOZ_ASSERT(responseHead, "No response head?");
    966 
    967  if (mInSpdyTunnel) {
    968    DebugOnly<nsresult> rv =
    969        responseHead->SetHeader(nsHttp::X_Firefox_Spdy_Proxy, "true"_ns);
    970    MOZ_ASSERT(NS_SUCCEEDED(rv));
    971  }
    972 
    973  // we won't change our keep-alive policy unless the server has explicitly
    974  // told us to do so.
    975 
    976  // inspect the connection headers for keep-alive info provided the
    977  // transaction completed successfully. In the case of a non-sensical close
    978  // and keep-alive favor the close out of conservatism.
    979 
    980  bool explicitKeepAlive = false;
    981  bool explicitClose =
    982      responseHead->HasHeaderValue(nsHttp::Connection, "close") ||
    983      responseHead->HasHeaderValue(nsHttp::Proxy_Connection, "close");
    984  if (!explicitClose) {
    985    explicitKeepAlive =
    986        responseHead->HasHeaderValue(nsHttp::Connection, "keep-alive") ||
    987        responseHead->HasHeaderValue(nsHttp::Proxy_Connection, "keep-alive");
    988  }
    989 
    990  // deal with 408 Server Timeouts
    991  uint16_t responseStatus = responseHead->Status();
    992  if (responseStatus == 408) {
    993    // timeouts that are not caused by persistent connection reuse should
    994    // not be retried for browser compatibility reasons. bug 907800. The
    995    // server driven close is implicit in the 408.
    996    explicitClose = true;
    997    explicitKeepAlive = false;
    998  }
    999 
   1000  if ((responseHead->Version() < HttpVersion::v1_1) ||
   1001      (requestHead->Version() < HttpVersion::v1_1)) {
   1002    // HTTP/1.0 connections are by default NOT persistent
   1003    mKeepAlive = explicitKeepAlive;
   1004  } else {
   1005    // HTTP/1.1 connections are by default persistent
   1006    mKeepAlive = !explicitClose;
   1007  }
   1008  mKeepAliveMask = mKeepAlive;
   1009 
   1010  // if this connection is persistent, then the server may send a "Keep-Alive"
   1011  // header specifying the maximum number of times the connection can be
   1012  // reused as well as the maximum amount of time the connection can be idle
   1013  // before the server will close it.  we ignore the max reuse count, because
   1014  // a "keep-alive" connection is by definition capable of being reused, and
   1015  // we only care about being able to reuse it once.  if a timeout is not
   1016  // specified then we use our advertized timeout value.
   1017  bool foundKeepAliveMax = false;
   1018  if (mKeepAlive) {
   1019    nsAutoCString keepAlive;
   1020    (void)responseHead->GetHeader(nsHttp::Keep_Alive, keepAlive);
   1021 
   1022    if (mUsingSpdyVersion == SpdyVersion::NONE) {
   1023      const char* cp = nsCRT::strcasestr(keepAlive.get(), "timeout=");
   1024      if (cp) {
   1025        mIdleTimeout = PR_SecondsToInterval((uint32_t)atoi(cp + 8));
   1026      } else {
   1027        mIdleTimeout = gHttpHandler->IdleTimeout() * mDefaultTimeoutFactor;
   1028      }
   1029 
   1030      cp = nsCRT::strcasestr(keepAlive.get(), "max=");
   1031      if (cp) {
   1032        int maxUses = atoi(cp + 4);
   1033        if (maxUses > 0) {
   1034          foundKeepAliveMax = true;
   1035          mRemainingConnectionUses = static_cast<uint32_t>(maxUses);
   1036        }
   1037      }
   1038    }
   1039 
   1040    LOG(("Connection can be reused [this=%p idle-timeout=%usec]\n", this,
   1041         PR_IntervalToSeconds(mIdleTimeout)));
   1042  }
   1043 
   1044  if (!foundKeepAliveMax && mRemainingConnectionUses &&
   1045      (mUsingSpdyVersion == SpdyVersion::NONE)) {
   1046    --mRemainingConnectionUses;
   1047  }
   1048 
   1049  switch (mState) {
   1050    case HttpConnectionState::SETTING_UP_TUNNEL: {
   1051      nsHttpTransaction* trans = mTransaction->QueryHttpTransaction();
   1052      // Distinguish SETTING_UP_TUNNEL for proxy or websocket via proxy
   1053      // See bug 1848013. Do not call HandleTunnelResponse for a tunnel
   1054      // connection created for WebSocket.
   1055      if (trans && trans->IsWebsocketUpgrade() &&
   1056          (trans->GetProxyConnectResponseCode() == 200 ||
   1057           (mForWebSocket && mInSpdyTunnel))) {
   1058        HandleWebSocketResponse(requestHead, responseHead, responseStatus);
   1059      } else {
   1060        HandleTunnelResponse(responseStatus, reset);
   1061      }
   1062      break;
   1063    }
   1064    default:
   1065      if (requestHead->HasHeader(nsHttp::Upgrade)) {
   1066        HandleWebSocketResponse(requestHead, responseHead, responseStatus);
   1067      } else if (responseStatus == 101) {
   1068        // We got an 101 but we are not asking of a WebSsocket?
   1069        Close(NS_ERROR_ABORT);
   1070      }
   1071  }
   1072 
   1073  mLastHttpResponseVersion = responseHead->Version();
   1074 
   1075  return NS_OK;
   1076 }
   1077 
   1078 void nsHttpConnection::HandleTunnelResponse(uint16_t responseStatus,
   1079                                            bool* reset) {
   1080  LOG(("nsHttpConnection::HandleTunnelResponse()"));
   1081  MOZ_ASSERT(TunnelSetupInProgress());
   1082  MOZ_ASSERT(mProxyConnectStream);
   1083  MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
   1084             "SPDY NPN Complete while using proxy connect stream");
   1085  // If we're doing a proxy connect, we need to check whether or not
   1086  // it was successful.  If so, we have to reset the transaction and step-up
   1087  // the socket connection if using SSL. Finally, we have to wake up the
   1088  // socket write request.
   1089 
   1090  if (responseStatus == 200) {
   1091    ChangeState(HttpConnectionState::REQUEST);
   1092  }
   1093  mProxyConnectStream = nullptr;
   1094  bool isHttps = mTransaction ? mTransaction->ConnectionInfo()->EndToEndSSL()
   1095                              : mConnInfo->EndToEndSSL();
   1096  bool onlyConnect = mTransactionCaps & NS_HTTP_CONNECT_ONLY;
   1097 
   1098  mTransaction->OnProxyConnectComplete(responseStatus);
   1099  if (responseStatus == 200) {
   1100    LOG(("proxy CONNECT succeeded! endtoendssl=%d onlyconnect=%d\n", isHttps,
   1101         onlyConnect));
   1102    // If we're only connecting, we don't need to reset the transaction
   1103    // state. We need to upgrade the socket now without doing the actual
   1104    // http request.
   1105    if (!onlyConnect) {
   1106      *reset = true;
   1107    }
   1108    nsresult rv;
   1109    if (isHttps) {
   1110      bool skipSSL = false;
   1111      if (mConnInfo->UsingHttpsProxy() ||
   1112          mTransactionCaps & NS_HTTP_TLS_TUNNEL) {
   1113        LOG(("%p SetupSecondaryTLS %s %d\n", this, mConnInfo->Origin(),
   1114             mConnInfo->OriginPort()));
   1115        SetupSecondaryTLS();
   1116      } else if (onlyConnect) {
   1117        MOZ_ASSERT(mConnInfo->UsingOnlyHttpProxy(), "Must be a HTTP proxy");
   1118 
   1119        // We have CONNECT only flag and a HTTP proxy is used here, so we can
   1120        // just skip setting up SSL. We have to mark this as complete to finish
   1121        // the transaction and be upgraded.
   1122        mTlsHandshaker->SetNPNComplete();
   1123        skipSSL = true;
   1124      }
   1125 
   1126      if (!skipSSL) {
   1127        rv = mTlsHandshaker->InitSSLParams(false, true);
   1128        LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
   1129      }
   1130    }
   1131    rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
   1132    // XXX what if this fails -- need to handle this error
   1133    MOZ_ASSERT(NS_SUCCEEDED(rv), "mSocketOut->AsyncWait failed");
   1134  } else {
   1135    LOG(("proxy CONNECT failed! endtoendssl=%d onlyconnect=%d\n", isHttps,
   1136         onlyConnect));
   1137    mTransaction->SetProxyConnectFailed();
   1138  }
   1139 }
   1140 
   1141 void nsHttpConnection::HandleWebSocketResponse(nsHttpRequestHead* requestHead,
   1142                                               nsHttpResponseHead* responseHead,
   1143                                               uint16_t responseStatus) {
   1144  LOG(("nsHttpConnection::HandleWebSocketResponse()"));
   1145 
   1146  // Don't use persistent connection for Upgrade unless there's an auth failure:
   1147  // some proxies expect to see auth response on persistent connection.
   1148  // Also allow persistent conn for h2, as we don't want to waste connections
   1149  // for multiplexed upgrades.
   1150  if (responseStatus != 401 && responseStatus != 407 && !mSpdySession) {
   1151    LOG(("HTTP Upgrade in play - disable keepalive for http/1.x\n"));
   1152    MarkAsDontReuse();
   1153  }
   1154 
   1155  // the new Http2StreamWebSocket breaks wpt on
   1156  // h2 basic authentication 401, due to MakeSticky() work around
   1157  // so we DontReuse() in this circumstance
   1158  if (mInSpdyTunnel && (responseStatus == 401 || responseStatus == 407)) {
   1159    MarkAsDontReuse();
   1160    return;
   1161  }
   1162 
   1163  if (responseStatus == 101) {
   1164    nsAutoCString upgradeReq;
   1165    bool hasUpgradeReq =
   1166        NS_SUCCEEDED(requestHead->GetHeader(nsHttp::Upgrade, upgradeReq));
   1167    nsAutoCString upgradeResp;
   1168    bool hasUpgradeResp =
   1169        NS_SUCCEEDED(responseHead->GetHeader(nsHttp::Upgrade, upgradeResp));
   1170    if (!hasUpgradeReq || !hasUpgradeResp ||
   1171        !nsHttp::FindToken(upgradeResp.get(), upgradeReq.get(),
   1172                           HTTP_HEADER_VALUE_SEPS)) {
   1173      LOG(("HTTP 101 Upgrade header mismatch req = %s, resp = %s\n",
   1174           upgradeReq.get(),
   1175           !upgradeResp.IsEmpty() ? upgradeResp.get()
   1176                                  : "RESPONSE's nsHttp::Upgrade is empty"));
   1177      Close(NS_ERROR_ABORT);
   1178    } else {
   1179      LOG(("HTTP Upgrade Response to %s\n", upgradeResp.get()));
   1180    }
   1181  }
   1182 }
   1183 
   1184 bool nsHttpConnection::IsReused() {
   1185  if (mIsReused) return true;
   1186  if (!mConsiderReusedAfterInterval) return false;
   1187 
   1188  // ReusedAfter allows a socket to be consider reused only after a certain
   1189  // interval of time has passed
   1190  return (PR_IntervalNow() - mConsiderReusedAfterEpoch) >=
   1191         mConsiderReusedAfterInterval;
   1192 }
   1193 
   1194 void nsHttpConnection::SetIsReusedAfter(uint32_t afterMilliseconds) {
   1195  mConsiderReusedAfterEpoch = PR_IntervalNow();
   1196  mConsiderReusedAfterInterval = PR_MillisecondsToInterval(afterMilliseconds);
   1197 }
   1198 
   1199 nsresult nsHttpConnection::TakeTransport(nsISocketTransport** aTransport,
   1200                                         nsIAsyncInputStream** aInputStream,
   1201                                         nsIAsyncOutputStream** aOutputStream) {
   1202  if (mUsingSpdyVersion != SpdyVersion::NONE) return NS_ERROR_FAILURE;
   1203  if (mTransaction && !mTransaction->IsDone()) return NS_ERROR_IN_PROGRESS;
   1204  if (!(mSocketTransport && mSocketIn && mSocketOut)) {
   1205    return NS_ERROR_NOT_INITIALIZED;
   1206  }
   1207 
   1208  if (mInputOverflow) mSocketIn = mInputOverflow.forget();
   1209 
   1210  // Change TCP Keepalive frequency to long-lived if currently short-lived.
   1211  if (mTCPKeepaliveConfig == kTCPKeepaliveShortLivedConfig) {
   1212    if (mTCPKeepaliveTransitionTimer) {
   1213      mTCPKeepaliveTransitionTimer->Cancel();
   1214      mTCPKeepaliveTransitionTimer = nullptr;
   1215    }
   1216    nsresult rv = StartLongLivedTCPKeepalives();
   1217    LOG(
   1218        ("nsHttpConnection::TakeTransport [%p] calling "
   1219         "StartLongLivedTCPKeepalives",
   1220         this));
   1221    if (NS_FAILED(rv)) {
   1222      LOG(
   1223          ("nsHttpConnection::TakeTransport [%p] "
   1224           "StartLongLivedTCPKeepalives failed rv[0x%" PRIx32 "]",
   1225           this, static_cast<uint32_t>(rv)));
   1226    }
   1227  }
   1228 
   1229  if (mHasTLSTransportLayer) {
   1230    RefPtr<TLSTransportLayer> tlsTransportLayer =
   1231        do_QueryObject(mSocketTransport);
   1232    if (tlsTransportLayer) {
   1233      // This transport layer is no longer owned by this connection.
   1234      tlsTransportLayer->ReleaseOwner();
   1235    }
   1236  }
   1237 
   1238  mSocketTransport->SetSecurityCallbacks(nullptr);
   1239  mSocketTransport->SetEventSink(nullptr, nullptr);
   1240 
   1241  mSocketTransport.forget(aTransport);
   1242  mSocketIn.forget(aInputStream);
   1243  mSocketOut.forget(aOutputStream);
   1244 
   1245  return NS_OK;
   1246 }
   1247 
   1248 uint32_t nsHttpConnection::ReadTimeoutTick(PRIntervalTime now) {
   1249  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1250 
   1251  // make sure timer didn't tick before Activate()
   1252  if (!mTransaction) return UINT32_MAX;
   1253 
   1254  // Spdy implements some timeout handling using the SPDY ping frame.
   1255  if (mSpdySession) {
   1256    return mSpdySession->ReadTimeoutTick(now);
   1257  }
   1258 
   1259  uint32_t nextTickAfter = UINT32_MAX;
   1260  // Timeout if the response is taking too long to arrive.
   1261  if (mResponseTimeoutEnabled) {
   1262    NS_WARNING_ASSERTION(
   1263        gHttpHandler->ResponseTimeoutEnabled(),
   1264        "Timing out a response, but response timeout is disabled!");
   1265 
   1266    PRIntervalTime initialResponseDelta = now - mLastWriteTime;
   1267 
   1268    if (initialResponseDelta > mTransaction->ResponseTimeout()) {
   1269      LOG(("canceling transaction: no response for %ums: timeout is %dms\n",
   1270           PR_IntervalToMilliseconds(initialResponseDelta),
   1271           PR_IntervalToMilliseconds(mTransaction->ResponseTimeout())));
   1272 
   1273      mResponseTimeoutEnabled = false;
   1274      SetCloseReason(ConnectionCloseReason::IDLE_TIMEOUT);
   1275      // This will also close the connection
   1276      CloseTransaction(mTransaction, NS_ERROR_NET_TIMEOUT);
   1277      return UINT32_MAX;
   1278    }
   1279    nextTickAfter = PR_IntervalToSeconds(mTransaction->ResponseTimeout()) -
   1280                    PR_IntervalToSeconds(initialResponseDelta);
   1281    nextTickAfter = std::max(nextTickAfter, 1U);
   1282  }
   1283 
   1284  if (!mTlsHandshaker->NPNComplete()) {
   1285    // We can reuse mLastWriteTime here, because it is set when the
   1286    // connection is activated and only change when a transaction
   1287    // succesfullu write to the socket and this can only happen after
   1288    // the TLS handshake is done.
   1289    PRIntervalTime initialTLSDelta = now - mLastWriteTime;
   1290    if (initialTLSDelta >
   1291        PR_MillisecondsToInterval(gHttpHandler->TLSHandshakeTimeout())) {
   1292      LOG(
   1293          ("canceling transaction: tls handshake takes too long: tls handshake "
   1294           "last %ums, timeout is %dms.",
   1295           PR_IntervalToMilliseconds(initialTLSDelta),
   1296           gHttpHandler->TLSHandshakeTimeout()));
   1297 
   1298      // This will also close the connection
   1299      SetCloseReason(ConnectionCloseReason::TLS_TIMEOUT);
   1300      CloseTransaction(mTransaction, NS_ERROR_NET_TIMEOUT);
   1301      return UINT32_MAX;
   1302    }
   1303  }
   1304 
   1305  return nextTickAfter;
   1306 }
   1307 
   1308 void nsHttpConnection::UpdateTCPKeepalive(nsITimer* aTimer, void* aClosure) {
   1309  MOZ_ASSERT(aTimer);
   1310  MOZ_ASSERT(aClosure);
   1311 
   1312  nsHttpConnection* self = static_cast<nsHttpConnection*>(aClosure);
   1313 
   1314  if (NS_WARN_IF(self->mUsingSpdyVersion != SpdyVersion::NONE)) {
   1315    return;
   1316  }
   1317 
   1318  // Do not reduce keepalive probe frequency for idle connections.
   1319  if (self->mIdleMonitoring) {
   1320    return;
   1321  }
   1322 
   1323  nsresult rv = self->StartLongLivedTCPKeepalives();
   1324  if (NS_FAILED(rv)) {
   1325    LOG(
   1326        ("nsHttpConnection::UpdateTCPKeepalive [%p] "
   1327         "StartLongLivedTCPKeepalives failed rv[0x%" PRIx32 "]",
   1328         self, static_cast<uint32_t>(rv)));
   1329  }
   1330 }
   1331 
   1332 void nsHttpConnection::GetTLSSocketControl(
   1333    nsITLSSocketControl** tlsSocketControl) {
   1334  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1335  LOG(("nsHttpConnection::GetTLSSocketControl trans=%p socket=%p\n",
   1336       mTransaction.get(), mSocketTransport.get()));
   1337 
   1338  *tlsSocketControl = nullptr;
   1339 
   1340  if (mTransaction && NS_SUCCEEDED(mTransaction->GetTransactionTLSSocketControl(
   1341                          tlsSocketControl))) {
   1342    return;
   1343  }
   1344 
   1345  if (mSocketTransport &&
   1346      NS_SUCCEEDED(mSocketTransport->GetTlsSocketControl(tlsSocketControl))) {
   1347    return;
   1348  }
   1349 }
   1350 
   1351 nsresult nsHttpConnection::PushBack(const char* data, uint32_t length) {
   1352  LOG(("nsHttpConnection::PushBack [this=%p, length=%d]\n", this, length));
   1353 
   1354  if (mInputOverflow) {
   1355    NS_ERROR("nsHttpConnection::PushBack only one buffer supported");
   1356    return NS_ERROR_UNEXPECTED;
   1357  }
   1358 
   1359  mInputOverflow = new nsPreloadedStream(mSocketIn, data, length);
   1360  return NS_OK;
   1361 }
   1362 
   1363 class HttpConnectionForceIO : public Runnable {
   1364 public:
   1365  HttpConnectionForceIO(nsHttpConnection* aConn, bool doRecv)
   1366      : Runnable("net::HttpConnectionForceIO"), mConn(aConn), mDoRecv(doRecv) {}
   1367 
   1368  NS_IMETHOD Run() override {
   1369    MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1370 
   1371    if (mDoRecv) {
   1372      if (!mConn->mSocketIn) return NS_OK;
   1373      return mConn->OnInputStreamReady(mConn->mSocketIn);
   1374    }
   1375 
   1376    MOZ_ASSERT(mConn->mForceSendPending);
   1377    mConn->mForceSendPending = false;
   1378 
   1379    if (!mConn->mSocketOut) {
   1380      return NS_OK;
   1381    }
   1382    return mConn->OnOutputStreamReady(mConn->mSocketOut);
   1383  }
   1384 
   1385 private:
   1386  RefPtr<nsHttpConnection> mConn;
   1387  bool mDoRecv;
   1388 };
   1389 
   1390 nsresult nsHttpConnection::ResumeSend() {
   1391  LOG(("nsHttpConnection::ResumeSend [this=%p]\n", this));
   1392 
   1393  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1394 
   1395  if (mSocketOut) {
   1396    return mSocketOut->AsyncWait(this, 0, 0, nullptr);
   1397  }
   1398 
   1399  MOZ_ASSERT_UNREACHABLE("no socket output stream");
   1400  return NS_ERROR_UNEXPECTED;
   1401 }
   1402 
   1403 nsresult nsHttpConnection::ResumeRecv() {
   1404  LOG(("nsHttpConnection::ResumeRecv [this=%p]\n", this));
   1405 
   1406  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1407 
   1408  // the mLastReadTime timestamp is used for finding slowish readers
   1409  // and can be pretty sensitive. For that reason we actually reset it
   1410  // when we ask to read (resume recv()) so that when we get called back
   1411  // with actual read data in OnSocketReadable() we are only measuring
   1412  // the latency between those two acts and not all the processing that
   1413  // may get done before the ResumeRecv() call
   1414  mLastReadTime = PR_IntervalNow();
   1415 
   1416  if (mSocketIn) {
   1417    if (mHasTLSTransportLayer) {
   1418      RefPtr<TLSTransportLayer> tlsTransportLayer =
   1419          do_QueryObject(mSocketTransport);
   1420      if (tlsTransportLayer) {
   1421        bool hasDataToRecv = tlsTransportLayer->HasDataToRecv();
   1422        if (hasDataToRecv && NS_SUCCEEDED(ForceRecv())) {
   1423          return NS_OK;
   1424        }
   1425        (void)mSocketIn->AsyncWait(this, 0, 0, nullptr);
   1426        // We have to return an error here to let the underlying layer know this
   1427        // connection doesn't read any data.
   1428        return NS_BASE_STREAM_WOULD_BLOCK;
   1429      }
   1430    }
   1431    return mSocketIn->AsyncWait(this, 0, 0, nullptr);
   1432  }
   1433 
   1434  MOZ_ASSERT_UNREACHABLE("no socket input stream");
   1435  return NS_ERROR_UNEXPECTED;
   1436 }
   1437 
   1438 void nsHttpConnection::ForceSendIO(nsITimer* aTimer, void* aClosure) {
   1439  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1440  nsHttpConnection* self = static_cast<nsHttpConnection*>(aClosure);
   1441  MOZ_ASSERT(aTimer == self->mForceSendTimer);
   1442  self->mForceSendTimer = nullptr;
   1443  NS_DispatchToCurrentThread(new HttpConnectionForceIO(self, false));
   1444 }
   1445 
   1446 nsresult nsHttpConnection::MaybeForceSendIO() {
   1447  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1448  // due to bug 1213084 sometimes real I/O events do not get serviced when
   1449  // NSPR derived I/O events are ready and this can cause a deadlock with
   1450  // https over https proxying. Normally we would expect the write callback to
   1451  // be invoked before this timer goes off, but set it at the old windows
   1452  // tick interval (kForceDelay) as a backup for those circumstances.
   1453  static const uint32_t kForceDelay = 17;  // ms
   1454 
   1455  if (mForceSendPending) {
   1456    return NS_OK;
   1457  }
   1458  MOZ_ASSERT(!mForceSendTimer);
   1459  mForceSendPending = true;
   1460  return NS_NewTimerWithFuncCallback(
   1461      getter_AddRefs(mForceSendTimer), nsHttpConnection::ForceSendIO, this,
   1462      kForceDelay, nsITimer::TYPE_ONE_SHOT,
   1463      "net::nsHttpConnection::MaybeForceSendIO"_ns);
   1464 }
   1465 
   1466 // trigger an asynchronous read
   1467 nsresult nsHttpConnection::ForceRecv() {
   1468  LOG(("nsHttpConnection::ForceRecv [this=%p]\n", this));
   1469  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1470 
   1471  return NS_DispatchToCurrentThread(new HttpConnectionForceIO(this, true));
   1472 }
   1473 
   1474 // trigger an asynchronous write
   1475 nsresult nsHttpConnection::ForceSend() {
   1476  LOG(("nsHttpConnection::ForceSend [this=%p]\n", this));
   1477  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1478 
   1479  return MaybeForceSendIO();
   1480 }
   1481 
   1482 void nsHttpConnection::BeginIdleMonitoring() {
   1483  LOG(("nsHttpConnection::BeginIdleMonitoring [this=%p]\n", this));
   1484  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1485  MOZ_ASSERT(!mTransaction, "BeginIdleMonitoring() while active");
   1486  MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
   1487             "Idle monitoring of spdy not allowed");
   1488 
   1489  LOG(("Entering Idle Monitoring Mode [this=%p]", this));
   1490  mIdleMonitoring = true;
   1491  if (mSocketIn) mSocketIn->AsyncWait(this, 0, 0, nullptr);
   1492 }
   1493 
   1494 void nsHttpConnection::EndIdleMonitoring() {
   1495  LOG(("nsHttpConnection::EndIdleMonitoring [this=%p]\n", this));
   1496  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1497  MOZ_ASSERT(!mTransaction, "EndIdleMonitoring() while active");
   1498 
   1499  if (mIdleMonitoring) {
   1500    LOG(("Leaving Idle Monitoring Mode [this=%p]", this));
   1501    mIdleMonitoring = false;
   1502    if (mSocketIn) mSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
   1503  }
   1504 }
   1505 
   1506 HttpVersion nsHttpConnection::Version() {
   1507  if (mUsingSpdyVersion != SpdyVersion::NONE) {
   1508    return HttpVersion::v2_0;
   1509  }
   1510  return mLastHttpResponseVersion;
   1511 }
   1512 
   1513 PRIntervalTime nsHttpConnection::LastWriteTime() { return mLastWriteTime; }
   1514 
   1515 //-----------------------------------------------------------------------------
   1516 // nsHttpConnection <private>
   1517 //-----------------------------------------------------------------------------
   1518 
   1519 void nsHttpConnection::CloseTransaction(nsAHttpTransaction* trans,
   1520                                        nsresult reason, bool aIsShutdown) {
   1521  LOG(("nsHttpConnection::CloseTransaction[this=%p trans=%p reason=%" PRIx32
   1522       "]\n",
   1523       this, trans, static_cast<uint32_t>(reason)));
   1524 
   1525  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1526 
   1527  if (mCurrentBytesRead > mMaxBytesRead) mMaxBytesRead = mCurrentBytesRead;
   1528 
   1529  // mask this error code because its not a real error.
   1530  if (reason == NS_BASE_STREAM_CLOSED) reason = NS_OK;
   1531 
   1532  if (mUsingSpdyVersion != SpdyVersion::NONE) {
   1533    DontReuse();
   1534    // if !mSpdySession then mUsingSpdyVersion must be false for canreuse()
   1535    mSpdySession->SetCleanShutdown(aIsShutdown);
   1536    mUsingSpdyVersion = SpdyVersion::NONE;
   1537    mSpdySession = nullptr;
   1538  }
   1539 
   1540  if ((NS_SUCCEEDED(reason) || NS_BASE_STREAM_CLOSED == reason) &&
   1541      trans->ConnectionInfo() &&
   1542      trans->ConnectionInfo()->GetIsTrrServiceChannel()) {
   1543    // save time of last successful response
   1544    mLastTRRResponseTime = TimeStamp::Now();
   1545  }
   1546 
   1547  if (mTransaction) {
   1548    LOG(("  closing associated mTransaction"));
   1549    if (NS_SUCCEEDED(reason)) {
   1550      mHttp1xTransactionCount += mTransaction->Http1xTransactionCount();
   1551    }
   1552 
   1553    mTransaction->Close(reason);
   1554    mTransaction = nullptr;
   1555  }
   1556 
   1557  {
   1558    MutexAutoLock lock(mCallbacksLock);
   1559    mCallbacks = nullptr;
   1560  }
   1561 
   1562  if (NS_FAILED(reason) && (reason != NS_BINDING_RETARGETED)) {
   1563    Close(reason, aIsShutdown);
   1564  }
   1565 
   1566  // flag the connection as reused here for convenience sake.  certainly
   1567  // it might be going away instead ;-)
   1568  mIsReused = true;
   1569 }
   1570 
   1571 bool nsHttpConnection::CheckCanWrite0RTTData() {
   1572  MOZ_ASSERT(mTlsHandshaker->EarlyDataAvailable());
   1573  nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
   1574  GetTLSSocketControl(getter_AddRefs(tlsSocketControl));
   1575  if (!tlsSocketControl) {
   1576    return false;
   1577  }
   1578  nsCOMPtr<nsITransportSecurityInfo> securityInfo;
   1579  if (NS_FAILED(
   1580          tlsSocketControl->GetSecurityInfo(getter_AddRefs(securityInfo)))) {
   1581    return false;
   1582  }
   1583  if (!securityInfo) {
   1584    return false;
   1585  }
   1586  nsAutoCString negotiatedNPN;
   1587  // If the following code fails means that the handshake is not done
   1588  // yet, so continue writing 0RTT data.
   1589  nsresult rv = securityInfo->GetNegotiatedNPN(negotiatedNPN);
   1590  if (NS_FAILED(rv)) {
   1591    return true;
   1592  }
   1593  bool earlyDataAccepted = false;
   1594  rv = tlsSocketControl->GetEarlyDataAccepted(&earlyDataAccepted);
   1595  // If 0RTT data is accepted we can continue writing data,
   1596  // if it is reject stop writing more data.
   1597  return NS_SUCCEEDED(rv) && earlyDataAccepted;
   1598 }
   1599 
   1600 nsresult nsHttpConnection::OnReadSegment(const char* buf, uint32_t count,
   1601                                         uint32_t* countRead) {
   1602  LOG(("nsHttpConnection::OnReadSegment [this=%p]\n", this));
   1603  if (count == 0) {
   1604    // some ReadSegments implementations will erroneously call the writer
   1605    // to consume 0 bytes worth of data.  we must protect against this case
   1606    // or else we'd end up closing the socket prematurely.
   1607    NS_ERROR("bad ReadSegments implementation");
   1608    return NS_ERROR_FAILURE;  // stop iterating
   1609  }
   1610 
   1611  // If we are waiting for 0RTT Response, check maybe nss has finished
   1612  // handshake already.
   1613  // IsAlive() calls drive the handshake and that may cause nss and necko
   1614  // to be out of sync.
   1615  if (mTlsHandshaker->EarlyDataAvailable() && !CheckCanWrite0RTTData()) {
   1616    MOZ_DIAGNOSTIC_ASSERT(mTlsHandshaker->TlsHandshakeComplitionPending());
   1617    LOG(
   1618        ("nsHttpConnection::OnReadSegment Do not write any data, wait"
   1619         " for EnsureNPNComplete to be called [this=%p]",
   1620         this));
   1621    *countRead = 0;
   1622    return NS_BASE_STREAM_WOULD_BLOCK;
   1623  }
   1624 
   1625  nsresult rv = mSocketOut->Write(buf, count, countRead);
   1626  if (NS_FAILED(rv)) {
   1627    mSocketOutCondition = rv;
   1628  } else if (*countRead == 0) {
   1629    mSocketOutCondition = NS_BASE_STREAM_CLOSED;
   1630  } else {
   1631    mLastWriteTime = PR_IntervalNow();
   1632    mSocketOutCondition = NS_OK;  // reset condition
   1633    if (!TunnelSetupInProgress()) {
   1634      mTotalBytesWritten += *countRead;
   1635      mExperienceState |= ConnectionExperienceState::First_Request_Sent;
   1636    }
   1637  }
   1638 
   1639  return mSocketOutCondition;
   1640 }
   1641 
   1642 nsresult nsHttpConnection::OnSocketWritable() {
   1643  LOG(("nsHttpConnection::OnSocketWritable [this=%p] host=%s\n", this,
   1644       mConnInfo->Origin()));
   1645 
   1646  nsresult rv;
   1647  uint32_t transactionBytes;
   1648  bool again = true;
   1649 
   1650  // Prevent STS thread from being blocked by single OnOutputStreamReady
   1651  // callback.
   1652  const uint32_t maxWriteAttempts = 128;
   1653  uint32_t writeAttempts = 0;
   1654 
   1655  if (mTransactionCaps & NS_HTTP_CONNECT_ONLY) {
   1656    if (!mConnInfo->UsingConnect()) {
   1657      // A CONNECT has been requested for this connection but will never
   1658      // be performed. This should never happen.
   1659      MOZ_ASSERT(false, "proxy connect will never happen");
   1660      LOG(("return failure because proxy connect will never happen\n"));
   1661      return NS_ERROR_FAILURE;
   1662    }
   1663 
   1664    if (mState == HttpConnectionState::REQUEST &&
   1665        mTlsHandshaker->EnsureNPNComplete()) {
   1666      // Don't need to check this each write attempt since it is only
   1667      // updated after OnSocketWritable completes.
   1668      // We've already done primary tls (if needed) and sent our CONNECT.
   1669      // If we're doing a CONNECT only request there's no need to write
   1670      // the http transaction.
   1671      LOG(("return NS_BASE_STREAM_CLOSED to make transaction closed\n"));
   1672      return NS_BASE_STREAM_CLOSED;
   1673    }
   1674  }
   1675 
   1676  do {
   1677    ++writeAttempts;
   1678    rv = mSocketOutCondition = NS_OK;
   1679    transactionBytes = 0;
   1680 
   1681    switch (mState) {
   1682      case HttpConnectionState::SETTING_UP_TUNNEL:
   1683        if (mConnInfo->UsingHttpsProxy() &&
   1684            !mTlsHandshaker->EnsureNPNComplete()) {
   1685          MOZ_DIAGNOSTIC_ASSERT(!mTlsHandshaker->EarlyDataAvailable());
   1686          mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
   1687        } else {
   1688          rv = SendConnectRequest(this, &transactionBytes);
   1689        }
   1690        break;
   1691      default: {
   1692        // The SSL handshake must be completed before the
   1693        // transaction->readsegments() processing can proceed because we need to
   1694        // know how to format the request differently for http/1, http/2, spdy,
   1695        // etc.. and that is negotiated with NPN/ALPN in the SSL handshake.
   1696        if (!mTlsHandshaker->EnsureNPNComplete() &&
   1697            (!mTlsHandshaker->EarlyDataUsed() ||
   1698             mTlsHandshaker->TlsHandshakeComplitionPending())) {
   1699          // The handshake is not done and we cannot write 0RTT data or nss has
   1700          // already finished 0RTT data.
   1701          mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
   1702        } else if (!mTransaction) {
   1703          rv = NS_ERROR_FAILURE;
   1704          LOG(("  No Transaction In OnSocketWritable\n"));
   1705        } else if (NS_SUCCEEDED(rv)) {
   1706          // for non spdy sessions let the connection manager know
   1707          if (!mReportedSpdy && mTlsHandshaker->NPNComplete()) {
   1708            mReportedSpdy = true;
   1709            MOZ_ASSERT(!mEverUsedSpdy);
   1710            gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false, false);
   1711          }
   1712 
   1713          LOG(("  writing transaction request stream\n"));
   1714          RefPtr<nsAHttpTransaction> transaction = mTransaction;
   1715          rv = transaction->ReadSegmentsAgain(this,
   1716                                              nsIOService::gDefaultSegmentSize,
   1717                                              &transactionBytes, &again);
   1718          if (mTlsHandshaker->EarlyDataUsed()) {
   1719            mContentBytesWritten0RTT += transactionBytes;
   1720            if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
   1721              // If an error happens while writting 0RTT data, restart
   1722              // the transactiions without 0RTT.
   1723              mTlsHandshaker->FinishNPNSetup(false, true);
   1724            }
   1725          } else {
   1726            mContentBytesWritten += transactionBytes;
   1727          }
   1728        }
   1729      }
   1730    }
   1731 
   1732    LOG(
   1733        ("nsHttpConnection::OnSocketWritable %p "
   1734         "ReadSegments returned [rv=%" PRIx32 " read=%u "
   1735         "sock-cond=%" PRIx32 " again=%d]\n",
   1736         this, static_cast<uint32_t>(rv), transactionBytes,
   1737         static_cast<uint32_t>(mSocketOutCondition), again));
   1738 
   1739    // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
   1740    if (rv == NS_BASE_STREAM_CLOSED &&
   1741        (mTransaction && !mTransaction->IsDone())) {
   1742      rv = NS_OK;
   1743      transactionBytes = 0;
   1744    }
   1745 
   1746    if (NS_FAILED(rv)) {
   1747      // if the transaction didn't want to write any more data, then
   1748      // wait for the transaction to call ResumeSend.
   1749      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   1750        rv = NS_OK;
   1751      }
   1752      again = false;
   1753    } else if (NS_FAILED(mSocketOutCondition)) {
   1754      if (mSocketOutCondition == NS_BASE_STREAM_WOULD_BLOCK) {
   1755        if (!mTlsHandshaker->EarlyDataCanNotBeUsed()) {
   1756          // continue writing
   1757          // We are not going to poll for write if the handshake is in progress,
   1758          // but early data cannot be used.
   1759          rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
   1760        }
   1761      } else {
   1762        rv = mSocketOutCondition;
   1763      }
   1764      again = false;
   1765    } else if (!transactionBytes) {
   1766      rv = NS_OK;
   1767 
   1768      if (mTransaction) {  // in case the ReadSegments stack called
   1769                           // CloseTransaction()
   1770        //
   1771        // at this point we've written out the entire transaction, and now we
   1772        // must wait for the server's response.  we manufacture a status message
   1773        // here to reflect the fact that we are waiting.  this message will be
   1774        // trumped (overwritten) if the server responds quickly.
   1775        //
   1776        mTransaction->OnTransportStatus(mSocketTransport,
   1777                                        NS_NET_STATUS_WAITING_FOR, 0);
   1778 
   1779        rv = ResumeRecv();  // start reading
   1780      }
   1781      // When Spdy tunnel is used we need to explicitly set when a request is
   1782      // done.
   1783      if ((mState != HttpConnectionState::SETTING_UP_TUNNEL) && !mSpdySession) {
   1784        nsHttpTransaction* trans =
   1785            mTransaction ? mTransaction->QueryHttpTransaction() : nullptr;
   1786        // needed for websocket over h2 (direct)
   1787        if (!trans ||
   1788            (!trans->IsWebsocketUpgrade() && !trans->IsForWebTransport())) {
   1789          mRequestDone = true;
   1790        }
   1791      }
   1792      again = false;
   1793    } else if (writeAttempts >= maxWriteAttempts) {
   1794      LOG(("  yield for other transactions\n"));
   1795      rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);  // continue writing
   1796      again = false;
   1797    }
   1798    // write more to the socket until error or end-of-request...
   1799  } while (again && gHttpHandler->Active());
   1800 
   1801  return rv;
   1802 }
   1803 
   1804 nsresult nsHttpConnection::OnWriteSegment(char* buf, uint32_t count,
   1805                                          uint32_t* countWritten) {
   1806  if (count == 0) {
   1807    // some WriteSegments implementations will erroneously call the reader
   1808    // to provide 0 bytes worth of data.  we must protect against this case
   1809    // or else we'd end up closing the socket prematurely.
   1810    NS_ERROR("bad WriteSegments implementation");
   1811    return NS_ERROR_FAILURE;  // stop iterating
   1812  }
   1813 
   1814  if (ChaosMode::isActive(ChaosFeature::IOAmounts) &&
   1815      ChaosMode::randomUint32LessThan(2)) {
   1816    // read 1...count bytes
   1817    count = ChaosMode::randomUint32LessThan(count) + 1;
   1818  }
   1819 
   1820  nsresult rv = mSocketIn->Read(buf, count, countWritten);
   1821  if (NS_FAILED(rv)) {
   1822    mSocketInCondition = rv;
   1823  } else if (*countWritten == 0) {
   1824    mSocketInCondition = NS_BASE_STREAM_CLOSED;
   1825  } else {
   1826    mSocketInCondition = NS_OK;  // reset condition
   1827    mExperienceState |= ConnectionExperienceState::First_Response_Received;
   1828  }
   1829 
   1830  return mSocketInCondition;
   1831 }
   1832 
   1833 nsresult nsHttpConnection::OnSocketReadable() {
   1834  LOG(("nsHttpConnection::OnSocketReadable [this=%p]\n", this));
   1835 
   1836  PRIntervalTime now = PR_IntervalNow();
   1837  PRIntervalTime delta = now - mLastReadTime;
   1838 
   1839  // Reset mResponseTimeoutEnabled to stop response timeout checks.
   1840  mResponseTimeoutEnabled = false;
   1841 
   1842  if ((mTransactionCaps & NS_HTTP_CONNECT_ONLY) && !mConnInfo->UsingConnect()) {
   1843    // A CONNECT has been requested for this connection but will never
   1844    // be performed. This should never happen.
   1845    MOZ_ASSERT(false, "proxy connect will never happen");
   1846    LOG(("return failure because proxy connect will never happen\n"));
   1847    return NS_ERROR_FAILURE;
   1848  }
   1849 
   1850  if (mKeepAliveMask && (delta >= mMaxHangTime)) {
   1851    LOG(("max hang time exceeded!\n"));
   1852    // give the handler a chance to create a new persistent connection to
   1853    // this host if we've been busy for too long.
   1854    mKeepAliveMask = false;
   1855    (void)gHttpHandler->ProcessPendingQ(mConnInfo);
   1856  }
   1857 
   1858  // Reduce the estimate of the time since last read by up to 1 RTT to
   1859  // accommodate exhausted sender TCP congestion windows or minor I/O delays.
   1860  mLastReadTime = now;
   1861 
   1862  nsresult rv = NS_OK;
   1863  uint32_t n;
   1864  bool again = true;
   1865 
   1866  do {
   1867    if (!TunnelSetupInProgress() && !mTlsHandshaker->EnsureNPNComplete()) {
   1868      // Unless we are setting up a tunnel via CONNECT, prevent reading
   1869      // from the socket until the results of NPN
   1870      // negotiation are known (which is determined from the write path).
   1871      // If the server speaks SPDY it is likely the readable data here is
   1872      // a spdy settings frame and without NPN it would be misinterpreted
   1873      // as HTTP/*
   1874 
   1875      LOG(
   1876          ("nsHttpConnection::OnSocketReadable %p return due to inactive "
   1877           "tunnel setup but incomplete NPN state\n",
   1878           this));
   1879      if (mTlsHandshaker->EarlyDataAvailable() || mHasTLSTransportLayer) {
   1880        rv = ResumeRecv();
   1881      }
   1882      break;
   1883    }
   1884 
   1885    mSocketInCondition = NS_OK;
   1886    if (!mTransaction) {
   1887      rv = NS_ERROR_FAILURE;
   1888      LOG(("  No Transaction In OnSocketWritable\n"));
   1889    } else {
   1890      RefPtr<nsAHttpTransaction> transaction = mTransaction;
   1891      rv = transaction->WriteSegmentsAgain(
   1892          this, nsIOService::gDefaultSegmentSize, &n, &again);
   1893    }
   1894    LOG(("nsHttpConnection::OnSocketReadable %p trans->ws rv=%" PRIx32
   1895         " n=%d socketin=%" PRIx32 "\n",
   1896         this, static_cast<uint32_t>(rv), n,
   1897         static_cast<uint32_t>(mSocketInCondition)));
   1898    if (NS_FAILED(rv)) {
   1899      // if the transaction didn't want to take any more data, then
   1900      // wait for the transaction to call ResumeRecv.
   1901      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   1902        rv = NS_OK;
   1903      }
   1904      again = false;
   1905    } else {
   1906      mCurrentBytesRead += n;
   1907      mTotalBytesRead += n;
   1908      if (NS_FAILED(mSocketInCondition)) {
   1909        // continue waiting for the socket if necessary...
   1910        if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) {
   1911          rv = ResumeRecv();
   1912        } else {
   1913          rv = mSocketInCondition;
   1914        }
   1915        again = false;
   1916      }
   1917    }
   1918    // read more from the socket until error...
   1919  } while (again && gHttpHandler->Active());
   1920 
   1921  return rv;
   1922 }
   1923 
   1924 void nsHttpConnection::SetupSecondaryTLS() {
   1925  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1926  MOZ_ASSERT(!mHasTLSTransportLayer);
   1927  LOG(("nsHttpConnection %p SetupSecondaryTLS %s %d\n", this,
   1928       mConnInfo->Origin(), mConnInfo->OriginPort()));
   1929 
   1930  nsHttpConnectionInfo* ci = nullptr;
   1931  if (mTransaction) {
   1932    ci = mTransaction->ConnectionInfo();
   1933  }
   1934  if (!ci) {
   1935    ci = mConnInfo;
   1936  }
   1937  MOZ_ASSERT(ci);
   1938 
   1939  RefPtr<TLSTransportLayer> transportLayer =
   1940      new TLSTransportLayer(mSocketTransport, mSocketIn, mSocketOut, this);
   1941  if (transportLayer->Init(ci->Origin(), ci->OriginPort())) {
   1942    mSocketIn = transportLayer->GetInputStreamWrapper();
   1943    mSocketOut = transportLayer->GetOutputStreamWrapper();
   1944    mSocketTransport = transportLayer;
   1945    mHasTLSTransportLayer = true;
   1946    LOG(("Create mTLSTransportLayer %p", this));
   1947  }
   1948 }
   1949 
   1950 void nsHttpConnection::SetInTunnel() {
   1951  mInSpdyTunnel = true;
   1952  mForcePlainText = true;
   1953 }
   1954 
   1955 // static
   1956 nsresult nsHttpConnection::MakeConnectString(nsAHttpTransaction* trans,
   1957                                             nsHttpRequestHead* request,
   1958                                             nsACString& result, bool h2ws,
   1959                                             bool aShouldResistFingerprinting) {
   1960  result.Truncate();
   1961  if (!trans->ConnectionInfo()) {
   1962    return NS_ERROR_NOT_INITIALIZED;
   1963  }
   1964 
   1965  DebugOnly<nsresult> rv{};
   1966 
   1967  rv = nsHttpHandler::GenerateHostPort(
   1968      nsDependentCString(trans->ConnectionInfo()->Origin()),
   1969      trans->ConnectionInfo()->OriginPort(), result);
   1970  MOZ_ASSERT(NS_SUCCEEDED(rv));
   1971 
   1972  // CONNECT host:port HTTP/1.1
   1973  request->SetMethod("CONNECT"_ns);
   1974  request->SetVersion(gHttpHandler->HttpVersion());
   1975  if (h2ws) {
   1976    // HTTP/2 websocket CONNECT forms need the full request URI
   1977    nsAutoCString requestURI;
   1978    trans->RequestHead()->RequestURI(requestURI);
   1979    request->SetRequestURI(requestURI);
   1980 
   1981    request->SetHTTPS(trans->RequestHead()->IsHTTPS());
   1982 
   1983    nsAutoCString val;
   1984    if (NS_SUCCEEDED(trans->RequestHead()->GetHeader(
   1985            nsHttp::Sec_WebSocket_Extensions, val))) {
   1986      rv = request->SetHeader(nsHttp::Sec_WebSocket_Extensions, val);
   1987      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1988    }
   1989    if (NS_SUCCEEDED(trans->RequestHead()->GetHeader(
   1990            nsHttp::Sec_WebSocket_Protocol, val))) {
   1991      rv = request->SetHeader(nsHttp::Sec_WebSocket_Protocol, val);
   1992      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1993    }
   1994    if (NS_SUCCEEDED(trans->RequestHead()->GetHeader(
   1995            nsHttp::Sec_WebSocket_Version, val))) {
   1996      rv = request->SetHeader(nsHttp::Sec_WebSocket_Version, val);
   1997      MOZ_ASSERT(NS_SUCCEEDED(rv));
   1998    }
   1999  } else {
   2000    request->SetRequestURI(result);
   2001  }
   2002  rv = request->SetHeader(nsHttp::User_Agent,
   2003                          gHttpHandler->UserAgent(aShouldResistFingerprinting));
   2004  MOZ_ASSERT(NS_SUCCEEDED(rv));
   2005 
   2006  // a CONNECT is always persistent
   2007  rv = request->SetHeader(nsHttp::Proxy_Connection, "keep-alive"_ns);
   2008  MOZ_ASSERT(NS_SUCCEEDED(rv));
   2009  rv = request->SetHeader(nsHttp::Connection, "keep-alive"_ns);
   2010  MOZ_ASSERT(NS_SUCCEEDED(rv));
   2011 
   2012  // all HTTP/1.1 requests must include a Host header (even though it
   2013  // may seem redundant in this case; see bug 82388).
   2014  rv = request->SetHeader(nsHttp::Host, result);
   2015  MOZ_ASSERT(NS_SUCCEEDED(rv));
   2016 
   2017  nsAutoCString val;
   2018  if (NS_SUCCEEDED(
   2019          trans->RequestHead()->GetHeader(nsHttp::Proxy_Authorization, val))) {
   2020    // we don't know for sure if this authorization is intended for the
   2021    // SSL proxy, so we add it just in case.
   2022    rv = request->SetHeader(nsHttp::Proxy_Authorization, val);
   2023    MOZ_ASSERT(NS_SUCCEEDED(rv));
   2024  }
   2025  if ((trans->Caps() & NS_HTTP_CONNECT_ONLY) &&
   2026      NS_SUCCEEDED(trans->RequestHead()->GetHeader(nsHttp::Upgrade, val))) {
   2027    // rfc7639 proposes using the ALPN header to indicate the protocol used
   2028    // in CONNECT when not used for TLS. The protocol is stored in Upgrade.
   2029    // We have to copy this header here since a new HEAD request is created
   2030    // for the CONNECT.
   2031    rv = request->SetHeader("ALPN"_ns, val);
   2032    MOZ_ASSERT(NS_SUCCEEDED(rv));
   2033  }
   2034 
   2035  result.Truncate();
   2036  request->Flatten(result, false);
   2037 
   2038  if (LOG1_ENABLED()) {
   2039    LOG(("nsHttpConnection::MakeConnectString for transaction=%p h2ws=%d[",
   2040         trans->QueryHttpTransaction(), h2ws));
   2041    LogHeaders(result.BeginReading());
   2042    LOG(("]"));
   2043  }
   2044 
   2045  result.AppendLiteral("\r\n");
   2046  return NS_OK;
   2047 }
   2048 
   2049 nsresult nsHttpConnection::StartShortLivedTCPKeepalives() {
   2050  if (mUsingSpdyVersion != SpdyVersion::NONE) {
   2051    return NS_OK;
   2052  }
   2053  MOZ_ASSERT(mSocketTransport);
   2054  if (!mSocketTransport) {
   2055    return NS_ERROR_NOT_INITIALIZED;
   2056  }
   2057 
   2058  nsresult rv = NS_OK;
   2059  int32_t idleTimeS = -1;
   2060  int32_t retryIntervalS = -1;
   2061  if (gHttpHandler->TCPKeepaliveEnabledForShortLivedConns()) {
   2062    // Set the idle time.
   2063    idleTimeS = gHttpHandler->GetTCPKeepaliveShortLivedIdleTime();
   2064    LOG(
   2065        ("nsHttpConnection::StartShortLivedTCPKeepalives[%p] "
   2066         "idle time[%ds].",
   2067         this, idleTimeS));
   2068 
   2069    retryIntervalS = std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
   2070    rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
   2071    if (NS_FAILED(rv)) {
   2072      return rv;
   2073    }
   2074    rv = mSocketTransport->SetKeepaliveEnabled(true);
   2075    mTCPKeepaliveConfig = kTCPKeepaliveShortLivedConfig;
   2076  } else {
   2077    rv = mSocketTransport->SetKeepaliveEnabled(false);
   2078    mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
   2079  }
   2080  if (NS_FAILED(rv)) {
   2081    return rv;
   2082  }
   2083 
   2084  // Start a timer to move to long-lived keepalive config.
   2085  if (!mTCPKeepaliveTransitionTimer) {
   2086    mTCPKeepaliveTransitionTimer = NS_NewTimer();
   2087  }
   2088 
   2089  if (mTCPKeepaliveTransitionTimer) {
   2090    int32_t time = gHttpHandler->GetTCPKeepaliveShortLivedTime();
   2091 
   2092    // Adjust |time| to ensure a full set of keepalive probes can be sent
   2093    // at the end of the short-lived phase.
   2094    if (gHttpHandler->TCPKeepaliveEnabledForShortLivedConns()) {
   2095      if (NS_WARN_IF(!gSocketTransportService)) {
   2096        return NS_ERROR_NOT_INITIALIZED;
   2097      }
   2098      int32_t probeCount = -1;
   2099      rv = gSocketTransportService->GetKeepaliveProbeCount(&probeCount);
   2100      if (NS_WARN_IF(NS_FAILED(rv))) {
   2101        return rv;
   2102      }
   2103      if (NS_WARN_IF(probeCount <= 0)) {
   2104        return NS_ERROR_UNEXPECTED;
   2105      }
   2106      // Add time for final keepalive probes, and 2 seconds for a buffer.
   2107      time += ((probeCount)*retryIntervalS) - (time % idleTimeS) + 2;
   2108    }
   2109    mTCPKeepaliveTransitionTimer->InitWithNamedFuncCallback(
   2110        nsHttpConnection::UpdateTCPKeepalive, this, (uint32_t)time * 1000,
   2111        nsITimer::TYPE_ONE_SHOT,
   2112        "net::nsHttpConnection::StartShortLivedTCPKeepalives"_ns);
   2113  } else {
   2114    NS_WARNING(
   2115        "nsHttpConnection::StartShortLivedTCPKeepalives failed to "
   2116        "create timer.");
   2117  }
   2118 
   2119  return NS_OK;
   2120 }
   2121 
   2122 nsresult nsHttpConnection::StartLongLivedTCPKeepalives() {
   2123  MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
   2124             "Don't use TCP Keepalive with SPDY!");
   2125  if (NS_WARN_IF(mUsingSpdyVersion != SpdyVersion::NONE)) {
   2126    return NS_OK;
   2127  }
   2128  MOZ_ASSERT(mSocketTransport);
   2129  if (!mSocketTransport) {
   2130    return NS_ERROR_NOT_INITIALIZED;
   2131  }
   2132 
   2133  nsresult rv = NS_OK;
   2134  if (gHttpHandler->TCPKeepaliveEnabledForLongLivedConns()) {
   2135    // Increase the idle time.
   2136    int32_t idleTimeS = gHttpHandler->GetTCPKeepaliveLongLivedIdleTime();
   2137    LOG(("nsHttpConnection::StartLongLivedTCPKeepalives[%p] idle time[%ds]",
   2138         this, idleTimeS));
   2139 
   2140    int32_t retryIntervalS =
   2141        std::max<int32_t>((int32_t)PR_IntervalToSeconds(mRtt), 1);
   2142    rv = mSocketTransport->SetKeepaliveVals(idleTimeS, retryIntervalS);
   2143    if (NS_FAILED(rv)) {
   2144      return rv;
   2145    }
   2146 
   2147    // Ensure keepalive is enabled, if current status is disabled.
   2148    if (mTCPKeepaliveConfig == kTCPKeepaliveDisabled) {
   2149      rv = mSocketTransport->SetKeepaliveEnabled(true);
   2150      if (NS_FAILED(rv)) {
   2151        return rv;
   2152      }
   2153    }
   2154    mTCPKeepaliveConfig = kTCPKeepaliveLongLivedConfig;
   2155  } else {
   2156    rv = mSocketTransport->SetKeepaliveEnabled(false);
   2157    mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
   2158  }
   2159 
   2160  if (NS_FAILED(rv)) {
   2161    return rv;
   2162  }
   2163  return NS_OK;
   2164 }
   2165 
   2166 nsresult nsHttpConnection::DisableTCPKeepalives() {
   2167  MOZ_ASSERT(mSocketTransport);
   2168  if (!mSocketTransport) {
   2169    return NS_ERROR_NOT_INITIALIZED;
   2170  }
   2171 
   2172  LOG(("nsHttpConnection::DisableTCPKeepalives [%p]", this));
   2173  if (mTCPKeepaliveConfig != kTCPKeepaliveDisabled) {
   2174    nsresult rv = mSocketTransport->SetKeepaliveEnabled(false);
   2175    if (NS_FAILED(rv)) {
   2176      return rv;
   2177    }
   2178    mTCPKeepaliveConfig = kTCPKeepaliveDisabled;
   2179  }
   2180  if (mTCPKeepaliveTransitionTimer) {
   2181    mTCPKeepaliveTransitionTimer->Cancel();
   2182    mTCPKeepaliveTransitionTimer = nullptr;
   2183  }
   2184  return NS_OK;
   2185 }
   2186 
   2187 //-----------------------------------------------------------------------------
   2188 // nsHttpConnection::nsISupports
   2189 //-----------------------------------------------------------------------------
   2190 
   2191 NS_IMPL_ADDREF(nsHttpConnection)
   2192 NS_IMPL_RELEASE(nsHttpConnection)
   2193 
   2194 NS_INTERFACE_MAP_BEGIN(nsHttpConnection)
   2195  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   2196  NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
   2197  NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
   2198  NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
   2199  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   2200  NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
   2201  NS_INTERFACE_MAP_ENTRY_CONCRETE(nsHttpConnection)
   2202 NS_INTERFACE_MAP_END
   2203 
   2204 //-----------------------------------------------------------------------------
   2205 // nsHttpConnection::nsIInputStreamCallback
   2206 //-----------------------------------------------------------------------------
   2207 
   2208 // called on the socket transport thread
   2209 NS_IMETHODIMP
   2210 nsHttpConnection::OnInputStreamReady(nsIAsyncInputStream* in) {
   2211  MOZ_ASSERT(in == mSocketIn, "unexpected stream");
   2212  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   2213 
   2214  if (mIdleMonitoring) {
   2215    MOZ_ASSERT(!mTransaction, "Idle Input Event While Active");
   2216 
   2217    // The only read event that is protocol compliant for an idle connection
   2218    // is an EOF, which we check for with CanReuse(). If the data is
   2219    // something else then just ignore it and suspend checking for EOF -
   2220    // our normal timers or protocol stack are the place to deal with
   2221    // any exception logic.
   2222 
   2223    if (!CanReuse()) {
   2224      LOG(("Server initiated close of idle conn %p\n", this));
   2225      (void)gHttpHandler->ConnMgr()->CloseIdleConnection(this);
   2226      return NS_OK;
   2227    }
   2228 
   2229    LOG(("Input data on idle conn %p, but not closing yet\n", this));
   2230    return NS_OK;
   2231  }
   2232 
   2233  // if the transaction was dropped...
   2234  if (!mTransaction) {
   2235    LOG(("  no transaction; ignoring event\n"));
   2236    return NS_OK;
   2237  }
   2238 
   2239  nsresult rv = OnSocketReadable();
   2240  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   2241    return rv;
   2242  }
   2243 
   2244  if (NS_FAILED(rv)) {
   2245    CloseTransaction(mTransaction, rv);
   2246  }
   2247 
   2248  return NS_OK;
   2249 }
   2250 
   2251 //-----------------------------------------------------------------------------
   2252 // nsHttpConnection::nsIOutputStreamCallback
   2253 //-----------------------------------------------------------------------------
   2254 
   2255 NS_IMETHODIMP
   2256 nsHttpConnection::OnOutputStreamReady(nsIAsyncOutputStream* out) {
   2257  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   2258  MOZ_ASSERT(out == mSocketOut, "unexpected socket");
   2259  // if the transaction was dropped...
   2260  if (!mTransaction) {
   2261    LOG(("  no transaction; ignoring event\n"));
   2262    return NS_OK;
   2263  }
   2264 
   2265  nsresult rv = OnSocketWritable();
   2266  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   2267    return NS_OK;
   2268  }
   2269 
   2270  if (NS_FAILED(rv)) CloseTransaction(mTransaction, rv);
   2271 
   2272  return NS_OK;
   2273 }
   2274 
   2275 //-----------------------------------------------------------------------------
   2276 // nsHttpConnection::nsITransportEventSink
   2277 //-----------------------------------------------------------------------------
   2278 
   2279 NS_IMETHODIMP
   2280 nsHttpConnection::OnTransportStatus(nsITransport* trans, nsresult status,
   2281                                    int64_t progress, int64_t progressMax) {
   2282  if (mTransaction) mTransaction->OnTransportStatus(trans, status, progress);
   2283  return NS_OK;
   2284 }
   2285 
   2286 //-----------------------------------------------------------------------------
   2287 // nsHttpConnection::nsIInterfaceRequestor
   2288 //-----------------------------------------------------------------------------
   2289 
   2290 // not called on the socket transport thread
   2291 NS_IMETHODIMP
   2292 nsHttpConnection::GetInterface(const nsIID& iid, void** result) {
   2293  // NOTE: This function is only called on the UI thread via sync proxy from
   2294  //       the socket transport thread.  If that weren't the case, then we'd
   2295  //       have to worry about the possibility of mTransaction going away
   2296  //       part-way through this function call.  See CloseTransaction.
   2297 
   2298  // NOTE - there is a bug here, the call to getinterface is proxied off the
   2299  // nss thread, not the ui thread as the above comment says. So there is
   2300  // indeed a chance of mTransaction going away. bug 615342
   2301 
   2302  MOZ_ASSERT(!OnSocketThread(), "on socket thread");
   2303 
   2304  nsCOMPtr<nsIInterfaceRequestor> callbacks;
   2305  {
   2306    MutexAutoLock lock(mCallbacksLock);
   2307    callbacks = mCallbacks;
   2308  }
   2309  if (callbacks) return callbacks->GetInterface(iid, result);
   2310  return NS_ERROR_NO_INTERFACE;
   2311 }
   2312 
   2313 void nsHttpConnection::CheckForTraffic(bool check) {
   2314  if (check) {
   2315    LOG((" CheckForTraffic conn %p\n", this));
   2316    if (mSpdySession) {
   2317      if (PR_IntervalToMilliseconds(IdleTime()) >= 500) {
   2318        // Send a ping to verify it is still alive if it has been idle
   2319        // more than half a second, the network changed events are
   2320        // rate-limited to one per 1000 ms.
   2321        LOG((" SendPing\n"));
   2322        mSpdySession->SendPing();
   2323      } else {
   2324        LOG((" SendPing skipped due to network activity\n"));
   2325      }
   2326    } else {
   2327      // If not SPDY, Store snapshot amount of data right now
   2328      mTrafficCount = mTotalBytesWritten + mTotalBytesRead;
   2329      mTrafficStamp = true;
   2330    }
   2331  } else {
   2332    // mark it as not checked
   2333    mTrafficStamp = false;
   2334  }
   2335 }
   2336 
   2337 void nsHttpConnection::SetEvent(nsresult aStatus) {
   2338  LOG(("nsHttpConnection::SetEvent [this=%p status=%" PRIx32 "]\n", this,
   2339       static_cast<uint32_t>(aStatus)));
   2340  if (!mBootstrappedTimingsSet) {
   2341    mBootstrappedTimingsSet = true;
   2342  }
   2343  switch (aStatus) {
   2344    case NS_NET_STATUS_RESOLVING_HOST:
   2345      mBootstrappedTimings.domainLookupStart = TimeStamp::Now();
   2346      break;
   2347    case NS_NET_STATUS_RESOLVED_HOST:
   2348      mBootstrappedTimings.domainLookupEnd = TimeStamp::Now();
   2349      break;
   2350    case NS_NET_STATUS_CONNECTING_TO:
   2351      mBootstrappedTimings.connectStart = TimeStamp::Now();
   2352      break;
   2353    case NS_NET_STATUS_CONNECTED_TO: {
   2354      TimeStamp tnow = TimeStamp::Now();
   2355      mBootstrappedTimings.tcpConnectEnd = tnow;
   2356      mBootstrappedTimings.connectEnd = tnow;
   2357      mBootstrappedTimings.secureConnectionStart = tnow;
   2358      break;
   2359    }
   2360    case NS_NET_STATUS_TLS_HANDSHAKE_STARTING:
   2361      mBootstrappedTimings.secureConnectionStart = TimeStamp::Now();
   2362      break;
   2363    case NS_NET_STATUS_TLS_HANDSHAKE_ENDED:
   2364      mBootstrappedTimings.connectEnd = TimeStamp::Now();
   2365      break;
   2366    default:
   2367      break;
   2368  }
   2369 }
   2370 
   2371 bool nsHttpConnection::NoClientCertAuth() const {
   2372  if (!mSocketTransport) {
   2373    return false;
   2374  }
   2375 
   2376  nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
   2377  mSocketTransport->GetTlsSocketControl(getter_AddRefs(tlsSocketControl));
   2378  if (!tlsSocketControl) {
   2379    return false;
   2380  }
   2381 
   2382  return !tlsSocketControl->GetClientCertSent();
   2383 }
   2384 
   2385 ExtendedCONNECTSupport nsHttpConnection::GetExtendedCONNECTSupport() {
   2386  LOG3(("nsHttpConnection::GetExtendedCONNECTSupport"));
   2387  if (!UsingSpdy()) {
   2388    return ExtendedCONNECTSupport::SUPPORTED;
   2389  }
   2390  LOG3(("nsHttpConnection::ExtendedCONNECTSupport checking spdy session"));
   2391  if (mSpdySession) {
   2392    return mSpdySession->GetExtendedCONNECTSupport();
   2393  }
   2394 
   2395  return ExtendedCONNECTSupport::NO_SUPPORT;
   2396 }
   2397 
   2398 bool nsHttpConnection::LastTransactionExpectedNoContent() {
   2399  return mLastTransactionExpectedNoContent;
   2400 }
   2401 
   2402 void nsHttpConnection::SetLastTransactionExpectedNoContent(bool val) {
   2403  mLastTransactionExpectedNoContent = val;
   2404 }
   2405 
   2406 bool nsHttpConnection::IsPersistent() { return IsKeepAlive() && !mDontReuse; }
   2407 
   2408 nsAHttpTransaction* nsHttpConnection::Transaction() { return mTransaction; }
   2409 
   2410 nsresult nsHttpConnection::GetSelfAddr(NetAddr* addr) {
   2411  if (!mSocketTransport) {
   2412    return NS_ERROR_FAILURE;
   2413  }
   2414  return mSocketTransport->GetSelfAddr(addr);
   2415 }
   2416 
   2417 nsresult nsHttpConnection::GetPeerAddr(NetAddr* addr) {
   2418  if (!mSocketTransport) {
   2419    return NS_ERROR_FAILURE;
   2420  }
   2421  return mSocketTransport->GetPeerAddr(addr);
   2422 }
   2423 
   2424 bool nsHttpConnection::ResolvedByTRR() {
   2425  bool val = false;
   2426  if (mSocketTransport) {
   2427    mSocketTransport->ResolvedByTRR(&val);
   2428  }
   2429  return val;
   2430 }
   2431 
   2432 nsIRequest::TRRMode nsHttpConnection::EffectiveTRRMode() {
   2433  nsIRequest::TRRMode mode = nsIRequest::TRR_DEFAULT_MODE;
   2434  if (mSocketTransport) {
   2435    mSocketTransport->GetEffectiveTRRMode(&mode);
   2436  }
   2437  return mode;
   2438 }
   2439 
   2440 TRRSkippedReason nsHttpConnection::TRRSkipReason() {
   2441  TRRSkippedReason reason = nsITRRSkipReason::TRR_UNSET;
   2442  if (mSocketTransport) {
   2443    mSocketTransport->GetTrrSkipReason(&reason);
   2444  }
   2445  return reason;
   2446 }
   2447 
   2448 bool nsHttpConnection::GetEchConfigUsed() {
   2449  bool val = false;
   2450  if (mSocketTransport) {
   2451    mSocketTransport->GetEchConfigUsed(&val);
   2452  }
   2453  return val;
   2454 }
   2455 
   2456 void nsHttpConnection::HandshakeDoneInternal() {
   2457  LOG(("nsHttpConnection::HandshakeDoneInternal [this=%p]\n", this));
   2458  if (mTlsHandshaker->NPNComplete()) {
   2459    return;
   2460  }
   2461 
   2462  ChangeConnectionState(ConnectionState::TRANSFERING);
   2463 
   2464  nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
   2465  GetTLSSocketControl(getter_AddRefs(tlsSocketControl));
   2466  if (!tlsSocketControl) {
   2467    mTlsHandshaker->FinishNPNSetup(false, false);
   2468    return;
   2469  }
   2470 
   2471  nsCOMPtr<nsITransportSecurityInfo> securityInfo;
   2472  if (NS_FAILED(
   2473          tlsSocketControl->GetSecurityInfo(getter_AddRefs(securityInfo)))) {
   2474    mTlsHandshaker->FinishNPNSetup(false, false);
   2475    return;
   2476  }
   2477  if (!securityInfo) {
   2478    mTlsHandshaker->FinishNPNSetup(false, false);
   2479    return;
   2480  }
   2481 
   2482  nsAutoCString negotiatedNPN;
   2483  DebugOnly<nsresult> rvDebug = securityInfo->GetNegotiatedNPN(negotiatedNPN);
   2484  MOZ_ASSERT(NS_SUCCEEDED(rvDebug));
   2485 
   2486  nsAutoCString transactionNPN;
   2487  transactionNPN = mConnInfo->GetNPNToken();
   2488  LOG(("negotiatedNPN: %s - transactionNPN: %s", negotiatedNPN.get(),
   2489       transactionNPN.get()));
   2490  if (!transactionNPN.IsEmpty() && negotiatedNPN != transactionNPN) {
   2491    LOG(("Resetting connection due to mismatched NPN token"));
   2492    mozilla::glean::network::alpn_mismatch_count.Get(negotiatedNPN).Add();
   2493    DontReuse();
   2494    if (mTransaction) {
   2495      mTransaction->Close(NS_ERROR_NET_RESET);
   2496    }
   2497    return;
   2498  }
   2499 
   2500  bool earlyDataAccepted = false;
   2501  if (mTlsHandshaker->EarlyDataUsed()) {
   2502    // Check if early data has been accepted.
   2503    nsresult rvEarlyData =
   2504        tlsSocketControl->GetEarlyDataAccepted(&earlyDataAccepted);
   2505    LOG(
   2506        ("nsHttpConnection::HandshakeDone [this=%p] - early data "
   2507         "that was sent during 0RTT %s been accepted [rv=%" PRIx32 "].",
   2508         this, earlyDataAccepted ? "has" : "has not",
   2509         static_cast<uint32_t>(rvEarlyData)));
   2510 
   2511    if (NS_FAILED(rvEarlyData) ||
   2512        (mTransaction &&
   2513         NS_FAILED(mTransaction->Finish0RTT(
   2514             !earlyDataAccepted,
   2515             negotiatedNPN != mTlsHandshaker->EarlyNegotiatedALPN())))) {
   2516      LOG(
   2517          ("nsHttpConnection::HandshakeDone [this=%p] closing transaction "
   2518           "%p",
   2519           this, mTransaction.get()));
   2520      if (mTransaction) {
   2521        mTransaction->Close(NS_ERROR_NET_RESET);
   2522      }
   2523      mTlsHandshaker->FinishNPNSetup(false, true);
   2524      return;
   2525    }
   2526    if (mDid0RTTSpdy &&
   2527        (negotiatedNPN != mTlsHandshaker->EarlyNegotiatedALPN())) {
   2528      Reset0RttForSpdy();
   2529    }
   2530  }
   2531 
   2532  if (mTlsHandshaker->EarlyDataAvailable() && !earlyDataAccepted) {
   2533    // When the early-data were used but not accepted, we need to start
   2534    // from the begining here and start writing the request again.
   2535    // The same is true if 0RTT was available but not used.
   2536    if (mSocketIn) {
   2537      mSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
   2538    }
   2539    (void)ResumeSend();
   2540  }
   2541 
   2542  int16_t tlsVersion;
   2543  tlsSocketControl->GetSSLVersionUsed(&tlsVersion);
   2544  mConnInfo->SetLessThanTls13(
   2545      (tlsVersion < nsITLSSocketControl::TLS_VERSION_1_3) &&
   2546      (tlsVersion != nsITLSSocketControl::SSL_VERSION_UNKNOWN));
   2547 #ifndef ANDROID
   2548  mTlsHandshaker->EarlyDataTelemetry(tlsVersion, earlyDataAccepted,
   2549                                     mContentBytesWritten0RTT);
   2550 #endif
   2551  mTlsHandshaker->EarlyDataDone();
   2552 
   2553  if (!earlyDataAccepted) {
   2554    LOG(
   2555        ("nsHttpConnection::HandshakeDone [this=%p] early data not "
   2556         "accepted or early data were not used",
   2557         this));
   2558 
   2559    const SpdyInformation* info = gHttpHandler->SpdyInfo();
   2560    if (negotiatedNPN.Equals(info->VersionString)) {
   2561      if (mTransaction) {
   2562        StartSpdy(tlsSocketControl, info->Version);
   2563      } else {
   2564        LOG(
   2565            ("nsHttpConnection::HandshakeDone [this=%p] set "
   2566             "mContinueHandshakeDone",
   2567             this));
   2568        RefPtr<nsHttpConnection> self = this;
   2569        mContinueHandshakeDone = [self = RefPtr{this},
   2570                                  tlsSocketControl(tlsSocketControl),
   2571                                  info(info->Version)]() {
   2572          LOG(("nsHttpConnection do mContinueHandshakeDone [this=%p]",
   2573               self.get()));
   2574          self->StartSpdy(tlsSocketControl, info);
   2575          self->mTlsHandshaker->FinishNPNSetup(true, true);
   2576        };
   2577        return;
   2578      }
   2579    }
   2580  } else {
   2581    LOG(("nsHttpConnection::HandshakeDone [this=%p] - %" PRId64 " bytes "
   2582         "has been sent during 0RTT.",
   2583         this, mContentBytesWritten0RTT));
   2584    mContentBytesWritten = mContentBytesWritten0RTT;
   2585 
   2586    if (mSpdySession) {
   2587      // We had already started 0RTT-spdy, now we need to fully set up
   2588      // spdy, since we know we're sticking with it.
   2589      LOG(
   2590          ("nsHttpConnection::HandshakeDone [this=%p] - finishing "
   2591           "StartSpdy for 0rtt spdy session %p",
   2592           this, mSpdySession.get()));
   2593      StartSpdy(tlsSocketControl, mSpdySession->SpdyVersion());
   2594    }
   2595  }
   2596 
   2597  mTlsHandshaker->FinishNPNSetup(true, true);
   2598  (void)ResumeSend();
   2599 }
   2600 
   2601 void nsHttpConnection::SetTunnelSetupDone() {
   2602  MOZ_ASSERT(mProxyConnectStream);
   2603  MOZ_ASSERT(mState == HttpConnectionState::SETTING_UP_TUNNEL);
   2604 
   2605  ChangeState(HttpConnectionState::REQUEST);
   2606  mProxyConnectStream = nullptr;
   2607 }
   2608 
   2609 nsresult nsHttpConnection::SetupProxyConnectStream() {
   2610  LOG(("nsHttpConnection::SetupStream\n"));
   2611  NS_ENSURE_TRUE(!mProxyConnectStream, NS_ERROR_ALREADY_INITIALIZED);
   2612  MOZ_ASSERT(mState == HttpConnectionState::SETTING_UP_TUNNEL);
   2613 
   2614  nsAutoCString buf;
   2615  nsHttpRequestHead request;
   2616  nsresult rv = MakeConnectString(mTransaction, &request, buf,
   2617                                  mForWebSocket && mInSpdyTunnel,
   2618                                  mTransactionCaps & NS_HTTP_USE_RFP);
   2619  if (NS_FAILED(rv)) {
   2620    return rv;
   2621  }
   2622  rv = NS_NewCStringInputStream(getter_AddRefs(mProxyConnectStream),
   2623                                std::move(buf));
   2624  return rv;
   2625 }
   2626 
   2627 nsresult nsHttpConnection::ReadFromStream(nsIInputStream* input, void* closure,
   2628                                          const char* buf, uint32_t offset,
   2629                                          uint32_t count, uint32_t* countRead) {
   2630  // thunk for nsIInputStream instance
   2631  nsHttpConnection* conn = (nsHttpConnection*)closure;
   2632  return conn->OnReadSegment(buf, count, countRead);
   2633 }
   2634 
   2635 nsresult nsHttpConnection::SendConnectRequest(void* closure,
   2636                                              uint32_t* transactionBytes) {
   2637  LOG(("  writing CONNECT request stream\n"));
   2638  return mProxyConnectStream->ReadSegments(ReadFromStream, closure,
   2639                                           nsIOService::gDefaultSegmentSize,
   2640                                           transactionBytes);
   2641 }
   2642 
   2643 WebTransportSessionBase* nsHttpConnection::GetWebTransportSession(
   2644    nsAHttpTransaction* aTransaction) {
   2645  LOG(
   2646      ("nsHttpConnection::GetWebTransportSession %p mSpdySession=%p "
   2647       "mExtendedCONNECTHttp2Session=%p",
   2648       this, mSpdySession.get(), mExtendedCONNECTHttp2Session.get()));
   2649  if (!mExtendedCONNECTHttp2Session) {
   2650    return nullptr;
   2651  }
   2652 
   2653  return mExtendedCONNECTHttp2Session->GetWebTransportSession(aTransaction);
   2654 }
   2655 
   2656 }  // namespace mozilla::net