blob: bda2e172d0132c6733bbdf1e8150837f0e0b75c0 [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
54class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
55 public:
56 HeaderTableDebugVisitor(const QuicClock* clock,
57 std::unique_ptr<QuicHpackDebugVisitor> visitor)
58 : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {}
59 HeaderTableDebugVisitor(const HeaderTableDebugVisitor&) = delete;
60 HeaderTableDebugVisitor& operator=(const HeaderTableDebugVisitor&) = delete;
61
62 int64_t OnNewEntry(const HpackEntry& entry) override {
63 QUIC_DVLOG(1) << entry.GetDebugString();
64 return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds();
65 }
66
67 void OnUseEntry(const HpackEntry& entry) override {
68 const QuicTime::Delta elapsed(
69 clock_->ApproximateNow() -
70 QuicTime::Delta::FromMicroseconds(entry.time_added()) -
71 QuicTime::Zero());
72 QUIC_DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
73 << " ms";
74 headers_stream_hpack_visitor_->OnUseEntry(elapsed);
75 }
76
77 private:
78 const QuicClock* clock_;
79 std::unique_ptr<QuicHpackDebugVisitor> headers_stream_hpack_visitor_;
80};
81
82} // namespace
83
84// A SpdyFramerVisitor that passes HEADERS frames to the QuicSpdyStream, and
85// closes the connection if any unexpected frames are received.
86class QuicSpdySession::SpdyFramerVisitor
87 : public SpdyFramerVisitorInterface,
88 public SpdyFramerDebugVisitorInterface {
89 public:
90 explicit SpdyFramerVisitor(QuicSpdySession* session) : session_(session) {}
91 SpdyFramerVisitor(const SpdyFramerVisitor&) = delete;
92 SpdyFramerVisitor& operator=(const SpdyFramerVisitor&) = delete;
93
94 SpdyHeadersHandlerInterface* OnHeaderFrameStart(
95 SpdyStreamId /* stream_id */) override {
96 return &header_list_;
97 }
98
99 void OnHeaderFrameEnd(SpdyStreamId /* stream_id */) override {
100 if (session_->IsConnected()) {
101 session_->OnHeaderList(header_list_);
102 }
103 header_list_.Clear();
104 }
105
106 void OnStreamFrameData(SpdyStreamId stream_id,
107 const char* data,
108 size_t len) override {
109 CloseConnection("SPDY DATA frame received.",
110 QUIC_INVALID_HEADERS_STREAM_DATA);
111 }
112
113 void OnStreamEnd(SpdyStreamId stream_id) override {
114 // The framer invokes OnStreamEnd after processing a frame that had the fin
115 // bit set.
116 }
117
118 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
119 CloseConnection("SPDY frame padding received.",
120 QUIC_INVALID_HEADERS_STREAM_DATA);
121 }
122
123 void OnError(Http2DecoderAdapter::SpdyFramerError error) override {
124 QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
125 switch (error) {
126 case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
127 code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
128 break;
129 default:
130 break;
131 }
132 CloseConnection(
133 QuicStrCat("SPDY framing error: ",
134 Http2DecoderAdapter::SpdyFramerErrorToString(error)),
135 code);
136 }
137
138 void OnDataFrameHeader(SpdyStreamId stream_id,
139 size_t length,
140 bool fin) override {
141 CloseConnection("SPDY DATA frame received.",
142 QUIC_INVALID_HEADERS_STREAM_DATA);
143 }
144
145 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {
146 CloseConnection("SPDY RST_STREAM frame received.",
147 QUIC_INVALID_HEADERS_STREAM_DATA);
148 }
149
150 void OnSetting(SpdySettingsId id, uint32_t value) override {
151 switch (id) {
152 case SETTINGS_HEADER_TABLE_SIZE:
153 session_->UpdateHeaderEncoderTableSize(value);
154 break;
155 case SETTINGS_ENABLE_PUSH:
156 if (session_->perspective() == Perspective::IS_SERVER) {
157 // See rfc7540, Section 6.5.2.
158 if (value > 1) {
159 CloseConnection(
160 QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
161 QUIC_INVALID_HEADERS_STREAM_DATA);
162 return;
163 }
164 session_->UpdateEnableServerPush(value > 0);
165 break;
166 } else {
167 CloseConnection(
168 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
169 QUIC_INVALID_HEADERS_STREAM_DATA);
170 }
171 break;
172 // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
173 // clients are actually sending it.
174 case SETTINGS_MAX_HEADER_LIST_SIZE:
175 break;
176 default:
177 CloseConnection(
178 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
179 QUIC_INVALID_HEADERS_STREAM_DATA);
180 }
181 }
182
183 void OnSettingsEnd() override {}
184
185 void OnPing(SpdyPingId unique_id, bool is_ack) override {
186 CloseConnection("SPDY PING frame received.",
187 QUIC_INVALID_HEADERS_STREAM_DATA);
188 }
189
190 void OnGoAway(SpdyStreamId last_accepted_stream_id,
191 SpdyErrorCode error_code) override {
192 CloseConnection("SPDY GOAWAY frame received.",
193 QUIC_INVALID_HEADERS_STREAM_DATA);
194 }
195
196 void OnHeaders(SpdyStreamId stream_id,
197 bool has_priority,
198 int weight,
199 SpdyStreamId /*parent_stream_id*/,
200 bool /*exclusive*/,
201 bool fin,
202 bool end) override {
203 if (!session_->IsConnected()) {
204 return;
205 }
206
207 // TODO(mpw): avoid down-conversion and plumb SpdyStreamPrecedence through
208 // QuicHeadersStream.
209 SpdyPriority priority =
210 has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
211 session_->OnHeaders(stream_id, has_priority, priority, fin);
212 }
213
214 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {
215 CloseConnection("SPDY WINDOW_UPDATE frame received.",
216 QUIC_INVALID_HEADERS_STREAM_DATA);
217 }
218
219 void OnPushPromise(SpdyStreamId stream_id,
220 SpdyStreamId promised_stream_id,
221 bool end) override {
222 if (!session_->supports_push_promise()) {
223 CloseConnection("PUSH_PROMISE not supported.",
224 QUIC_INVALID_HEADERS_STREAM_DATA);
225 return;
226 }
227 if (!session_->IsConnected()) {
228 return;
229 }
230 session_->OnPushPromise(stream_id, promised_stream_id, end);
231 }
232
233 void OnContinuation(SpdyStreamId stream_id, bool end) override {}
234
235 void OnPriority(SpdyStreamId stream_id,
236 SpdyStreamId parent_id,
237 int weight,
238 bool exclusive) override {
239 if (session_->connection()->transport_version() <= QUIC_VERSION_39) {
240 CloseConnection("SPDY PRIORITY frame received.",
241 QUIC_INVALID_HEADERS_STREAM_DATA);
242 return;
243 }
244 if (!session_->IsConnected()) {
245 return;
246 }
247 // TODO (wangyix): implement real HTTP/2 weights and dependencies instead of
248 // converting to SpdyPriority.
249 SpdyPriority priority = Http2WeightToSpdy3Priority(weight);
250 session_->OnPriority(stream_id, priority);
251 }
252
253 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override {
254 CloseConnection("Unknown frame type received.",
255 QUIC_INVALID_HEADERS_STREAM_DATA);
256 return false;
257 }
258
259 // SpdyFramerDebugVisitorInterface implementation
260 void OnSendCompressedFrame(SpdyStreamId stream_id,
261 SpdyFrameType type,
262 size_t payload_len,
263 size_t frame_len) override {
264 if (payload_len == 0) {
265 QUIC_BUG << "Zero payload length.";
266 return;
267 }
268 int compression_pct = 100 - (100 * frame_len) / payload_len;
269 QUIC_DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
270 }
271
272 void OnReceiveCompressedFrame(SpdyStreamId stream_id,
273 SpdyFrameType type,
274 size_t frame_len) override {
275 if (session_->IsConnected()) {
276 session_->OnCompressedFrameSize(frame_len);
277 }
278 }
279
280 void set_max_uncompressed_header_bytes(
281 size_t set_max_uncompressed_header_bytes) {
282 header_list_.set_max_header_list_size(set_max_uncompressed_header_bytes);
283 }
284
285 private:
vasilvvc48c8712019-03-11 13:38:16 -0700286 void CloseConnection(const std::string& details, QuicErrorCode code) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500287 if (session_->IsConnected()) {
288 session_->CloseConnectionWithDetails(code, details);
289 }
290 }
291
292 private:
293 QuicSpdySession* session_;
294 QuicHeaderList header_list_;
295};
296
297QuicHpackDebugVisitor::QuicHpackDebugVisitor() {}
298
299QuicHpackDebugVisitor::~QuicHpackDebugVisitor() {}
300
301QuicSpdySession::QuicSpdySession(
302 QuicConnection* connection,
303 QuicSession::Visitor* visitor,
304 const QuicConfig& config,
305 const ParsedQuicVersionVector& supported_versions)
306 : QuicSession(connection, visitor, config, supported_versions),
307 max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
308 server_push_enabled_(true),
309 stream_id_(
310 QuicUtils::GetInvalidStreamId(connection->transport_version())),
311 promised_stream_id_(
312 QuicUtils::GetInvalidStreamId(connection->transport_version())),
313 fin_(false),
314 frame_len_(0),
315 uncompressed_frame_len_(0),
316 supports_push_promise_(perspective() == Perspective::IS_CLIENT),
317 spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
318 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
319 h2_deframer_.set_visitor(spdy_framer_visitor_.get());
320 h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
321 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
322}
323
324QuicSpdySession::~QuicSpdySession() {
325 // Set the streams' session pointers in closed and dynamic stream lists
326 // to null to avoid subsequent use of this session.
327 for (auto& stream : *closed_streams()) {
328 static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
329 }
330 for (auto const& kv : zombie_streams()) {
331 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
332 }
333 for (auto const& kv : dynamic_streams()) {
334 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
335 }
336}
337
338void QuicSpdySession::Initialize() {
339 QuicSession::Initialize();
340
341 if (perspective() == Perspective::IS_SERVER) {
342 set_largest_peer_created_stream_id(
343 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
344 } else {
345 QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
346 DCHECK_EQ(headers_stream_id,
347 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
348 }
349
350 if (VersionUsesQpack(connection()->transport_version())) {
351 qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this);
352 qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this);
353 }
354
355 headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
356 DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
357 headers_stream_->id());
358 RegisterStaticStream(
359 QuicUtils::GetHeadersStreamId(connection()->transport_version()),
360 headers_stream_.get());
361
362 set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
363
364 // Limit HPACK buffering to 2x header list size limit.
365 set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_);
366}
367
368void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) {
369 DCHECK(VersionUsesQpack(connection()->transport_version()));
370
371 // TODO(112770235): Signal connection error on decoder stream errors.
372 QUIC_NOTREACHED();
373}
374
375void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece data) {
376 DCHECK(VersionUsesQpack(connection()->transport_version()));
377
378 // TODO(112770235): Send encoder stream data on encoder stream.
379 QUIC_NOTREACHED();
380}
381
382void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) {
383 DCHECK(VersionUsesQpack(connection()->transport_version()));
384
385 // TODO(112770235): Signal connection error on encoder stream errors.
386 QUIC_NOTREACHED();
387}
388
389void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) {
390 DCHECK(VersionUsesQpack(connection()->transport_version()));
391
392 // TODO(112770235): Send decoder stream data on decoder stream.
393 QUIC_NOTREACHED();
394}
395
396void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id,
397 SpdyPriority priority) {
398 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
399 if (!stream) {
400 // It's quite possible to receive headers after a stream has been reset.
401 return;
402 }
403 stream->OnStreamHeadersPriority(priority);
404}
405
406void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id,
407 bool fin,
408 size_t frame_len,
409 const QuicHeaderList& header_list) {
410 if (QuicContainsKey(static_streams(), stream_id)) {
411 connection()->CloseConnection(
412 QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static",
413 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
414 return;
415 }
416 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
417 if (stream == nullptr) {
418 // The stream no longer exists, but trailing headers may contain the final
419 // byte offset necessary for flow control and open stream accounting.
420 size_t final_byte_offset = 0;
421 for (const auto& header : header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700422 const std::string& header_key = header.first;
423 const std::string& header_value = header.second;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500424 if (header_key == kFinalOffsetHeaderKey) {
425 if (!QuicTextUtils::StringToSizeT(header_value, &final_byte_offset)) {
426 connection()->CloseConnection(
427 QUIC_INVALID_HEADERS_STREAM_DATA,
428 "Trailers are malformed (no final offset)",
429 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
430 return;
431 }
432 DVLOG(1) << "Received final byte offset in trailers for stream "
433 << stream_id << ", which no longer exists.";
434 OnFinalByteOffsetReceived(stream_id, final_byte_offset);
435 }
436 }
437
438 // It's quite possible to receive headers after a stream has been reset.
439 return;
440 }
441 stream->OnStreamHeaderList(fin, frame_len, header_list);
442}
443
444void QuicSpdySession::OnPriorityFrame(QuicStreamId stream_id,
445 SpdyPriority priority) {
446 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
447 if (!stream) {
448 // It's quite possible to receive a PRIORITY frame after a stream has been
449 // reset.
450 return;
451 }
452 stream->OnPriorityFrame(priority);
453}
454
455size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
456 return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
457 iov.iov_len);
458}
459
460size_t QuicSpdySession::WriteHeadersOnHeadersStream(
461 QuicStreamId id,
462 SpdyHeaderBlock headers,
463 bool fin,
464 SpdyPriority priority,
465 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
466 return WriteHeadersOnHeadersStreamImpl(
467 id, std::move(headers), fin,
468 /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority),
469 /* exclusive = */ false, std::move(ack_listener));
470}
471
472size_t QuicSpdySession::WritePriority(QuicStreamId id,
473 QuicStreamId parent_stream_id,
474 int weight,
475 bool exclusive) {
476 if (connection()->transport_version() <= QUIC_VERSION_39) {
477 return 0;
478 }
479 SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
480 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
481 headers_stream_->WriteOrBufferData(
482 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
483 return frame.size();
484}
485
486size_t QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
487 QuicStreamId promised_stream_id,
488 SpdyHeaderBlock headers) {
489 if (perspective() == Perspective::IS_CLIENT) {
490 QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
491 return 0;
492 }
493
494 SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
495 std::move(headers));
496 // PUSH_PROMISE must not be the last frame sent out, at least followed by
497 // response headers.
498 push_promise.set_fin(false);
499
500 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
501 headers_stream_->WriteOrBufferData(
502 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
503 return frame.size();
504}
505
506size_t QuicSpdySession::SendMaxHeaderListSize(size_t value) {
507 SpdySettingsIR settings_frame;
508 settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
509
510 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame));
511 headers_stream_->WriteOrBufferData(
512 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
513 return frame.size();
514}
515
516QpackEncoder* QuicSpdySession::qpack_encoder() {
517 DCHECK(VersionUsesQpack(connection()->transport_version()));
518
519 return qpack_encoder_.get();
520}
521
522QpackDecoder* QuicSpdySession::qpack_decoder() {
523 DCHECK(VersionUsesQpack(connection()->transport_version()));
524
525 return qpack_decoder_.get();
526}
527
528QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
529 const QuicStreamId stream_id) {
530 return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id));
531}
532
533void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
534 QuicSession::OnCryptoHandshakeEvent(event);
535 if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
536 SendMaxHeaderListSize(max_inbound_header_list_size_);
537 }
538}
539
540// True if there are open HTTP requests.
541bool QuicSpdySession::ShouldKeepConnectionAlive() const {
542 // Change to check if there are open HTTP requests.
543 // When IETF QUIC control and QPACK streams are used, those will need to be
544 // subtracted from this count to ensure only request streams are counted.
545 return GetNumOpenDynamicStreams() > 0;
546}
547
548bool QuicSpdySession::ShouldBufferIncomingStream(QuicStreamId id) const {
549 DCHECK_EQ(QUIC_VERSION_99, connection()->transport_version());
550 return !QuicUtils::IsBidirectionalStreamId(id);
551}
552
553size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
554 QuicStreamId id,
555 spdy::SpdyHeaderBlock headers,
556 bool fin,
557 QuicStreamId parent_stream_id,
558 int weight,
559 bool exclusive,
560 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
561 SpdyHeadersIR headers_frame(id, std::move(headers));
562 headers_frame.set_fin(fin);
563 if (perspective() == Perspective::IS_CLIENT) {
564 headers_frame.set_has_priority(true);
565 headers_frame.set_parent_stream_id(parent_stream_id);
566 headers_frame.set_weight(weight);
567 headers_frame.set_exclusive(exclusive);
568 }
569 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
570 headers_stream_->WriteOrBufferData(
571 QuicStringPiece(frame.data(), frame.size()), false,
572 std::move(ack_listener));
573 return frame.size();
574}
575
576void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id,
577 QuicStreamId promised_stream_id,
578 size_t frame_len,
579 const QuicHeaderList& header_list) {
vasilvvc48c8712019-03-11 13:38:16 -0700580 std::string error =
581 "OnPromiseHeaderList should be overridden in client code.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500582 QUIC_BUG << error;
583 connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
584 ConnectionCloseBehavior::SILENT_CLOSE);
585}
586
587bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
588 return false;
589}
590
591void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
592 bool has_priority,
593 SpdyPriority priority,
594 bool fin) {
595 if (has_priority) {
596 if (perspective() == Perspective::IS_CLIENT) {
597 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
598 "Server must not send priorities.");
599 return;
600 }
601 OnStreamHeadersPriority(stream_id, priority);
602 } else {
603 if (perspective() == Perspective::IS_SERVER) {
604 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
605 "Client must send priorities.");
606 return;
607 }
608 }
609 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
610 stream_id_);
611 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
612 promised_stream_id_);
613 stream_id_ = stream_id;
614 fin_ = fin;
615}
616
617void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
618 SpdyStreamId promised_stream_id,
619 bool end) {
620 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
621 stream_id_);
622 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
623 promised_stream_id_);
624 stream_id_ = stream_id;
625 promised_stream_id_ = promised_stream_id;
626}
627
628// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
629// This occurs in many places in this file.
630void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
631 SpdyPriority priority) {
632 if (perspective() == Perspective::IS_CLIENT) {
633 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
634 "Server must not send PRIORITY frames.");
635 return;
636 }
637 OnPriorityFrame(stream_id, priority);
638}
639
640void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
641 QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
642 << header_list.DebugString();
643 if (promised_stream_id_ ==
644 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
645 OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
646 } else {
647 OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
648 header_list);
649 }
650 // Reset state for the next frame.
651 promised_stream_id_ =
652 QuicUtils::GetInvalidStreamId(connection()->transport_version());
653 stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
654 fin_ = false;
655 frame_len_ = 0;
656 uncompressed_frame_len_ = 0;
657}
658
659void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
660 frame_len_ += frame_len;
661}
662
663void QuicSpdySession::SetHpackEncoderDebugVisitor(
664 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
665 spdy_framer_.SetEncoderHeaderTableDebugVisitor(
666 std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
667 connection()->helper()->GetClock(), std::move(visitor))));
668}
669
670void QuicSpdySession::SetHpackDecoderDebugVisitor(
671 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
672 h2_deframer_.SetDecoderHeaderTableDebugVisitor(
673 QuicMakeUnique<HeaderTableDebugVisitor>(
674 connection()->helper()->GetClock(), std::move(visitor)));
675}
676
677void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
678 spdy_framer_.UpdateHeaderEncoderTableSize(value);
679}
680
681void QuicSpdySession::UpdateEnableServerPush(bool value) {
682 set_server_push_enabled(value);
683}
684
685void QuicSpdySession::set_max_uncompressed_header_bytes(
686 size_t set_max_uncompressed_header_bytes) {
687 spdy_framer_visitor_->set_max_uncompressed_header_bytes(
688 set_max_uncompressed_header_bytes);
689}
690
691void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700692 const std::string& details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500693 connection()->CloseConnection(
694 error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
695}
696
QUICHE teamc2653c42019-03-08 13:30:06 -0800697bool QuicSpdySession::HasActiveRequestStreams() const {
698 // TODO(renjietang): Exclude static streams.
699 return !dynamic_streams().empty();
700}
701
QUICHE teama6ef0a62019-03-07 20:34:33 -0500702} // namespace quic