blob: 6352d7b75adfdcbd055f2923b4c2f0ebff761602 [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
bnc3fc60df2019-07-17 11:55:10 -070012#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h"
14#include "net/third_party/quiche/src/quic/core/quic_utils.h"
15#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
20#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
21#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
23#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h"
24
25using http2::Http2DecoderAdapter;
26using spdy::HpackEntry;
27using spdy::HpackHeaderTable;
28using spdy::Http2WeightToSpdy3Priority;
29using spdy::SETTINGS_ENABLE_PUSH;
30using spdy::SETTINGS_HEADER_TABLE_SIZE;
31using spdy::SETTINGS_MAX_HEADER_LIST_SIZE;
32using spdy::Spdy3PriorityToHttp2Weight;
33using spdy::SpdyErrorCode;
34using spdy::SpdyFramer;
35using spdy::SpdyFramerDebugVisitorInterface;
36using spdy::SpdyFramerVisitorInterface;
37using spdy::SpdyFrameType;
38using spdy::SpdyHeaderBlock;
39using spdy::SpdyHeadersHandlerInterface;
40using spdy::SpdyHeadersIR;
41using spdy::SpdyKnownSettingsId;
42using spdy::SpdyPingId;
43using spdy::SpdyPriority;
44using spdy::SpdyPriorityIR;
45using spdy::SpdyPushPromiseIR;
46using spdy::SpdySerializedFrame;
47using spdy::SpdySettingsId;
48using spdy::SpdySettingsIR;
49using spdy::SpdyStreamId;
50
51namespace quic {
52
53namespace {
54
renjietangbb1c4892019-05-24 15:58:44 -070055// TODO(renjietang): remove this once HTTP/3 error codes are adopted.
56const uint16_t kHttpUnknownStreamType = 0x0D;
57
QUICHE teama6ef0a62019-03-07 20:34:33 -050058class HeaderTableDebugVisitor : public HpackHeaderTable::DebugVisitorInterface {
59 public:
60 HeaderTableDebugVisitor(const QuicClock* clock,
61 std::unique_ptr<QuicHpackDebugVisitor> visitor)
62 : clock_(clock), headers_stream_hpack_visitor_(std::move(visitor)) {}
63 HeaderTableDebugVisitor(const HeaderTableDebugVisitor&) = delete;
64 HeaderTableDebugVisitor& operator=(const HeaderTableDebugVisitor&) = delete;
65
66 int64_t OnNewEntry(const HpackEntry& entry) override {
67 QUIC_DVLOG(1) << entry.GetDebugString();
68 return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds();
69 }
70
71 void OnUseEntry(const HpackEntry& entry) override {
72 const QuicTime::Delta elapsed(
73 clock_->ApproximateNow() -
74 QuicTime::Delta::FromMicroseconds(entry.time_added()) -
75 QuicTime::Zero());
76 QUIC_DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
77 << " ms";
78 headers_stream_hpack_visitor_->OnUseEntry(elapsed);
79 }
80
81 private:
82 const QuicClock* clock_;
83 std::unique_ptr<QuicHpackDebugVisitor> headers_stream_hpack_visitor_;
84};
85
86} // namespace
87
88// A SpdyFramerVisitor that passes HEADERS frames to the QuicSpdyStream, and
89// closes the connection if any unexpected frames are received.
90class QuicSpdySession::SpdyFramerVisitor
91 : public SpdyFramerVisitorInterface,
92 public SpdyFramerDebugVisitorInterface {
93 public:
94 explicit SpdyFramerVisitor(QuicSpdySession* session) : session_(session) {}
95 SpdyFramerVisitor(const SpdyFramerVisitor&) = delete;
96 SpdyFramerVisitor& operator=(const SpdyFramerVisitor&) = delete;
97
98 SpdyHeadersHandlerInterface* OnHeaderFrameStart(
99 SpdyStreamId /* stream_id */) override {
100 return &header_list_;
101 }
102
103 void OnHeaderFrameEnd(SpdyStreamId /* stream_id */) override {
104 if (session_->IsConnected()) {
105 session_->OnHeaderList(header_list_);
106 }
107 header_list_.Clear();
108 }
109
dschinazi17d42422019-06-18 16:35:07 -0700110 void OnStreamFrameData(SpdyStreamId /*stream_id*/,
111 const char* /*data*/,
112 size_t /*len*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 CloseConnection("SPDY DATA frame received.",
114 QUIC_INVALID_HEADERS_STREAM_DATA);
115 }
116
dschinazi17d42422019-06-18 16:35:07 -0700117 void OnStreamEnd(SpdyStreamId /*stream_id*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118 // The framer invokes OnStreamEnd after processing a frame that had the fin
119 // bit set.
120 }
121
dschinazi17d42422019-06-18 16:35:07 -0700122 void OnStreamPadding(SpdyStreamId /*stream_id*/, size_t /*len*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123 CloseConnection("SPDY frame padding received.",
124 QUIC_INVALID_HEADERS_STREAM_DATA);
125 }
126
127 void OnError(Http2DecoderAdapter::SpdyFramerError error) override {
128 QuicErrorCode code = QUIC_INVALID_HEADERS_STREAM_DATA;
129 switch (error) {
130 case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
131 code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
132 break;
133 default:
134 break;
135 }
136 CloseConnection(
137 QuicStrCat("SPDY framing error: ",
138 Http2DecoderAdapter::SpdyFramerErrorToString(error)),
139 code);
140 }
141
dschinazi17d42422019-06-18 16:35:07 -0700142 void OnDataFrameHeader(SpdyStreamId /*stream_id*/,
143 size_t /*length*/,
144 bool /*fin*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500145 CloseConnection("SPDY DATA frame received.",
146 QUIC_INVALID_HEADERS_STREAM_DATA);
147 }
148
dschinazi17d42422019-06-18 16:35:07 -0700149 void OnRstStream(SpdyStreamId /*stream_id*/,
150 SpdyErrorCode /*error_code*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500151 CloseConnection("SPDY RST_STREAM frame received.",
152 QUIC_INVALID_HEADERS_STREAM_DATA);
153 }
154
155 void OnSetting(SpdySettingsId id, uint32_t value) override {
156 switch (id) {
157 case SETTINGS_HEADER_TABLE_SIZE:
158 session_->UpdateHeaderEncoderTableSize(value);
159 break;
160 case SETTINGS_ENABLE_PUSH:
161 if (session_->perspective() == Perspective::IS_SERVER) {
162 // See rfc7540, Section 6.5.2.
163 if (value > 1) {
164 CloseConnection(
165 QuicStrCat("Invalid value for SETTINGS_ENABLE_PUSH: ", value),
166 QUIC_INVALID_HEADERS_STREAM_DATA);
167 return;
168 }
169 session_->UpdateEnableServerPush(value > 0);
170 break;
171 } else {
172 CloseConnection(
173 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
174 QUIC_INVALID_HEADERS_STREAM_DATA);
175 }
176 break;
177 // TODO(fayang): Need to support SETTINGS_MAX_HEADER_LIST_SIZE when
178 // clients are actually sending it.
179 case SETTINGS_MAX_HEADER_LIST_SIZE:
180 break;
181 default:
182 CloseConnection(
183 QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id),
184 QUIC_INVALID_HEADERS_STREAM_DATA);
185 }
186 }
187
188 void OnSettingsEnd() override {}
189
dschinazi17d42422019-06-18 16:35:07 -0700190 void OnPing(SpdyPingId /*unique_id*/, bool /*is_ack*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500191 CloseConnection("SPDY PING frame received.",
192 QUIC_INVALID_HEADERS_STREAM_DATA);
193 }
194
dschinazi17d42422019-06-18 16:35:07 -0700195 void OnGoAway(SpdyStreamId /*last_accepted_stream_id*/,
196 SpdyErrorCode /*error_code*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500197 CloseConnection("SPDY GOAWAY frame received.",
198 QUIC_INVALID_HEADERS_STREAM_DATA);
199 }
200
201 void OnHeaders(SpdyStreamId stream_id,
202 bool has_priority,
203 int weight,
204 SpdyStreamId /*parent_stream_id*/,
205 bool /*exclusive*/,
206 bool fin,
dschinazi17d42422019-06-18 16:35:07 -0700207 bool /*end*/) override {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500208 if (!session_->IsConnected()) {
209 return;
210 }
211
renjietang2abedac2019-05-20 14:04:50 -0700212 if (VersionUsesQpack(session_->connection()->transport_version())) {
213 CloseConnection("HEADERS frame not allowed on headers stream.",
214 QUIC_INVALID_HEADERS_STREAM_DATA);
215 return;
216 }
217
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218 SpdyPriority priority =
219 has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
fayang476683a2019-07-25 12:42:16 -0700220 session_->OnHeaders(stream_id, has_priority,
221 spdy::SpdyStreamPrecedence(priority), fin);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222 }
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);
fayang476683a2019-07-25 12:42:16 -0700261 session_->OnPriority(stream_id, spdy::SpdyStreamPrecedence(priority));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500262 }
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
bnc2bda4092019-07-24 09:32:39 -0700292 void set_max_header_list_size(size_t max_header_list_size) {
293 header_list_.set_max_header_list_size(max_header_list_size);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500294 }
295
296 private:
vasilvvc48c8712019-03-11 13:38:16 -0700297 void CloseConnection(const std::string& details, QuicErrorCode code) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298 if (session_->IsConnected()) {
299 session_->CloseConnectionWithDetails(code, details);
300 }
301 }
302
303 private:
304 QuicSpdySession* session_;
305 QuicHeaderList header_list_;
306};
307
308QuicHpackDebugVisitor::QuicHpackDebugVisitor() {}
309
310QuicHpackDebugVisitor::~QuicHpackDebugVisitor() {}
311
312QuicSpdySession::QuicSpdySession(
313 QuicConnection* connection,
314 QuicSession::Visitor* visitor,
315 const QuicConfig& config,
316 const ParsedQuicVersionVector& supported_versions)
317 : QuicSession(connection, visitor, config, supported_versions),
318 max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
renjietang3a1bb802019-06-11 10:42:41 -0700319 max_outbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500320 server_push_enabled_(true),
321 stream_id_(
322 QuicUtils::GetInvalidStreamId(connection->transport_version())),
323 promised_stream_id_(
324 QuicUtils::GetInvalidStreamId(connection->transport_version())),
325 fin_(false),
326 frame_len_(0),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500327 supports_push_promise_(perspective() == Perspective::IS_CLIENT),
328 spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
329 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
330 h2_deframer_.set_visitor(spdy_framer_visitor_.get());
331 h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
332 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
333}
334
335QuicSpdySession::~QuicSpdySession() {
336 // Set the streams' session pointers in closed and dynamic stream lists
337 // to null to avoid subsequent use of this session.
338 for (auto& stream : *closed_streams()) {
339 static_cast<QuicSpdyStream*>(stream.get())->ClearSession();
340 }
341 for (auto const& kv : zombie_streams()) {
342 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
343 }
renjietang55d182a2019-07-12 10:26:25 -0700344 for (auto const& kv : stream_map()) {
renjietangb663b862019-07-08 16:02:39 -0700345 if (!kv.second->is_static()) {
346 static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession();
renjietang2da2afb2019-05-13 17:22:14 -0700347 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348 }
349}
350
351void QuicSpdySession::Initialize() {
352 QuicSession::Initialize();
353
dschinazi552accc2019-06-17 17:07:34 -0700354 if (!connection()->version().DoesNotHaveHeadersStream()) {
355 if (perspective() == Perspective::IS_SERVER) {
356 set_largest_peer_created_stream_id(
357 QuicUtils::GetHeadersStreamId(connection()->transport_version()));
358 } else {
359 QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
360 DCHECK_EQ(headers_stream_id, QuicUtils::GetHeadersStreamId(
361 connection()->transport_version()));
362 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500363 }
364
365 if (VersionUsesQpack(connection()->transport_version())) {
renjietangc2aa5cb2019-06-20 12:22:53 -0700366 qpack_encoder_ =
367 QuicMakeUnique<QpackEncoder>(this, &encoder_stream_sender_delegate_);
368 qpack_decoder_ =
369 QuicMakeUnique<QpackDecoder>(this, &decoder_stream_sender_delegate_);
bncbdd303e2019-07-09 05:33:17 -0700370 // TODO(b/112770235): Send SETTINGS_QPACK_MAX_TABLE_CAPACITY with value
371 // kDefaultQpackMaxDynamicTableCapacity.
372 qpack_decoder_->SetMaximumDynamicTableCapacity(
373 kDefaultQpackMaxDynamicTableCapacity);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500374 }
375
renjietang9818f8c2019-07-16 11:12:27 -0700376 auto headers_stream = QuicMakeUnique<QuicHeadersStream>((this));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500377 DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()),
renjietang9818f8c2019-07-16 11:12:27 -0700378 headers_stream->id());
renjietang3a1bb802019-06-11 10:42:41 -0700379
renjietang9818f8c2019-07-16 11:12:27 -0700380 headers_stream_ = headers_stream.get();
381 RegisterStaticStream(std::move(headers_stream),
renjietang0e9980b2019-07-11 12:00:21 -0700382 /*stream_already_counted = */ false);
renjietangb663b862019-07-08 16:02:39 -0700383
384 if (VersionHasStreamType(connection()->transport_version())) {
renjietang3a1bb802019-06-11 10:42:41 -0700385 auto send_control = QuicMakeUnique<QuicSendControlStream>(
renjietang7498c8c2019-07-02 19:28:42 -0700386 GetNextOutgoingUnidirectionalStreamId(), this,
387 max_inbound_header_list_size_);
renjietang3a1bb802019-06-11 10:42:41 -0700388 send_control_stream_ = send_control.get();
renjietang0e9980b2019-07-11 12:00:21 -0700389 RegisterStaticStream(std::move(send_control),
390 /*stream_already_counted = */ false);
renjietangfbeb5bf2019-04-19 15:06:20 -0700391 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500392
bnc2bda4092019-07-24 09:32:39 -0700393 spdy_framer_visitor_->set_max_header_list_size(max_inbound_header_list_size_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394
395 // Limit HPACK buffering to 2x header list size limit.
bnc2bda4092019-07-24 09:32:39 -0700396 h2_deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
397 2 * max_inbound_header_list_size_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500398}
399
dschinazi17d42422019-06-18 16:35:07 -0700400void QuicSpdySession::OnDecoderStreamError(QuicStringPiece /*error_message*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 DCHECK(VersionUsesQpack(connection()->transport_version()));
402
403 // TODO(112770235): Signal connection error on decoder stream errors.
404 QUIC_NOTREACHED();
405}
406
dschinazi17d42422019-06-18 16:35:07 -0700407void QuicSpdySession::OnEncoderStreamError(QuicStringPiece /*error_message*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500408 DCHECK(VersionUsesQpack(connection()->transport_version()));
409
410 // TODO(112770235): Signal connection error on encoder stream errors.
411 QUIC_NOTREACHED();
412}
413
fayang476683a2019-07-25 12:42:16 -0700414void QuicSpdySession::OnStreamHeadersPriority(
415 QuicStreamId stream_id,
416 const spdy::SpdyStreamPrecedence& precedence) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500417 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 }
fayang476683a2019-07-25 12:42:16 -0700422 stream->OnStreamHeadersPriority(precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500423}
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
fayang476683a2019-07-25 12:42:16 -0700463void QuicSpdySession::OnPriorityFrame(
464 QuicStreamId stream_id,
465 const spdy::SpdyStreamPrecedence& precedence) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500466 QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
467 if (!stream) {
468 // It's quite possible to receive a PRIORITY frame after a stream has been
469 // reset.
470 return;
471 }
fayang476683a2019-07-25 12:42:16 -0700472 stream->OnPriorityFrame(precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500473}
474
475size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
476 return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
477 iov.iov_len);
478}
479
480size_t QuicSpdySession::WriteHeadersOnHeadersStream(
481 QuicStreamId id,
482 SpdyHeaderBlock headers,
483 bool fin,
fayang476683a2019-07-25 12:42:16 -0700484 const spdy::SpdyStreamPrecedence& precedence,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700486 DCHECK(!VersionUsesQpack(connection()->transport_version()));
487
QUICHE teama6ef0a62019-03-07 20:34:33 -0500488 return WriteHeadersOnHeadersStreamImpl(
489 id, std::move(headers), fin,
fayang476683a2019-07-25 12:42:16 -0700490 /* parent_stream_id = */ 0,
491 Spdy3PriorityToHttp2Weight(precedence.spdy3_priority()),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500492 /* exclusive = */ false, std::move(ack_listener));
493}
494
495size_t QuicSpdySession::WritePriority(QuicStreamId id,
496 QuicStreamId parent_stream_id,
497 int weight,
498 bool exclusive) {
499 if (connection()->transport_version() <= QUIC_VERSION_39) {
500 return 0;
501 }
502 SpdyPriorityIR priority_frame(id, parent_stream_id, weight, exclusive);
503 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700504 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500505 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
506 return frame.size();
507}
508
renjietang7498c8c2019-07-02 19:28:42 -0700509void QuicSpdySession::WriteH3Priority(const PriorityFrame& priority) {
510 DCHECK(VersionHasStreamType(connection()->transport_version()));
511 DCHECK(perspective() == Perspective::IS_CLIENT)
512 << "Server must not send priority";
513
514 send_control_stream_->WritePriority(priority);
515}
516
renjietangf4f47122019-07-22 12:08:53 -0700517void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
518 QuicStreamId promised_stream_id,
519 SpdyHeaderBlock headers) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500520 if (perspective() == Perspective::IS_CLIENT) {
521 QUIC_BUG << "Client shouldn't send PUSH_PROMISE";
renjietangf4f47122019-07-22 12:08:53 -0700522 return;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500523 }
524
525 SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
526 std::move(headers));
527 // PUSH_PROMISE must not be the last frame sent out, at least followed by
528 // response headers.
529 push_promise.set_fin(false);
530
531 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
renjietangfbeb5bf2019-04-19 15:06:20 -0700532 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500533 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500534}
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())) {
renjietang7498c8c2019-07-02 19:28:42 -0700538 send_control_stream_->SendSettingsFrame();
renjietang3a1bb802019-06-11 10:42:41 -0700539 return;
540 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500541 SpdySettingsIR settings_frame;
542 settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, value);
543
544 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(settings_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700545 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500546 QuicStringPiece(frame.data(), frame.size()), false, nullptr);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500547}
548
549QpackEncoder* QuicSpdySession::qpack_encoder() {
550 DCHECK(VersionUsesQpack(connection()->transport_version()));
551
552 return qpack_encoder_.get();
553}
554
555QpackDecoder* QuicSpdySession::qpack_decoder() {
556 DCHECK(VersionUsesQpack(connection()->transport_version()));
557
558 return qpack_decoder_.get();
559}
560
561QuicSpdyStream* QuicSpdySession::GetSpdyDataStream(
562 const QuicStreamId stream_id) {
renjietang880d2432019-07-16 13:14:37 -0700563 QuicStream* stream = nullptr;
564 if (GetQuicReloadableFlag(quic_inline_getorcreatedynamicstream) &&
565 GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream)) {
566 QUIC_RELOADABLE_FLAG_COUNT(quic_inline_getorcreatedynamicstream);
567 stream = GetOrCreateStream(stream_id);
568 } else {
569 stream = GetOrCreateDynamicStream(stream_id);
570 }
renjietang495d5972019-07-10 14:51:28 -0700571 if (GetQuicReloadableFlag(quic_handle_staticness_for_spdy_stream) && stream &&
572 stream->is_static()) {
573 QUIC_RELOADABLE_FLAG_COUNT(quic_handle_staticness_for_spdy_stream);
574 QUIC_BUG << "GetSpdyDataStream returns static stream";
575 connection()->CloseConnection(
576 QUIC_INVALID_STREAM_ID, "stream is static",
577 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
578 return nullptr;
579 }
rchda26cdb2019-05-17 11:57:37 -0700580 DCHECK(!stream || !stream->is_static());
581 return static_cast<QuicSpdyStream*>(stream);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500582}
583
584void QuicSpdySession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
585 QuicSession::OnCryptoHandshakeEvent(event);
586 if (event == HANDSHAKE_CONFIRMED && config()->SupportMaxHeaderListSize()) {
587 SendMaxHeaderListSize(max_inbound_header_list_size_);
588 }
589}
590
591// True if there are open HTTP requests.
592bool QuicSpdySession::ShouldKeepConnectionAlive() const {
593 // Change to check if there are open HTTP requests.
594 // When IETF QUIC control and QPACK streams are used, those will need to be
595 // subtracted from this count to ensure only request streams are counted.
596 return GetNumOpenDynamicStreams() > 0;
597}
598
renjietange76b2da2019-05-13 14:50:23 -0700599bool QuicSpdySession::UsesPendingStreams() const {
bnc36c47282019-06-21 05:17:59 -0700600 // QuicSpdySession supports PendingStreams, therefore this method should
601 // eventually just return true. However, pending streams can only be used if
602 // unidirectional stream type is supported.
603 return VersionHasStreamType(connection()->transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500604}
605
606size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
607 QuicStreamId id,
608 spdy::SpdyHeaderBlock headers,
609 bool fin,
610 QuicStreamId parent_stream_id,
611 int weight,
612 bool exclusive,
613 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) {
renjietang2abedac2019-05-20 14:04:50 -0700614 DCHECK(!VersionUsesQpack(connection()->transport_version()));
615
QUICHE teama6ef0a62019-03-07 20:34:33 -0500616 SpdyHeadersIR headers_frame(id, std::move(headers));
617 headers_frame.set_fin(fin);
618 if (perspective() == Perspective::IS_CLIENT) {
619 headers_frame.set_has_priority(true);
620 headers_frame.set_parent_stream_id(parent_stream_id);
621 headers_frame.set_weight(weight);
622 headers_frame.set_exclusive(exclusive);
623 }
624 SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
renjietangfbeb5bf2019-04-19 15:06:20 -0700625 headers_stream()->WriteOrBufferData(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500626 QuicStringPiece(frame.data(), frame.size()), false,
627 std::move(ack_listener));
628 return frame.size();
629}
630
dschinazi17d42422019-06-18 16:35:07 -0700631void QuicSpdySession::OnPromiseHeaderList(
632 QuicStreamId /*stream_id*/,
633 QuicStreamId /*promised_stream_id*/,
634 size_t /*frame_len*/,
635 const QuicHeaderList& /*header_list*/) {
vasilvvc48c8712019-03-11 13:38:16 -0700636 std::string error =
637 "OnPromiseHeaderList should be overridden in client code.";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500638 QUIC_BUG << error;
639 connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
640 ConnectionCloseBehavior::SILENT_CLOSE);
641}
642
643bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
644 return false;
645}
646
647void QuicSpdySession::OnHeaders(SpdyStreamId stream_id,
648 bool has_priority,
fayang476683a2019-07-25 12:42:16 -0700649 const spdy::SpdyStreamPrecedence& precedence,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500650 bool fin) {
651 if (has_priority) {
652 if (perspective() == Perspective::IS_CLIENT) {
653 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
654 "Server must not send priorities.");
655 return;
656 }
fayang476683a2019-07-25 12:42:16 -0700657 OnStreamHeadersPriority(stream_id, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500658 } else {
659 if (perspective() == Perspective::IS_SERVER) {
660 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
661 "Client must send priorities.");
662 return;
663 }
664 }
665 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
666 stream_id_);
667 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
668 promised_stream_id_);
669 stream_id_ = stream_id;
670 fin_ = fin;
671}
672
673void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
renjietangcd8fab32019-06-17 16:22:16 -0700674 SpdyStreamId promised_stream_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500675 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
676 stream_id_);
677 DCHECK_EQ(QuicUtils::GetInvalidStreamId(connection()->transport_version()),
678 promised_stream_id_);
679 stream_id_ = stream_id;
680 promised_stream_id_ = promised_stream_id;
681}
682
683// TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
684// This occurs in many places in this file.
685void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
fayang476683a2019-07-25 12:42:16 -0700686 const spdy::SpdyStreamPrecedence& precedence) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500687 if (perspective() == Perspective::IS_CLIENT) {
688 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
689 "Server must not send PRIORITY frames.");
690 return;
691 }
fayang476683a2019-07-25 12:42:16 -0700692 OnPriorityFrame(stream_id, precedence);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500693}
694
695void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
696 QUIC_DVLOG(1) << "Received header list for stream " << stream_id_ << ": "
697 << header_list.DebugString();
698 if (promised_stream_id_ ==
699 QuicUtils::GetInvalidStreamId(connection()->transport_version())) {
700 OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
701 } else {
702 OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
703 header_list);
704 }
705 // Reset state for the next frame.
706 promised_stream_id_ =
707 QuicUtils::GetInvalidStreamId(connection()->transport_version());
708 stream_id_ = QuicUtils::GetInvalidStreamId(connection()->transport_version());
709 fin_ = false;
710 frame_len_ = 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500711}
712
713void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
714 frame_len_ += frame_len;
715}
716
717void QuicSpdySession::SetHpackEncoderDebugVisitor(
718 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
719 spdy_framer_.SetEncoderHeaderTableDebugVisitor(
720 std::unique_ptr<HeaderTableDebugVisitor>(new HeaderTableDebugVisitor(
721 connection()->helper()->GetClock(), std::move(visitor))));
722}
723
724void QuicSpdySession::SetHpackDecoderDebugVisitor(
725 std::unique_ptr<QuicHpackDebugVisitor> visitor) {
726 h2_deframer_.SetDecoderHeaderTableDebugVisitor(
727 QuicMakeUnique<HeaderTableDebugVisitor>(
728 connection()->helper()->GetClock(), std::move(visitor)));
729}
730
731void QuicSpdySession::UpdateHeaderEncoderTableSize(uint32_t value) {
732 spdy_framer_.UpdateHeaderEncoderTableSize(value);
733}
734
735void QuicSpdySession::UpdateEnableServerPush(bool value) {
736 set_server_push_enabled(value);
737}
738
QUICHE teama6ef0a62019-03-07 20:34:33 -0500739void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
vasilvvc48c8712019-03-11 13:38:16 -0700740 const std::string& details) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500741 connection()->CloseConnection(
742 error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
743}
744
QUICHE teamc2653c42019-03-08 13:30:06 -0800745bool QuicSpdySession::HasActiveRequestStreams() const {
renjietangfbeb5bf2019-04-19 15:06:20 -0700746 // In the case where session is destructed by calling
renjietang55d182a2019-07-12 10:26:25 -0700747 // stream_map().clear(), we will have incorrect accounting here.
renjietangfbeb5bf2019-04-19 15:06:20 -0700748 // TODO(renjietang): Modify destructors and make this a DCHECK.
renjietang55d182a2019-07-12 10:26:25 -0700749 if (static_cast<size_t>(stream_map().size()) >
renjietangfbeb5bf2019-04-19 15:06:20 -0700750 num_incoming_static_streams() + num_outgoing_static_streams()) {
renjietang55d182a2019-07-12 10:26:25 -0700751 return stream_map().size() - num_incoming_static_streams() -
renjietangfbeb5bf2019-04-19 15:06:20 -0700752 num_outgoing_static_streams() >
753 0;
754 }
755 return false;
QUICHE teamc2653c42019-03-08 13:30:06 -0800756}
757
renjietangbb1c4892019-05-24 15:58:44 -0700758bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
759 DCHECK(VersionHasStreamType(connection()->transport_version()));
renjietanga553da02019-06-24 11:57:04 -0700760 DCHECK(connection()->connected());
renjietang0c558862019-05-08 13:26:23 -0700761 struct iovec iov;
762 if (!pending->sequencer()->GetReadableRegion(&iov)) {
renjietangbb1c4892019-05-24 15:58:44 -0700763 // The first byte hasn't been received yet.
764 return false;
renjietang0c558862019-05-08 13:26:23 -0700765 }
766
767 QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len);
renjietangbb1c4892019-05-24 15:58:44 -0700768 uint8_t stream_type_length = reader.PeekVarInt62Length();
renjietang0c558862019-05-08 13:26:23 -0700769 uint64_t stream_type = 0;
770 if (!reader.ReadVarInt62(&stream_type)) {
renjietangbb1c4892019-05-24 15:58:44 -0700771 return false;
renjietang0c558862019-05-08 13:26:23 -0700772 }
renjietangbb1c4892019-05-24 15:58:44 -0700773 pending->MarkConsumed(stream_type_length);
renjietang0c558862019-05-08 13:26:23 -0700774
renjietang0c558862019-05-08 13:26:23 -0700775 switch (stream_type) {
renjietang3a1bb802019-06-11 10:42:41 -0700776 case kControlStream: { // HTTP/3 control stream.
777 auto receive_stream = QuicMakeUnique<QuicReceiveControlStream>(pending);
778 receive_control_stream_ = receive_stream.get();
renjietang0e9980b2019-07-11 12:00:21 -0700779 RegisterStaticStream(std::move(receive_stream),
780 /*stream_already_counted = */ true);
renjietang3a1bb802019-06-11 10:42:41 -0700781 receive_control_stream_->SetUnblocked();
782 return true;
783 }
renjietangbb1c4892019-05-24 15:58:44 -0700784 case kServerPushStream: { // Push Stream.
renjietangbaea59c2019-05-29 15:08:14 -0700785 QuicSpdyStream* stream = CreateIncomingStream(pending);
renjietangbb1c4892019-05-24 15:58:44 -0700786 stream->SetUnblocked();
787 return true;
788 }
789 case kQpackEncoderStream: // QPACK encoder stream.
renjietang0c558862019-05-08 13:26:23 -0700790 // TODO(bnc): Create QPACK encoder stream.
791 break;
renjietangbb1c4892019-05-24 15:58:44 -0700792 case kQpackDecoderStream: // QPACK decoder stream.
renjietang0c558862019-05-08 13:26:23 -0700793 // TODO(bnc): Create QPACK decoder stream.
794 break;
795 default:
renjietangbb1c4892019-05-24 15:58:44 -0700796 SendStopSending(kHttpUnknownStreamType, pending->id());
renjietang0c558862019-05-08 13:26:23 -0700797 }
renjietangbb1c4892019-05-24 15:58:44 -0700798 return false;
renjietang0c558862019-05-08 13:26:23 -0700799}
800
QUICHE teama6ef0a62019-03-07 20:34:33 -0500801} // namespace quic