tor-browser

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

Http2StreamTunnel.cpp (21074B)


      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 // 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 "nsHttpHandler.h"
     17 #include "Http2StreamTunnel.h"
     18 #include "nsHttpConnectionInfo.h"
     19 #include "nsQueryObject.h"
     20 #include "nsProxyRelease.h"
     21 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     22 #include "Http2Session.h"
     23 
     24 namespace mozilla::net {
     25 
     26 NS_IMPL_ADDREF_INHERITED(Http2StreamTunnel, Http2StreamBase)
     27 NS_IMPL_RELEASE_INHERITED(Http2StreamTunnel, Http2StreamBase)
     28 
     29 NS_INTERFACE_MAP_BEGIN(Http2StreamTunnel)
     30  NS_INTERFACE_MAP_ENTRY(nsITransport)
     31  NS_INTERFACE_MAP_ENTRY_CONCRETE(Http2StreamTunnel)
     32  NS_INTERFACE_MAP_ENTRY(nsITransport)
     33  NS_INTERFACE_MAP_ENTRY(nsISocketTransport)
     34 NS_INTERFACE_MAP_END
     35 
     36 Http2StreamTunnel::Http2StreamTunnel(Http2Session* session, int32_t priority,
     37                                     uint64_t bcId,
     38                                     nsHttpConnectionInfo* aConnectionInfo)
     39    : Http2StreamBase(0, session, priority, bcId),
     40      mConnectionInfo(aConnectionInfo) {}
     41 
     42 Http2StreamTunnel::~Http2StreamTunnel() { ClearTransactionsBlockedOnTunnel(); }
     43 
     44 void Http2StreamTunnel::HandleResponseHeaders(nsACString& aHeadersOut,
     45                                              int32_t httpResponseCode) {}
     46 
     47 // TODO We do not need this. Fix in bug 1772212.
     48 void Http2StreamTunnel::ClearTransactionsBlockedOnTunnel() {
     49  nsresult rv = gHttpHandler->ConnMgr()->ProcessPendingQ(mConnectionInfo);
     50  if (NS_FAILED(rv)) {
     51    LOG3(
     52        ("Http2StreamTunnel::ClearTransactionsBlockedOnTunnel %p\n"
     53         "  ProcessPendingQ failed: %" PRIX32,
     54         this, static_cast<uint32_t>(rv)));
     55  }
     56 }
     57 
     58 NS_IMETHODIMP
     59 Http2StreamTunnel::SetKeepaliveEnabled(bool aKeepaliveEnabled) {
     60  return NS_ERROR_NOT_IMPLEMENTED;
     61 }
     62 
     63 NS_IMETHODIMP
     64 Http2StreamTunnel::SetKeepaliveVals(int32_t keepaliveIdleTime,
     65                                    int32_t keepaliveRetryInterval) {
     66  return NS_ERROR_NOT_IMPLEMENTED;
     67 }
     68 
     69 NS_IMETHODIMP
     70 Http2StreamTunnel::GetSecurityCallbacks(
     71    nsIInterfaceRequestor** aSecurityCallbacks) {
     72  return mSocketTransport->GetSecurityCallbacks(aSecurityCallbacks);
     73 }
     74 
     75 NS_IMETHODIMP
     76 Http2StreamTunnel::SetSecurityCallbacks(
     77    nsIInterfaceRequestor* aSecurityCallbacks) {
     78  return NS_OK;
     79 }
     80 
     81 NS_IMETHODIMP
     82 Http2StreamTunnel::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize,
     83                                   uint32_t aSegmentCount,
     84                                   nsIInputStream** _retval) {
     85  return NS_ERROR_NOT_IMPLEMENTED;
     86 }
     87 
     88 NS_IMETHODIMP
     89 Http2StreamTunnel::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize,
     90                                    uint32_t aSegmentCount,
     91                                    nsIOutputStream** _retval) {
     92  return NS_ERROR_NOT_IMPLEMENTED;
     93 }
     94 
     95 void Http2StreamTunnel::CloseStream(nsresult aReason) {
     96  LOG(("Http2StreamTunnel::CloseStream this=%p", this));
     97  RefPtr<Http2Session> session = Session();
     98  if (NS_SUCCEEDED(mCondition)) {
     99    mSession = nullptr;
    100    // Let the session pickup that the stream has been closed.
    101    mCondition = aReason;
    102    if (NS_SUCCEEDED(aReason)) {
    103      aReason = NS_BASE_STREAM_CLOSED;
    104    }
    105    mOutput->OnSocketReady(aReason);
    106    mInput->OnSocketReady(aReason);
    107  }
    108  mClosed = true;
    109 }
    110 
    111 NS_IMETHODIMP
    112 Http2StreamTunnel::Close(nsresult aReason) {
    113  LOG(("Http2StreamTunnel::Close this=%p", this));
    114  RefPtr<Http2Session> session = Session();
    115  if (NS_SUCCEEDED(mCondition)) {
    116    if (NS_SUCCEEDED(aReason)) {
    117      aReason = NS_BASE_STREAM_CLOSED;
    118    }
    119    mOutput->CloseWithStatus(aReason);
    120    mInput->CloseWithStatus(aReason);
    121    // Let the session pickup that the stream has been closed.
    122    mCondition = aReason;
    123    // Clear the session in the end to make sure that CleanupStream() can be
    124    // called in CloseWithStatus().
    125    mSession = nullptr;
    126  }
    127  return NS_OK;
    128 }
    129 
    130 NS_IMETHODIMP
    131 Http2StreamTunnel::SetEventSink(nsITransportEventSink* aSink,
    132                                nsIEventTarget* aEventTarget) {
    133  return NS_OK;
    134 }
    135 
    136 NS_IMETHODIMP
    137 Http2StreamTunnel::Bind(NetAddr* aLocalAddr) {
    138  return NS_ERROR_NOT_IMPLEMENTED;
    139 }
    140 
    141 NS_IMETHODIMP
    142 Http2StreamTunnel::GetEchConfigUsed(bool* aEchConfigUsed) {
    143  return NS_ERROR_NOT_IMPLEMENTED;
    144 }
    145 
    146 NS_IMETHODIMP
    147 Http2StreamTunnel::SetEchConfig(const nsACString& aEchConfig) {
    148  return NS_ERROR_NOT_IMPLEMENTED;
    149 }
    150 
    151 NS_IMETHODIMP
    152 Http2StreamTunnel::ResolvedByTRR(bool* aResolvedByTRR) {
    153  return NS_ERROR_NOT_IMPLEMENTED;
    154 }
    155 
    156 NS_IMETHODIMP Http2StreamTunnel::GetEffectiveTRRMode(
    157    nsIRequest::TRRMode* aEffectiveTRRMode) {
    158  return NS_ERROR_NOT_IMPLEMENTED;
    159 }
    160 
    161 NS_IMETHODIMP Http2StreamTunnel::GetTrrSkipReason(
    162    nsITRRSkipReason::value* aTrrSkipReason) {
    163  return NS_ERROR_NOT_IMPLEMENTED;
    164 }
    165 
    166 NS_IMETHODIMP
    167 Http2StreamTunnel::IsAlive(bool* aAlive) {
    168  RefPtr<Http2Session> session = Session();
    169  if (mSocketTransport && session) {
    170    return mSocketTransport->IsAlive(aAlive);
    171  }
    172  *aAlive = false;
    173  return NS_OK;
    174 }
    175 
    176 #define FWD_TS_T_PTR(fx, ts) \
    177  NS_IMETHODIMP              \
    178  Http2StreamTunnel::fx(ts* arg) { return mSocketTransport->fx(arg); }
    179 
    180 #define FWD_TS_T_ADDREF(fx, ts) \
    181  NS_IMETHODIMP                 \
    182  Http2StreamTunnel::fx(ts** arg) { return mSocketTransport->fx(arg); }
    183 
    184 #define FWD_TS_T(fx, ts) \
    185  NS_IMETHODIMP          \
    186  Http2StreamTunnel::fx(ts arg) { return mSocketTransport->fx(arg); }
    187 
    188 FWD_TS_T_PTR(GetKeepaliveEnabled, bool);
    189 FWD_TS_T_PTR(GetSendBufferSize, uint32_t);
    190 FWD_TS_T(SetSendBufferSize, uint32_t);
    191 FWD_TS_T_PTR(GetPort, int32_t);
    192 FWD_TS_T_PTR(GetPeerAddr, mozilla::net::NetAddr);
    193 FWD_TS_T_PTR(GetSelfAddr, mozilla::net::NetAddr);
    194 FWD_TS_T_ADDREF(GetScriptablePeerAddr, nsINetAddr);
    195 FWD_TS_T_ADDREF(GetScriptableSelfAddr, nsINetAddr);
    196 FWD_TS_T_ADDREF(GetTlsSocketControl, nsITLSSocketControl);
    197 FWD_TS_T_PTR(GetConnectionFlags, uint32_t);
    198 FWD_TS_T(SetConnectionFlags, uint32_t);
    199 FWD_TS_T(SetIsPrivate, bool);
    200 FWD_TS_T_PTR(GetTlsFlags, uint32_t);
    201 FWD_TS_T(SetTlsFlags, uint32_t);
    202 FWD_TS_T_PTR(GetRecvBufferSize, uint32_t);
    203 FWD_TS_T(SetRecvBufferSize, uint32_t);
    204 FWD_TS_T_PTR(GetResetIPFamilyPreference, bool);
    205 
    206 nsresult Http2StreamTunnel::GetOriginAttributes(
    207    mozilla::OriginAttributes* aOriginAttributes) {
    208  return mSocketTransport->GetOriginAttributes(aOriginAttributes);
    209 }
    210 
    211 nsresult Http2StreamTunnel::SetOriginAttributes(
    212    const mozilla::OriginAttributes& aOriginAttributes) {
    213  return mSocketTransport->SetOriginAttributes(aOriginAttributes);
    214 }
    215 
    216 NS_IMETHODIMP
    217 Http2StreamTunnel::GetScriptableOriginAttributes(
    218    JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) {
    219  return mSocketTransport->GetScriptableOriginAttributes(aCx,
    220                                                         aOriginAttributes);
    221 }
    222 
    223 NS_IMETHODIMP
    224 Http2StreamTunnel::SetScriptableOriginAttributes(
    225    JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) {
    226  return mSocketTransport->SetScriptableOriginAttributes(aCx,
    227                                                         aOriginAttributes);
    228 }
    229 
    230 NS_IMETHODIMP
    231 Http2StreamTunnel::GetHost(nsACString& aHost) {
    232  return mSocketTransport->GetHost(aHost);
    233 }
    234 
    235 NS_IMETHODIMP
    236 Http2StreamTunnel::GetTimeout(uint32_t aType, uint32_t* _retval) {
    237  return mSocketTransport->GetTimeout(aType, _retval);
    238 }
    239 
    240 NS_IMETHODIMP
    241 Http2StreamTunnel::SetTimeout(uint32_t aType, uint32_t aValue) {
    242  return mSocketTransport->SetTimeout(aType, aValue);
    243 }
    244 
    245 NS_IMETHODIMP
    246 Http2StreamTunnel::SetReuseAddrPort(bool aReuseAddrPort) {
    247  return mSocketTransport->SetReuseAddrPort(aReuseAddrPort);
    248 }
    249 
    250 NS_IMETHODIMP
    251 Http2StreamTunnel::SetLinger(bool aPolarity, int16_t aTimeout) {
    252  return mSocketTransport->SetLinger(aPolarity, aTimeout);
    253 }
    254 
    255 NS_IMETHODIMP
    256 Http2StreamTunnel::GetQoSBits(uint8_t* aQoSBits) {
    257  return mSocketTransport->GetQoSBits(aQoSBits);
    258 }
    259 
    260 NS_IMETHODIMP
    261 Http2StreamTunnel::SetQoSBits(uint8_t aQoSBits) {
    262  return mSocketTransport->SetQoSBits(aQoSBits);
    263 }
    264 
    265 NS_IMETHODIMP
    266 Http2StreamTunnel::GetRetryDnsIfPossible(bool* aRetry) {
    267  return mSocketTransport->GetRetryDnsIfPossible(aRetry);
    268 }
    269 
    270 NS_IMETHODIMP
    271 Http2StreamTunnel::GetStatus(nsresult* aStatus) {
    272  return mSocketTransport->GetStatus(aStatus);
    273 }
    274 
    275 already_AddRefed<nsHttpConnection> Http2StreamTunnel::CreateHttpConnection(
    276    nsAHttpTransaction* httpTransaction, nsIInterfaceRequestor* aCallbacks,
    277    PRIntervalTime aRtt, bool aIsExtendedCONNECT) {
    278  mInput = new InputStreamTunnel(this);
    279  mOutput = new OutputStreamTunnel(this);
    280  RefPtr<nsHttpConnection> conn = new nsHttpConnection();
    281 
    282  conn->SetTransactionCaps(httpTransaction->Caps());
    283  nsresult rv =
    284      conn->Init(httpTransaction->ConnectionInfo(),
    285                 gHttpHandler->ConnMgr()->MaxRequestDelay(), this, mInput,
    286                 mOutput, true, NS_OK, aCallbacks, aRtt, aIsExtendedCONNECT);
    287  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
    288  mTransaction = httpTransaction;
    289  return conn.forget();
    290 }
    291 
    292 nsresult Http2StreamTunnel::CallToReadData(uint32_t count,
    293                                           uint32_t* countRead) {
    294  LOG(("Http2StreamTunnel::CallToReadData this=%p", this));
    295  return mOutput->OnSocketReady(NS_OK);
    296 }
    297 
    298 nsresult Http2StreamTunnel::CallToWriteData(uint32_t count,
    299                                            uint32_t* countWritten) {
    300  LOG(("Http2StreamTunnel::CallToWriteData this=%p", this));
    301  if (!mInput->HasCallback()) {
    302    return NS_BASE_STREAM_WOULD_BLOCK;
    303  }
    304  return mInput->OnSocketReady(NS_OK);
    305 }
    306 
    307 nsresult Http2StreamTunnel::GenerateHeaders(nsCString& aCompressedData,
    308                                            uint8_t& firstFrameFlags) {
    309  nsAutoCString authorityHeader;
    310  authorityHeader = mConnectionInfo->GetOrigin();
    311  authorityHeader.Append(':');
    312  authorityHeader.AppendInt(mConnectionInfo->OriginPort());
    313 
    314  RefPtr<Http2Session> session = Session();
    315 
    316  LOG3(("Http2StreamTunnel %p Stream ID 0x%X [session=%p] for %s\n", this,
    317        mStreamID, session.get(), authorityHeader.get()));
    318 
    319  mRequestBodyLenRemaining = 0x0fffffffffffffffULL;
    320 
    321  nsresult rv = session->Compressor()->EncodeHeaderBlock(
    322      mFlatHttpRequestHeaders, "CONNECT"_ns, EmptyCString(), authorityHeader,
    323      EmptyCString(), EmptyCString(), true, aCompressedData, true);
    324  NS_ENSURE_SUCCESS(rv, rv);
    325 
    326  return NS_OK;
    327 }
    328 
    329 OutputStreamTunnel::OutputStreamTunnel(Http2StreamTunnel* aStream)
    330    : mWeakStream(aStream) {}
    331 
    332 OutputStreamTunnel::~OutputStreamTunnel() = default;
    333 
    334 nsresult OutputStreamTunnel::OnSocketReady(nsresult condition) {
    335  LOG(("OutputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32
    336       " callback=%p]\n",
    337       this, static_cast<uint32_t>(condition), mCallback.get()));
    338 
    339  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    340 
    341  nsCOMPtr<nsIOutputStreamCallback> callback;
    342 
    343  // update condition, but be careful not to erase an already
    344  // existing error condition.
    345  if (NS_SUCCEEDED(mCondition)) {
    346    mCondition = condition;
    347  }
    348  callback = std::move(mCallback);
    349 
    350  nsresult rv = NS_OK;
    351  if (callback) {
    352    rv = callback->OnOutputStreamReady(this);
    353    MaybeSetRequestDone(callback);
    354  }
    355 
    356  return rv;
    357 }
    358 
    359 void OutputStreamTunnel::MaybeSetRequestDone(
    360    nsIOutputStreamCallback* aCallback) {
    361  RefPtr<nsHttpConnection> conn = do_QueryObject(aCallback);
    362  if (!conn) {
    363    return;
    364  }
    365 
    366  RefPtr<Http2StreamTunnel> tunnel;
    367  nsresult rv = GetStream(getter_AddRefs(tunnel));
    368  if (NS_FAILED(rv)) {
    369    return;
    370  }
    371 
    372  if (conn->RequestDone()) {
    373    tunnel->SetRequestDone();
    374  }
    375 }
    376 
    377 NS_IMPL_ISUPPORTS(OutputStreamTunnel, nsIOutputStream, nsIAsyncOutputStream)
    378 
    379 NS_IMETHODIMP
    380 OutputStreamTunnel::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); }
    381 
    382 NS_IMETHODIMP
    383 OutputStreamTunnel::Flush() { return NS_OK; }
    384 
    385 NS_IMETHODIMP
    386 OutputStreamTunnel::StreamStatus() { return mCondition; }
    387 
    388 NS_IMETHODIMP
    389 OutputStreamTunnel::Write(const char* buf, uint32_t count,
    390                          uint32_t* countWritten) {
    391  LOG(("OutputStreamTunnel::Write [this=%p count=%u]\n", this, count));
    392 
    393  *countWritten = 0;
    394  if (NS_FAILED(mCondition)) {
    395    return mCondition;
    396  }
    397 
    398  RefPtr<Http2StreamTunnel> tunnel;
    399  nsresult rv = GetStream(getter_AddRefs(tunnel));
    400  if (NS_FAILED(rv)) {
    401    return rv;
    402  }
    403 
    404  return tunnel->OnReadSegment(buf, count, countWritten);
    405 }
    406 
    407 NS_IMETHODIMP
    408 OutputStreamTunnel::WriteSegments(nsReadSegmentFun reader, void* closure,
    409                                  uint32_t count, uint32_t* countRead) {
    410  // stream is unbuffered
    411  return NS_ERROR_NOT_IMPLEMENTED;
    412 }
    413 
    414 NS_IMETHODIMP
    415 OutputStreamTunnel::WriteFrom(nsIInputStream* stream, uint32_t count,
    416                              uint32_t* countRead) {
    417  return NS_ERROR_NOT_IMPLEMENTED;
    418 }
    419 
    420 NS_IMETHODIMP
    421 OutputStreamTunnel::IsNonBlocking(bool* nonblocking) {
    422  *nonblocking = true;
    423  return NS_OK;
    424 }
    425 
    426 NS_IMETHODIMP
    427 OutputStreamTunnel::CloseWithStatus(nsresult reason) {
    428  LOG(("OutputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n",
    429       this, static_cast<uint32_t>(reason)));
    430  mCondition = reason;
    431 
    432  RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get();
    433  mWeakStream = nullptr;
    434  if (!tunnel) {
    435    return NS_OK;
    436  }
    437  RefPtr<Http2Session> session = tunnel->Session();
    438  if (!session) {
    439    return NS_OK;
    440  }
    441  session->CleanupStream(tunnel, reason, Http2Session::CANCEL_ERROR);
    442  return NS_OK;
    443 }
    444 
    445 NS_IMETHODIMP
    446 OutputStreamTunnel::AsyncWait(nsIOutputStreamCallback* callback, uint32_t flags,
    447                              uint32_t amount, nsIEventTarget* target) {
    448  LOG(("OutputStreamTunnel::AsyncWait [this=%p]\n", this));
    449 
    450  // The following parametr are not used:
    451  MOZ_ASSERT(!flags);
    452  MOZ_ASSERT(!amount);
    453  (void)target;
    454 
    455  RefPtr<OutputStreamTunnel> self(this);
    456  if (NS_FAILED(mCondition)) {
    457    (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    458        "OutputStreamTunnel::CallOnSocketReady",
    459        [self{std::move(self)}]() { self->OnSocketReady(NS_OK); }));
    460  } else if (callback) {
    461    // Inform the proxy connection that the inner connetion wants to
    462    // read data.
    463    RefPtr<Http2StreamTunnel> tunnel;
    464    nsresult rv = GetStream(getter_AddRefs(tunnel));
    465    if (NS_FAILED(rv)) {
    466      return rv;
    467    }
    468    RefPtr<Http2Session> session;
    469    rv = GetSession(getter_AddRefs(session));
    470    if (NS_FAILED(rv)) {
    471      return rv;
    472    }
    473    session->TransactionHasDataToWrite(tunnel);
    474  }
    475 
    476  mCallback = callback;
    477  return NS_OK;
    478 }
    479 
    480 InputStreamTunnel::InputStreamTunnel(Http2StreamTunnel* aStream)
    481    : mWeakStream(aStream) {}
    482 
    483 InputStreamTunnel::~InputStreamTunnel() = default;
    484 
    485 nsresult InputStreamTunnel::OnSocketReady(nsresult condition) {
    486  LOG(("InputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 "]\n", this,
    487       static_cast<uint32_t>(condition)));
    488 
    489  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
    490 
    491  nsCOMPtr<nsIInputStreamCallback> callback;
    492 
    493  // update condition, but be careful not to erase an already
    494  // existing error condition.
    495  if (NS_SUCCEEDED(mCondition)) {
    496    mCondition = condition;
    497  }
    498  callback = std::move(mCallback);
    499 
    500  return callback ? callback->OnInputStreamReady(this) : NS_OK;
    501 }
    502 
    503 NS_IMPL_ISUPPORTS(InputStreamTunnel, nsIInputStream, nsIAsyncInputStream)
    504 
    505 NS_IMETHODIMP
    506 InputStreamTunnel::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); }
    507 
    508 NS_IMETHODIMP
    509 InputStreamTunnel::Available(uint64_t* avail) {
    510  LOG(("InputStreamTunnel::Available [this=%p]\n", this));
    511 
    512  if (NS_FAILED(mCondition)) {
    513    return mCondition;
    514  }
    515 
    516  return NS_ERROR_FAILURE;
    517 }
    518 
    519 NS_IMETHODIMP
    520 InputStreamTunnel::StreamStatus() {
    521  LOG(("InputStreamTunnel::StreamStatus [this=%p]\n", this));
    522 
    523  return mCondition;
    524 }
    525 
    526 NS_IMETHODIMP
    527 InputStreamTunnel::Read(char* buf, uint32_t count, uint32_t* countRead) {
    528  LOG(("InputStreamTunnel::Read [this=%p count=%u]\n", this, count));
    529 
    530  *countRead = 0;
    531 
    532  if (NS_FAILED(mCondition)) {
    533    return mCondition;
    534  }
    535 
    536  RefPtr<Http2StreamTunnel> tunnel;
    537  nsresult rv = GetStream(getter_AddRefs(tunnel));
    538  if (NS_FAILED(rv)) {
    539    return rv;
    540  }
    541 
    542  return tunnel->OnWriteSegment(buf, count, countRead);
    543 }
    544 
    545 NS_IMETHODIMP
    546 InputStreamTunnel::ReadSegments(nsWriteSegmentFun writer, void* closure,
    547                                uint32_t count, uint32_t* countRead) {
    548  // socket stream is unbuffered
    549  return NS_ERROR_NOT_IMPLEMENTED;
    550 }
    551 
    552 NS_IMETHODIMP
    553 InputStreamTunnel::IsNonBlocking(bool* nonblocking) {
    554  *nonblocking = true;
    555  return NS_OK;
    556 }
    557 
    558 NS_IMETHODIMP
    559 InputStreamTunnel::CloseWithStatus(nsresult reason) {
    560  LOG(("InputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n",
    561       this, static_cast<uint32_t>(reason)));
    562  mCondition = reason;
    563 
    564  RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get();
    565  mWeakStream = nullptr;
    566  if (!tunnel) {
    567    return NS_OK;
    568  }
    569  RefPtr<Http2Session> session = tunnel->Session();
    570  if (!session) {
    571    return NS_OK;
    572  }
    573  session->CleanupStream(tunnel, reason, Http2Session::CANCEL_ERROR);
    574  return NS_OK;
    575 }
    576 
    577 NS_IMETHODIMP
    578 InputStreamTunnel::AsyncWait(nsIInputStreamCallback* callback, uint32_t flags,
    579                             uint32_t amount, nsIEventTarget* target) {
    580  LOG(("InputStreamTunnel::AsyncWait [this=%p mCondition=%x]\n", this,
    581       static_cast<uint32_t>(mCondition)));
    582 
    583  // The following parametr are not used:
    584  MOZ_ASSERT(!flags);
    585  MOZ_ASSERT(!amount);
    586  (void)target;
    587 
    588  RefPtr<InputStreamTunnel> self(this);
    589  if (NS_FAILED(mCondition)) {
    590    (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    591        "InputStreamTunnel::CallOnSocketReady",
    592        [self{std::move(self)}]() { self->OnSocketReady(NS_OK); }));
    593  } else if (callback) {
    594    // Inform the proxy connection that the inner connetion wants to
    595    // read data.
    596    RefPtr<Http2StreamTunnel> tunnel;
    597    nsresult rv = GetStream(getter_AddRefs(tunnel));
    598    if (NS_FAILED(rv)) {
    599      return rv;
    600    }
    601    RefPtr<Http2Session> session;
    602    rv = GetSession(getter_AddRefs(session));
    603    if (NS_FAILED(rv)) {
    604      return rv;
    605    }
    606    if (tunnel->DataBuffered()) {
    607      session->TransactionHasDataToRecv(tunnel);
    608    }
    609  }
    610 
    611  mCallback = callback;
    612  return NS_OK;
    613 }
    614 
    615 nsresult OutputStreamTunnel::GetStream(Http2StreamTunnel** aStream) {
    616  RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get();
    617  MOZ_ASSERT(tunnel);
    618  if (!tunnel) {
    619    return NS_ERROR_UNEXPECTED;
    620  }
    621 
    622  tunnel.forget(aStream);
    623  return NS_OK;
    624 }
    625 
    626 nsresult OutputStreamTunnel::GetSession(Http2Session** aSession) {
    627  RefPtr<Http2StreamTunnel> tunnel;
    628  nsresult rv = GetStream(getter_AddRefs(tunnel));
    629  if (NS_FAILED(rv)) {
    630    return rv;
    631  }
    632  RefPtr<Http2Session> session = tunnel->Session();
    633  MOZ_ASSERT(session);
    634  if (!session) {
    635    return NS_ERROR_UNEXPECTED;
    636  }
    637 
    638  session.forget(aSession);
    639  return NS_OK;
    640 }
    641 
    642 nsresult InputStreamTunnel::GetStream(Http2StreamTunnel** aStream) {
    643  RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get();
    644  MOZ_ASSERT(tunnel);
    645  if (!tunnel) {
    646    return NS_ERROR_UNEXPECTED;
    647  }
    648 
    649  tunnel.forget(aStream);
    650  return NS_OK;
    651 }
    652 
    653 nsresult InputStreamTunnel::GetSession(Http2Session** aSession) {
    654  RefPtr<Http2StreamTunnel> tunnel;
    655  nsresult rv = GetStream(getter_AddRefs(tunnel));
    656  if (NS_FAILED(rv)) {
    657    return rv;
    658  }
    659  RefPtr<Http2Session> session = tunnel->Session();
    660  if (!session) {
    661    return NS_ERROR_UNEXPECTED;
    662  }
    663 
    664  session.forget(aSession);
    665  return NS_OK;
    666 }
    667 
    668 Http2StreamWebSocket::Http2StreamWebSocket(
    669    Http2Session* session, int32_t priority, uint64_t bcId,
    670    nsHttpConnectionInfo* aConnectionInfo)
    671    : Http2StreamTunnel(session, priority, bcId, aConnectionInfo) {
    672  LOG(("Http2StreamWebSocket ctor:%p", this));
    673 }
    674 
    675 Http2StreamWebSocket::~Http2StreamWebSocket() {
    676  LOG(("Http2StreamWebSocket dtor:%p", this));
    677 }
    678 
    679 nsresult Http2StreamWebSocket::GenerateHeaders(nsCString& aCompressedData,
    680                                               uint8_t& firstFrameFlags) {
    681  nsHttpRequestHead* head = mTransaction->RequestHead();
    682 
    683  nsAutoCString authorityHeader;
    684  nsresult rv = head->GetHeader(nsHttp::Host, authorityHeader);
    685  NS_ENSURE_SUCCESS(rv, rv);
    686 
    687  RefPtr<Http2Session> session = Session();
    688  LOG3(("Http2StreamWebSocket %p Stream ID 0x%X [session=%p] for %s\n", this,
    689        mStreamID, session.get(), authorityHeader.get()));
    690 
    691  nsDependentCString scheme(head->IsHTTPS() ? "https" : "http");
    692  nsAutoCString path;
    693  head->Path(path);
    694 
    695  rv = session->Compressor()->EncodeHeaderBlock(
    696      mFlatHttpRequestHeaders, "CONNECT"_ns, path, authorityHeader, scheme,
    697      "websocket"_ns, false, aCompressedData, true);
    698  NS_ENSURE_SUCCESS(rv, rv);
    699 
    700  mRequestBodyLenRemaining = 0x0fffffffffffffffULL;
    701 
    702  return NS_OK;
    703 }
    704 
    705 void Http2StreamWebSocket::CloseStream(nsresult aReason) {
    706  LOG(("Http2StreamWebSocket::CloseStream this=%p aReason=%x", this,
    707       static_cast<uint32_t>(aReason)));
    708  if (mTransaction) {
    709    mTransaction->Close(aReason);
    710    mTransaction = nullptr;
    711  }
    712  Http2StreamTunnel::CloseStream(aReason);
    713 }
    714 
    715 }  // namespace mozilla::net