tor-browser

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

Http3StreamTunnel.cpp (23637B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et tw=80 : */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // HttpLog.h should generally be included first
      8 #include "HttpLog.h"
      9 
     10 #include "nsHttpHandler.h"
     11 #include "Http3StreamTunnel.h"
     12 #include "Http3Session.h"
     13 #include "nsQueryObject.h"
     14 
     15 namespace mozilla::net {
     16 
     17 //-----------------------------------------------------------------------------
     18 // Http3TransportLayer::InputStreamTunnel impl
     19 //-----------------------------------------------------------------------------
     20 
     21 NS_IMPL_QUERY_INTERFACE(Http3TransportLayer::InputStreamTunnel, nsIInputStream,
     22                        nsIAsyncInputStream)
     23 
     24 NS_IMETHODIMP_(MozExternalRefCountType)
     25 Http3TransportLayer::InputStreamTunnel::AddRef() {
     26  return mTransport->AddRef();
     27 }
     28 
     29 NS_IMETHODIMP_(MozExternalRefCountType)
     30 Http3TransportLayer::InputStreamTunnel::Release() {
     31  return mTransport->Release();
     32 }
     33 
     34 Http3TransportLayer::InputStreamTunnel::InputStreamTunnel(
     35    Http3TransportLayer* aTransport)
     36    : mTransport(aTransport) {}
     37 
     38 NS_IMETHODIMP
     39 Http3TransportLayer::InputStreamTunnel::Close() {
     40  LOG(("Http3TransportLayer::InputStreamTunnel::Close [this=%p]\n", this));
     41  return CloseWithStatus(NS_BASE_STREAM_CLOSED);
     42 }
     43 
     44 NS_IMETHODIMP Http3TransportLayer::InputStreamTunnel::Available(
     45    uint64_t* avail) {
     46  LOG(("Http3TransportLayer::InputStreamTunnel::Available [this=%p]\n", this));
     47 
     48  if (NS_FAILED(mCondition)) {
     49    return mCondition;
     50  }
     51 
     52  return NS_ERROR_FAILURE;
     53 }
     54 
     55 NS_IMETHODIMP Http3TransportLayer::InputStreamTunnel::StreamStatus() {
     56  LOG(("Http3TransportLayer::InputStreamTunnel::StreamStatus [this=%p]\n",
     57       this));
     58  return mCondition;
     59 }
     60 
     61 NS_IMETHODIMP
     62 Http3TransportLayer::InputStreamTunnel::Read(char* buf, uint32_t count,
     63                                             uint32_t* countRead) {
     64  LOG(("Http3TransportLayer::InputStreamTunnel::Read [this=%p]\n", this));
     65 
     66  *countRead = 0;
     67 
     68  if (NS_FAILED(mCondition)) {
     69    return mCondition;
     70  }
     71 
     72  RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
     73  if (!tunnel) {
     74    return NS_ERROR_UNEXPECTED;
     75  }
     76 
     77  return tunnel->OnWriteSegment(buf, count, countRead);
     78 }
     79 
     80 NS_IMETHODIMP
     81 Http3TransportLayer::InputStreamTunnel::ReadSegments(nsWriteSegmentFun writer,
     82                                                     void* closure,
     83                                                     uint32_t count,
     84                                                     uint32_t* countRead) {
     85  return NS_ERROR_NOT_IMPLEMENTED;
     86 }
     87 
     88 NS_IMETHODIMP
     89 Http3TransportLayer::InputStreamTunnel::IsNonBlocking(bool* nonblocking) {
     90  *nonblocking = true;
     91  return NS_OK;
     92 }
     93 
     94 NS_IMETHODIMP
     95 Http3TransportLayer::InputStreamTunnel::CloseWithStatus(nsresult reason) {
     96  LOG(
     97      ("Http3TransportLayer::InputStreamTunnel::CloseWithStatus [this=%p "
     98       "reason=%" PRIx32 "]\n",
     99       this, static_cast<uint32_t>(reason)));
    100  mCondition = reason;
    101 
    102  RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    103  if (!tunnel) {
    104    return NS_OK;
    105  }
    106 
    107  tunnel->CleanupStream(reason);
    108  return NS_OK;
    109 }
    110 
    111 nsresult Http3TransportLayer::InputStreamTunnel::OnSocketReady(
    112    nsresult condition) {
    113  LOG(("InputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 "]\n", this,
    114       static_cast<uint32_t>(condition)));
    115 
    116  nsCOMPtr<nsIInputStreamCallback> callback;
    117 
    118  // update condition, but be careful not to erase an already
    119  // existing error condition.
    120  if (NS_SUCCEEDED(mCondition)) {
    121    mCondition = condition;
    122  }
    123  callback = std::move(mCallback);
    124 
    125  return callback ? callback->OnInputStreamReady(this) : NS_OK;
    126 }
    127 
    128 NS_IMETHODIMP
    129 Http3TransportLayer::InputStreamTunnel::AsyncWait(
    130    nsIInputStreamCallback* callback, uint32_t flags, uint32_t amount,
    131    nsIEventTarget* target) {
    132  LOG(
    133      ("Http3TransportLayer::InputStreamTunnel::AsyncWait [this=%p, "
    134       "callback=%p]\n",
    135       this, callback));
    136  // The following parameters are not used:
    137  MOZ_ASSERT(!flags);
    138  MOZ_ASSERT(!amount);
    139  (void)target;
    140 
    141  RefPtr<InputStreamTunnel> self(this);
    142  if (NS_FAILED(mCondition)) {
    143    (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    144        "InputStreamTunnel::CallOnSocketReady",
    145        [self{std::move(self)}]() { self->OnSocketReady(self->mCondition); }));
    146  } else if (callback) {
    147    RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    148    if (!tunnel) {
    149      return NS_ERROR_UNEXPECTED;
    150    }
    151    tunnel->HasDataToRead();
    152  }
    153 
    154  mCallback = callback;
    155  return NS_OK;
    156 }
    157 
    158 //-----------------------------------------------------------------------------
    159 // Http3TransportLayer::OutputStreamTunnel impl
    160 //-----------------------------------------------------------------------------
    161 
    162 NS_IMPL_QUERY_INTERFACE(Http3TransportLayer::OutputStreamTunnel,
    163                        nsIOutputStream, nsIAsyncOutputStream)
    164 
    165 NS_IMETHODIMP_(MozExternalRefCountType)
    166 Http3TransportLayer::OutputStreamTunnel::AddRef() {
    167  return mTransport->AddRef();
    168 }
    169 
    170 NS_IMETHODIMP_(MozExternalRefCountType)
    171 Http3TransportLayer::OutputStreamTunnel::Release() {
    172  return mTransport->Release();
    173 }
    174 
    175 Http3TransportLayer::OutputStreamTunnel::OutputStreamTunnel(
    176    Http3TransportLayer* aTransport)
    177    : mTransport(aTransport) {}
    178 
    179 NS_IMETHODIMP
    180 Http3TransportLayer::OutputStreamTunnel::Close() {
    181  LOG(("Http3TransportLayer::OutputStreamTunnel::Close [this=%p]\n", this));
    182  return CloseWithStatus(NS_BASE_STREAM_CLOSED);
    183 }
    184 
    185 NS_IMETHODIMP
    186 Http3TransportLayer::OutputStreamTunnel::Flush() {
    187  LOG(("Http3TransportLayer::OutputStreamTunnel::Flush [this=%p]\n", this));
    188  return NS_OK;
    189 }
    190 
    191 NS_IMETHODIMP
    192 Http3TransportLayer::OutputStreamTunnel::StreamStatus() {
    193  LOG(("TLSTransportLayerOutputStream::StreamStatus [this=%p]\n", this));
    194  return mCondition;
    195 }
    196 
    197 NS_IMETHODIMP
    198 Http3TransportLayer::OutputStreamTunnel::Write(const char* buf, uint32_t count,
    199                                               uint32_t* countWritten) {
    200  LOG(("Http3TransportLayer::OutputStreamTunnel::Write [this=%p count=%u]\n",
    201       this, count));
    202  *countWritten = 0;
    203  if (NS_FAILED(mCondition)) {
    204    return mCondition;
    205  }
    206 
    207  RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    208  if (!tunnel) {
    209    return NS_ERROR_UNEXPECTED;
    210  }
    211 
    212  tunnel->HasDataToWrite();
    213  return tunnel->OnReadSegment(buf, count, countWritten);
    214 }
    215 
    216 NS_IMETHODIMP
    217 Http3TransportLayer::OutputStreamTunnel::WriteSegments(nsReadSegmentFun reader,
    218                                                       void* closure,
    219                                                       uint32_t count,
    220                                                       uint32_t* countRead) {
    221  return NS_ERROR_NOT_IMPLEMENTED;
    222 }
    223 
    224 NS_IMETHODIMP
    225 Http3TransportLayer::OutputStreamTunnel::WriteFrom(nsIInputStream* stream,
    226                                                   uint32_t count,
    227                                                   uint32_t* countRead) {
    228  return NS_ERROR_NOT_IMPLEMENTED;
    229 }
    230 
    231 NS_IMETHODIMP
    232 Http3TransportLayer::OutputStreamTunnel::IsNonBlocking(bool* nonblocking) {
    233  *nonblocking = true;
    234  return NS_OK;
    235 }
    236 
    237 NS_IMETHODIMP
    238 Http3TransportLayer::OutputStreamTunnel::CloseWithStatus(nsresult reason) {
    239  LOG(("OutputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n",
    240       this, static_cast<uint32_t>(reason)));
    241  mCondition = reason;
    242 
    243  RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    244  if (!tunnel) {
    245    return NS_OK;
    246  }
    247 
    248  tunnel->CleanupStream(reason);
    249  return NS_OK;
    250 }
    251 
    252 nsresult Http3TransportLayer::OutputStreamTunnel::OnSocketReady(
    253    nsresult condition) {
    254  LOG(("OutputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32
    255       " callback=%p]\n",
    256       this, static_cast<uint32_t>(condition), mCallback.get()));
    257 
    258  nsCOMPtr<nsIOutputStreamCallback> callback;
    259 
    260  // update condition, but be careful not to erase an already
    261  // existing error condition.
    262  if (NS_SUCCEEDED(mCondition)) {
    263    mCondition = condition;
    264  }
    265  callback = std::move(mCallback);
    266 
    267  nsresult rv = NS_OK;
    268  if (callback) {
    269    rv = callback->OnOutputStreamReady(this);
    270    MaybeSetRequestDone(callback);
    271  }
    272 
    273  return rv;
    274 }
    275 
    276 void Http3TransportLayer::OutputStreamTunnel::MaybeSetRequestDone(
    277    nsIOutputStreamCallback* aCallback) {
    278  RefPtr<nsHttpConnection> conn = do_QueryObject(aCallback);
    279  if (!conn) {
    280    return;
    281  }
    282 
    283  RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    284  if (!tunnel) {
    285    return;
    286  }
    287 
    288  if (conn->RequestDone()) {
    289    tunnel->SetRequestDone();
    290  }
    291 }
    292 
    293 NS_IMETHODIMP
    294 Http3TransportLayer::OutputStreamTunnel::AsyncWait(
    295    nsIOutputStreamCallback* callback, uint32_t flags, uint32_t amount,
    296    nsIEventTarget* target) {
    297  LOG(("OutputStreamTunnel::AsyncWait [this=%p]\n", this));
    298 
    299  // The following parameters are not used:
    300  MOZ_ASSERT(!flags);
    301  MOZ_ASSERT(!amount);
    302  (void)target;
    303 
    304  RefPtr<OutputStreamTunnel> self(this);
    305  if (NS_FAILED(mCondition)) {
    306    (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    307        "OutputStreamTunnel::CallOnSocketReady",
    308        [self{std::move(self)}]() { self->OnSocketReady(self->mCondition); }));
    309  } else if (callback) {
    310    // Inform the proxy connection that the inner connetion wants to
    311    // read data.
    312    RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream();
    313    if (!tunnel) {
    314      return NS_ERROR_UNEXPECTED;
    315    }
    316    tunnel->HasDataToWrite();
    317  }
    318 
    319  mCallback = callback;
    320  return NS_OK;
    321 }
    322 
    323 //-----------------------------------------------------------------------------
    324 // Http3TransportLayer impl
    325 //-----------------------------------------------------------------------------
    326 
    327 NS_IMPL_ISUPPORTS(Http3TransportLayer, nsISocketTransport, nsITransport,
    328                  nsIInputStreamCallback, nsIOutputStreamCallback)
    329 
    330 Http3TransportLayer::Http3TransportLayer(Http3StreamTunnel* aStream)
    331    : mStream(aStream), mInput(this), mOutput(this) {
    332  LOG(("Http3TransportLayer ctor %p", this));
    333 }
    334 
    335 Http3TransportLayer::~Http3TransportLayer() {
    336  LOG(("Http3TransportLayer dtor %p", this));
    337 }
    338 
    339 already_AddRefed<Http3StreamTunnel> Http3TransportLayer::GetStream() {
    340  RefPtr<Http3StreamTunnel> stream = mStream;
    341  return stream.forget();
    342 }
    343 
    344 nsIAsyncInputStream* Http3TransportLayer::GetInput() { return &mInput; }
    345 
    346 nsIAsyncOutputStream* Http3TransportLayer::GetOutput() { return &mOutput; }
    347 
    348 nsresult Http3TransportLayer::CallToReadData() {
    349  LOG(("Http3TransportLayer::CallToReadData this=%p", this));
    350  return mOutput.OnSocketReady(NS_OK);
    351 }
    352 
    353 nsresult Http3TransportLayer::CallToWriteData() {
    354  LOG(("Http3TransportLayer::CallToWriteData this=%p", this));
    355  if (!mInput.HasCallback()) {
    356    return NS_BASE_STREAM_WOULD_BLOCK;
    357  }
    358  return mInput.OnSocketReady(NS_OK);
    359 }
    360 
    361 NS_IMETHODIMP
    362 Http3TransportLayer::OnInputStreamReady(nsIAsyncInputStream* in) {
    363  return NS_OK;
    364 }
    365 
    366 NS_IMETHODIMP
    367 Http3TransportLayer::OnOutputStreamReady(nsIAsyncOutputStream* out) {
    368  return NS_OK;
    369 }
    370 
    371 NS_IMETHODIMP
    372 Http3TransportLayer::SetKeepaliveEnabled(bool aKeepaliveEnabled) {
    373  return NS_ERROR_NOT_IMPLEMENTED;
    374 }
    375 
    376 NS_IMETHODIMP
    377 Http3TransportLayer::SetKeepaliveVals(int32_t keepaliveIdleTime,
    378                                      int32_t keepaliveRetryInterval) {
    379  return NS_ERROR_NOT_IMPLEMENTED;
    380 }
    381 
    382 NS_IMETHODIMP
    383 Http3TransportLayer::GetSecurityCallbacks(
    384    nsIInterfaceRequestor** aSecurityCallbacks) {
    385  return NS_ERROR_NOT_IMPLEMENTED;
    386 }
    387 
    388 NS_IMETHODIMP
    389 Http3TransportLayer::SetSecurityCallbacks(
    390    nsIInterfaceRequestor* aSecurityCallbacks) {
    391  return NS_OK;
    392 }
    393 
    394 NS_IMETHODIMP
    395 Http3TransportLayer::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize,
    396                                     uint32_t aSegmentCount,
    397                                     nsIInputStream** _retval) {
    398  return NS_ERROR_NOT_IMPLEMENTED;
    399 }
    400 
    401 NS_IMETHODIMP
    402 Http3TransportLayer::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize,
    403                                      uint32_t aSegmentCount,
    404                                      nsIOutputStream** _retval) {
    405  return NS_ERROR_NOT_IMPLEMENTED;
    406 }
    407 
    408 NS_IMETHODIMP
    409 Http3TransportLayer::Close(nsresult aReason) {
    410  LOG(("Http3TransportLayer::Close [this=%p reason=%" PRIx32 "]\n", this,
    411       static_cast<uint32_t>(aReason)));
    412  if (NS_SUCCEEDED(mCondition)) {
    413    if (NS_SUCCEEDED(aReason)) {
    414      aReason = NS_BASE_STREAM_CLOSED;
    415    }
    416    mOutput.CloseWithStatus(aReason);
    417    mInput.CloseWithStatus(aReason);
    418    // Let the session pickup that the stream has been closed.
    419    mCondition = aReason;
    420  }
    421  return NS_OK;
    422 }
    423 
    424 void Http3TransportLayer::OnStreamClosed(nsresult aReason) {
    425  LOG(("Http3TransportLayer::OnStreamClosed this=%p", this));
    426  if (NS_SUCCEEDED(mCondition)) {
    427    if (NS_SUCCEEDED(aReason)) {
    428      aReason = NS_BASE_STREAM_CLOSED;
    429    }
    430    mOutput.OnSocketReady(aReason);
    431    mInput.OnSocketReady(aReason);
    432    mCondition = aReason;
    433  }
    434 }
    435 
    436 NS_IMETHODIMP
    437 Http3TransportLayer::SetEventSink(nsITransportEventSink* aSink,
    438                                  nsIEventTarget* aEventTarget) {
    439  return NS_OK;
    440 }
    441 
    442 NS_IMETHODIMP
    443 Http3TransportLayer::Bind(NetAddr* aLocalAddr) {
    444  return NS_ERROR_NOT_IMPLEMENTED;
    445 }
    446 
    447 NS_IMETHODIMP
    448 Http3TransportLayer::GetEchConfigUsed(bool* aEchConfigUsed) {
    449  return NS_ERROR_NOT_IMPLEMENTED;
    450 }
    451 
    452 NS_IMETHODIMP
    453 Http3TransportLayer::SetEchConfig(const nsACString& aEchConfig) {
    454  return NS_ERROR_NOT_IMPLEMENTED;
    455 }
    456 
    457 NS_IMETHODIMP
    458 Http3TransportLayer::ResolvedByTRR(bool* aResolvedByTRR) {
    459  return NS_ERROR_NOT_IMPLEMENTED;
    460 }
    461 
    462 NS_IMETHODIMP Http3TransportLayer::GetEffectiveTRRMode(
    463    nsIRequest::TRRMode* aEffectiveTRRMode) {
    464  return NS_ERROR_NOT_IMPLEMENTED;
    465 }
    466 
    467 NS_IMETHODIMP Http3TransportLayer::GetTrrSkipReason(
    468    nsITRRSkipReason::value* aTrrSkipReason) {
    469  return NS_ERROR_NOT_IMPLEMENTED;
    470 }
    471 
    472 #define FWD_H3ST_PTR(fx, ts) \
    473  NS_IMETHODIMP              \
    474  Http3TransportLayer::fx(ts* arg) { return NS_OK; }
    475 
    476 #define FWD_H3ST_ADDREF(fx, ts) \
    477  NS_IMETHODIMP                 \
    478  Http3TransportLayer::fx(ts** arg) { return NS_OK; }
    479 
    480 #define FWD_H3ST(fx, ts) \
    481  NS_IMETHODIMP          \
    482  Http3TransportLayer::fx(ts arg) { return NS_OK; }
    483 
    484 FWD_H3ST_PTR(GetKeepaliveEnabled, bool);
    485 FWD_H3ST_PTR(GetSendBufferSize, uint32_t);
    486 FWD_H3ST(SetSendBufferSize, uint32_t);
    487 FWD_H3ST_PTR(GetPort, int32_t);
    488 FWD_H3ST_PTR(GetSelfAddr, mozilla::net::NetAddr);
    489 FWD_H3ST_ADDREF(GetScriptablePeerAddr, nsINetAddr);
    490 FWD_H3ST_ADDREF(GetScriptableSelfAddr, nsINetAddr);
    491 FWD_H3ST_PTR(GetConnectionFlags, uint32_t);
    492 FWD_H3ST(SetConnectionFlags, uint32_t);
    493 FWD_H3ST(SetIsPrivate, bool);
    494 FWD_H3ST_PTR(GetTlsFlags, uint32_t);
    495 FWD_H3ST(SetTlsFlags, uint32_t);
    496 FWD_H3ST_PTR(GetRecvBufferSize, uint32_t);
    497 FWD_H3ST(SetRecvBufferSize, uint32_t);
    498 FWD_H3ST_PTR(GetResetIPFamilyPreference, bool);
    499 
    500 nsresult Http3TransportLayer::IsAlive(bool* aAlive) {
    501  *aAlive = true;
    502  return NS_OK;
    503 }
    504 
    505 nsresult Http3TransportLayer::GetPeerAddr(NetAddr* addr) {
    506  // TODO: what address we should use?
    507  NetAddr peerAddr;
    508  peerAddr.InitFromString("127.0.0.1"_ns);
    509  *addr = peerAddr;
    510  return NS_OK;
    511 }
    512 
    513 nsresult Http3TransportLayer::GetTlsSocketControl(
    514    nsITLSSocketControl** tlsSocketControl) {
    515  return NS_OK;
    516 }
    517 
    518 nsresult Http3TransportLayer::GetOriginAttributes(
    519    mozilla::OriginAttributes* aOriginAttributes) {
    520  return NS_OK;
    521 }
    522 
    523 nsresult Http3TransportLayer::SetOriginAttributes(
    524    const mozilla::OriginAttributes& aOriginAttributes) {
    525  return NS_OK;
    526 }
    527 
    528 NS_IMETHODIMP
    529 Http3TransportLayer::GetScriptableOriginAttributes(
    530    JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) {
    531  return NS_OK;
    532 }
    533 
    534 NS_IMETHODIMP
    535 Http3TransportLayer::SetScriptableOriginAttributes(
    536    JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) {
    537  return NS_OK;
    538 }
    539 
    540 NS_IMETHODIMP
    541 Http3TransportLayer::GetHost(nsACString& aHost) { return NS_OK; }
    542 
    543 NS_IMETHODIMP
    544 Http3TransportLayer::GetTimeout(uint32_t aType, uint32_t* _retval) {
    545  return NS_OK;
    546 }
    547 
    548 NS_IMETHODIMP
    549 Http3TransportLayer::SetTimeout(uint32_t aType, uint32_t aValue) {
    550  return NS_OK;
    551 }
    552 
    553 NS_IMETHODIMP
    554 Http3TransportLayer::SetReuseAddrPort(bool aReuseAddrPort) { return NS_OK; }
    555 
    556 NS_IMETHODIMP
    557 Http3TransportLayer::SetLinger(bool aPolarity, int16_t aTimeout) {
    558  return NS_OK;
    559 }
    560 
    561 NS_IMETHODIMP
    562 Http3TransportLayer::GetQoSBits(uint8_t* aQoSBits) { return NS_OK; }
    563 
    564 NS_IMETHODIMP
    565 Http3TransportLayer::SetQoSBits(uint8_t aQoSBits) { return NS_OK; }
    566 
    567 NS_IMETHODIMP
    568 Http3TransportLayer::GetRetryDnsIfPossible(bool* aRetry) { return NS_OK; }
    569 
    570 NS_IMETHODIMP
    571 Http3TransportLayer::GetStatus(nsresult* aStatus) {
    572  *aStatus = mCondition;
    573  return NS_OK;
    574 }
    575 
    576 //-----------------------------------------------------------------------------
    577 // Http3StreamTunnel impl
    578 //-----------------------------------------------------------------------------
    579 
    580 Http3StreamTunnel::Http3StreamTunnel(nsAHttpTransaction* aTrans,
    581                                     Http3Session* aSession,
    582                                     uint64_t aCurrentBrowserId)
    583    : Http3Stream(aTrans, aSession, ClassOfService(), aCurrentBrowserId) {
    584  LOG(("Http3StreamTunnel ctor %p", this));
    585 }
    586 
    587 Http3StreamTunnel::~Http3StreamTunnel() {
    588  LOG(("Http3StreamTunnel dtor %p", this));
    589 }
    590 
    591 nsresult Http3StreamTunnel::TryActivating() {
    592  nsProxyInfo* info = mTransaction->ConnectionInfo()->ProxyInfo();
    593  if (!info) {
    594    return NS_ERROR_UNEXPECTED;
    595  }
    596 
    597  nsAutoCString host;
    598  DebugOnly<nsresult> rv{};
    599  rv = nsHttpHandler::GenerateHostPort(
    600      nsDependentCString(mTransaction->ConnectionInfo()->Origin()),
    601      mTransaction->ConnectionInfo()->OriginPort(), host);
    602  MOZ_ASSERT(NS_SUCCEEDED(rv));
    603 
    604  LOG(("Http3StreamTunnel::TryActivating [auth=%s]", host.get()));
    605  return mSession->TryActivating("CONNECT"_ns, ""_ns, host, ""_ns,
    606                                 mFlatHttpRequestHeaders, &mStreamId, this);
    607 }
    608 
    609 void Http3StreamTunnel::Close(nsresult aResult) {
    610  LOG(("Http3StreamTunnel::Close %p", this));
    611  if (mClosed) {
    612    return;
    613  }
    614  mClosed = true;
    615 
    616  mRecvState = RECV_DONE;
    617  mSendState = SEND_DONE;
    618 
    619  mSession = nullptr;
    620 
    621  if (mTransaction) {
    622    mTransaction->Close(aResult);
    623  }
    624 
    625  if (mTransport) {
    626    mTransport->OnStreamClosed(aResult);
    627    mTransport = nullptr;
    628  }
    629 }
    630 
    631 nsresult Http3StreamTunnel::ReadSegments() {
    632  LOG(("Http3StreamTunnel::ReadSegments %p mSendState=%d mRecvState=%d", this,
    633       mSendState, mRecvState));
    634  if (mRecvState == RECV_DONE) {
    635    // Don't transmit any request frames if the peer cannot respond or respone
    636    // is already done.
    637    LOG3(
    638        ("Http3StreamTunnel %p ReadSegments request stream aborted due to"
    639         " response side closure\n",
    640         this));
    641    return NS_ERROR_ABORT;
    642  }
    643 
    644  if (mSendState == SEND_DONE) {
    645    return NS_OK;
    646  }
    647 
    648  if (!mTransport) {
    649    return NS_ERROR_UNEXPECTED;
    650  }
    651 
    652  nsresult rv = mTransport->CallToReadData();
    653 
    654  if (mSendState == WAITING_TO_ACTIVATE &&
    655      (NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK)) {
    656    LOG3(("Http3StreamTunnel %p ReadSegments forcing OnReadSegment call\n",
    657          this));
    658    uint32_t wasted = 0;
    659    nsresult rv2 = OnReadSegment("", 0, &wasted);
    660 
    661    LOG3(("  OnReadSegment returned 0x%08" PRIx32, static_cast<uint32_t>(rv2)));
    662  }
    663 
    664  return rv;
    665 }
    666 
    667 nsresult Http3StreamTunnel::BufferInput() {
    668  char buf[SimpleBufferPage::kSimpleBufferPageSize];
    669  uint32_t countWritten;
    670  nsresult rv = mSession->ReadResponseData(
    671      mStreamId, buf, SimpleBufferPage::kSimpleBufferPageSize, &countWritten,
    672      &mFin);
    673  if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
    674    return rv;
    675  }
    676  LOG(("Http3StreamTunnel::BufferInput %p countWritten=%d mFin=%d", this,
    677       countWritten, mFin));
    678  if (countWritten == 0) {
    679    if (mFin) {
    680      mRecvState = RECV_DONE;
    681      rv = NS_BASE_STREAM_CLOSED;
    682    } else {
    683      rv = NS_BASE_STREAM_WOULD_BLOCK;
    684    }
    685  } else {
    686    mTotalRead += countWritten;
    687    if (mFin) {
    688      mRecvState = RECEIVED_FIN;
    689    }
    690  }
    691  if (NS_SUCCEEDED(rv)) {
    692    rv = mSimpleBuffer.Write(buf, countWritten);
    693    if (NS_FAILED(rv)) {
    694      MOZ_ASSERT(rv == NS_ERROR_OUT_OF_MEMORY);
    695      return NS_ERROR_OUT_OF_MEMORY;
    696    }
    697  }
    698  return rv;
    699 }
    700 
    701 nsresult Http3StreamTunnel::WriteSegments() {
    702  LOG(("Http3StreamTunnel::WriteSegments [this=%p]", this));
    703  if (mRecvState == RECV_DONE) {
    704    return NS_OK;
    705  }
    706 
    707  if (!mTransport) {
    708    return NS_ERROR_UNEXPECTED;
    709  }
    710 
    711  nsresult rv = NS_OK;
    712  bool again = true;
    713 
    714  do {
    715    mSocketInCondition = NS_OK;
    716    rv = mTransport->CallToWriteData();
    717    if (mRecvState == RECV_DONE) {
    718      return NS_ERROR_UNEXPECTED;
    719    }
    720 
    721    // When CallToWriteData() returns NS_BASE_STREAM_WOULD_BLOCK, it means the
    722    // consumer can't accept data at the moment. We need to read the data into a
    723    // buffer so it won't block other streams.
    724    if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
    725      rv = BufferInput();
    726    }
    727 
    728    if (mRecvState == RECEIVED_FIN) {
    729      rv = NS_BASE_STREAM_CLOSED;
    730      mRecvState = RECV_DONE;
    731    }
    732 
    733    if (NS_FAILED(rv)) {
    734      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
    735        rv = NS_OK;
    736      }
    737      again = false;
    738    } else if (NS_FAILED(mSocketInCondition)) {
    739      if (mSocketInCondition != NS_BASE_STREAM_WOULD_BLOCK) {
    740        rv = mSocketInCondition;
    741      }
    742      again = false;
    743    }
    744  } while (again && gHttpHandler->Active());
    745 
    746  return rv;
    747 }
    748 
    749 nsresult Http3StreamTunnel::OnWriteSegment(char* buf, uint32_t count,
    750                                           uint32_t* countWritten) {
    751  LOG(("Http3StreamTunnel::OnWriteSegment [this=%p, state=%d", this,
    752       mRecvState));
    753  // Sometimes we have read data from the network and stored it in a pipe
    754  // so that other streams can proceed when the gecko caller is not processing
    755  // data events fast enough and flow control hasn't caught up yet. This
    756  // gets the stored data out of that pipe
    757  if (mSimpleBuffer.Available()) {
    758    *countWritten = mSimpleBuffer.Read(buf, count);
    759    MOZ_ASSERT(*countWritten);
    760    LOG3(
    761        ("Http3StreamTunnel::OnWriteSegment read from flow "
    762         "control buffer %p %d",
    763         this, *countWritten));
    764    return NS_OK;
    765  }
    766 
    767  return Http3Stream::OnWriteSegment(buf, count, countWritten);
    768 }
    769 
    770 void Http3StreamTunnel::SetRequestDone() {
    771  LOG(("Http3StreamTunnel::SetRequestDone %p", this));
    772 }
    773 
    774 void Http3StreamTunnel::HasDataToWrite() {
    775  mSession->StreamHasDataToWrite(this);
    776 }
    777 
    778 void Http3StreamTunnel::HasDataToRead() {
    779  // We can't always call ConnectSlowConsumer(), because it triggers
    780  // ForceRecv(),
    781  // which posts a runnable to call WriteSegments() again. When we already have
    782  // data buffered, this is fine. The consumer can read data from the buffer.
    783  // However, if no data is buffered, doing this would create a busy loop that
    784  // continuously waits for data.
    785  if (mSimpleBuffer.Available()) {
    786    mSession->ConnectSlowConsumer(this);
    787  }
    788 }
    789 
    790 already_AddRefed<nsHttpConnection> Http3StreamTunnel::CreateHttpConnection(
    791    nsIInterfaceRequestor* aCallbacks, PRIntervalTime aRtt,
    792    bool aIsExtendedCONNECT) {
    793  mTransport = new Http3TransportLayer(this);
    794  RefPtr<nsHttpConnection> conn = new nsHttpConnection();
    795 
    796  conn->SetTransactionCaps(mTransaction->Caps());
    797  nsresult rv =
    798      conn->Init(mTransaction->ConnectionInfo(),
    799                 gHttpHandler->ConnMgr()->MaxRequestDelay(), mTransport,
    800                 mTransport->GetInput(), mTransport->GetOutput(), true, NS_OK,
    801                 aCallbacks, aRtt, aIsExtendedCONNECT);
    802  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    803  return conn.forget();
    804 }
    805 
    806 void Http3StreamTunnel::CleanupStream(nsresult aReason) {
    807  if (mSession) {
    808    LOG(("Http3StreamTunnel::CleanupStream %p", this));
    809    mSession->CloseStream(this, aReason);
    810  }
    811 }
    812 
    813 }  // namespace mozilla::net