blob: b9006ca82056f1ff7a0af3f25c43f89ffdee7ab4 [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
109 void OnStreamFrameData(SpdyStreamId stream_id,
110 const char* data,
111 size_t len) override {
112 CloseConnection("SPDY DATA frame received.",
113 QUIC_INVALID_HEADERS_STREAM_DATA);
114 }
115
116 void OnStreamEnd(SpdyStreamId stream_id) override {
117 // The framer invokes OnStreamEnd after processing a frame that had the fin
118 // bit set.
119 }
120
121 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
122 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
141 void OnDataFrameHeader(SpdyStreamId stream_id,
142 size_t length,
143 bool fin) override {
144 CloseConnection("SPDY DATA frame received.",
145 QUIC_INVALID_HEADERS_STREAM_DATA);
146 }
147
148 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {
149 CloseConnection("SPDY RST_STREAM frame received.",
150 QUIC_INVALID_HEADERS_STREAM_DATA);
151 }
152
153 void OnSetting(SpdySettingsId id, uint32_t value) override {
154 switch (id) {
155 case SETTINGS_HEADER_TABLE_SIZE:
156 session_->UpdateHeaderEncoderTableSize(value);
157 break;
158 case SETTINGS_ENABLE_PUSH:
159 if (session_->perspective() == Perspective::IS_SERVER) {
160 // See rfc7540, Section 6.5.2.
161 if (value > 1) {
162 CloseConnection(
163 QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
164 QUIC_INVALID_HEADERS_STREAM_DATA);
165 return;
166 }
167 session_->UpdateEnableServerPush(value > 0);
168 break;
169 } else {
170 CloseConnection(
171 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
172 QUIC_INVALID_HEADERS_STREAM_DATA);
173 }
174 break;
175 // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
176 // clients are actually sending it.
177 case SETTINGS_MAX_HEADER_LIST_SIZE:
178 break;
179 default:
180 CloseConnection(
181 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
182 QUIC_INVALID_HEADERS_STREAM_DATA);
183 }
184 }
185
186 void OnSettingsEnd() override {}
187
188 void OnPing(SpdyPingId unique_id, bool is_ack) override {
189 CloseConnection("SPDY PING frame received.",
190 QUIC_INVALID_HEADERS_STREAM_DATA);
191 }
192
193 void OnGoAway(SpdyStreamId last_accepted_stream_id,
194 SpdyErrorCode error_code) override {
195 CloseConnection("SPDY GOAWAY frame received.",
196 QUIC_INVALID_HEADERS_STREAM_DATA);
197 }
198
199 void OnHeaders(SpdyStreamId stream_id,
200 bool has_priority,
201 int weight,
202 SpdyStreamId /*parent_stream_id*/,
203 bool /*exclusive*/,
204 bool fin,
205 bool end) override {
206 if (!session_->IsConnected()) {
207 return;
208 }
209
renjietang2abedac2019-05-20 14:04:50 -0700210 if (VersionUsesQpack(session_->connection()->transport_version())) {
211 CloseConnection("HEADERS frame not allowed on headers stream.",
212 QUIC_INVALID_HEADERS_STREAM_DATA);
213 return;
214 }
215
QUICHE teama6ef0a62019-03-07 20:34:33 -0500216 // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
217 // QuicHeadersStream.
218 SpdyPriority priority =
219 has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
220 session_->OnHeaders(stream_id, has_priority, priority, fin);
221 }
222
223 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
224 CloseConnection("SPDY WINDOW_UPDATE frame received.",
225 QUIC_INVALID_HEADERS_STREAM_DATA);
226 }
227
228 void OnPushPromise(SpdyStreamId stream_id,
229 SpdyStreamId promised_stream_id,
230 bool end) override {
231 if (!session_->supports_push_promise()) {
232 CloseConnection("PUSH_PROMISE not supported.",
233 QUIC_INVALID_HEADERS_STREAM_DATA);
234 return;
235 }
236 if (!session_->IsConnected()) {
237 return;
238 }
renjietangcd8fab32019-06-17 16:22:16 -0700239 session_->OnPushPromise(stream_id, promised_stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500240 }
241
242 void OnContinuation(SpdyStreamId stream_id, bool end) override {}
243
244 void OnPriority(SpdyStreamId stream_id,
245 SpdyStreamId parent_id,
246 int weight,
247 bool exclusive) override {
248 if (session_->connection()->transport_version() <= QUIC_VERSION_39) {
249 CloseConnection("SPDY PRIORITY frame received.",
250 QUIC_INVALID_HEADERS_STREAM_DATA);
251 return;
252 }
253 if (!session_->IsConnected()) {
254 return;
255 }
256 // TODO (wangyix): implement real HTTP/2 weights and dependencies instead of
257 // converting to SpdyPriority.
258 SpdyPriority priority = Http2WeightToSpdy3Priority(weight);
259 session_->OnPriority(stream_id, priority);
260 }
261
262 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override {
263 CloseConnection("Unknown frame type received.",
264 QUIC_INVALID_HEADERS_STREAM_DATA);
265 return false;
266 }
267
268 // SpdyFramerDebugVisitorInterface implementation
269 void OnSendCompressedFrame(SpdyStreamId stream_id,
270 SpdyFrameType type,
271 size_t payload_len,
272 size_t frame_len) override {
273 if (payload_len == 0) {
274 QUIC_BUG << "Zero payload length.";
275 return;
276 }
277 int compression_pct = 100 - (100 * frame_len) / payload_len;
278 QUIC_DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
279 }
280
281 void OnReceiveCompressedFrame(SpdyStreamId stream_id,
282 SpdyFrameType type,
283 size_t frame_len) override {
284 if (session_->IsConnected()) {
285 session_->OnCompressedFrameSize(frame_len);
286 }
287 }
288
289 void set_max_uncompressed_header_bytes(
290 size_t set_max_uncompressed_header_bytes) {
291 header_list_.set_max_header_list_size(set_max_uncompressed_header_bytes);
292 }
293
294 private:
vasilvvc48c8712019-03-11 13:38:16 -0700295 void CloseConnection(const std::string& details, QuicErrorCode code) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296 if (session_->IsConnected()) {
297 session_->CloseConnectionWithDetails(code, details);
298 }
299 }
300
301 private:
302 QuicSpdySession* session_;
303 QuicHeaderList header_list_;
304};
305
306QuicHpackDebugVisitor::QuicHpackDebugVisitor() {}
307
308QuicHpackDebugVisitor::~QuicHpackDebugVisitor() {}
309
310QuicSpdySession::QuicSpdySession(
311 QuicConnection* connection,
312 QuicSession::Visitor* visitor,
313 const QuicConfig& config,
314 const ParsedQuicVersionVector& supported_versions)
315 : QuicSession(connection, visitor, config, supported_versions),
316 max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
renjietang3a1bb802019-06-11 10:42:41 -0700317 max_outbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500318 server_push_enabled_(true),
319 stream_id_(
320 QuicUtils::GetInvalidStreamId(connection->transport_version())),
321 promised_stream_id_(
322 QuicUtils::GetInvalidStreamId(connection->transport_version())),
323 fin_(false),
324 frame_len_(0),
325 uncompressed_frame_len_(0),
326 supports_push_promise_(perspective() == Perspective::IS_CLIENT),
327 spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
328 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
329 h2_deframer_.set_visitor(spdy_framer_visitor_.get());
330 h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
331 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
332}
333
334QuicSpdySession::~QuicSpdySession() {
335 // Set the streams' session pointers in closed and dynamic stream lists
336 // to null to avoid subsequent use of this session.
337 for (auto& stream : *closed_streams()) {
338 static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
339 }
340 for (auto const& kv : zombie_streams()) {
341 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
342 }
343 for (auto const& kv : dynamic_streams()) {
renjietang2da2afb2019-05-13 17:22:14 -0700344 if (eliminate_static_stream_map() && kv.second->is_static()) {
345 continue;
346 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500347 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
348 }
349}
350
351void QuicSpdySession::Initialize() {
352 QuicSession::Initialize();
353
354 if (perspective() == Perspective::IS_SERVER) {
355 set_largest_peer_created_stream_id(
356 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
357 } else {
358 QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
359 DCHECK_EQ(headers_stream_id,
360 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
361 }
362
363 if (VersionUsesQpack(connection()->transport_version())) {
364 qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this);
365 qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this);
366 }
367
368 headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
369 DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
370 headers_stream_->id());
renjietang615f13b2019-05-06 17:08:02 -0700371 if (!eliminate_static_stream_map()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700372 RegisterStaticStream(
373 QuicUtils::GetHeadersStreamId(connection()->transport_version()),
374 headers_stream_.get());
375 } else {
rchda26cdb2019-05-17 11:57:37 -0700376 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 7, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700377 unowned_headers_stream_ = headers_stream_.get();
renjietang3a1bb802019-06-11 10:42:41 -0700378 RegisterStaticStreamNew(std::move(headers_stream_),
379 /*stream_already_counted = */ false);
380 }
381
382 if (VersionHasStreamType(connection()->transport_version()) &&
383 eliminate_static_stream_map()) {
384 auto send_control = QuicMakeUnique<QuicSendControlStream>(
385 GetNextOutgoingUnidirectionalStreamId(), this);
386 send_control_stream_ = send_control.get();
387 RegisterStaticStreamNew(std::move(send_control),
388 /*stream_already_counted = */ false);
renjietangfbeb5bf2019-04-19 15:06:20 -0700389 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500390
391 set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
392
393 // Limit HPACK buffering to 2x header list size limit.
394 set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
395}
396
397void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) {
398 DCHECK(VersionUsesQpack(connection()->transport_version()));
399
400 // TODO(112770235): Signal connection error on decoder stream errors.
401 QUIC_NOTREACHED();
402}
403
404void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece data) {
405 DCHECK(VersionUsesQpack(connection()->transport_version()));
406
407 // TODO(112770235): Send encoder stream data on encoder stream.
408 QUIC_NOTREACHED();
409}
410
411void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) {
412 DCHECK(VersionUsesQpack(connection()->transport_version()));
413
414 // TODO(112770235): Signal connection error on encoder stream errors.
415 QUIC_NOTREACHED();
416}
417
418void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) {
419 DCHECK(VersionUsesQpack(connection()->transport_version()));
420
421 // TODO(112770235): Send decoder stream data on decoder stream.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500422}
423
424void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
425 SpdyPriority priority) {
426 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
427 if (!stream) {
428 // It's quite possible to receive headers after a stream has been reset.
429 return;
430 }
431 stream->OnStreamHeadersPriority(priority);
432}
433
434void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
435 bool fin,
436 size_t frame_len,
437 const QuicHeaderList& header_list) {
rchda26cdb2019-05-17 11:57:37 -0700438 if (IsStaticStream(stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500439 connection()->CloseConnection(
440 QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static",
441 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
442 return;
443 }
444 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
445 if (stream == nullptr) {
446 // The stream no longer exists, but trailing headers may contain the final
447 // byte offset necessary for flow control and open stream accounting.
448 size_t final_byte_offset = 0;
449 for (const auto& header : header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700450 const std::string& header_key = header.first;
451 const std::string& header_value = header.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500452 if (header_key == kFinalOffsetHeaderKey) {
453 if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
454 connection()->CloseConnection(
455 QUIC_INVALID_HEADERS_STREAM_DATA,
456 "Trailers are malformed (no final offset)",
457 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
458 return;
459 }
bnc5de87052019-05-03 14:21:53 -0700460 QUIC_DVLOG(1) << "Received final byte offset in trailers for stream "
461 << stream_id << ", which no longer exists.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500462 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
463 }
464 }
465
466 // It's quite possible to receive headers after a stream has been reset.
467 return;
468 }
469 stream->OnStreamHeaderList(fin, frame_len, header_list);
470}
471
472void QuicSpdySession::OnPriorityFrame(QuicStreamId stream_id,
473 SpdyPriority priority) {
474 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
475 if (!stream) {
476 // It's quite possible to receive a PRIORITY frame after a stream has been
477 // reset.
478 return;
479 }
480 stream->OnPriorityFrame(priority);
481}
482
483size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
484 return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
485 iov.iov_len);
486}
487
488size_t QuicSpdySession::WriteHeadersOnHeadersStream(
489 QuicStreamId id,
490 SpdyHeaderBlock headers,
491 bool fin,
492 SpdyPriority priority,
493 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700494 DCHECK(!VersionUsesQpack(connection()->transport_version()));
495
QUICHE teama6ef0a62019-03-07 20:34:33 -0500496 return WriteHeadersOnHeadersStreamImpl(
497 id, std::move(headers), fin,
498 /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
499 /* exclusive = */ false, std::move(ack_listener));
500}
501
502size_t QuicSpdySession::WritePriority(QuicStreamId id,
503 QuicStreamId parent_stream_id,
504 int weight,
505 bool exclusive) {
506 if (connection()->transport_version() <= QUIC_VERSION_39) {
507 return 0;
508 }
509 SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
510 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700511 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500512 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
513 return frame.size();
514}
515
516size_t QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
517 QuicStreamId promised_stream_id,
518 SpdyHeaderBlock headers) {
519 if (perspective() == Perspective::IS_CLIENT) {
520 QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
521 return 0;
522 }
523
524 SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
525 std::move(headers));
526 // PUSH_PROMISE must not be the last frame sent out, at least followed by
527 // response headers.
528 push_promise.set_fin(false);
529
530 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
renjietangfbeb5bf2019-04-19 15:06:20 -0700531 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500532 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
533 return frame.size();
534}
535
QUICHE team2252b702019-05-14 23:55:14 -0400536void QuicSpdySession::SendMaxHeaderListSize(size_t value) {
renjietang3a1bb802019-06-11 10:42:41 -0700537 if (VersionHasStreamType(connection()->transport_version())) {
538 SettingsFrame settings;
539 settings.values[kSettingsMaxHeaderListSize] = value;
540 send_control_stream_->SendSettingsFrame(settings);
541 return;
542 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500543 SpdySettingsIR settings_frame;
544 settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
545
546 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700547 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500548 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500549}
550
551QpackEncoder* QuicSpdySession::qpack_encoder() {
552 DCHECK(VersionUsesQpack(connection()->transport_version()));
553
554 return qpack_encoder_.get();
555}
556
557QpackDecoder* QuicSpdySession::qpack_decoder() {
558 DCHECK(VersionUsesQpack(connection()->transport_version()));
559
560 return qpack_decoder_.get();
561}
562
563QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
564 const QuicStreamId stream_id) {
rchda26cdb2019-05-17 11:57:37 -0700565 QuicStream* stream = GetOrCreateDynamicStream(stream_id);
566 DCHECK(!stream || !stream->is_static());
567 return static_cast<QuicSpdyStream*>(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500568}
569
570void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
571 QuicSession::OnCryptoHandshakeEvent(event);
572 if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
573 SendMaxHeaderListSize(max_inbound_header_list_size_);
574 }
575}
576
577// True if there are open HTTP requests.
578bool QuicSpdySession::ShouldKeepConnectionAlive() const {
579 // Change to check if there are open HTTP requests.
580 // When IETF QUIC control and QPACK streams are used, those will need to be
581 // subtracted from this count to ensure only request streams are counted.
582 return GetNumOpenDynamicStreams() > 0;
583}
584
renjietange76b2da2019-05-13 14:50:23 -0700585bool QuicSpdySession::UsesPendingStreams() const {
renjietangbb1c4892019-05-24 15:58:44 -0700586 DCHECK(VersionHasStreamType(connection()->transport_version()));
587 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500588}
589
590size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
591 QuicStreamId id,
592 spdy::SpdyHeaderBlock headers,
593 bool fin,
594 QuicStreamId parent_stream_id,
595 int weight,
596 bool exclusive,
597 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700598 DCHECK(!VersionUsesQpack(connection()->transport_version()));
599
QUICHE teama6ef0a62019-03-07 20:34:33 -0500600 SpdyHeadersIR headers_frame(id, std::move(headers));
601 headers_frame.set_fin(fin);
602 if (perspective() == Perspective::IS_CLIENT) {
603 headers_frame.set_has_priority(true);
604 headers_frame.set_parent_stream_id(parent_stream_id);
605 headers_frame.set_weight(weight);
606 headers_frame.set_exclusive(exclusive);
607 }
608 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700609 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500610 QuicStringPiece(frame.data(), frame.size()), false,
611 std::move(ack_listener));
612 return frame.size();
613}
614
615void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
616 QuicStreamId promised_stream_id,
617 size_t frame_len,
618 const QuicHeaderList& header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700619 std::string error =
620 "OnPromiseHeaderList should be overridden in client code.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500621 QUIC_BUG << error;
622 connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
623 ConnectionCloseBehavior::SILENT_CLOSE);
624}
625
626bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
627 return false;
628}
629
630void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
631 bool has_priority,
632 SpdyPriority priority,
633 bool fin) {
634 if (has_priority) {
635 if (perspective() == Perspective::IS_CLIENT) {
636 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
637 "Server must not send priorities.");
638 return;
639 }
640 OnStreamHeadersPriority(stream_id, priority);
641 } else {
642 if (perspective() == Perspective::IS_SERVER) {
643 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
644 "Client must send priorities.");
645 return;
646 }
647 }
648 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
649 stream_id_);
650 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
651 promised_stream_id_);
652 stream_id_ = stream_id;
653 fin_ = fin;
654}
655
656void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
renjietangcd8fab32019-06-17 16:22:16 -0700657 SpdyStreamId promised_stream_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500658 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
659 stream_id_);
660 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
661 promised_stream_id_);
662 stream_id_ = stream_id;
663 promised_stream_id_ = promised_stream_id;
664}
665
666// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
667// This occurs in many places in this file.
668void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
669 SpdyPriority priority) {
670 if (perspective() == Perspective::IS_CLIENT) {
671 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
672 "Server must not send PRIORITY frames.");
673 return;
674 }
675 OnPriorityFrame(stream_id, priority);
676}
677
678void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
679 QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
680 << header_list.DebugString();
681 if (promised_stream_id_ ==
682 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
683 OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
684 } else {
685 OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
686 header_list);
687 }
688 // Reset state for the next frame.
689 promised_stream_id_ =
690 QuicUtils::GetInvalidStreamId(connection()->transport_version());
691 stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
692 fin_ = false;
693 frame_len_ = 0;
694 uncompressed_frame_len_ = 0;
695}
696
697void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
698 frame_len_ += frame_len;
699}
700
701void QuicSpdySession::SetHpackEncoderDebugVisitor(
702 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
703 spdy_framer_.SetEncoderHeaderTableDebugVisitor(
704 std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
705 connection()->helper()->GetClock(), std::move(visitor))));
706}
707
708void QuicSpdySession::SetHpackDecoderDebugVisitor(
709 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
710 h2_deframer_.SetDecoderHeaderTableDebugVisitor(
711 QuicMakeUnique<HeaderTableDebugVisitor>(
712 connection()->helper()->GetClock(), std::move(visitor)));
713}
714
715void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
716 spdy_framer_.UpdateHeaderEncoderTableSize(value);
717}
718
719void QuicSpdySession::UpdateEnableServerPush(bool value) {
720 set_server_push_enabled(value);
721}
722
723void QuicSpdySession::set_max_uncompressed_header_bytes(
724 size_t set_max_uncompressed_header_bytes) {
725 spdy_framer_visitor_->set_max_uncompressed_header_bytes(
726 set_max_uncompressed_header_bytes);
727}
728
729void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700730 const std::string& details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500731 connection()->CloseConnection(
732 error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
733}
734
QUICHE teamc2653c42019-03-08 13:30:06 -0800735bool QuicSpdySession::HasActiveRequestStreams() const {
renjietang615f13b2019-05-06 17:08:02 -0700736 if (!eliminate_static_stream_map()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700737 return !dynamic_streams().empty();
738 }
739 // In the case where session is destructed by calling
740 // dynamic_streams().clear(), we will have incorrect accounting here.
741 // TODO(renjietang): Modify destructors and make this a DCHECK.
rchda26cdb2019-05-17 11:57:37 -0700742 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 9, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700743 if (static_cast<size_t>(dynamic_streams().size()) >
744 num_incoming_static_streams() + num_outgoing_static_streams()) {
745 return dynamic_streams().size() - num_incoming_static_streams() -
746 num_outgoing_static_streams() >
747 0;
748 }
749 return false;
QUICHE teamc2653c42019-03-08 13:30:06 -0800750}
751
renjietangbb1c4892019-05-24 15:58:44 -0700752bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
753 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietang0c558862019-05-08 13:26:23 -0700754 struct iovec iov;
755 if (!pending->sequencer()->GetReadableRegion(&iov)) {
renjietangbb1c4892019-05-24 15:58:44 -0700756 // The first byte hasn't been received yet.
757 return false;
renjietang0c558862019-05-08 13:26:23 -0700758 }
759
760 QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len);
renjietangbb1c4892019-05-24 15:58:44 -0700761 uint8_t stream_type_length = reader.PeekVarInt62Length();
renjietang0c558862019-05-08 13:26:23 -0700762 uint64_t stream_type = 0;
763 if (!reader.ReadVarInt62(&stream_type)) {
renjietangbb1c4892019-05-24 15:58:44 -0700764 return false;
renjietang0c558862019-05-08 13:26:23 -0700765 }
renjietangbb1c4892019-05-24 15:58:44 -0700766 pending->MarkConsumed(stream_type_length);
renjietang0c558862019-05-08 13:26:23 -0700767
renjietang0c558862019-05-08 13:26:23 -0700768 switch (stream_type) {
renjietang3a1bb802019-06-11 10:42:41 -0700769 case kControlStream: { // HTTP/3 control stream.
770 auto receive_stream = QuicMakeUnique<QuicReceiveControlStream>(pending);
771 receive_control_stream_ = receive_stream.get();
772 RegisterStaticStreamNew(std::move(receive_stream),
773 /*stream_already_counted = */ true);
774 receive_control_stream_->SetUnblocked();
775 return true;
776 }
renjietangbb1c4892019-05-24 15:58:44 -0700777 case kServerPushStream: { // Push Stream.
renjietangbaea59c2019-05-29 15:08:14 -0700778 QuicSpdyStream* stream = CreateIncomingStream(pending);
renjietangbb1c4892019-05-24 15:58:44 -0700779 stream->SetUnblocked();
780 return true;
781 }
782 case kQpackEncoderStream: // QPACK encoder stream.
renjietang0c558862019-05-08 13:26:23 -0700783 // TODO(bnc): Create QPACK encoder stream.
784 break;
renjietangbb1c4892019-05-24 15:58:44 -0700785 case kQpackDecoderStream: // QPACK decoder stream.
renjietang0c558862019-05-08 13:26:23 -0700786 // TODO(bnc): Create QPACK decoder stream.
787 break;
788 default:
renjietangbb1c4892019-05-24 15:58:44 -0700789 SendStopSending(kHttpUnknownStreamType, pending->id());
renjietang0c558862019-05-08 13:26:23 -0700790 }
renjietangbb1c4892019-05-24 15:58:44 -0700791 return false;
renjietang0c558862019-05-08 13:26:23 -0700792}
793
QUICHE teama6ef0a62019-03-07 20:34:33 -0500794} // namespace quic