File: Http2Stream.cpp

package info (click to toggle)
firefox 147.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,683,324 kB
  • sloc: cpp: 7,607,156; javascript: 6,532,492; ansic: 3,775,158; python: 1,415,368; xml: 634,556; asm: 438,949; java: 186,241; sh: 62,751; makefile: 18,079; objc: 13,092; perl: 12,808; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (145 lines) | stat: -rw-r--r-- 5,096 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// HttpLog.h should generally be included first
#include "HttpLog.h"

#include "Http2Stream.h"
#include "nsHttp.h"
#include "nsHttpConnectionInfo.h"
#include "nsHttpRequestHead.h"
#include "nsISocketTransport.h"
#include "Http2Session.h"
#include "nsIRequestContext.h"
#include "nsHttpTransaction.h"
#include "nsSocketTransportService2.h"
#include "mozilla/glean/NetwerkProtocolHttpMetrics.h"

namespace mozilla::net {

Http2Stream::Http2Stream(nsAHttpTransaction* httpTransaction,
                         Http2Session* session, int32_t priority, uint64_t bcId)
    : Http2StreamBase((httpTransaction->QueryHttpTransaction())
                          ? httpTransaction->QueryHttpTransaction()->BrowserId()
                          : 0,
                      session, priority, bcId),
      mTransaction(httpTransaction) {
  LOG1(("Http2Stream::Http2Stream %p trans=%p", this, httpTransaction));
}

Http2Stream::~Http2Stream() {}

void Http2Stream::CloseStream(nsresult reason) {
  if (reason == NS_ERROR_NET_RESET &&
      mTransaction->ConnectionInfo()->IsHttp3ProxyConnection()) {
    // If we got NS_ERROR_NET_RESET, the transaction will be retried. When
    // MASQUE proxy is used, keep the Alt-Svc in the connection info. Dropping
    // it could trigger an unintended proxy connection fallback.
    mTransaction->DoNotRemoveAltSvc();
  }
  mTransaction->Close(reason);
  mSession = nullptr;
  mClosed = true;
}

uint32_t Http2Stream::GetWireStreamId() {
  // >0 even numbered IDs are pushed streams.
  // odd numbered IDs are pulled streams.
  // 0 is the sink for a pushed stream.
  if (!mStreamID) {
    return 0;
  }

  if (mState == RESERVED_BY_REMOTE) {
    // h2-14 prevents sending a window update in this state
    return 0;
  }
  return mStreamID;
}

nsresult Http2Stream::OnWriteSegment(char* buf, uint32_t count,
                                     uint32_t* countWritten) {
  LOG3(("Http2Stream::OnWriteSegment %p count=%d state=%x 0x%X\n", this, count,
        mUpstreamState, mStreamID));

  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
  MOZ_ASSERT(mSegmentWriter);

  return Http2StreamBase::OnWriteSegment(buf, count, countWritten);
}

nsresult Http2Stream::CallToReadData(uint32_t count, uint32_t* countRead) {
  return mTransaction->ReadSegments(this, count, countRead);
}

nsresult Http2Stream::CallToWriteData(uint32_t count, uint32_t* countWritten) {
  return mTransaction->WriteSegments(this, count, countWritten);
}

// This is really a headers frame, but open is pretty clear from a workflow pov
nsresult Http2Stream::GenerateHeaders(nsCString& aCompressedData,
                                      uint8_t& firstFrameFlags) {
  nsHttpRequestHead* head = mTransaction->RequestHead();
  nsAutoCString requestURI;
  head->RequestURI(requestURI);
  RefPtr<Http2Session> session = Session();
  LOG3(("Http2Stream %p Stream ID 0x%X [session=%p] for URI %s\n", this,
        mStreamID, session.get(), requestURI.get()));

  nsAutoCString authorityHeader;
  nsresult rv = head->GetHeader(nsHttp::Host, authorityHeader);
  if (NS_FAILED(rv)) {
    MOZ_ASSERT(false);
    return rv;
  }

  nsDependentCString scheme(head->IsHTTPS() ? "https" : "http");

  nsAutoCString method;
  nsAutoCString path;
  head->Method(method);
  head->Path(path);

  bool mayAddTEHeader = true;
  nsAutoCString teHeader;
  rv = head->GetHeader(nsHttp::TE, teHeader);
  if (NS_SUCCEEDED(rv) && teHeader.Equals("moz_no_te_trailers"_ns)) {
    // This is a hack that allows extensions or devtools to
    // skip adding the TE header. This is necessary to be able to
    // ship interventions when websites misbehave when the TE:trailers
    // header is sent (see bug 1954533).
    mayAddTEHeader = false;
  }

  rv = session->Compressor()->EncodeHeaderBlock(
      mFlatHttpRequestHeaders, method, path, authorityHeader, scheme,
      EmptyCString(), false, aCompressedData, mayAddTEHeader);
  NS_ENSURE_SUCCESS(rv, rv);

  int64_t clVal = session->Compressor()->GetParsedContentLength();
  if (clVal != -1) {
    mRequestBodyLenRemaining = clVal;
  }

  // Determine whether to put the fin bit on the header frame or whether
  // to wait for a data packet to put it on.

  if (head->IsGet() || head->IsHead()) {
    // for GET and HEAD place the fin bit right on the
    // header packet
    firstFrameFlags |= Http2Session::kFlag_END_STREAM;
  } else if (head->IsPost() || head->IsPut() || head->IsConnect()) {
    // place fin in a data frame even for 0 length messages for iterop
  } else if (!mRequestBodyLenRemaining) {
    // for other HTTP extension methods, rely on the content-length
    // to determine whether or not to put fin on headers
    firstFrameFlags |= Http2Session::kFlag_END_STREAM;
  }

  return NS_OK;
}

}  // namespace mozilla::net