blob: 701a4c53fc4e3131d56567af91ce6c890ca02f43 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
6
7#include <algorithm>
8#include <cstdint>
vasilvv872e7a32019-03-12 16:42:44 -07009#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include <utility>
11
12#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
13#include "net/third_party/quiche/src/quic/core/quic_utils.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
22#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h"
23
24using http2::Http2DecoderAdapter;
25using spdy::HpackEntry;
26using spdy::HpackHeaderTable;
27using spdy::Http2WeightToSpdy3Priority;
28using spdy::SETTINGS_ENABLE_PUSH;
29using spdy::SETTINGS_HEADER_TABLE_SIZE;
30using spdy::SETTINGS_MAX_HEADER_LIST_SIZE;
31using spdy::Spdy3PriorityToHttp2Weight;
32using spdy::SpdyErrorCode;
33using spdy::SpdyFramer;
34using spdy::SpdyFramerDebugVisitorInterface;
35using spdy::SpdyFramerVisitorInterface;
36using spdy::SpdyFrameType;
37using spdy::SpdyHeaderBlock;
38using spdy::SpdyHeadersHandlerInterface;
39using spdy::SpdyHeadersIR;
40using spdy::SpdyKnownSettingsId;
41using spdy::SpdyPingId;
42using spdy::SpdyPriority;
43using spdy::SpdyPriorityIR;
44using spdy::SpdyPushPromiseIR;
45using spdy::SpdySerializedFrame;
46using spdy::SpdySettingsId;
47using spdy::SpdySettingsIR;
48using spdy::SpdyStreamId;
49
50namespace quic {
51
52namespace {
53
renjietangbb1c4892019-05-24 15:58:44 -070054// TODO(renjietang): remove this once HTTP/3 error codes are adopted.
55const uint16_t kHttpUnknownStreamType = 0x0D;
56
QUICHE teama6ef0a62019-03-07 20:34:33 -050057class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
58 public:
59 HeaderTableDebugVisitor(const QuicClock* clock,
60 std::unique_ptr<QuicHpackDebugVisitor> visitor)
61 : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {}
62 HeaderTableDebugVisitor(const HeaderTableDebugVisitor&) = delete;
63 HeaderTableDebugVisitor& operator=(const HeaderTableDebugVisitor&) = delete;
64
65 int64_t OnNewEntry(const HpackEntry& entry) override {
66 QUIC_DVLOG(1) << entry.GetDebugString();
67 return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds();
68 }
69
70 void OnUseEntry(const HpackEntry& entry) override {
71 const QuicTime::Delta elapsed(
72 clock_->ApproximateNow() -
73 QuicTime::Delta::FromMicroseconds(entry.time_added()) -
74 QuicTime::Zero());
75 QUIC_DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
76 << " ms";
77 headers_stream_hpack_visitor_->OnUseEntry(elapsed);
78 }
79
80 private:
81 const QuicClock* clock_;
82 std::unique_ptr<QuicHpackDebugVisitor> headers_stream_hpack_visitor_;
83};
84
85} // namespace
86
87// A SpdyFramerVisitor that passes HEADERS frames to the QuicSpdyStream, and
88// closes the connection if any unexpected frames are received.
89class QuicSpdySession::SpdyFramerVisitor
90 : public SpdyFramerVisitorInterface,
91 public SpdyFramerDebugVisitorInterface {
92 public:
93 explicit SpdyFramerVisitor(QuicSpdySession* session) : session_(session) {}
94 SpdyFramerVisitor(const SpdyFramerVisitor&) = delete;
95 SpdyFramerVisitor& operator=(const SpdyFramerVisitor&) = delete;
96
97 SpdyHeadersHandlerInterface* OnHeaderFrameStart(
98 SpdyStreamId /* stream_id */) override {
99 return &header_list_;
100 }
101
102 void OnHeaderFrameEnd(SpdyStreamId /* stream_id */) override {
103 if (session_->IsConnected()) {
104 session_->OnHeaderList(header_list_);
105 }
106 header_list_.Clear();
107 }
108
dschinazi17d42422019-06-18 16:35:07 -0700109 void OnStreamFrameData(SpdyStreamId /*stream_id*/,
110 const char* /*data*/,
111 size_t /*len*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 CloseConnection("SPDY DATA frame received.",
113 QUIC_INVALID_HEADERS_STREAM_DATA);
114 }
115
dschinazi17d42422019-06-18 16:35:07 -0700116 void OnStreamEnd(SpdyStreamId /*stream_id*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 // The framer invokes OnStreamEnd after processing a frame that had the fin
118 // bit set.
119 }
120
dschinazi17d42422019-06-18 16:35:07 -0700121 void OnStreamPadding(SpdyStreamId /*stream_id*/, size_t /*len*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 CloseConnection("SPDY frame padding received.",
123 QUIC_INVALID_HEADERS_STREAM_DATA);
124 }
125
126 void OnError(Http2DecoderAdapter::SpdyFramerError error) override {
127 QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
128 switch (error) {
129 case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
130 code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
131 break;
132 default:
133 break;
134 }
135 CloseConnection(
136 QuicStrCat("SPDY framing error: ",
137 Http2DecoderAdapter::SpdyFramerErrorToString(error)),
138 code);
139 }
140
dschinazi17d42422019-06-18 16:35:07 -0700141 void OnDataFrameHeader(SpdyStreamId /*stream_id*/,
142 size_t /*length*/,
143 bool /*fin*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500144 CloseConnection("SPDY DATA frame received.",
145 QUIC_INVALID_HEADERS_STREAM_DATA);
146 }
147
dschinazi17d42422019-06-18 16:35:07 -0700148 void OnRstStream(SpdyStreamId /*stream_id*/,
149 SpdyErrorCode /*error_code*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500150 CloseConnection("SPDY RST_STREAM frame received.",
151 QUIC_INVALID_HEADERS_STREAM_DATA);
152 }
153
154 void OnSetting(SpdySettingsId id, uint32_t value) override {
155 switch (id) {
156 case SETTINGS_HEADER_TABLE_SIZE:
157 session_->UpdateHeaderEncoderTableSize(value);
158 break;
159 case SETTINGS_ENABLE_PUSH:
160 if (session_->perspective() == Perspective::IS_SERVER) {
161 // See rfc7540, Section 6.5.2.
162 if (value > 1) {
163 CloseConnection(
164 QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
165 QUIC_INVALID_HEADERS_STREAM_DATA);
166 return;
167 }
168 session_->UpdateEnableServerPush(value > 0);
169 break;
170 } else {
171 CloseConnection(
172 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
173 QUIC_INVALID_HEADERS_STREAM_DATA);
174 }
175 break;
176 // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
177 // clients are actually sending it.
178 case SETTINGS_MAX_HEADER_LIST_SIZE:
179 break;
180 default:
181 CloseConnection(
182 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
183 QUIC_INVALID_HEADERS_STREAM_DATA);
184 }
185 }
186
187 void OnSettingsEnd() override {}
188
dschinazi17d42422019-06-18 16:35:07 -0700189 void OnPing(SpdyPingId /*unique_id*/, bool /*is_ack*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500190 CloseConnection("SPDY PING frame received.",
191 QUIC_INVALID_HEADERS_STREAM_DATA);
192 }
193
dschinazi17d42422019-06-18 16:35:07 -0700194 void OnGoAway(SpdyStreamId /*last_accepted_stream_id*/,
195 SpdyErrorCode /*error_code*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500196 CloseConnection("SPDY GOAWAY frame received.",
197 QUIC_INVALID_HEADERS_STREAM_DATA);
198 }
199
200 void OnHeaders(SpdyStreamId stream_id,
201 bool has_priority,
202 int weight,
203 SpdyStreamId /*parent_stream_id*/,
204 bool /*exclusive*/,
205 bool fin,
dschinazi17d42422019-06-18 16:35:07 -0700206 bool /*end*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500207 if (!session_->IsConnected()) {
208 return;
209 }
210
renjietang2abedac2019-05-20 14:04:50 -0700211 if (VersionUsesQpack(session_->connection()->transport_version())) {
212 CloseConnection("HEADERS frame not allowed on headers stream.",
213 QUIC_INVALID_HEADERS_STREAM_DATA);
214 return;
215 }
216
QUICHE teama6ef0a62019-03-07 20:34:33 -0500217 // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
218 // QuicHeadersStream.
219 SpdyPriority priority =
220 has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
221 session_->OnHeaders(stream_id, has_priority, priority, fin);
222 }
223
dschinazi17d42422019-06-18 16:35:07 -0700224 void OnWindowUpdate(SpdyStreamId /*stream_id*/,
225 int /*delta_window_size*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500226 CloseConnection("SPDY WINDOW_UPDATE frame received.",
227 QUIC_INVALID_HEADERS_STREAM_DATA);
228 }
229
230 void OnPushPromise(SpdyStreamId stream_id,
231 SpdyStreamId promised_stream_id,
dschinazi17d42422019-06-18 16:35:07 -0700232 bool /*end*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 if (!session_->supports_push_promise()) {
234 CloseConnection("PUSH_PROMISE not supported.",
235 QUIC_INVALID_HEADERS_STREAM_DATA);
236 return;
237 }
238 if (!session_->IsConnected()) {
239 return;
240 }
renjietangcd8fab32019-06-17 16:22:16 -0700241 session_->OnPushPromise(stream_id, promised_stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500242 }
243
dschinazi17d42422019-06-18 16:35:07 -0700244 void OnContinuation(SpdyStreamId /*stream_id*/, bool /*end*/) override {}
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245
246 void OnPriority(SpdyStreamId stream_id,
dschinazi17d42422019-06-18 16:35:07 -0700247 SpdyStreamId /*parent_id*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248 int weight,
dschinazi17d42422019-06-18 16:35:07 -0700249 bool /*exclusive*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500250 if (session_->connection()->transport_version() <= QUIC_VERSION_39) {
251 CloseConnection("SPDY PRIORITY frame received.",
252 QUIC_INVALID_HEADERS_STREAM_DATA);
253 return;
254 }
255 if (!session_->IsConnected()) {
256 return;
257 }
258 // TODO (wangyix): implement real HTTP/2 weights and dependencies instead of
259 // converting to SpdyPriority.
260 SpdyPriority priority = Http2WeightToSpdy3Priority(weight);
261 session_->OnPriority(stream_id, priority);
262 }
263
dschinazi17d42422019-06-18 16:35:07 -0700264 bool OnUnknownFrame(SpdyStreamId /*stream_id*/,
265 uint8_t /*frame_type*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500266 CloseConnection("Unknown frame type received.",
267 QUIC_INVALID_HEADERS_STREAM_DATA);
268 return false;
269 }
270
271 // SpdyFramerDebugVisitorInterface implementation
dschinazi17d42422019-06-18 16:35:07 -0700272 void OnSendCompressedFrame(SpdyStreamId /*stream_id*/,
273 SpdyFrameType /*type*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500274 size_t payload_len,
275 size_t frame_len) override {
276 if (payload_len == 0) {
277 QUIC_BUG << "Zero payload length.";
278 return;
279 }
280 int compression_pct = 100 - (100 * frame_len) / payload_len;
281 QUIC_DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
282 }
283
dschinazi17d42422019-06-18 16:35:07 -0700284 void OnReceiveCompressedFrame(SpdyStreamId /*stream_id*/,
285 SpdyFrameType /*type*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500286 size_t frame_len) override {
287 if (session_->IsConnected()) {
288 session_->OnCompressedFrameSize(frame_len);
289 }
290 }
291
dschinazi82875de2019-07-09 17:14:25 -0700292 void set_max_uncompressed_header_bytes(
293 size_t set_max_uncompressed_header_bytes) {
294 header_list_.set_max_header_list_size(set_max_uncompressed_header_bytes);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295 }
296
297 private:
vasilvvc48c8712019-03-11 13:38:16 -0700298 void CloseConnection(const std::string& details, QuicErrorCode code) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500299 if (session_->IsConnected()) {
300 session_->CloseConnectionWithDetails(code, details);
301 }
302 }
303
304 private:
305 QuicSpdySession* session_;
306 QuicHeaderList header_list_;
307};
308
309QuicHpackDebugVisitor::QuicHpackDebugVisitor() {}
310
311QuicHpackDebugVisitor::~QuicHpackDebugVisitor() {}
312
313QuicSpdySession::QuicSpdySession(
314 QuicConnection* connection,
315 QuicSession::Visitor* visitor,
316 const QuicConfig& config,
317 const ParsedQuicVersionVector& supported_versions)
318 : QuicSession(connection, visitor, config, supported_versions),
319 max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
renjietang3a1bb802019-06-11 10:42:41 -0700320 max_outbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500321 server_push_enabled_(true),
322 stream_id_(
323 QuicUtils::GetInvalidStreamId(connection->transport_version())),
324 promised_stream_id_(
325 QuicUtils::GetInvalidStreamId(connection->transport_version())),
326 fin_(false),
327 frame_len_(0),
328 uncompressed_frame_len_(0),
329 supports_push_promise_(perspective() == Perspective::IS_CLIENT),
330 spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
331 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
332 h2_deframer_.set_visitor(spdy_framer_visitor_.get());
333 h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
334 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
335}
336
337QuicSpdySession::~QuicSpdySession() {
338 // Set the streams' session pointers in closed and dynamic stream lists
339 // to null to avoid subsequent use of this session.
340 for (auto& stream : *closed_streams()) {
341 static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
342 }
343 for (auto const& kv : zombie_streams()) {
344 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
345 }
346 for (auto const& kv : dynamic_streams()) {
renjietangb663b862019-07-08 16:02:39 -0700347 if (!kv.second->is_static()) {
348 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
renjietang2da2afb2019-05-13 17:22:14 -0700349 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 }
351}
352
353void QuicSpdySession::Initialize() {
354 QuicSession::Initialize();
355
dschinazi552accc2019-06-17 17:07:34 -0700356 if (!connection()->version().DoesNotHaveHeadersStream()) {
357 if (perspective() == Perspective::IS_SERVER) {
358 set_largest_peer_created_stream_id(
359 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
360 } else {
361 QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
362 DCHECK_EQ(headers_stream_id, QuicUtils::GetHeadersStreamId(
363 connection()->transport_version()));
364 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365 }
366
367 if (VersionUsesQpack(connection()->transport_version())) {
renjietangc2aa5cb2019-06-20 12:22:53 -0700368 qpack_encoder_ =
369 QuicMakeUnique<QpackEncoder>(this, &encoder_stream_sender_delegate_);
370 qpack_decoder_ =
371 QuicMakeUnique<QpackDecoder>(this, &decoder_stream_sender_delegate_);
bncbdd303e2019-07-09 05:33:17 -0700372 // TODO(b/112770235): Send SETTINGS_QPACK_MAX_TABLE_CAPACITY with value
373 // kDefaultQpackMaxDynamicTableCapacity.
374 qpack_decoder_->SetMaximumDynamicTableCapacity(
375 kDefaultQpackMaxDynamicTableCapacity);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500376 }
377
378 headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
379 DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
380 headers_stream_->id());
renjietang3a1bb802019-06-11 10:42:41 -0700381
renjietangb663b862019-07-08 16:02:39 -0700382 unowned_headers_stream_ = headers_stream_.get();
renjietang0e9980b2019-07-11 12:00:21 -0700383 RegisterStaticStream(std::move(headers_stream_),
384 /*stream_already_counted = */ false);
renjietangb663b862019-07-08 16:02:39 -0700385
386 if (VersionHasStreamType(connection()->transport_version())) {
renjietang3a1bb802019-06-11 10:42:41 -0700387 auto send_control = QuicMakeUnique<QuicSendControlStream>(
renjietang7498c8c2019-07-02 19:28:42 -0700388 GetNextOutgoingUnidirectionalStreamId(), this,
389 max_inbound_header_list_size_);
renjietang3a1bb802019-06-11 10:42:41 -0700390 send_control_stream_ = send_control.get();
renjietang0e9980b2019-07-11 12:00:21 -0700391 RegisterStaticStream(std::move(send_control),
392 /*stream_already_counted = */ false);
renjietangfbeb5bf2019-04-19 15:06:20 -0700393 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394
dschinazi82875de2019-07-09 17:14:25 -0700395 set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500396
397 // Limit HPACK buffering to 2x header list size limit.
dschinazi82875de2019-07-09 17:14:25 -0700398 set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399}
400
dschinazi17d42422019-06-18 16:35:07 -0700401void QuicSpdySession::OnDecoderStreamError(QuicStringPiece /*error_message*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500402 DCHECK(VersionUsesQpack(connection()->transport_version()));
403
404 // TODO(112770235): Signal connection error on decoder stream errors.
405 QUIC_NOTREACHED();
406}
407
dschinazi17d42422019-06-18 16:35:07 -0700408void QuicSpdySession::OnEncoderStreamError(QuicStringPiece /*error_message*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500409 DCHECK(VersionUsesQpack(connection()->transport_version()));
410
411 // TODO(112770235): Signal connection error on encoder stream errors.
412 QUIC_NOTREACHED();
413}
414
QUICHE teama6ef0a62019-03-07 20:34:33 -0500415void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
416 SpdyPriority priority) {
417 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
418 if (!stream) {
419 // It's quite possible to receive headers after a stream has been reset.
420 return;
421 }
422 stream->OnStreamHeadersPriority(priority);
423}
424
425void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
426 bool fin,
427 size_t frame_len,
428 const QuicHeaderList& header_list) {
rchda26cdb2019-05-17 11:57:37 -0700429 if (IsStaticStream(stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500430 connection()->CloseConnection(
431 QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static",
432 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
433 return;
434 }
435 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
436 if (stream == nullptr) {
437 // The stream no longer exists, but trailing headers may contain the final
438 // byte offset necessary for flow control and open stream accounting.
439 size_t final_byte_offset = 0;
440 for (const auto& header : header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700441 const std::string& header_key = header.first;
442 const std::string& header_value = header.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500443 if (header_key == kFinalOffsetHeaderKey) {
444 if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
445 connection()->CloseConnection(
446 QUIC_INVALID_HEADERS_STREAM_DATA,
447 "Trailers are malformed (no final offset)",
448 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
449 return;
450 }
bnc5de87052019-05-03 14:21:53 -0700451 QUIC_DVLOG(1) << "Received final byte offset in trailers for stream "
452 << stream_id << ", which no longer exists.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
454 }
455 }
456
457 // It's quite possible to receive headers after a stream has been reset.
458 return;
459 }
460 stream->OnStreamHeaderList(fin, frame_len, header_list);
461}
462
463void QuicSpdySession::OnPriorityFrame(QuicStreamId stream_id,
464 SpdyPriority priority) {
465 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
466 if (!stream) {
467 // It's quite possible to receive a PRIORITY frame after a stream has been
468 // reset.
469 return;
470 }
471 stream->OnPriorityFrame(priority);
472}
473
474size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
475 return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
476 iov.iov_len);
477}
478
479size_t QuicSpdySession::WriteHeadersOnHeadersStream(
480 QuicStreamId id,
481 SpdyHeaderBlock headers,
482 bool fin,
483 SpdyPriority priority,
484 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700485 DCHECK(!VersionUsesQpack(connection()->transport_version()));
486
QUICHE teama6ef0a62019-03-07 20:34:33 -0500487 return WriteHeadersOnHeadersStreamImpl(
488 id, std::move(headers), fin,
489 /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
490 /* exclusive = */ false, std::move(ack_listener));
491}
492
493size_t QuicSpdySession::WritePriority(QuicStreamId id,
494 QuicStreamId parent_stream_id,
495 int weight,
496 bool exclusive) {
497 if (connection()->transport_version() <= QUIC_VERSION_39) {
498 return 0;
499 }
500 SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
501 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700502 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500503 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
504 return frame.size();
505}
506
renjietang7498c8c2019-07-02 19:28:42 -0700507void QuicSpdySession::WriteH3Priority(const PriorityFrame& priority) {
508 DCHECK(VersionHasStreamType(connection()->transport_version()));
509 DCHECK(perspective() == Perspective::IS_CLIENT)
510 << "Server must not send priority";
511
512 send_control_stream_->WritePriority(priority);
513}
514
QUICHE teama6ef0a62019-03-07 20:34:33 -0500515size_t QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
516 QuicStreamId promised_stream_id,
517 SpdyHeaderBlock headers) {
518 if (perspective() == Perspective::IS_CLIENT) {
519 QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
520 return 0;
521 }
522
523 SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
524 std::move(headers));
525 // PUSH_PROMISE must not be the last frame sent out, at least followed by
526 // response headers.
527 push_promise.set_fin(false);
528
529 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
renjietangfbeb5bf2019-04-19 15:06:20 -0700530 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500531 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
532 return frame.size();
533}
534
QUICHE team2252b702019-05-14 23:55:14 -0400535void QuicSpdySession::SendMaxHeaderListSize(size_t value) {
renjietang3a1bb802019-06-11 10:42:41 -0700536 if (VersionHasStreamType(connection()->transport_version())) {
renjietang7498c8c2019-07-02 19:28:42 -0700537 send_control_stream_->SendSettingsFrame();
renjietang3a1bb802019-06-11 10:42:41 -0700538 return;
539 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500540 SpdySettingsIR settings_frame;
541 settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
542
543 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700544 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500545 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500546}
547
548QpackEncoder* QuicSpdySession::qpack_encoder() {
549 DCHECK(VersionUsesQpack(connection()->transport_version()));
550
551 return qpack_encoder_.get();
552}
553
554QpackDecoder* QuicSpdySession::qpack_decoder() {
555 DCHECK(VersionUsesQpack(connection()->transport_version()));
556
557 return qpack_decoder_.get();
558}
559
560QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
561 const QuicStreamId stream_id) {
rchda26cdb2019-05-17 11:57:37 -0700562 QuicStream* stream = GetOrCreateDynamicStream(stream_id);
renjietang495d5972019-07-10 14:51:28 -0700563 if (GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream) && stream &&
564 stream->is_static()) {
565 QUIC_RELOADABLE_FLAG_COUNT(quic_handle_staticness_for_spdy_stream);
566 QUIC_BUG << "GetSpdyDataStream returns static stream";
567 connection()->CloseConnection(
568 QUIC_INVALID_STREAM_ID, "stream is static",
569 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
570 return nullptr;
571 }
rchda26cdb2019-05-17 11:57:37 -0700572 DCHECK(!stream || !stream->is_static());
573 return static_cast<QuicSpdyStream*>(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500574}
575
576void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
577 QuicSession::OnCryptoHandshakeEvent(event);
578 if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
579 SendMaxHeaderListSize(max_inbound_header_list_size_);
580 }
581}
582
583// True if there are open HTTP requests.
584bool QuicSpdySession::ShouldKeepConnectionAlive() const {
585 // Change to check if there are open HTTP requests.
586 // When IETF QUIC control and QPACK streams are used, those will need to be
587 // subtracted from this count to ensure only request streams are counted.
588 return GetNumOpenDynamicStreams() > 0;
589}
590
renjietange76b2da2019-05-13 14:50:23 -0700591bool QuicSpdySession::UsesPendingStreams() const {
bnc36c47282019-06-21 05:17:59 -0700592 // QuicSpdySession supports PendingStreams, therefore this method should
593 // eventually just return true. However, pending streams can only be used if
594 // unidirectional stream type is supported.
595 return VersionHasStreamType(connection()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500596}
597
598size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
599 QuicStreamId id,
600 spdy::SpdyHeaderBlock headers,
601 bool fin,
602 QuicStreamId parent_stream_id,
603 int weight,
604 bool exclusive,
605 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700606 DCHECK(!VersionUsesQpack(connection()->transport_version()));
607
QUICHE teama6ef0a62019-03-07 20:34:33 -0500608 SpdyHeadersIR headers_frame(id, std::move(headers));
609 headers_frame.set_fin(fin);
610 if (perspective() == Perspective::IS_CLIENT) {
611 headers_frame.set_has_priority(true);
612 headers_frame.set_parent_stream_id(parent_stream_id);
613 headers_frame.set_weight(weight);
614 headers_frame.set_exclusive(exclusive);
615 }
616 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700617 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500618 QuicStringPiece(frame.data(), frame.size()), false,
619 std::move(ack_listener));
620 return frame.size();
621}
622
dschinazi17d42422019-06-18 16:35:07 -0700623void QuicSpdySession::OnPromiseHeaderList(
624 QuicStreamId /*stream_id*/,
625 QuicStreamId /*promised_stream_id*/,
626 size_t /*frame_len*/,
627 const QuicHeaderList& /*header_list*/) {
vasilvvc48c8712019-03-11 13:38:16 -0700628 std::string error =
629 "OnPromiseHeaderList should be overridden in client code.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500630 QUIC_BUG << error;
631 connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
632 ConnectionCloseBehavior::SILENT_CLOSE);
633}
634
635bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
636 return false;
637}
638
639void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
640 bool has_priority,
641 SpdyPriority priority,
642 bool fin) {
643 if (has_priority) {
644 if (perspective() == Perspective::IS_CLIENT) {
645 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
646 "Server must not send priorities.");
647 return;
648 }
649 OnStreamHeadersPriority(stream_id, priority);
650 } else {
651 if (perspective() == Perspective::IS_SERVER) {
652 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
653 "Client must send priorities.");
654 return;
655 }
656 }
657 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
658 stream_id_);
659 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
660 promised_stream_id_);
661 stream_id_ = stream_id;
662 fin_ = fin;
663}
664
665void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
renjietangcd8fab32019-06-17 16:22:16 -0700666 SpdyStreamId promised_stream_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500667 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
668 stream_id_);
669 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
670 promised_stream_id_);
671 stream_id_ = stream_id;
672 promised_stream_id_ = promised_stream_id;
673}
674
675// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
676// This occurs in many places in this file.
677void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
678 SpdyPriority priority) {
679 if (perspective() == Perspective::IS_CLIENT) {
680 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
681 "Server must not send PRIORITY frames.");
682 return;
683 }
684 OnPriorityFrame(stream_id, priority);
685}
686
687void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
688 QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
689 << header_list.DebugString();
690 if (promised_stream_id_ ==
691 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
692 OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
693 } else {
694 OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
695 header_list);
696 }
697 // Reset state for the next frame.
698 promised_stream_id_ =
699 QuicUtils::GetInvalidStreamId(connection()->transport_version());
700 stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
701 fin_ = false;
702 frame_len_ = 0;
703 uncompressed_frame_len_ = 0;
704}
705
706void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
707 frame_len_ += frame_len;
708}
709
710void QuicSpdySession::SetHpackEncoderDebugVisitor(
711 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
712 spdy_framer_.SetEncoderHeaderTableDebugVisitor(
713 std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
714 connection()->helper()->GetClock(), std::move(visitor))));
715}
716
717void QuicSpdySession::SetHpackDecoderDebugVisitor(
718 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
719 h2_deframer_.SetDecoderHeaderTableDebugVisitor(
720 QuicMakeUnique<HeaderTableDebugVisitor>(
721 connection()->helper()->GetClock(), std::move(visitor)));
722}
723
724void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
725 spdy_framer_.UpdateHeaderEncoderTableSize(value);
726}
727
728void QuicSpdySession::UpdateEnableServerPush(bool value) {
729 set_server_push_enabled(value);
730}
731
dschinazi82875de2019-07-09 17:14:25 -0700732void QuicSpdySession::set_max_uncompressed_header_bytes(
733 size_t set_max_uncompressed_header_bytes) {
734 spdy_framer_visitor_->set_max_uncompressed_header_bytes(
735 set_max_uncompressed_header_bytes);
736}
737
QUICHE teama6ef0a62019-03-07 20:34:33 -0500738void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700739 const std::string& details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500740 connection()->CloseConnection(
741 error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
742}
743
QUICHE teamc2653c42019-03-08 13:30:06 -0800744bool QuicSpdySession::HasActiveRequestStreams() const {
renjietangfbeb5bf2019-04-19 15:06:20 -0700745 // In the case where session is destructed by calling
746 // dynamic_streams().clear(), we will have incorrect accounting here.
747 // TODO(renjietang): Modify destructors and make this a DCHECK.
renjietangfbeb5bf2019-04-19 15:06:20 -0700748 if (static_cast<size_t>(dynamic_streams().size()) >
749 num_incoming_static_streams() + num_outgoing_static_streams()) {
750 return dynamic_streams().size() - num_incoming_static_streams() -
751 num_outgoing_static_streams() >
752 0;
753 }
754 return false;
QUICHE teamc2653c42019-03-08 13:30:06 -0800755}
756
renjietangbb1c4892019-05-24 15:58:44 -0700757bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
758 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietanga553da02019-06-24 11:57:04 -0700759 DCHECK(connection()->connected());
renjietang0c558862019-05-08 13:26:23 -0700760 struct iovec iov;
761 if (!pending->sequencer()->GetReadableRegion(&iov)) {
renjietangbb1c4892019-05-24 15:58:44 -0700762 // The first byte hasn't been received yet.
763 return false;
renjietang0c558862019-05-08 13:26:23 -0700764 }
765
766 QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len);
renjietangbb1c4892019-05-24 15:58:44 -0700767 uint8_t stream_type_length = reader.PeekVarInt62Length();
renjietang0c558862019-05-08 13:26:23 -0700768 uint64_t stream_type = 0;
769 if (!reader.ReadVarInt62(&stream_type)) {
renjietangbb1c4892019-05-24 15:58:44 -0700770 return false;
renjietang0c558862019-05-08 13:26:23 -0700771 }
renjietangbb1c4892019-05-24 15:58:44 -0700772 pending->MarkConsumed(stream_type_length);
renjietang0c558862019-05-08 13:26:23 -0700773
renjietang0c558862019-05-08 13:26:23 -0700774 switch (stream_type) {
renjietang3a1bb802019-06-11 10:42:41 -0700775 case kControlStream: { // HTTP/3 control stream.
776 auto receive_stream = QuicMakeUnique<QuicReceiveControlStream>(pending);
777 receive_control_stream_ = receive_stream.get();
renjietang0e9980b2019-07-11 12:00:21 -0700778 RegisterStaticStream(std::move(receive_stream),
779 /*stream_already_counted = */ true);
renjietang3a1bb802019-06-11 10:42:41 -0700780 receive_control_stream_->SetUnblocked();
781 return true;
782 }
renjietangbb1c4892019-05-24 15:58:44 -0700783 case kServerPushStream: { // Push Stream.
renjietangbaea59c2019-05-29 15:08:14 -0700784 QuicSpdyStream* stream = CreateIncomingStream(pending);
renjietangbb1c4892019-05-24 15:58:44 -0700785 stream->SetUnblocked();
786 return true;
787 }
788 case kQpackEncoderStream: // QPACK encoder stream.
renjietang0c558862019-05-08 13:26:23 -0700789 // TODO(bnc): Create QPACK encoder stream.
790 break;
renjietangbb1c4892019-05-24 15:58:44 -0700791 case kQpackDecoderStream: // QPACK decoder stream.
renjietang0c558862019-05-08 13:26:23 -0700792 // TODO(bnc): Create QPACK decoder stream.
793 break;
794 default:
renjietangbb1c4892019-05-24 15:58:44 -0700795 SendStopSending(kHttpUnknownStreamType, pending->id());
renjietang0c558862019-05-08 13:26:23 -0700796 }
renjietangbb1c4892019-05-24 15:58:44 -0700797 return false;
renjietang0c558862019-05-08 13:26:23 -0700798}
799
QUICHE teama6ef0a62019-03-07 20:34:33 -0500800} // namespace quic