blob: 35b2d5ef305fe7a16832b1cd6992b96939d89232 [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 }
239 session_->OnPushPromise(stream_id, promised_stream_id, end);
240 }
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),
317 server_push_enabled_(true),
318 stream_id_(
319 QuicUtils::GetInvalidStreamId(connection->transport_version())),
320 promised_stream_id_(
321 QuicUtils::GetInvalidStreamId(connection->transport_version())),
322 fin_(false),
323 frame_len_(0),
324 uncompressed_frame_len_(0),
325 supports_push_promise_(perspective() == Perspective::IS_CLIENT),
326 spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
327 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
328 h2_deframer_.set_visitor(spdy_framer_visitor_.get());
329 h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
330 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
331}
332
333QuicSpdySession::~QuicSpdySession() {
334 // Set the streams' session pointers in closed and dynamic stream lists
335 // to null to avoid subsequent use of this session.
336 for (auto& stream : *closed_streams()) {
337 static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
338 }
339 for (auto const& kv : zombie_streams()) {
340 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
341 }
342 for (auto const& kv : dynamic_streams()) {
renjietang2da2afb2019-05-13 17:22:14 -0700343 if (eliminate_static_stream_map() && kv.second->is_static()) {
344 continue;
345 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500346 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
347 }
348}
349
350void QuicSpdySession::Initialize() {
351 QuicSession::Initialize();
352
353 if (perspective() == Perspective::IS_SERVER) {
354 set_largest_peer_created_stream_id(
355 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
356 } else {
357 QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
358 DCHECK_EQ(headers_stream_id,
359 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
360 }
361
362 if (VersionUsesQpack(connection()->transport_version())) {
363 qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this);
364 qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this);
365 }
366
367 headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
368 DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
369 headers_stream_->id());
renjietang615f13b2019-05-06 17:08:02 -0700370 if (!eliminate_static_stream_map()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700371 RegisterStaticStream(
372 QuicUtils::GetHeadersStreamId(connection()->transport_version()),
373 headers_stream_.get());
374 } else {
rchda26cdb2019-05-17 11:57:37 -0700375 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 7, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700376 unowned_headers_stream_ = headers_stream_.get();
377 RegisterStaticStreamNew(std::move(headers_stream_));
378 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500379
380 set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
381
382 // Limit HPACK buffering to 2x header list size limit.
383 set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
384}
385
386void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) {
387 DCHECK(VersionUsesQpack(connection()->transport_version()));
388
389 // TODO(112770235): Signal connection error on decoder stream errors.
390 QUIC_NOTREACHED();
391}
392
393void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece data) {
394 DCHECK(VersionUsesQpack(connection()->transport_version()));
395
396 // TODO(112770235): Send encoder stream data on encoder stream.
397 QUIC_NOTREACHED();
398}
399
400void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) {
401 DCHECK(VersionUsesQpack(connection()->transport_version()));
402
403 // TODO(112770235): Signal connection error on encoder stream errors.
404 QUIC_NOTREACHED();
405}
406
407void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) {
408 DCHECK(VersionUsesQpack(connection()->transport_version()));
409
410 // TODO(112770235): Send decoder stream data on decoder stream.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500411}
412
413void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
414 SpdyPriority priority) {
415 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
416 if (!stream) {
417 // It's quite possible to receive headers after a stream has been reset.
418 return;
419 }
420 stream->OnStreamHeadersPriority(priority);
421}
422
423void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
424 bool fin,
425 size_t frame_len,
426 const QuicHeaderList& header_list) {
rchda26cdb2019-05-17 11:57:37 -0700427 if (IsStaticStream(stream_id)) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500428 connection()->CloseConnection(
429 QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static",
430 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
431 return;
432 }
433 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
434 if (stream == nullptr) {
435 // The stream no longer exists, but trailing headers may contain the final
436 // byte offset necessary for flow control and open stream accounting.
437 size_t final_byte_offset = 0;
438 for (const auto& header : header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700439 const std::string& header_key = header.first;
440 const std::string& header_value = header.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500441 if (header_key == kFinalOffsetHeaderKey) {
442 if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
443 connection()->CloseConnection(
444 QUIC_INVALID_HEADERS_STREAM_DATA,
445 "Trailers are malformed (no final offset)",
446 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
447 return;
448 }
bnc5de87052019-05-03 14:21:53 -0700449 QUIC_DVLOG(1) << "Received final byte offset in trailers for stream "
450 << stream_id << ", which no longer exists.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500451 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
452 }
453 }
454
455 // It's quite possible to receive headers after a stream has been reset.
456 return;
457 }
458 stream->OnStreamHeaderList(fin, frame_len, header_list);
459}
460
461void QuicSpdySession::OnPriorityFrame(QuicStreamId stream_id,
462 SpdyPriority priority) {
463 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
464 if (!stream) {
465 // It's quite possible to receive a PRIORITY frame after a stream has been
466 // reset.
467 return;
468 }
469 stream->OnPriorityFrame(priority);
470}
471
472size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
473 return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
474 iov.iov_len);
475}
476
477size_t QuicSpdySession::WriteHeadersOnHeadersStream(
478 QuicStreamId id,
479 SpdyHeaderBlock headers,
480 bool fin,
481 SpdyPriority priority,
482 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700483 DCHECK(!VersionUsesQpack(connection()->transport_version()));
484
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485 return WriteHeadersOnHeadersStreamImpl(
486 id, std::move(headers), fin,
487 /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
488 /* exclusive = */ false, std::move(ack_listener));
489}
490
491size_t QuicSpdySession::WritePriority(QuicStreamId id,
492 QuicStreamId parent_stream_id,
493 int weight,
494 bool exclusive) {
495 if (connection()->transport_version() <= QUIC_VERSION_39) {
496 return 0;
497 }
498 SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
499 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700500 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500501 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
502 return frame.size();
503}
504
505size_t QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
506 QuicStreamId promised_stream_id,
507 SpdyHeaderBlock headers) {
508 if (perspective() == Perspective::IS_CLIENT) {
509 QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
510 return 0;
511 }
512
513 SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
514 std::move(headers));
515 // PUSH_PROMISE must not be the last frame sent out, at least followed by
516 // response headers.
517 push_promise.set_fin(false);
518
519 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
renjietangfbeb5bf2019-04-19 15:06:20 -0700520 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500521 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
522 return frame.size();
523}
524
QUICHE team2252b702019-05-14 23:55:14 -0400525void QuicSpdySession::SendMaxHeaderListSize(size_t value) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500526 SpdySettingsIR settings_frame;
527 settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
528
529 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame));
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);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500532}
533
534QpackEncoder* QuicSpdySession::qpack_encoder() {
535 DCHECK(VersionUsesQpack(connection()->transport_version()));
536
537 return qpack_encoder_.get();
538}
539
540QpackDecoder* QuicSpdySession::qpack_decoder() {
541 DCHECK(VersionUsesQpack(connection()->transport_version()));
542
543 return qpack_decoder_.get();
544}
545
546QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
547 const QuicStreamId stream_id) {
rchda26cdb2019-05-17 11:57:37 -0700548 QuicStream* stream = GetOrCreateDynamicStream(stream_id);
549 DCHECK(!stream || !stream->is_static());
550 return static_cast<QuicSpdyStream*>(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500551}
552
553void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
554 QuicSession::OnCryptoHandshakeEvent(event);
555 if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
556 SendMaxHeaderListSize(max_inbound_header_list_size_);
557 }
558}
559
560// True if there are open HTTP requests.
561bool QuicSpdySession::ShouldKeepConnectionAlive() const {
562 // Change to check if there are open HTTP requests.
563 // When IETF QUIC control and QPACK streams are used, those will need to be
564 // subtracted from this count to ensure only request streams are counted.
565 return GetNumOpenDynamicStreams() > 0;
566}
567
renjietange76b2da2019-05-13 14:50:23 -0700568bool QuicSpdySession::UsesPendingStreams() const {
renjietangbb1c4892019-05-24 15:58:44 -0700569 DCHECK(VersionHasStreamType(connection()->transport_version()));
570 return true;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500571}
572
573size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
574 QuicStreamId id,
575 spdy::SpdyHeaderBlock headers,
576 bool fin,
577 QuicStreamId parent_stream_id,
578 int weight,
579 bool exclusive,
580 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700581 DCHECK(!VersionUsesQpack(connection()->transport_version()));
582
QUICHE teama6ef0a62019-03-07 20:34:33 -0500583 SpdyHeadersIR headers_frame(id, std::move(headers));
584 headers_frame.set_fin(fin);
585 if (perspective() == Perspective::IS_CLIENT) {
586 headers_frame.set_has_priority(true);
587 headers_frame.set_parent_stream_id(parent_stream_id);
588 headers_frame.set_weight(weight);
589 headers_frame.set_exclusive(exclusive);
590 }
591 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700592 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500593 QuicStringPiece(frame.data(), frame.size()), false,
594 std::move(ack_listener));
595 return frame.size();
596}
597
598void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
599 QuicStreamId promised_stream_id,
600 size_t frame_len,
601 const QuicHeaderList& header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700602 std::string error =
603 "OnPromiseHeaderList should be overridden in client code.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500604 QUIC_BUG << error;
605 connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
606 ConnectionCloseBehavior::SILENT_CLOSE);
607}
608
609bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
610 return false;
611}
612
613void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
614 bool has_priority,
615 SpdyPriority priority,
616 bool fin) {
617 if (has_priority) {
618 if (perspective() == Perspective::IS_CLIENT) {
619 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
620 "Server must not send priorities.");
621 return;
622 }
623 OnStreamHeadersPriority(stream_id, priority);
624 } else {
625 if (perspective() == Perspective::IS_SERVER) {
626 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
627 "Client must send priorities.");
628 return;
629 }
630 }
631 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
632 stream_id_);
633 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
634 promised_stream_id_);
635 stream_id_ = stream_id;
636 fin_ = fin;
637}
638
639void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
640 SpdyStreamId promised_stream_id,
641 bool end) {
642 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
643 stream_id_);
644 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
645 promised_stream_id_);
646 stream_id_ = stream_id;
647 promised_stream_id_ = promised_stream_id;
648}
649
650// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
651// This occurs in many places in this file.
652void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
653 SpdyPriority priority) {
654 if (perspective() == Perspective::IS_CLIENT) {
655 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
656 "Server must not send PRIORITY frames.");
657 return;
658 }
659 OnPriorityFrame(stream_id, priority);
660}
661
662void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
663 QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
664 << header_list.DebugString();
665 if (promised_stream_id_ ==
666 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
667 OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
668 } else {
669 OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
670 header_list);
671 }
672 // Reset state for the next frame.
673 promised_stream_id_ =
674 QuicUtils::GetInvalidStreamId(connection()->transport_version());
675 stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
676 fin_ = false;
677 frame_len_ = 0;
678 uncompressed_frame_len_ = 0;
679}
680
681void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
682 frame_len_ += frame_len;
683}
684
685void QuicSpdySession::SetHpackEncoderDebugVisitor(
686 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
687 spdy_framer_.SetEncoderHeaderTableDebugVisitor(
688 std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
689 connection()->helper()->GetClock(), std::move(visitor))));
690}
691
692void QuicSpdySession::SetHpackDecoderDebugVisitor(
693 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
694 h2_deframer_.SetDecoderHeaderTableDebugVisitor(
695 QuicMakeUnique<HeaderTableDebugVisitor>(
696 connection()->helper()->GetClock(), std::move(visitor)));
697}
698
699void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
700 spdy_framer_.UpdateHeaderEncoderTableSize(value);
701}
702
703void QuicSpdySession::UpdateEnableServerPush(bool value) {
704 set_server_push_enabled(value);
705}
706
707void QuicSpdySession::set_max_uncompressed_header_bytes(
708 size_t set_max_uncompressed_header_bytes) {
709 spdy_framer_visitor_->set_max_uncompressed_header_bytes(
710 set_max_uncompressed_header_bytes);
711}
712
713void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700714 const std::string& details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500715 connection()->CloseConnection(
716 error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
717}
718
QUICHE teamc2653c42019-03-08 13:30:06 -0800719bool QuicSpdySession::HasActiveRequestStreams() const {
renjietang615f13b2019-05-06 17:08:02 -0700720 if (!eliminate_static_stream_map()) {
renjietangfbeb5bf2019-04-19 15:06:20 -0700721 return !dynamic_streams().empty();
722 }
723 // In the case where session is destructed by calling
724 // dynamic_streams().clear(), we will have incorrect accounting here.
725 // TODO(renjietang): Modify destructors and make this a DCHECK.
rchda26cdb2019-05-17 11:57:37 -0700726 QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_3, 9, 17);
renjietangfbeb5bf2019-04-19 15:06:20 -0700727 if (static_cast<size_t>(dynamic_streams().size()) >
728 num_incoming_static_streams() + num_outgoing_static_streams()) {
729 return dynamic_streams().size() - num_incoming_static_streams() -
730 num_outgoing_static_streams() >
731 0;
732 }
733 return false;
QUICHE teamc2653c42019-03-08 13:30:06 -0800734}
735
renjietangbb1c4892019-05-24 15:58:44 -0700736bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
737 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietang0c558862019-05-08 13:26:23 -0700738 struct iovec iov;
739 if (!pending->sequencer()->GetReadableRegion(&iov)) {
renjietangbb1c4892019-05-24 15:58:44 -0700740 // The first byte hasn't been received yet.
741 return false;
renjietang0c558862019-05-08 13:26:23 -0700742 }
743
744 QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len);
renjietangbb1c4892019-05-24 15:58:44 -0700745 uint8_t stream_type_length = reader.PeekVarInt62Length();
renjietang0c558862019-05-08 13:26:23 -0700746 uint64_t stream_type = 0;
747 if (!reader.ReadVarInt62(&stream_type)) {
renjietangbb1c4892019-05-24 15:58:44 -0700748 return false;
renjietang0c558862019-05-08 13:26:23 -0700749 }
renjietangbb1c4892019-05-24 15:58:44 -0700750 pending->MarkConsumed(stream_type_length);
renjietang0c558862019-05-08 13:26:23 -0700751
renjietang0c558862019-05-08 13:26:23 -0700752 switch (stream_type) {
renjietangbb1c4892019-05-24 15:58:44 -0700753 case kControlStream: // HTTP/3 control stream.
renjietang0c558862019-05-08 13:26:23 -0700754 // TODO(renjietang): Create incoming control stream.
755 break;
renjietangbb1c4892019-05-24 15:58:44 -0700756 case kServerPushStream: { // Push Stream.
757 QuicSpdyStream* stream = CreateIncomingStream(std::move(*pending));
758 stream->SetUnblocked();
759 return true;
760 }
761 case kQpackEncoderStream: // QPACK encoder stream.
renjietang0c558862019-05-08 13:26:23 -0700762 // TODO(bnc): Create QPACK encoder stream.
763 break;
renjietangbb1c4892019-05-24 15:58:44 -0700764 case kQpackDecoderStream: // QPACK decoder stream.
renjietang0c558862019-05-08 13:26:23 -0700765 // TODO(bnc): Create QPACK decoder stream.
766 break;
767 default:
renjietangbb1c4892019-05-24 15:58:44 -0700768 SendStopSending(kHttpUnknownStreamType, pending->id());
renjietang0c558862019-05-08 13:26:23 -0700769 }
renjietangbb1c4892019-05-24 15:58:44 -0700770 return false;
renjietang0c558862019-05-08 13:26:23 -0700771}
772
QUICHE teama6ef0a62019-03-07 20:34:33 -0500773} // namespace quic