tor-browser

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

HttpConnectionUDP.cpp (39869B)


      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 #define TLS_EARLY_DATA_NOT_AVAILABLE 0
     17 #define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
     18 #define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
     19 
     20 #include "ASpdySession.h"
     21 #include "ConnectionHandle.h"
     22 #include "mozilla/StaticPrefs_network.h"
     23 #include "mozilla/glean/NetwerkMetrics.h"
     24 #include "HttpConnectionUDP.h"
     25 #include "nsHttpHandler.h"
     26 #include "Http3Session.h"
     27 #include "nsComponentManagerUtils.h"
     28 #include "nsIHttpChannelInternal.h"
     29 #include "nsISocketProvider.h"
     30 #include "nsNetAddr.h"
     31 #include "nsINetAddr.h"
     32 #include "nsStringStream.h"
     33 
     34 namespace mozilla {
     35 namespace net {
     36 
     37 //-----------------------------------------------------------------------------
     38 // ConnectUDPTransaction
     39 //-----------------------------------------------------------------------------
     40 
     41 class ConnectUDPTransaction : public nsAHttpTransaction {
     42 public:
     43  NS_DECL_THREADSAFE_ISUPPORTS
     44 
     45  explicit ConnectUDPTransaction(nsAHttpTransaction* aTrans,
     46                                 nsIInputStream* aStream)
     47      : mTransaction(aTrans), mProxyConnectStream(aStream) {
     48    LOG(("ConnectUDPTransaction ctor: %p", this));
     49  }
     50 
     51  void SetConnection(nsAHttpConnection* aConn) override { mConnection = aConn; }
     52  nsAHttpConnection* Connection() override { return mConnection; }
     53  void GetSecurityCallbacks(nsIInterfaceRequestor** aCallbacks) override {
     54    mTransaction->GetSecurityCallbacks(aCallbacks);
     55  }
     56  void OnTransportStatus(nsITransport* transport, nsresult status,
     57                         int64_t progress) override {
     58    mTransaction->OnTransportStatus(transport, status, progress);
     59  }
     60  bool IsDone() override { return mIsDone; }
     61  nsresult Status() override { return mTransaction->Status(); }
     62  uint32_t Caps() override { return mTransaction->Caps(); }
     63 
     64  static nsresult ReadRequestSegment(nsIInputStream* stream, void* closure,
     65                                     const char* buf, uint32_t offset,
     66                                     uint32_t count, uint32_t* countRead) {
     67    ConnectUDPTransaction* trans = (ConnectUDPTransaction*)closure;
     68    nsresult rv = trans->mReader->OnReadSegment(buf, count, countRead);
     69    return rv;
     70  }
     71 
     72  [[nodiscard]] nsresult ReadSegments(nsAHttpSegmentReader* reader,
     73                                      uint32_t count,
     74                                      uint32_t* countRead) override {
     75    mReader = reader;
     76    (void)mProxyConnectStream->ReadSegments(ReadRequestSegment, this, count,
     77                                            countRead);
     78    mReader = nullptr;
     79    uint64_t avil = 0;
     80    (void)mProxyConnectStream->Available(&avil);
     81    if (!avil) {
     82      mIsDone = true;
     83    }
     84    return NS_OK;
     85  }
     86  [[nodiscard]] nsresult WriteSegments(nsAHttpSegmentWriter* writer,
     87                                       uint32_t count,
     88                                       uint32_t* countWritten) override {
     89    // This is hacky. We should set Connection properly in
     90    // nsHttpConnectionMgr::DispatchTransaction.
     91    if (!mTransaction->Connection()) {
     92      mTransaction->SetConnection(mConnection);
     93    }
     94    nsresult rv = mTransaction->WriteSegments(writer, count, countWritten);
     95    mTransaction = nullptr;
     96    return rv;
     97  }
     98  void Close(nsresult reason) override {
     99    LOG(("ConnectUDPTransaction close mTransaction=%p", mTransaction.get()));
    100    if (mTransaction) {
    101      mTransaction->Close(reason);
    102    }
    103  }
    104  nsHttpConnectionInfo* ConnectionInfo() override {
    105    return mTransaction->ConnectionInfo();
    106  }
    107  void SetProxyConnectFailed() override {
    108    mTransaction->SetProxyConnectFailed();
    109  }
    110  nsHttpRequestHead* RequestHead() override {
    111    return mTransaction->RequestHead();
    112  }
    113  uint32_t Http1xTransactionCount() override { return 0; }
    114  [[nodiscard]] nsresult TakeSubTransactions(
    115      nsTArray<RefPtr<nsAHttpTransaction>>& outTransactions) override {
    116    return NS_OK;
    117  }
    118 
    119 protected:
    120  virtual ~ConnectUDPTransaction() {
    121    LOG(("ConnectUDPTransaction dtor: %p", this));
    122  }
    123 
    124  RefPtr<nsAHttpTransaction> mTransaction;
    125  nsCOMPtr<nsIInputStream> mProxyConnectStream;
    126  RefPtr<nsAHttpConnection> mConnection;
    127  bool mIsDone = false;
    128  nsAHttpSegmentReader* mReader = nullptr;
    129 };
    130 
    131 NS_IMPL_ISUPPORTS(ConnectUDPTransaction, nsISupportsWeakReference)
    132 
    133 //-----------------------------------------------------------------------------
    134 // Http3ConnectTransaction
    135 //-----------------------------------------------------------------------------
    136 
    137 // We need a dummy transaction to keep the Http3StreamTunnel alive.
    138 // Http3StreamTunnel instances are owned via the transaction-to-stream map
    139 // in Http3Session::mStreamTransactionHash.
    140 class Http3ConnectTransaction : public ConnectUDPTransaction {
    141 public:
    142  explicit Http3ConnectTransaction(uint32_t aCaps, nsHttpConnectionInfo* aInfo)
    143      : ConnectUDPTransaction(nullptr, nullptr),
    144        mCaps(aCaps),
    145        mConnInfo(aInfo) {
    146    LOG(("Http3ConnectTransaction ctor: %p", this));
    147  }
    148 
    149  uint32_t Caps() override { return mCaps; }
    150  nsHttpConnectionInfo* ConnectionInfo() override { return mConnInfo; }
    151 
    152  void OnTransportStatus(nsITransport* transport, nsresult status,
    153                         int64_t progress) override {}
    154 
    155  [[nodiscard]] nsresult ReadSegments(nsAHttpSegmentReader* reader,
    156                                      uint32_t count,
    157                                      uint32_t* countRead) override {
    158    MOZ_ASSERT_UNREACHABLE("Shouldn't be called");
    159    return NS_ERROR_NOT_IMPLEMENTED;
    160  }
    161  [[nodiscard]] nsresult WriteSegments(nsAHttpSegmentWriter* writer,
    162                                       uint32_t count,
    163                                       uint32_t* countWritten) override {
    164    MOZ_ASSERT_UNREACHABLE("Shouldn't be called");
    165    return NS_ERROR_NOT_IMPLEMENTED;
    166  }
    167 
    168  void Close(nsresult reason) override { mConnection = nullptr; }
    169 
    170 private:
    171  virtual ~Http3ConnectTransaction() {
    172    LOG(("Http3ConnectTransaction dtor: %p", this));
    173  }
    174 
    175  uint32_t mCaps = 0;
    176  RefPtr<nsHttpConnectionInfo> mConnInfo;
    177 };
    178 
    179 //-----------------------------------------------------------------------------
    180 // HttpConnectionUDP <public>
    181 //-----------------------------------------------------------------------------
    182 
    183 HttpConnectionUDP::HttpConnectionUDP() : mHttpHandler(gHttpHandler) {
    184  LOG(("Creating HttpConnectionUDP @%p\n", this));
    185 }
    186 
    187 HttpConnectionUDP::~HttpConnectionUDP() {
    188  LOG(("Destroying HttpConnectionUDP @%p\n", this));
    189 
    190  if (mForceSendTimer) {
    191    mForceSendTimer->Cancel();
    192    mForceSendTimer = nullptr;
    193  }
    194 
    195  MOZ_ASSERT(mQueuedHttpConnectTransaction.IsEmpty(),
    196             "Should not have any queued transactions");
    197  MOZ_ASSERT(mQueuedConnectUdpTransaction.IsEmpty(),
    198             "Should not have any queued transactions");
    199 }
    200 
    201 nsresult HttpConnectionUDP::Init(nsHttpConnectionInfo* info,
    202                                 nsIDNSRecord* dnsRecord, nsresult status,
    203                                 nsIInterfaceRequestor* callbacks,
    204                                 uint32_t caps) {
    205  LOG1(("HttpConnectionUDP::Init this=%p", this));
    206  NS_ENSURE_ARG_POINTER(info);
    207  NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
    208 
    209  mConnInfo = info;
    210  MOZ_ASSERT(mConnInfo);
    211  MOZ_ASSERT(mConnInfo->IsHttp3() || mConnInfo->IsHttp3ProxyConnection());
    212 
    213  mErrorBeforeConnect = status;
    214  mAlpnToken = mConnInfo->GetNPNToken();
    215  if (NS_FAILED(mErrorBeforeConnect)) {
    216    // See explanation for non-strictness of this operation in
    217    // SetSecurityCallbacks.
    218    mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
    219        "HttpConnectionUDP::mCallbacks", callbacks, false);
    220    SetCloseReason(ToCloseReason(mErrorBeforeConnect));
    221    return mErrorBeforeConnect;
    222  }
    223 
    224  nsCOMPtr<nsIDNSAddrRecord> dnsAddrRecord = do_QueryInterface(dnsRecord);
    225  if (!dnsAddrRecord) {
    226    return NS_ERROR_FAILURE;
    227  }
    228  dnsAddrRecord->IsTRR(&mResolvedByTRR);
    229  dnsAddrRecord->GetEffectiveTRRMode(&mEffectiveTRRMode);
    230  dnsAddrRecord->GetTrrSkipReason(&mTRRSkipReason);
    231  NetAddr peerAddr;
    232  uint16_t port =
    233      mConnInfo->IsHttp3ProxyConnection()
    234          ? mConnInfo->ProxyPort()
    235          : (!mConnInfo->GetRoutedHost().IsEmpty() ? mConnInfo->RoutedPort()
    236                                                   : mConnInfo->OriginPort());
    237 
    238  nsresult rv = dnsAddrRecord->GetNextAddr(port, &peerAddr);
    239  if (NS_FAILED(rv)) {
    240    return rv;
    241  }
    242 
    243  // We are disabling 0.0.0.0 for non-test purposes.
    244  // See https://github.com/whatwg/fetch/pull/1763 for context.
    245  if (peerAddr.IsIPAddrAny()) {
    246    if (StaticPrefs::network_socket_ip_addr_any_disabled()) {
    247      LOG(("Connection refused because of 0.0.0.0 IP address\n"));
    248      return NS_ERROR_CONNECTION_REFUSED;
    249    }
    250  }
    251 
    252  mSocket = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
    253  if (NS_FAILED(rv)) {
    254    return rv;
    255  }
    256 
    257  return InitCommon(mSocket, peerAddr, callbacks, caps, false);
    258 }
    259 
    260 nsresult HttpConnectionUDP::InitWithSocket(nsHttpConnectionInfo* info,
    261                                           nsIUDPSocket* aSocket,
    262                                           NetAddr aPeerAddr,
    263                                           nsIInterfaceRequestor* callbacks,
    264                                           uint32_t caps) {
    265  LOG1(("HttpConnectionUDP::InitWithSocket this=%p", this));
    266  NS_ENSURE_ARG_POINTER(info);
    267  NS_ENSURE_TRUE(!mConnInfo, NS_ERROR_ALREADY_INITIALIZED);
    268 
    269  mConnInfo = info;
    270  MOZ_ASSERT(mConnInfo->IsHttp3() || mConnInfo->IsHttp3ProxyConnection());
    271 
    272  mErrorBeforeConnect = NS_OK;
    273  mAlpnToken = mConnInfo->GetNPNToken();
    274 
    275  return InitCommon(aSocket, aPeerAddr, callbacks, caps, true);
    276 }
    277 
    278 nsresult HttpConnectionUDP::InitCommon(nsIUDPSocket* aSocket,
    279                                       const NetAddr& aPeerAddr,
    280                                       nsIInterfaceRequestor* callbacks,
    281                                       uint32_t caps, bool isInTunnel) {
    282  mSocket = aSocket;
    283 
    284  NetAddr local;
    285  local.raw.family = aPeerAddr.raw.family;
    286  nsresult rv = mSocket->InitWithAddress(&local, nullptr, false, 1);
    287  if (NS_FAILED(rv)) {
    288    mSocket = nullptr;
    289    return rv;
    290  }
    291 
    292  rv = mSocket->SetRecvBufferSize(
    293      StaticPrefs::network_http_http3_recvBufferSize());
    294  if (NS_FAILED(rv)) {
    295    LOG(("HttpConnectionUDP::InitCommon SetRecvBufferSize failed %d [this=%p]",
    296         static_cast<uint32_t>(rv), this));
    297    mSocket->Close();
    298    mSocket = nullptr;
    299    return rv;
    300  }
    301 
    302  if (aPeerAddr.raw.family == AF_INET) {
    303    rv = mSocket->SetDontFragment(true);
    304    if (NS_FAILED(rv)) {
    305      LOG(("HttpConnectionUDP::InitCommon SetDontFragment failed %d [this=%p]",
    306           static_cast<uint32_t>(rv), this));
    307    }
    308  }
    309 
    310  // get the resulting socket address.
    311  rv = mSocket->GetLocalAddr(getter_AddRefs(mSelfAddr));
    312  if (NS_FAILED(rv)) {
    313    mSocket->Close();
    314    mSocket = nullptr;
    315    return rv;
    316  }
    317 
    318  uint32_t providerFlags = 0;
    319  if (caps & NS_HTTP_LOAD_ANONYMOUS) {
    320    providerFlags |= nsISocketProvider::ANONYMOUS_CONNECT;
    321  }
    322  if (mConnInfo->GetPrivate()) {
    323    providerFlags |= nsISocketProvider::NO_PERMANENT_STORAGE;
    324  }
    325  if (((caps & NS_HTTP_BE_CONSERVATIVE) || mConnInfo->GetBeConservative()) &&
    326      gHttpHandler->ConnMgr()->BeConservativeIfProxied(
    327          mConnInfo->ProxyInfo())) {
    328    providerFlags |= nsISocketProvider::BE_CONSERVATIVE;
    329  }
    330  if ((caps & NS_HTTP_IS_RETRY) ||
    331      (mConnInfo->GetTlsFlags() &
    332       nsIHttpChannelInternal::TLS_FLAG_CONFIGURE_AS_RETRY)) {
    333    providerFlags |= nsISocketProvider::IS_RETRY;
    334  }
    335 
    336  if (mResolvedByTRR) {
    337    providerFlags |= nsISocketProvider::USED_PRIVATE_DNS;
    338  }
    339 
    340  mPeerAddr = new nsNetAddr(&aPeerAddr);
    341  mHttp3Session = new Http3Session();
    342  rv = mHttp3Session->Init(mConnInfo, mSelfAddr, mPeerAddr, this, providerFlags,
    343                           callbacks, mSocket, isInTunnel);
    344  if (NS_FAILED(rv)) {
    345    LOG(
    346        ("HttpConnectionUDP::InitCommon Http3Session::Init failed [this=%p "
    347         "rv=%x]",
    348         this, static_cast<uint32_t>(rv)));
    349    mSocket->Close();
    350    mSocket = nullptr;
    351    mHttp3Session = nullptr;
    352    return rv;
    353  }
    354 
    355  mIsInTunnel = isInTunnel;
    356  if (mIsInTunnel) {
    357    mHttp3Session->SetIsInTunnel();
    358  }
    359 
    360  ChangeConnectionState(ConnectionState::INITED);
    361  // See explanation for non-strictness of this operation in
    362  // SetSecurityCallbacks.
    363  mCallbacks = new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
    364      "HttpConnectionUDP::mCallbacks", callbacks, false);
    365 
    366  // Call SyncListen at the end of this function. This call will actually
    367  // attach the sockte to SocketTransportService.
    368  rv = mSocket->SyncListen(this);
    369  if (NS_FAILED(rv)) {
    370    mSocket->Close();
    371    mSocket = nullptr;
    372    return rv;
    373  }
    374 
    375  return NS_OK;
    376 }
    377 
    378 // called on the socket thread
    379 nsresult HttpConnectionUDP::Activate(nsAHttpTransaction* trans, uint32_t caps,
    380                                     int32_t pri) {
    381  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    382  LOG1(("HttpConnectionUDP::Activate [this=%p trans=%p caps=%x]\n", this, trans,
    383        caps));
    384 
    385  nsHttpTransaction* hTrans = trans->QueryHttpTransaction();
    386  nsHttpConnectionInfo* transCI = trans->ConnectionInfo();
    387  NetAddr peerAddr;
    388  if (!transCI->UsingProxy() && hTrans &&
    389      NS_SUCCEEDED(GetPeerAddr(&peerAddr))) {
    390    // set the targetIpAddressSpace in the transaction object, this might be
    391    // needed by the channel for determining the kind of LNA permissions and/or
    392    // LNA telemetry
    393    if (!hTrans->AllowedToConnectToIpAddressSpace(
    394            peerAddr.GetIpAddressSpace())) {
    395      // we could probably fail early and avoid recreating the H3 session
    396      // See Bug 1968908
    397      CloseTransaction(mHttp3Session, NS_ERROR_LOCAL_NETWORK_ACCESS_DENIED);
    398      trans->Close(NS_ERROR_LOCAL_NETWORK_ACCESS_DENIED);
    399      return NS_ERROR_LOCAL_NETWORK_ACCESS_DENIED;
    400    }
    401  }
    402 
    403  if (!mExperienced && !trans->IsNullTransaction()) {
    404    mHasFirstHttpTransaction = true;
    405    // For QUIC we have HttpConnectionUDP before the actual connection
    406    // has been establish so wait for TLS handshake to be finished before
    407    // we mark the connection 'experienced'.
    408    if (!mExperienced && mHttp3Session && mHttp3Session->IsConnected()) {
    409      mExperienced = true;
    410    }
    411    if (mBootstrappedTimingsSet) {
    412      mBootstrappedTimingsSet = false;
    413      if (hTrans) {
    414        hTrans->BootstrapTimings(mBootstrappedTimings);
    415      }
    416    }
    417    mBootstrappedTimings = TimingStruct();
    418  }
    419 
    420  mTransactionCaps = caps;
    421  mPriority = pri;
    422 
    423  NS_ENSURE_ARG_POINTER(trans);
    424 
    425  mErrorBeforeConnect = CheckTunnelIsNeeded(trans);
    426 
    427  // Connection failures are Activated() just like regular transacions.
    428  // If we don't have a confirmation of a connected socket then test it
    429  // with a write() to get relevant error code.
    430  if (NS_FAILED(mErrorBeforeConnect)) {
    431    CloseTransaction(nullptr, mErrorBeforeConnect);
    432    trans->Close(mErrorBeforeConnect);
    433    gHttpHandler->ExcludeHttp3(mConnInfo);
    434    return mErrorBeforeConnect;
    435  }
    436 
    437  // When mIsInTunnel is false, this HttpConnectionUDP represents the *outer*
    438  // connection to the proxy. If a proxy CONNECT is still in progress,
    439  // we need to queue the transaction until the outer connection is fully
    440  // established.
    441  //
    442  // Important: we must not reset the transaction while the outer connection
    443  // is still connecting. Resetting here could lead to opening another HTTP/3
    444  // connection.
    445  if (IsProxyConnectInProgress() && !mIsInTunnel && hTrans) {
    446    if (!mConnected) {
    447      mQueuedHttpConnectTransaction.AppendElement(hTrans);
    448      (void)ResumeSend();
    449    } else {
    450      // Don’t call ResetTransaction() directly here.
    451      // HttpConnectionUDP::Activate() may be invoked from
    452      // nsHttpConnectionMgr::DispatchSpdyPendingQ(), which could run while
    453      // enumerating all connection entries. ResetTransaction() can insert a new
    454      // “wild” entry, and modifying the connection-entry table during iteration
    455      // is not allowed.
    456      RefPtr<HttpConnectionUDP> self(this);
    457      RefPtr<nsHttpTransaction> httpTransaction(hTrans);
    458      NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    459          "HttpConnectionUDP::ResetTransaction",
    460          [self{std::move(self)},
    461           httpTransaction{std::move(httpTransaction)}]() {
    462            self->ResetTransaction(httpTransaction);
    463          }));
    464    }
    465    return NS_OK;
    466  }
    467 
    468  // This is the CONNECT-UDP case. When mIsInTunnel is true, this is
    469  // the *inner* connection from the proxy tunnel to the destination website.
    470  // If the proxy CONNECT is still in progress, we cannot send any data
    471  // yet because Http3ConnectUDPStream is not allowed to transmit until the
    472  // tunnel is established. In this case, we queue the transaction and will
    473  // add it to the Http3Session once the proxy CONNECT completes.
    474  if (mIsInTunnel && IsProxyConnectInProgress() && hTrans) {
    475    LOG(("Queue trans %p due to proxy connct in progress", hTrans));
    476    mQueuedConnectUdpTransaction.AppendElement(hTrans);
    477    return NS_OK;
    478  }
    479 
    480  if (!mHttp3Session->AddStream(trans, pri, mCallbacks)) {
    481    MOZ_ASSERT(false);  // this cannot happen!
    482    trans->Close(NS_ERROR_ABORT);
    483    return NS_ERROR_FAILURE;
    484  }
    485 
    486  if (mHasFirstHttpTransaction && mExperienced) {
    487    mHasFirstHttpTransaction = false;
    488    mExperienceState |= ConnectionExperienceState::Experienced;
    489  }
    490 
    491  (void)ResumeSend();
    492  return NS_OK;
    493 }
    494 
    495 void HttpConnectionUDP::OnConnected() {
    496  LOG(("HttpConnectionUDP::OnConnected %p", this));
    497  MOZ_ASSERT(!mConnected, "Called more than once");
    498 
    499  mConnected = true;
    500  if (mIsInTunnel) {
    501    return;
    502  }
    503 
    504  for (const auto& trans : mQueuedHttpConnectTransaction) {
    505    ResetTransaction(trans);
    506  }
    507  mQueuedHttpConnectTransaction.Clear();
    508 }
    509 
    510 already_AddRefed<nsIInputStream> HttpConnectionUDP::CreateProxyConnectStream(
    511    nsAHttpTransaction* trans) {
    512  UniquePtr<nsHttpRequestHead> request = MakeUnique<nsHttpRequestHead>();
    513  nsAutoCString host;
    514  DebugOnly<nsresult> rv{};
    515  rv = nsHttpHandler::GenerateHostPort(
    516      nsDependentCString(trans->ConnectionInfo()->Origin()),
    517      trans->ConnectionInfo()->OriginPort(), host);
    518  MOZ_ASSERT(NS_SUCCEEDED(rv));
    519 
    520  request->SetMethod("CONNECT"_ns);
    521  request->SetVersion(gHttpHandler->HttpVersion());
    522 
    523  bool shouldResistFingerprinting = trans->Caps() & NS_HTTP_USE_RFP;
    524  rv = request->SetHeader(nsHttp::User_Agent,
    525                          gHttpHandler->UserAgent(shouldResistFingerprinting));
    526  MOZ_ASSERT(NS_SUCCEEDED(rv));
    527 
    528  rv = request->SetHeader(nsHttp::Host, host);
    529  MOZ_ASSERT(NS_SUCCEEDED(rv));
    530 
    531  nsAutoCString val;
    532  if (NS_SUCCEEDED(
    533          trans->RequestHead()->GetHeader(nsHttp::Proxy_Authorization, val))) {
    534    // TODO: we should use Proxy_Authorization here.
    535    rv = request->SetHeader(nsHttp::Authorization, val);
    536    MOZ_ASSERT(NS_SUCCEEDED(rv));
    537  }
    538 
    539  nsAutoCString result;
    540  request->Flatten(result, false);
    541  if (LOG1_ENABLED()) {
    542    LOG(("HttpConnectionUDP::MakeConnectString for transaction=%p[",
    543         trans->QueryHttpTransaction()));
    544    LogHeaders(result.BeginReading());
    545    LOG(("]"));
    546  }
    547  result.AppendLiteral("\r\n");
    548 
    549  nsCOMPtr<nsIInputStream> stream;
    550  NS_NewCStringInputStream(getter_AddRefs(stream), std::move(result));
    551  return stream.forget();
    552 }
    553 
    554 nsresult HttpConnectionUDP::CreateTunnelStream(
    555    nsAHttpTransaction* httpTransaction, HttpConnectionBase** aHttpConnection,
    556    bool aIsExtendedCONNECT) {
    557  LOG(("HttpConnectionUDP::CreateTunnelStream %p", this));
    558  if (!mHttp3Session) {
    559    return NS_ERROR_UNEXPECTED;
    560  }
    561 
    562  bool isHttp3 = httpTransaction->ConnectionInfo()->IsHttp3();
    563 
    564  if (!isHttp3) {
    565    RefPtr<Http3ConnectTransaction> trans = new Http3ConnectTransaction(
    566        httpTransaction->Caps(), httpTransaction->ConnectionInfo());
    567    RefPtr<nsHttpConnection> conn =
    568        mHttp3Session->CreateTunnelStream(trans, mCallbacks, mRtt, false);
    569    RefPtr<ConnectionHandle> handle = new ConnectionHandle(conn);
    570    trans->SetConnection(handle);
    571 
    572    conn.forget(aHttpConnection);
    573    return NS_OK;
    574  }
    575 
    576  nsCOMPtr<nsIInputStream> proxyConnectStream =
    577      CreateProxyConnectStream(httpTransaction);
    578  if (!proxyConnectStream) {
    579    return NS_ERROR_OUT_OF_MEMORY;
    580  }
    581 
    582  RefPtr<ConnectUDPTransaction> trans =
    583      new ConnectUDPTransaction(httpTransaction, proxyConnectStream);
    584  RefPtr<HttpConnectionUDP> conn =
    585      mHttp3Session->CreateTunnelStream(trans, mCallbacks);
    586  RefPtr<ConnectionHandle> handle = new ConnectionHandle(conn);
    587  trans->SetConnection(handle);
    588 
    589  conn.forget(aHttpConnection);
    590  return NS_OK;
    591 }
    592 
    593 void HttpConnectionUDP::Close(nsresult reason, bool aIsShutdown) {
    594  LOG(("HttpConnectionUDP::Close [this=%p reason=%" PRIx32 "]\n", this,
    595       static_cast<uint32_t>(reason)));
    596 
    597  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    598 
    599  if (mConnectionState != ConnectionState::CLOSED) {
    600    RecordConnectionCloseTelemetry(reason);
    601    ChangeConnectionState(ConnectionState::CLOSED);
    602  }
    603 
    604  if (mForceSendTimer) {
    605    mForceSendTimer->Cancel();
    606    mForceSendTimer = nullptr;
    607  }
    608 
    609  if (!mTrafficCategory.IsEmpty()) {
    610    HttpTrafficAnalyzer* hta = gHttpHandler->GetHttpTrafficAnalyzer();
    611    if (hta) {
    612      hta->IncrementHttpConnection(std::move(mTrafficCategory));
    613      MOZ_ASSERT(mTrafficCategory.IsEmpty());
    614    }
    615  }
    616 
    617  nsCOMPtr<nsIUDPSocket> socket = std::move(mSocket);
    618  if (socket) {
    619    socket->Close();
    620  }
    621  if (mHttp3Session) {
    622    mHttp3Session->SetCleanShutdown(true);
    623    mHttp3Session->Close(reason);
    624    mHttp3Session = nullptr;
    625  }
    626 
    627  for (const auto& trans : mQueuedHttpConnectTransaction) {
    628    trans->Close(reason);
    629  }
    630  mQueuedHttpConnectTransaction.Clear();
    631  for (const auto& trans : mQueuedConnectUdpTransaction) {
    632    trans->Close(reason);
    633  }
    634  mQueuedConnectUdpTransaction.Clear();
    635 }
    636 
    637 void HttpConnectionUDP::DontReuse() {
    638  LOG(("HttpConnectionUDP::DontReuse %p http3session=%p\n", this,
    639       mHttp3Session.get()));
    640  mDontReuse = true;
    641  if (mHttp3Session) {
    642    mHttp3Session->DontReuse();
    643  }
    644 }
    645 
    646 bool HttpConnectionUDP::TestJoinConnection(const nsACString& hostname,
    647                                           int32_t port) {
    648  if (mHttp3Session && CanDirectlyActivate()) {
    649    return mHttp3Session->TestJoinConnection(hostname, port);
    650  }
    651 
    652  return false;
    653 }
    654 
    655 bool HttpConnectionUDP::JoinConnection(const nsACString& hostname,
    656                                       int32_t port) {
    657  if (mHttp3Session && CanDirectlyActivate()) {
    658    return mHttp3Session->JoinConnection(hostname, port);
    659  }
    660 
    661  return false;
    662 }
    663 
    664 bool HttpConnectionUDP::CanReuse() {
    665  if (NS_FAILED(mErrorBeforeConnect)) {
    666    return false;
    667  }
    668  if (mDontReuse) {
    669    return false;
    670  }
    671 
    672  if (mHttp3Session) {
    673    return mHttp3Session->CanReuse();
    674  }
    675  return false;
    676 }
    677 
    678 bool HttpConnectionUDP::CanDirectlyActivate() {
    679  // return true if a new transaction can be addded to ths connection at any
    680  // time through Activate(). In practice this means this is a healthy SPDY
    681  // connection with room for more concurrent streams.
    682 
    683  if (mHttp3Session) {
    684    return CanReuse();
    685  }
    686  return false;
    687 }
    688 
    689 //----------------------------------------------------------------------------
    690 // HttpConnectionUDP::nsAHttpConnection compatible methods
    691 //----------------------------------------------------------------------------
    692 
    693 nsresult HttpConnectionUDP::OnHeadersAvailable(nsAHttpTransaction* trans,
    694                                               nsHttpRequestHead* requestHead,
    695                                               nsHttpResponseHead* responseHead,
    696                                               bool* reset) {
    697  LOG(
    698      ("HttpConnectionUDP::OnHeadersAvailable [this=%p trans=%p "
    699       "response-head=%p]\n",
    700       this, trans, responseHead));
    701 
    702  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    703  NS_ENSURE_ARG_POINTER(trans);
    704  MOZ_ASSERT(responseHead, "No response head?");
    705 
    706  DebugOnly<nsresult> rv =
    707      responseHead->SetHeader(nsHttp::X_Firefox_Http3, mAlpnToken);
    708  MOZ_ASSERT(NS_SUCCEEDED(rv));
    709 
    710  uint16_t responseStatus = responseHead->Status();
    711  nsHttpTransaction* hTrans = trans->QueryHttpTransaction();
    712  if (mState == HttpConnectionState::SETTING_UP_TUNNEL) {
    713    HandleTunnelResponse(hTrans, responseStatus, reset);
    714    return NS_OK;
    715  }
    716 
    717  // deal with 408 Server Timeouts
    718  static const PRIntervalTime k1000ms = PR_MillisecondsToInterval(1000);
    719  if (responseStatus == 408) {
    720    // If this error could be due to a persistent connection reuse then
    721    // we pass an error code of NS_ERROR_NET_RESET to
    722    // trigger the transaction 'restart' mechanism.  We tell it to reset its
    723    // response headers so that it will be ready to receive the new response.
    724    if (mIsReused &&
    725        ((PR_IntervalNow() - mHttp3Session->LastWriteTime()) < k1000ms)) {
    726      CloseTransaction(mHttp3Session, NS_ERROR_NET_RESET);
    727      *reset = true;
    728      return NS_OK;
    729    }
    730  }
    731 
    732  return NS_OK;
    733 }
    734 
    735 void HttpConnectionUDP::HandleTunnelResponse(
    736    nsHttpTransaction* aHttpTransaction, uint16_t responseStatus, bool* reset) {
    737  LOG(("HttpConnectionUDP::HandleTunnelResponse mIsInTunnel=%d", mIsInTunnel));
    738  MOZ_ASSERT(TunnelSetupInProgress());
    739  MOZ_ASSERT(mIsInTunnel);
    740 
    741  if (responseStatus == 200) {
    742    ChangeState(HttpConnectionState::REQUEST);
    743  }
    744 
    745  bool onlyConnect = mTransactionCaps & NS_HTTP_CONNECT_ONLY;
    746  aHttpTransaction->OnProxyConnectComplete(responseStatus);
    747  if (responseStatus == 200) {
    748    LOG(("proxy CONNECT succeeded! onlyconnect=%d mIsInTunnel=%d\n",
    749         onlyConnect, mIsInTunnel));
    750    // If we're only connecting, we don't need to reset the transaction
    751    // state. We need to upgrade the socket now without doing the actual
    752    // http request.
    753    if (!onlyConnect) {
    754      *reset = true;
    755    }
    756 
    757    for (const auto& trans : mQueuedConnectUdpTransaction) {
    758      LOG(("add trans=%p", trans.get()));
    759      if (!mHttp3Session->AddStream(trans, trans->Priority(), mCallbacks)) {
    760        MOZ_ASSERT(false);  // this cannot happen!
    761        trans->Close(NS_ERROR_ABORT);
    762      }
    763    }
    764    mQueuedConnectUdpTransaction.Clear();
    765    mProxyConnectSucceeded = true;
    766    (void)ResumeSend();
    767  } else {
    768    LOG(("proxy CONNECT failed! onlyconnect=%d\n", onlyConnect));
    769    aHttpTransaction->SetProxyConnectFailed();
    770    mQueuedConnectUdpTransaction.Clear();
    771  }
    772 }
    773 
    774 void HttpConnectionUDP::ResetTransaction(nsHttpTransaction* aHttpTransaction) {
    775  LOG(("HttpConnectionUDP::ResetTransaction [this=%p mState=%d]\n", this,
    776       static_cast<uint32_t>(mState)));
    777 
    778  RefPtr<nsHttpConnectionInfo> wildCardProxyCi;
    779  nsresult rv = mConnInfo->CreateWildCard(getter_AddRefs(wildCardProxyCi));
    780  if (NS_FAILED(rv)) {
    781    CloseTransaction(mHttp3Session, rv);
    782    aHttpTransaction->Close(rv);
    783    return;
    784  }
    785 
    786  // Both Http3Session and nsHttpTransaction keeps a strong reference to a
    787  // ConnectionHandle, which itself holds a strong ref back to the concrete
    788  // connection, and when the last reference to the handle drops, the underlying
    789  // connection is released.
    790  // Notes:
    791  // 1) SetConnection() may drop the previous
    792  //    connection reference, which can immediately destroy that handle.
    793  // Avoid calling it unless we actually need to create/attach a handle.
    794  // 2) For speculative connections, the transaction may already have a handle.
    795  //    Reuse it rather than creating a new one.
    796  // 3) Only set the session's connection if it doesn't already have one.
    797  if (!mHttp3Session->Connection()) {
    798    if (!aHttpTransaction->Connection()) {
    799      RefPtr<ConnectionHandle> handle = new ConnectionHandle(this);
    800      aHttpTransaction->SetConnection(handle);
    801    }
    802    mHttp3Session->SetConnection(aHttpTransaction->Connection());
    803  }
    804  aHttpTransaction->SetConnection(nullptr);
    805  gHttpHandler->ConnMgr()->MoveToWildCardConnEntry(mConnInfo, wildCardProxyCi,
    806                                                   this);
    807  mConnInfo = wildCardProxyCi;
    808  aHttpTransaction->DoNotRemoveAltSvc();
    809  aHttpTransaction->Close(NS_ERROR_NET_RESET);
    810 }
    811 
    812 bool HttpConnectionUDP::IsReused() { return mIsReused; }
    813 
    814 nsresult HttpConnectionUDP::TakeTransport(
    815    nsISocketTransport** aTransport, nsIAsyncInputStream** aInputStream,
    816    nsIAsyncOutputStream** aOutputStream) {
    817  return NS_ERROR_FAILURE;
    818 }
    819 
    820 void HttpConnectionUDP::GetTLSSocketControl(nsITLSSocketControl** secinfo) {
    821  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    822  LOG(("HttpConnectionUDP::GetTLSSocketControl http3Session=%p\n",
    823       mHttp3Session.get()));
    824 
    825  if (mHttp3Session &&
    826      NS_SUCCEEDED(mHttp3Session->GetTransactionTLSSocketControl(secinfo))) {
    827    return;
    828  }
    829 
    830  *secinfo = nullptr;
    831 }
    832 
    833 nsresult HttpConnectionUDP::PushBack(const char* data, uint32_t length) {
    834  LOG(("HttpConnectionUDP::PushBack [this=%p, length=%d]\n", this, length));
    835 
    836  return NS_ERROR_UNEXPECTED;
    837 }
    838 
    839 class HttpConnectionUDPForceIO : public Runnable {
    840 public:
    841  HttpConnectionUDPForceIO(HttpConnectionUDP* aConn, bool doRecv)
    842      : Runnable("net::HttpConnectionUDPForceIO"),
    843        mConn(aConn),
    844        mDoRecv(doRecv) {}
    845 
    846  NS_IMETHOD Run() override {
    847    MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    848 
    849    if (mDoRecv) {
    850      return mConn->RecvData();
    851    }
    852 
    853    MOZ_ASSERT(mConn->mForceSendPending);
    854    mConn->mForceSendPending = false;
    855 
    856    return mConn->SendData();
    857  }
    858 
    859 private:
    860  RefPtr<HttpConnectionUDP> mConn;
    861  bool mDoRecv;
    862 };
    863 
    864 nsresult HttpConnectionUDP::ResumeSend() {
    865  LOG(("HttpConnectionUDP::ResumeSend [this=%p]\n", this));
    866  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    867  RefPtr<HttpConnectionUDP> self(this);
    868  NS_DispatchToCurrentThread(
    869      NS_NewRunnableFunction("HttpConnectionUDP::CallSendData",
    870                             [self{std::move(self)}]() { self->SendData(); }));
    871  return NS_OK;
    872 }
    873 
    874 nsresult HttpConnectionUDP::ResumeRecv() { return NS_OK; }
    875 
    876 void HttpConnectionUDP::ForceSendIO(nsITimer* aTimer, void* aClosure) {
    877  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    878  HttpConnectionUDP* self = static_cast<HttpConnectionUDP*>(aClosure);
    879  MOZ_ASSERT(aTimer == self->mForceSendTimer);
    880  self->mForceSendTimer = nullptr;
    881  NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(self, false));
    882 }
    883 
    884 nsresult HttpConnectionUDP::MaybeForceSendIO() {
    885  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    886  // due to bug 1213084 sometimes real I/O events do not get serviced when
    887  // NSPR derived I/O events are ready and this can cause a deadlock with
    888  // https over https proxying. Normally we would expect the write callback to
    889  // be invoked before this timer goes off, but set it at the old windows
    890  // tick interval (kForceDelay) as a backup for those circumstances.
    891  static const uint32_t kForceDelay = 17;  // ms
    892 
    893  if (mForceSendPending) {
    894    return NS_OK;
    895  }
    896  MOZ_ASSERT(!mForceSendTimer);
    897  mForceSendPending = true;
    898  return NS_NewTimerWithFuncCallback(
    899      getter_AddRefs(mForceSendTimer), HttpConnectionUDP::ForceSendIO, this,
    900      kForceDelay, nsITimer::TYPE_ONE_SHOT,
    901      "net::HttpConnectionUDP::MaybeForceSendIO"_ns);
    902 }
    903 
    904 // trigger an asynchronous read
    905 nsresult HttpConnectionUDP::ForceRecv() {
    906  LOG(("HttpConnectionUDP::ForceRecv [this=%p]\n", this));
    907  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    908 
    909  return NS_DispatchToCurrentThread(new HttpConnectionUDPForceIO(this, true));
    910 }
    911 
    912 // trigger an asynchronous write
    913 nsresult HttpConnectionUDP::ForceSend() {
    914  LOG(("HttpConnectionUDP::ForceSend [this=%p]\n", this));
    915  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    916 
    917  return MaybeForceSendIO();
    918 }
    919 
    920 HttpVersion HttpConnectionUDP::Version() { return HttpVersion::v3_0; }
    921 
    922 PRIntervalTime HttpConnectionUDP::LastWriteTime() {
    923  return mHttp3Session->LastWriteTime();
    924 }
    925 
    926 //-----------------------------------------------------------------------------
    927 // HttpConnectionUDP <private>
    928 //-----------------------------------------------------------------------------
    929 
    930 void HttpConnectionUDP::CloseTransaction(nsAHttpTransaction* trans,
    931                                         nsresult reason, bool aIsShutdown) {
    932  LOG(("HttpConnectionUDP::CloseTransaction[this=%p trans=%p reason=%" PRIx32
    933       "]\n",
    934       this, trans, static_cast<uint32_t>(reason)));
    935 
    936  // CloseTransaction may be called by nsHttpTransaction when a fallback
    937  // is needed. In this case, the transaction is still in mQueuedTransaction
    938  // and the proxy connect is still in progress.
    939  bool transInQueue = mQueuedHttpConnectTransaction.Contains(trans) ||
    940                      mQueuedConnectUdpTransaction.Contains(trans);
    941  MOZ_ASSERT(trans == mHttp3Session ||
    942             (transInQueue && IsProxyConnectInProgress()));
    943  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    944 
    945  if (NS_SUCCEEDED(reason) || (reason == NS_BASE_STREAM_CLOSED)) {
    946    return;
    947  }
    948 
    949  // The connection and security errors clear out alt-svc mappings
    950  // in case any previously validated ones are now invalid
    951  if (((reason == NS_ERROR_NET_RESET) ||
    952       (NS_ERROR_GET_MODULE(reason) == NS_ERROR_MODULE_SECURITY)) &&
    953      mConnInfo && !(mTransactionCaps & NS_HTTP_ERROR_SOFTLY)) {
    954    gHttpHandler->ClearHostMapping(mConnInfo);
    955  }
    956 
    957  mDontReuse = true;
    958  if (mHttp3Session) {
    959    // When proxy connnect failed, we call Http3Session::SetCleanShutdown to
    960    // force Http3Session to release this UDP connection.
    961    mHttp3Session->SetCleanShutdown(aIsShutdown || transInQueue ||
    962                                    (mIsInTunnel && !mProxyConnectSucceeded));
    963    mHttp3Session->Close(reason);
    964    if (!mHttp3Session->IsClosed()) {
    965      // During closing phase we still keep mHttp3Session session,
    966      // to resend CLOSE_CONNECTION frames.
    967      return;
    968    }
    969  }
    970 
    971  mHttp3Session = nullptr;
    972 
    973  {
    974    MutexAutoLock lock(mCallbacksLock);
    975    mCallbacks = nullptr;
    976  }
    977 
    978  Close(reason, aIsShutdown);
    979 
    980  // flag the connection as reused here for convenience sake. certainly
    981  // it might be going away instead ;-)
    982  mIsReused = true;
    983 }
    984 
    985 void HttpConnectionUDP::OnQuicTimeoutExpired() {
    986  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    987  LOG(("HttpConnectionUDP::OnQuicTimeoutExpired [this=%p]\n", this));
    988  // if the transaction was dropped...
    989  if (!mHttp3Session) {
    990    LOG(("  no transaction; ignoring event\n"));
    991    return;
    992  }
    993 
    994  nsresult rv = mHttp3Session->ProcessOutputAndEvents(mSocket);
    995  if (NS_FAILED(rv)) {
    996    CloseTransaction(mHttp3Session, rv);
    997  }
    998 }
    999 
   1000 //-----------------------------------------------------------------------------
   1001 // HttpConnectionUDP::nsISupports
   1002 //-----------------------------------------------------------------------------
   1003 
   1004 NS_IMPL_ADDREF(HttpConnectionUDP)
   1005 NS_IMPL_RELEASE(HttpConnectionUDP)
   1006 
   1007 NS_INTERFACE_MAP_BEGIN(HttpConnectionUDP)
   1008  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   1009  NS_INTERFACE_MAP_ENTRY(nsIUDPSocketSyncListener)
   1010  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   1011  NS_INTERFACE_MAP_ENTRY(HttpConnectionBase)
   1012  NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpConnectionUDP)
   1013 NS_INTERFACE_MAP_END
   1014 
   1015 void HttpConnectionUDP::NotifyDataRead() {
   1016  mExperienceState |= ConnectionExperienceState::First_Response_Received;
   1017 }
   1018 
   1019 void HttpConnectionUDP::NotifyDataWrite() {
   1020  mExperienceState |= ConnectionExperienceState::First_Request_Sent;
   1021 }
   1022 
   1023 // called on the socket transport thread
   1024 nsresult HttpConnectionUDP::RecvData() {
   1025  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1026 
   1027  // if the transaction was dropped...
   1028  if (!mHttp3Session) {
   1029    LOG(("  no Http3Session; ignoring event\n"));
   1030    return NS_OK;
   1031  }
   1032 
   1033  nsresult rv = mHttp3Session->RecvData(mSocket);
   1034  LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
   1035       static_cast<uint32_t>(rv)));
   1036 
   1037  if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
   1038 
   1039  return NS_OK;
   1040 }
   1041 
   1042 // called on the socket transport thread
   1043 nsresult HttpConnectionUDP::SendData() {
   1044  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
   1045 
   1046  // if the transaction was dropped...
   1047  if (!mHttp3Session) {
   1048    LOG(("  no Http3Session; ignoring event\n"));
   1049    return NS_OK;
   1050  }
   1051 
   1052  nsresult rv = mHttp3Session->SendData(mSocket);
   1053  LOG(("HttpConnectionUDP::OnInputReady %p rv=%" PRIx32, this,
   1054       static_cast<uint32_t>(rv)));
   1055 
   1056  if (NS_FAILED(rv)) CloseTransaction(mHttp3Session, rv);
   1057 
   1058  return NS_OK;
   1059 }
   1060 
   1061 //-----------------------------------------------------------------------------
   1062 // HttpConnectionUDP::nsIInterfaceRequestor
   1063 //-----------------------------------------------------------------------------
   1064 
   1065 // not called on the socket transport thread
   1066 NS_IMETHODIMP
   1067 HttpConnectionUDP::GetInterface(const nsIID& iid, void** result) {
   1068  // NOTE: This function is only called on the UI thread via sync proxy from
   1069  //       the socket transport thread.  If that weren't the case, then we'd
   1070  //       have to worry about the possibility of mHttp3Session going away
   1071  //       part-way through this function call.  See CloseTransaction.
   1072 
   1073  // NOTE - there is a bug here, the call to getinterface is proxied off the
   1074  // nss thread, not the ui thread as the above comment says. So there is
   1075  // indeed a chance of mSession going away. bug 615342
   1076 
   1077  MOZ_ASSERT(!OnSocketThread(), "on socket thread");
   1078 
   1079  nsCOMPtr<nsIInterfaceRequestor> callbacks;
   1080  {
   1081    MutexAutoLock lock(mCallbacksLock);
   1082    callbacks = mCallbacks;
   1083  }
   1084  if (callbacks) return callbacks->GetInterface(iid, result);
   1085  return NS_ERROR_NO_INTERFACE;
   1086 }
   1087 
   1088 void HttpConnectionUDP::SetEvent(nsresult aStatus) {
   1089  switch (aStatus) {
   1090    case NS_NET_STATUS_RESOLVING_HOST:
   1091      mBootstrappedTimings.domainLookupStart = TimeStamp::Now();
   1092      break;
   1093    case NS_NET_STATUS_RESOLVED_HOST:
   1094      mBootstrappedTimings.domainLookupEnd = TimeStamp::Now();
   1095      break;
   1096    case NS_NET_STATUS_CONNECTING_TO:
   1097      mBootstrappedTimings.connectStart = TimeStamp::Now();
   1098      mBootstrappedTimings.secureConnectionStart =
   1099          mBootstrappedTimings.connectStart;
   1100      break;
   1101    case NS_NET_STATUS_CONNECTED_TO:
   1102      mBootstrappedTimings.connectEnd = TimeStamp::Now();
   1103      break;
   1104    default:
   1105      break;
   1106  }
   1107 }
   1108 
   1109 bool HttpConnectionUDP::LastTransactionExpectedNoContent() {
   1110  return mLastTransactionExpectedNoContent;
   1111 }
   1112 
   1113 void HttpConnectionUDP::SetLastTransactionExpectedNoContent(bool val) {
   1114  mLastTransactionExpectedNoContent = val;
   1115 }
   1116 
   1117 bool HttpConnectionUDP::IsPersistent() { return !mDontReuse; }
   1118 
   1119 nsAHttpTransaction* HttpConnectionUDP::Transaction() { return mHttp3Session; }
   1120 
   1121 int64_t HttpConnectionUDP::BytesWritten() {
   1122  if (!mHttp3Session) {
   1123    return 0;
   1124  }
   1125  return mHttp3Session->GetBytesWritten();
   1126 }
   1127 
   1128 NS_IMETHODIMP HttpConnectionUDP::OnPacketReceived(nsIUDPSocket* aSocket) {
   1129  RecvData();
   1130  return NS_OK;
   1131 }
   1132 
   1133 NS_IMETHODIMP HttpConnectionUDP::OnStopListening(nsIUDPSocket* aSocket,
   1134                                                 nsresult aStatus) {
   1135  // At this point, the UDP socket has already been closed. Set aIsShutdown to
   1136  // true to ensure that mHttp3Session is also closed.
   1137  CloseTransaction(mHttp3Session, aStatus, true);
   1138  return NS_OK;
   1139 }
   1140 
   1141 nsresult HttpConnectionUDP::GetSelfAddr(NetAddr* addr) {
   1142  if (mSelfAddr) {
   1143    return mSelfAddr->GetNetAddr(addr);
   1144  }
   1145  return NS_ERROR_FAILURE;
   1146 }
   1147 
   1148 nsresult HttpConnectionUDP::GetPeerAddr(NetAddr* addr) {
   1149  if (mPeerAddr) {
   1150    return mPeerAddr->GetNetAddr(addr);
   1151  }
   1152  return NS_ERROR_FAILURE;
   1153 }
   1154 
   1155 bool HttpConnectionUDP::ResolvedByTRR() { return mResolvedByTRR; }
   1156 
   1157 nsIRequest::TRRMode HttpConnectionUDP::EffectiveTRRMode() {
   1158  return mEffectiveTRRMode;
   1159 }
   1160 
   1161 TRRSkippedReason HttpConnectionUDP::TRRSkipReason() { return mTRRSkipReason; }
   1162 
   1163 Http3Stats HttpConnectionUDP::GetStats() {
   1164  if (!mHttp3Session) {
   1165    return Http3Stats();
   1166  }
   1167  return mHttp3Session->GetStats();
   1168 }
   1169 
   1170 }  // namespace net
   1171 }  // namespace mozilla