summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/http2/adapter/oghttp2_session.cc
blob: 2222fed4b6bb53fcef18142bce5c6040f00ca84d (plain)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include "http2/adapter/oghttp2_session.h"

#include "absl/strings/escaping.h"

namespace http2 {
namespace adapter {

void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockStart() {
  visitor_.OnBeginHeadersForStream(stream_id_);
}

void OgHttp2Session::PassthroughHeadersHandler::OnHeader(
    absl::string_view key,
    absl::string_view value) {
  visitor_.OnHeaderForStream(stream_id_, key, value);
}

void OgHttp2Session::PassthroughHeadersHandler::OnHeaderBlockEnd(
    size_t /* uncompressed_header_bytes */,
    size_t /* compressed_header_bytes */) {
  visitor_.OnEndHeadersForStream(stream_id_);
}

OgHttp2Session::OgHttp2Session(Http2VisitorInterface& visitor, Options options)
    : visitor_(visitor), headers_handler_(visitor), options_(options) {
  decoder_.set_visitor(this);
  if (options_.perspective == Perspective::kServer) {
    remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix,
                          spdy::kHttp2ConnectionHeaderPrefixSize};
  }
}

OgHttp2Session::~OgHttp2Session() {}

ssize_t OgHttp2Session::ProcessBytes(absl::string_view bytes) {
  ssize_t preface_consumed = 0;
  if (!remaining_preface_.empty()) {
    QUICHE_VLOG(2) << "Preface bytes remaining: " << remaining_preface_.size();
    // decoder_ does not understand the client connection preface.
    size_t min_size = std::min(remaining_preface_.size(), bytes.size());
    if (!absl::StartsWith(remaining_preface_, bytes.substr(0, min_size))) {
      // Preface doesn't match!
      QUICHE_DLOG(INFO) << "Preface doesn't match! Expected: ["
                        << absl::CEscape(remaining_preface_) << "], actual: ["
                        << absl::CEscape(bytes) << "]";
      visitor_.OnConnectionError();
      return -1;
    }
    remaining_preface_.remove_prefix(min_size);
    bytes.remove_prefix(min_size);
    if (!remaining_preface_.empty()) {
      QUICHE_VLOG(2) << "Preface bytes remaining: "
                     << remaining_preface_.size();
      return min_size;
    }
    preface_consumed = min_size;
  }
  ssize_t result = decoder_.ProcessInput(bytes.data(), bytes.size());
  return result < 0 ? result : result + preface_consumed;
}

int OgHttp2Session::Consume(Http2StreamId stream_id, size_t num_bytes) {
  auto it = stream_map_.find(stream_id);
  if (it == stream_map_.end()) {
    // TODO(b/181586191): LOG_ERROR rather than QUICHE_BUG.
    QUICHE_BUG(stream_consume_notfound)
        << "Stream " << stream_id << " not found";
  } else {
    it->second.window_manager.MarkDataFlushed(num_bytes);
  }
  return 0;  // Remove?
}

void OgHttp2Session::EnqueueFrame(std::unique_ptr<spdy::SpdyFrameIR> frame) {
  frames_.push_back(std::move(frame));
}

std::string OgHttp2Session::GetBytesToWrite(absl::optional<size_t> max_bytes) {
  const size_t serialized_max =
      max_bytes ? max_bytes.value() : std::numeric_limits<size_t>::max();
  std::string serialized = std::move(serialized_prefix_);
  while (serialized.size() < serialized_max && !frames_.empty()) {
    spdy::SpdySerializedFrame frame = framer_.SerializeFrame(*frames_.front());
    absl::StrAppend(&serialized, absl::string_view(frame));
    frames_.pop_front();
  }
  if (serialized.size() > serialized_max) {
    serialized_prefix_ = serialized.substr(serialized_max);
    serialized.resize(serialized_max);
  }
  return serialized;
}

void OgHttp2Session::OnError(http2::Http2DecoderAdapter::SpdyFramerError error,
                             std::string detailed_error) {
  QUICHE_VLOG(1) << "Error: "
                 << http2::Http2DecoderAdapter::SpdyFramerErrorToString(error)
                 << " details: " << detailed_error;
  visitor_.OnConnectionError();
}

void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id,
                                    size_t length,
                                    uint8_t type,
                                    uint8_t flags) {
  visitor_.OnFrameHeader(stream_id, length, type, flags);
}

