tor-browser

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

Http2Stream.cpp (5096B)


      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 "Http2Stream.h"
     11 #include "nsHttp.h"
     12 #include "nsHttpConnectionInfo.h"
     13 #include "nsHttpRequestHead.h"
     14 #include "nsISocketTransport.h"
     15 #include "Http2Session.h"
     16 #include "nsIRequestContext.h"
     17 #include "nsHttpTransaction.h"
     18 #include "nsSocketTransportService2.h"
     19 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     20 
     21 namespace mozilla::net {
     22 
     23 Http2Stream::Http2Stream(nsAHttpTransaction* httpTransaction,
     24                         Http2Session* session, int32_t priority, uint64_t bcId)
     25    : Http2StreamBase((httpTransaction->QueryHttpTransaction())
     26                          ? httpTransaction->QueryHttpTransaction()->BrowserId()
     27                          : 0,
     28                      session, priority, bcId),
     29      mTransaction(httpTransaction) {
     30  LOG1(("Http2Stream::Http2Stream %p trans=%p", this, httpTransaction));
     31 }
     32 
     33 Http2Stream::~Http2Stream() {}
     34 
     35 void Http2Stream::CloseStream(nsresult reason) {
     36  if (reason == NS_ERROR_NET_RESET &&
     37      mTransaction->ConnectionInfo()->IsHttp3ProxyConnection()) {
     38    // If we got NS_ERROR_NET_RESET, the transaction will be retried. When
     39    // MASQUE proxy is used, keep the Alt-Svc in the connection info. Dropping
     40    // it could trigger an unintended proxy connection fallback.
     41    mTransaction->DoNotRemoveAltSvc();
     42  }
     43  mTransaction->Close(reason);
     44  mSession = nullptr;
     45  mClosed = true;
     46 }
     47 
     48 uint32_t Http2Stream::GetWireStreamId() {
     49  // >0 even numbered IDs are pushed streams.
     50  // odd numbered IDs are pulled streams.
     51  // 0 is the sink for a pushed stream.
     52  if (!mStreamID) {
     53    return 0;
     54  }
     55 
     56  if (mState == RESERVED_BY_REMOTE) {
     57    // h2-14 prevents sending a window update in this state
     58    return 0;
     59  }
     60  return mStreamID;
     61 }
     62 
     63 nsresult Http2Stream::OnWriteSegment(char* buf, uint32_t count,
     64                                     uint32_t* countWritten) {
     65  LOG3(("Http2Stream::OnWriteSegment %p count=%d state=%x 0x%X\n", this, count,
     66        mUpstreamState, mStreamID));
     67 
     68  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     69  MOZ_ASSERT(mSegmentWriter);
     70 
     71  return Http2StreamBase::OnWriteSegment(buf, count, countWritten);
     72 }
     73 
     74 nsresult Http2Stream::CallToReadData(uint32_t count, uint32_t* countRead) {
     75  return mTransaction->ReadSegments(this, count, countRead);
     76 }
     77 
     78 nsresult Http2Stream::CallToWriteData(uint32_t count, uint32_t* countWritten) {
     79  return mTransaction->WriteSegments(this, count, countWritten);
     80 }
     81 
     82 // This is really a headers frame, but open is pretty clear from a workflow pov
     83 nsresult Http2Stream::GenerateHeaders(nsCString& aCompressedData,
     84                                      uint8_t& firstFrameFlags) {
     85  nsHttpRequestHead* head = mTransaction->RequestHead();
     86  nsAutoCString requestURI;
     87  head->RequestURI(requestURI);
     88  RefPtr<Http2Session> session = Session();
     89  LOG3(("Http2Stream %p Stream ID 0x%X [session=%p] for URI %s\n", this,
     90        mStreamID, session.get(), requestURI.get()));
     91 
     92  nsAutoCString authorityHeader;
     93  nsresult rv = head->GetHeader(nsHttp::Host, authorityHeader);
     94  if (NS_FAILED(rv)) {
     95    MOZ_ASSERT(false);
     96    return rv;
     97  }
     98 
     99  nsDependentCString scheme(head->IsHTTPS() ? "https" : "http");
    100 
    101  nsAutoCString method;
    102  nsAutoCString path;
    103  head->Method(method);
    104  head->Path(path);
    105 
    106  bool mayAddTEHeader = true;
    107  nsAutoCString teHeader;
    108  rv = head->GetHeader(nsHttp::TE, teHeader);
    109  if (NS_SUCCEEDED(rv) && teHeader.Equals("moz_no_te_trailers"_ns)) {
    110    // This is a hack that allows extensions or devtools to
    111    // skip adding the TE header. This is necessary to be able to
    112    // ship interventions when websites misbehave when the TE:trailers
    113    // header is sent (see bug 1954533).
    114    mayAddTEHeader = false;
    115  }
    116 
    117  rv = session->Compressor()->EncodeHeaderBlock(
    118      mFlatHttpRequestHeaders, method, path, authorityHeader, scheme,
    119      EmptyCString(), false, aCompressedData, mayAddTEHeader);
    120  NS_ENSURE_SUCCESS(rv, rv);
    121 
    122  int64_t clVal = session->Compressor()->GetParsedContentLength();
    123  if (clVal != -1) {
    124    mRequestBodyLenRemaining = clVal;
    125  }
    126 
    127  // Determine whether to put the fin bit on the header frame or whether
    128  // to wait for a data packet to put it on.
    129 
    130  if (head->IsGet() || head->IsHead()) {
    131    // for GET and HEAD place the fin bit right on the
    132    // header packet
    133    firstFrameFlags |= Http2Session::kFlag_END_STREAM;
    134  } else if (head->IsPost() || head->IsPut() || head->IsConnect()) {
    135    // place fin in a data frame even for 0 length messages for iterop
    136  } else if (!mRequestBodyLenRemaining) {
    137    // for other HTTP extension methods, rely on the content-length
    138    // to determine whether or not to put fin on headers
    139    firstFrameFlags |= Http2Session::kFlag_END_STREAM;
    140  }
    141 
    142  return NS_OK;
    143 }
    144 
    145 }  // namespace mozilla::net