void OgHttp2Session::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
                                       size_t length,
                                       bool fin) {
  visitor_.OnBeginDataForStream(stream_id, length);
}

void OgHttp2Session::OnStreamFrameData(spdy::SpdyStreamId stream_id,
                                       const char* data,
                                       size_t len) {
  visitor_.OnDataForStream(stream_id, absl::string_view(data, len));
}

void OgHttp2Session::OnStreamEnd(spdy::SpdyStreamId stream_id) {
  visitor_.OnEndStream(stream_id);
}

void OgHttp2Session::OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/,
                                       size_t /*value*/) {
  // TODO(181586191): handle padding
}

void OgHttp2Session::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) {
  // TODO(181586191): handle padding
}

spdy::SpdyHeadersHandlerInterface* OgHttp2Session::OnHeaderFrameStart(
    spdy::SpdyStreamId stream_id) {
  headers_handler_.set_stream_id(stream_id);
  return &headers_handler_;
}

void OgHttp2Session::OnHeaderFrameEnd(spdy::SpdyStreamId stream_id) {
  headers_handler_.set_stream_id(0);
}

void OgHttp2Session::OnRstStream(spdy::SpdyStreamId stream_id,
                                 spdy::SpdyErrorCode error_code) {
  visitor_.OnRstStream(stream_id, TranslateErrorCode(error_code));
  visitor_.OnCloseStream(stream_id, TranslateErrorCode(error_code));
}

void OgHttp2Session::OnSettings() {
  visitor_.OnSettingsStart();
}

void OgHttp2Session::OnSetting(spdy::SpdySettingsId id, uint32_t value) {
  visitor_.OnSetting({id, value});
}

void OgHttp2Session::OnSettingsEnd() {
  visitor_.OnSettingsEnd();
}

void OgHttp2Session::OnSettingsAck() {
  visitor_.OnSettingsAck();
}

void OgHttp2Session::OnPing(spdy::SpdyPingId unique_id, bool is_ack) {
  visitor_.OnPing(unique_id, is_ack);
}

void OgHttp2Session::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
                              spdy::SpdyErrorCode error_code) {
  received_goaway_ = true;
  visitor_.OnGoAway(last_accepted_stream_id, TranslateErrorCode(error_code),
                    "");
}

bool OgHttp2Session::OnGoAwayFrameData(const char* goaway_data, size_t len) {
  // Opaque data is currently ignored.
  return true;
}

void OgHttp2Session::OnHeaders(spdy::SpdyStreamId stream_id,
                               bool has_priority,
                               int weight,
                               spdy::SpdyStreamId parent_stream_id,
                               bool exclusive,
                               bool fin,
                               bool end) {}

void OgHttp2Session::OnWindowUpdate(spdy::SpdyStreamId stream_id,
                                    int delta_window_size) {
  if (stream_id == 0) {
    peer_window_ += delta_window_size;
  } else {
    auto it = stream_map_.find(stream_id);
    if (it == stream_map_.end()) {
      QUICHE_VLOG(1) << "Stream " << stream_id << " not found!";
    } else {
      it->second.send_window += delta_window_size;
    }
  }
  visitor_.OnWindowUpdate(stream_id, delta_window_size);
}

void OgHttp2Session::OnPushPromise(spdy::SpdyStreamId stream_id,
                                   spdy::SpdyStreamId promised_stream_id,
                                   bool end) {}

void OgHttp2Session::OnContinuation(spdy::SpdyStreamId stream_id, bool end) {}

void OgHttp2Session::OnAltSvc(spdy::SpdyStreamId /*stream_id*/,
                              absl::string_view /*origin*/,
                              const spdy::SpdyAltSvcWireFormat::
                                  AlternativeServiceVector& /*altsvc_vector*/) {
}

void OgHttp2Session::OnPriority(spdy::SpdyStreamId stream_id,
                                spdy::SpdyStreamId parent_stream_id,
                                int weight,
                                bool exclusive) {}

void OgHttp2Session::OnPriorityUpdate(spdy::SpdyStreamId prioritized_stream_id,
                                      absl::string_view priority_field_value) {}

bool OgHttp2Session::OnUnknownFrame(spdy::SpdyStreamId stream_id,
                                    uint8_t frame_type) {
  return true;
}

}  // namespace adapter
}  // namespace http2