• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 "quiche/quic/core/http/quic_spdy_session.h"
6 
7 #include <algorithm>
8 #include <cstdint>
9 #include <limits>
10 #include <memory>
11 #include <string>
12 #include <utility>
13 
14 #include "absl/base/attributes.h"
15 #include "absl/strings/numbers.h"
16 #include "absl/strings/str_cat.h"
17 #include "absl/strings/string_view.h"
18 #include "quiche/quic/core/http/http_constants.h"
19 #include "quiche/quic/core/http/http_decoder.h"
20 #include "quiche/quic/core/http/http_frames.h"
21 #include "quiche/quic/core/http/quic_headers_stream.h"
22 #include "quiche/quic/core/http/web_transport_http3.h"
23 #include "quiche/quic/core/quic_error_codes.h"
24 #include "quiche/quic/core/quic_types.h"
25 #include "quiche/quic/core/quic_utils.h"
26 #include "quiche/quic/core/quic_versions.h"
27 #include "quiche/quic/platform/api/quic_bug_tracker.h"
28 #include "quiche/quic/platform/api/quic_exported_stats.h"
29 #include "quiche/quic/platform/api/quic_flag_utils.h"
30 #include "quiche/quic/platform/api/quic_flags.h"
31 #include "quiche/quic/platform/api/quic_logging.h"
32 #include "quiche/quic/platform/api/quic_stack_trace.h"
33 #include "quiche/common/platform/api/quiche_mem_slice.h"
34 #include "quiche/spdy/core/http2_frame_decoder_adapter.h"
35 
36 using http2::Http2DecoderAdapter;
37 using spdy::Http2HeaderBlock;
38 using spdy::Http2WeightToSpdy3Priority;
39 using spdy::Spdy3PriorityToHttp2Weight;
40 using spdy::SpdyErrorCode;
41 using spdy::SpdyFramer;
42 using spdy::SpdyFramerDebugVisitorInterface;
43 using spdy::SpdyFramerVisitorInterface;
44 using spdy::SpdyFrameType;
45 using spdy::SpdyHeadersHandlerInterface;
46 using spdy::SpdyHeadersIR;
47 using spdy::SpdyPingId;
48 using spdy::SpdyPriority;
49 using spdy::SpdyPriorityIR;
50 using spdy::SpdyPushPromiseIR;
51 using spdy::SpdySerializedFrame;
52 using spdy::SpdySettingsId;
53 using spdy::SpdyStreamId;
54 
55 namespace quic {
56 
57 ABSL_CONST_INIT const size_t kMaxUnassociatedWebTransportStreams = 24;
58 
59 namespace {
60 
61 // Limit on HPACK encoder dynamic table size.
62 // Only used for Google QUIC, not IETF QUIC.
63 constexpr uint64_t kHpackEncoderDynamicTableSizeLimit = 16384;
64 
65 #define ENDPOINT \
66   (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
67 
68 // Class to forward ACCEPT_CH frame to QuicSpdySession,
69 // and ignore every other frame.
70 class AlpsFrameDecoder : public HttpDecoder::Visitor {
71  public:
AlpsFrameDecoder(QuicSpdySession * session)72   explicit AlpsFrameDecoder(QuicSpdySession* session) : session_(session) {}
73   ~AlpsFrameDecoder() override = default;
74 
75   // HttpDecoder::Visitor implementation.
OnError(HttpDecoder *)76   void OnError(HttpDecoder* /*decoder*/) override {}
OnMaxPushIdFrame()77   bool OnMaxPushIdFrame() override {
78     error_detail_ = "MAX_PUSH_ID frame forbidden";
79     return false;
80   }
OnGoAwayFrame(const GoAwayFrame &)81   bool OnGoAwayFrame(const GoAwayFrame& /*frame*/) override {
82     error_detail_ = "GOAWAY frame forbidden";
83     return false;
84   }
OnSettingsFrameStart(QuicByteCount)85   bool OnSettingsFrameStart(QuicByteCount /*header_length*/) override {
86     return true;
87   }
OnSettingsFrame(const SettingsFrame & frame)88   bool OnSettingsFrame(const SettingsFrame& frame) override {
89     if (settings_frame_received_via_alps_) {
90       error_detail_ = "multiple SETTINGS frames";
91       return false;
92     }
93 
94     settings_frame_received_via_alps_ = true;
95 
96     error_detail_ = session_->OnSettingsFrameViaAlps(frame);
97     return !error_detail_;
98   }
OnDataFrameStart(QuicByteCount,QuicByteCount)99   bool OnDataFrameStart(QuicByteCount /*header_length*/, QuicByteCount
100                         /*payload_length*/) override {
101     error_detail_ = "DATA frame forbidden";
102     return false;
103   }
OnDataFramePayload(absl::string_view)104   bool OnDataFramePayload(absl::string_view /*payload*/) override {
105     QUICHE_NOTREACHED();
106     return false;
107   }
OnDataFrameEnd()108   bool OnDataFrameEnd() override {
109     QUICHE_NOTREACHED();
110     return false;
111   }
OnHeadersFrameStart(QuicByteCount,QuicByteCount)112   bool OnHeadersFrameStart(QuicByteCount /*header_length*/,
113                            QuicByteCount /*payload_length*/) override {
114     error_detail_ = "HEADERS frame forbidden";
115     return false;
116   }
OnHeadersFramePayload(absl::string_view)117   bool OnHeadersFramePayload(absl::string_view /*payload*/) override {
118     QUICHE_NOTREACHED();
119     return false;
120   }
OnHeadersFrameEnd()121   bool OnHeadersFrameEnd() override {
122     QUICHE_NOTREACHED();
123     return false;
124   }
OnPriorityUpdateFrameStart(QuicByteCount)125   bool OnPriorityUpdateFrameStart(QuicByteCount /*header_length*/) override {
126     error_detail_ = "PRIORITY_UPDATE frame forbidden";
127     return false;
128   }
OnPriorityUpdateFrame(const PriorityUpdateFrame &)129   bool OnPriorityUpdateFrame(const PriorityUpdateFrame& /*frame*/) override {
130     QUICHE_NOTREACHED();
131     return false;
132   }
OnAcceptChFrameStart(QuicByteCount)133   bool OnAcceptChFrameStart(QuicByteCount /*header_length*/) override {
134     return true;
135   }
OnAcceptChFrame(const AcceptChFrame & frame)136   bool OnAcceptChFrame(const AcceptChFrame& frame) override {
137     session_->OnAcceptChFrameReceivedViaAlps(frame);
138     return true;
139   }
OnWebTransportStreamFrameType(QuicByteCount,WebTransportSessionId)140   void OnWebTransportStreamFrameType(
141       QuicByteCount /*header_length*/,
142       WebTransportSessionId /*session_id*/) override {
143     QUICHE_NOTREACHED();
144   }
OnUnknownFrameStart(uint64_t,QuicByteCount,QuicByteCount)145   bool OnUnknownFrameStart(uint64_t /*frame_type*/,
146                            QuicByteCount
147                            /*header_length*/,
148                            QuicByteCount /*payload_length*/) override {
149     return true;
150   }
OnUnknownFramePayload(absl::string_view)151   bool OnUnknownFramePayload(absl::string_view /*payload*/) override {
152     return true;
153   }
OnUnknownFrameEnd()154   bool OnUnknownFrameEnd() override { return true; }
155 
error_detail() const156   const absl::optional<std::string>& error_detail() const {
157     return error_detail_;
158   }
159 
160  private:
161   QuicSpdySession* const session_;
162   absl::optional<std::string> error_detail_;
163 
164   // True if SETTINGS frame has been received via ALPS.
165   bool settings_frame_received_via_alps_ = false;
166 };
167 
168 }  // namespace
169 
170 // A SpdyFramerVisitor that passes HEADERS frames to the QuicSpdyStream, and
171 // closes the connection if any unexpected frames are received.
172 class QuicSpdySession::SpdyFramerVisitor
173     : public SpdyFramerVisitorInterface,
174       public SpdyFramerDebugVisitorInterface {
175  public:
SpdyFramerVisitor(QuicSpdySession * session)176   explicit SpdyFramerVisitor(QuicSpdySession* session) : session_(session) {}
177   SpdyFramerVisitor(const SpdyFramerVisitor&) = delete;
178   SpdyFramerVisitor& operator=(const SpdyFramerVisitor&) = delete;
179 
OnHeaderFrameStart(SpdyStreamId)180   SpdyHeadersHandlerInterface* OnHeaderFrameStart(
181       SpdyStreamId /* stream_id */) override {
182     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
183     return &header_list_;
184   }
185 
OnHeaderFrameEnd(SpdyStreamId)186   void OnHeaderFrameEnd(SpdyStreamId /* stream_id */) override {
187     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
188 
189     LogHeaderCompressionRatioHistogram(
190         /* using_qpack = */ false,
191         /* is_sent = */ false, header_list_.compressed_header_bytes(),
192         header_list_.uncompressed_header_bytes());
193 
194     if (session_->IsConnected()) {
195       session_->OnHeaderList(header_list_);
196     }
197     header_list_.Clear();
198   }
199 
OnStreamFrameData(SpdyStreamId,const char *,size_t)200   void OnStreamFrameData(SpdyStreamId /*stream_id*/, const char* /*data*/,
201                          size_t /*len*/) override {
202     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
203     CloseConnection("SPDY DATA frame received.",
204                     QUIC_INVALID_HEADERS_STREAM_DATA);
205   }
206 
OnStreamEnd(SpdyStreamId)207   void OnStreamEnd(SpdyStreamId /*stream_id*/) override {
208     // The framer invokes OnStreamEnd after processing a frame that had the fin
209     // bit set.
210   }
211 
OnStreamPadding(SpdyStreamId,size_t)212   void OnStreamPadding(SpdyStreamId /*stream_id*/, size_t /*len*/) override {
213     CloseConnection("SPDY frame padding received.",
214                     QUIC_INVALID_HEADERS_STREAM_DATA);
215   }
216 
OnError(Http2DecoderAdapter::SpdyFramerError error,std::string detailed_error)217   void OnError(Http2DecoderAdapter::SpdyFramerError error,
218                std::string detailed_error) override {
219     QuicErrorCode code;
220     switch (error) {
221       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INDEX_VARINT_ERROR:
222         code = QUIC_HPACK_INDEX_VARINT_ERROR;
223         break;
224       case Http2DecoderAdapter::SpdyFramerError::
225           SPDY_HPACK_NAME_LENGTH_VARINT_ERROR:
226         code = QUIC_HPACK_NAME_LENGTH_VARINT_ERROR;
227         break;
228       case Http2DecoderAdapter::SpdyFramerError::
229           SPDY_HPACK_VALUE_LENGTH_VARINT_ERROR:
230         code = QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR;
231         break;
232       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_NAME_TOO_LONG:
233         code = QUIC_HPACK_NAME_TOO_LONG;
234         break;
235       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_VALUE_TOO_LONG:
236         code = QUIC_HPACK_VALUE_TOO_LONG;
237         break;
238       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_NAME_HUFFMAN_ERROR:
239         code = QUIC_HPACK_NAME_HUFFMAN_ERROR;
240         break;
241       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_VALUE_HUFFMAN_ERROR:
242         code = QUIC_HPACK_VALUE_HUFFMAN_ERROR;
243         break;
244       case Http2DecoderAdapter::SpdyFramerError::
245           SPDY_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE:
246         code = QUIC_HPACK_MISSING_DYNAMIC_TABLE_SIZE_UPDATE;
247         break;
248       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INVALID_INDEX:
249         code = QUIC_HPACK_INVALID_INDEX;
250         break;
251       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_INVALID_NAME_INDEX:
252         code = QUIC_HPACK_INVALID_NAME_INDEX;
253         break;
254       case Http2DecoderAdapter::SpdyFramerError::
255           SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED:
256         code = QUIC_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_NOT_ALLOWED;
257         break;
258       case Http2DecoderAdapter::SpdyFramerError::
259           SPDY_HPACK_INITIAL_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK:
260         code = QUIC_HPACK_INITIAL_TABLE_SIZE_UPDATE_IS_ABOVE_LOW_WATER_MARK;
261         break;
262       case Http2DecoderAdapter::SpdyFramerError::
263           SPDY_HPACK_DYNAMIC_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING:
264         code = QUIC_HPACK_TABLE_SIZE_UPDATE_IS_ABOVE_ACKNOWLEDGED_SETTING;
265         break;
266       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_TRUNCATED_BLOCK:
267         code = QUIC_HPACK_TRUNCATED_BLOCK;
268         break;
269       case Http2DecoderAdapter::SpdyFramerError::SPDY_HPACK_FRAGMENT_TOO_LONG:
270         code = QUIC_HPACK_FRAGMENT_TOO_LONG;
271         break;
272       case Http2DecoderAdapter::SpdyFramerError::
273           SPDY_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT:
274         code = QUIC_HPACK_COMPRESSED_HEADER_SIZE_EXCEEDS_LIMIT;
275         break;
276       case Http2DecoderAdapter::SpdyFramerError::SPDY_DECOMPRESS_FAILURE:
277         code = QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE;
278         break;
279       default:
280         code = QUIC_INVALID_HEADERS_STREAM_DATA;
281     }
282     CloseConnection(
283         absl::StrCat("SPDY framing error: ", detailed_error,
284                      Http2DecoderAdapter::SpdyFramerErrorToString(error)),
285         code);
286   }
287 
OnDataFrameHeader(SpdyStreamId,size_t,bool)288   void OnDataFrameHeader(SpdyStreamId /*stream_id*/, size_t /*length*/,
289                          bool /*fin*/) override {
290     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
291     CloseConnection("SPDY DATA frame received.",
292                     QUIC_INVALID_HEADERS_STREAM_DATA);
293   }
294 
OnRstStream(SpdyStreamId,SpdyErrorCode)295   void OnRstStream(SpdyStreamId /*stream_id*/,
296                    SpdyErrorCode /*error_code*/) override {
297     CloseConnection("SPDY RST_STREAM frame received.",
298                     QUIC_INVALID_HEADERS_STREAM_DATA);
299   }
300 
OnSetting(SpdySettingsId id,uint32_t value)301   void OnSetting(SpdySettingsId id, uint32_t value) override {
302     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
303     session_->OnSetting(id, value);
304   }
305 
OnSettingsEnd()306   void OnSettingsEnd() override {
307     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
308   }
309 
OnPing(SpdyPingId,bool)310   void OnPing(SpdyPingId /*unique_id*/, bool /*is_ack*/) override {
311     CloseConnection("SPDY PING frame received.",
312                     QUIC_INVALID_HEADERS_STREAM_DATA);
313   }
314 
OnGoAway(SpdyStreamId,SpdyErrorCode)315   void OnGoAway(SpdyStreamId /*last_accepted_stream_id*/,
316                 SpdyErrorCode /*error_code*/) override {
317     CloseConnection("SPDY GOAWAY frame received.",
318                     QUIC_INVALID_HEADERS_STREAM_DATA);
319   }
320 
OnHeaders(SpdyStreamId stream_id,size_t,bool has_priority,int weight,SpdyStreamId,bool,bool fin,bool)321   void OnHeaders(SpdyStreamId stream_id, size_t /*payload_length*/,
322                  bool has_priority, int weight,
323                  SpdyStreamId /*parent_stream_id*/, bool /*exclusive*/,
324                  bool fin, bool /*end*/) override {
325     if (!session_->IsConnected()) {
326       return;
327     }
328 
329     if (VersionUsesHttp3(session_->transport_version())) {
330       CloseConnection("HEADERS frame not allowed on headers stream.",
331                       QUIC_INVALID_HEADERS_STREAM_DATA);
332       return;
333     }
334 
335     QUIC_BUG_IF(quic_bug_12477_1,
336                 session_->destruction_indicator() != 123456789)
337         << "QuicSpdyStream use after free. "
338         << session_->destruction_indicator() << QuicStackTrace();
339 
340     SpdyPriority priority =
341         has_priority ? Http2WeightToSpdy3Priority(weight) : 0;
342     session_->OnHeaders(stream_id, has_priority,
343                         spdy::SpdyStreamPrecedence(priority), fin);
344   }
345 
OnWindowUpdate(SpdyStreamId,int)346   void OnWindowUpdate(SpdyStreamId /*stream_id*/,
347                       int /*delta_window_size*/) override {
348     CloseConnection("SPDY WINDOW_UPDATE frame received.",
349                     QUIC_INVALID_HEADERS_STREAM_DATA);
350   }
351 
OnPushPromise(SpdyStreamId stream_id,SpdyStreamId promised_stream_id,bool)352   void OnPushPromise(SpdyStreamId stream_id, SpdyStreamId promised_stream_id,
353                      bool /*end*/) override {
354     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
355     if (session_->perspective() != Perspective::IS_CLIENT) {
356       CloseConnection("PUSH_PROMISE not supported.",
357                       QUIC_INVALID_HEADERS_STREAM_DATA);
358       return;
359     }
360     if (!session_->IsConnected()) {
361       return;
362     }
363     session_->OnPushPromise(stream_id, promised_stream_id);
364   }
365 
OnContinuation(SpdyStreamId,size_t,bool)366   void OnContinuation(SpdyStreamId /*stream_id*/, size_t /*payload_size*/,
367                       bool /*end*/) override {}
368 
OnPriority(SpdyStreamId stream_id,SpdyStreamId,int weight,bool)369   void OnPriority(SpdyStreamId stream_id, SpdyStreamId /* parent_id */,
370                   int weight, bool /* exclusive */) override {
371     QUICHE_DCHECK(!VersionUsesHttp3(session_->transport_version()));
372     if (!session_->IsConnected()) {
373       return;
374     }
375     SpdyPriority priority = Http2WeightToSpdy3Priority(weight);
376     session_->OnPriority(stream_id, spdy::SpdyStreamPrecedence(priority));
377   }
378 
OnPriorityUpdate(SpdyStreamId,absl::string_view)379   void OnPriorityUpdate(SpdyStreamId /*prioritized_stream_id*/,
380                         absl::string_view /*priority_field_value*/) override {}
381 
OnUnknownFrame(SpdyStreamId,uint8_t)382   bool OnUnknownFrame(SpdyStreamId /*stream_id*/,
383                       uint8_t /*frame_type*/) override {
384     CloseConnection("Unknown frame type received.",
385                     QUIC_INVALID_HEADERS_STREAM_DATA);
386     return false;
387   }
388 
OnUnknownFrameStart(SpdyStreamId,size_t,uint8_t,uint8_t)389   void OnUnknownFrameStart(SpdyStreamId /*stream_id*/, size_t /*length*/,
390                            uint8_t /*type*/, uint8_t /*flags*/) override {}
391 
OnUnknownFramePayload(SpdyStreamId,absl::string_view)392   void OnUnknownFramePayload(SpdyStreamId /*stream_id*/,
393                              absl::string_view /*payload*/) override {}
394 
395   // SpdyFramerDebugVisitorInterface implementation
OnSendCompressedFrame(SpdyStreamId,SpdyFrameType,size_t payload_len,size_t frame_len)396   void OnSendCompressedFrame(SpdyStreamId /*stream_id*/, SpdyFrameType /*type*/,
397                              size_t payload_len, size_t frame_len) override {
398     if (payload_len == 0) {
399       QUIC_BUG(quic_bug_10360_1) << "Zero payload length.";
400       return;
401     }
402     int compression_pct = 100 - (100 * frame_len) / payload_len;
403     QUIC_DVLOG(1) << "Net.QuicHpackCompressionPercentage: " << compression_pct;
404   }
405 
OnReceiveCompressedFrame(SpdyStreamId,SpdyFrameType,size_t frame_len)406   void OnReceiveCompressedFrame(SpdyStreamId /*stream_id*/,
407                                 SpdyFrameType /*type*/,
408                                 size_t frame_len) override {
409     if (session_->IsConnected()) {
410       session_->OnCompressedFrameSize(frame_len);
411     }
412   }
413 
set_max_header_list_size(size_t max_header_list_size)414   void set_max_header_list_size(size_t max_header_list_size) {
415     header_list_.set_max_header_list_size(max_header_list_size);
416   }
417 
418  private:
CloseConnection(const std::string & details,QuicErrorCode code)419   void CloseConnection(const std::string& details, QuicErrorCode code) {
420     if (session_->IsConnected()) {
421       session_->CloseConnectionWithDetails(code, details);
422     }
423   }
424 
425   QuicSpdySession* session_;
426   QuicHeaderList header_list_;
427 };
428 
Http3DebugVisitor()429 Http3DebugVisitor::Http3DebugVisitor() {}
430 
~Http3DebugVisitor()431 Http3DebugVisitor::~Http3DebugVisitor() {}
432 
433 // Expected unidirectional static streams Requirement can be found at
434 // https://tools.ietf.org/html/draft-ietf-quic-http-22#section-6.2.
QuicSpdySession(QuicConnection * connection,QuicSession::Visitor * visitor,const QuicConfig & config,const ParsedQuicVersionVector & supported_versions)435 QuicSpdySession::QuicSpdySession(
436     QuicConnection* connection, QuicSession::Visitor* visitor,
437     const QuicConfig& config, const ParsedQuicVersionVector& supported_versions)
438     : QuicSession(connection, visitor, config, supported_versions,
439                   /*num_expected_unidirectional_static_streams = */
440                   VersionUsesHttp3(connection->transport_version())
441                       ? static_cast<QuicStreamCount>(
442                             kHttp3StaticUnidirectionalStreamCount)
443                       : 0u,
444                   std::make_unique<DatagramObserver>(this)),
445       send_control_stream_(nullptr),
446       receive_control_stream_(nullptr),
447       qpack_encoder_receive_stream_(nullptr),
448       qpack_decoder_receive_stream_(nullptr),
449       qpack_encoder_send_stream_(nullptr),
450       qpack_decoder_send_stream_(nullptr),
451       qpack_maximum_dynamic_table_capacity_(
452           kDefaultQpackMaxDynamicTableCapacity),
453       qpack_maximum_blocked_streams_(kDefaultMaximumBlockedStreams),
454       max_inbound_header_list_size_(kDefaultMaxUncompressedHeaderSize),
455       max_outbound_header_list_size_(std::numeric_limits<size_t>::max()),
456       stream_id_(
457           QuicUtils::GetInvalidStreamId(connection->transport_version())),
458       promised_stream_id_(
459           QuicUtils::GetInvalidStreamId(connection->transport_version())),
460       frame_len_(0),
461       fin_(false),
462       spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
463       spdy_framer_visitor_(new SpdyFramerVisitor(this)),
464       debug_visitor_(nullptr),
465       destruction_indicator_(123456789),
466       allow_extended_connect_(
467           GetQuicReloadableFlag(quic_verify_request_headers_2) &&
468           perspective() == Perspective::IS_SERVER &&
469           VersionUsesHttp3(transport_version())) {
470   h2_deframer_.set_visitor(spdy_framer_visitor_.get());
471   h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
472   spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
473 }
474 
~QuicSpdySession()475 QuicSpdySession::~QuicSpdySession() {
476   QUIC_BUG_IF(quic_bug_12477_2, destruction_indicator_ != 123456789)
477       << "QuicSpdySession use after free. " << destruction_indicator_
478       << QuicStackTrace();
479   destruction_indicator_ = 987654321;
480 }
481 
Initialize()482 void QuicSpdySession::Initialize() {
483   QuicSession::Initialize();
484 
485   FillSettingsFrame();
486   if (!VersionUsesHttp3(transport_version())) {
487     if (perspective() == Perspective::IS_SERVER) {
488       set_largest_peer_created_stream_id(
489           QuicUtils::GetHeadersStreamId(transport_version()));
490     } else {
491       QuicStreamId headers_stream_id = GetNextOutgoingBidirectionalStreamId();
492       QUICHE_DCHECK_EQ(headers_stream_id,
493                        QuicUtils::GetHeadersStreamId(transport_version()));
494     }
495     auto headers_stream = std::make_unique<QuicHeadersStream>((this));
496     QUICHE_DCHECK_EQ(QuicUtils::GetHeadersStreamId(transport_version()),
497                      headers_stream->id());
498 
499     headers_stream_ = headers_stream.get();
500     ActivateStream(std::move(headers_stream));
501   } else {
502     qpack_encoder_ = std::make_unique<QpackEncoder>(this);
503     qpack_decoder_ =
504         std::make_unique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_,
505                                        qpack_maximum_blocked_streams_, this);
506     MaybeInitializeHttp3UnidirectionalStreams();
507   }
508 
509   spdy_framer_visitor_->set_max_header_list_size(max_inbound_header_list_size_);
510 
511   // Limit HPACK buffering to 2x header list size limit.
512   h2_deframer_.GetHpackDecoder()->set_max_decode_buffer_size_bytes(
513       2 * max_inbound_header_list_size_);
514 }
515 
FillSettingsFrame()516 void QuicSpdySession::FillSettingsFrame() {
517   settings_.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
518       qpack_maximum_dynamic_table_capacity_;
519   settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
520       qpack_maximum_blocked_streams_;
521   settings_.values[SETTINGS_MAX_FIELD_SECTION_SIZE] =
522       max_inbound_header_list_size_;
523   if (version().UsesHttp3()) {
524     switch (LocalHttpDatagramSupport()) {
525       case HttpDatagramSupport::kNone:
526         break;
527       case HttpDatagramSupport::kDraft04:
528         settings_.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
529         break;
530       case HttpDatagramSupport::kRfc:
531         settings_.values[SETTINGS_H3_DATAGRAM] = 1;
532         break;
533       case HttpDatagramSupport::kRfcAndDraft04:
534         settings_.values[SETTINGS_H3_DATAGRAM] = 1;
535         settings_.values[SETTINGS_H3_DATAGRAM_DRAFT04] = 1;
536         break;
537     }
538   }
539   if (WillNegotiateWebTransport()) {
540     settings_.values[SETTINGS_WEBTRANS_DRAFT00] = 1;
541   }
542   if (allow_extended_connect()) {
543     QUIC_RELOADABLE_FLAG_COUNT_N(quic_verify_request_headers_2, 1, 3);
544     settings_.values[SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
545   }
546 }
547 
OnDecoderStreamError(QuicErrorCode error_code,absl::string_view error_message)548 void QuicSpdySession::OnDecoderStreamError(QuicErrorCode error_code,
549                                            absl::string_view error_message) {
550   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
551 
552   CloseConnectionWithDetails(
553       error_code, absl::StrCat("Decoder stream error: ", error_message));
554 }
555 
OnEncoderStreamError(QuicErrorCode error_code,absl::string_view error_message)556 void QuicSpdySession::OnEncoderStreamError(QuicErrorCode error_code,
557                                            absl::string_view error_message) {
558   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
559 
560   CloseConnectionWithDetails(
561       error_code, absl::StrCat("Encoder stream error: ", error_message));
562 }
563 
OnStreamHeadersPriority(QuicStreamId stream_id,const spdy::SpdyStreamPrecedence & precedence)564 void QuicSpdySession::OnStreamHeadersPriority(
565     QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
566   QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
567   if (!stream) {
568     // It's quite possible to receive headers after a stream has been reset.
569     return;
570   }
571   stream->OnStreamHeadersPriority(precedence);
572 }
573 
OnStreamHeaderList(QuicStreamId stream_id,bool fin,size_t frame_len,const QuicHeaderList & header_list)574 void QuicSpdySession::OnStreamHeaderList(QuicStreamId stream_id, bool fin,
575                                          size_t frame_len,
576                                          const QuicHeaderList& header_list) {
577   if (IsStaticStream(stream_id)) {
578     connection()->CloseConnection(
579         QUIC_INVALID_HEADERS_STREAM_DATA, "stream is static",
580         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
581     return;
582   }
583   QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
584   if (stream == nullptr) {
585     // The stream no longer exists, but trailing headers may contain the final
586     // byte offset necessary for flow control and open stream accounting.
587     size_t final_byte_offset = 0;
588     for (const auto& header : header_list) {
589       const std::string& header_key = header.first;
590       const std::string& header_value = header.second;
591       if (header_key == kFinalOffsetHeaderKey) {
592         if (!absl::SimpleAtoi(header_value, &final_byte_offset)) {
593           connection()->CloseConnection(
594               QUIC_INVALID_HEADERS_STREAM_DATA,
595               "Trailers are malformed (no final offset)",
596               ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
597           return;
598         }
599         QUIC_DVLOG(1) << ENDPOINT
600                       << "Received final byte offset in trailers for stream "
601                       << stream_id << ", which no longer exists.";
602         OnFinalByteOffsetReceived(stream_id, final_byte_offset);
603       }
604     }
605 
606     // It's quite possible to receive headers after a stream has been reset.
607     return;
608   }
609   stream->OnStreamHeaderList(fin, frame_len, header_list);
610 }
611 
OnPriorityFrame(QuicStreamId stream_id,const spdy::SpdyStreamPrecedence & precedence)612 void QuicSpdySession::OnPriorityFrame(
613     QuicStreamId stream_id, const spdy::SpdyStreamPrecedence& precedence) {
614   QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
615   if (!stream) {
616     // It's quite possible to receive a PRIORITY frame after a stream has been
617     // reset.
618     return;
619   }
620   stream->OnPriorityFrame(precedence);
621 }
622 
OnPriorityUpdateForRequestStream(QuicStreamId stream_id,HttpStreamPriority priority)623 bool QuicSpdySession::OnPriorityUpdateForRequestStream(
624     QuicStreamId stream_id, HttpStreamPriority priority) {
625   if (perspective() == Perspective::IS_CLIENT ||
626       !QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
627       !QuicUtils::IsClientInitiatedStreamId(transport_version(), stream_id)) {
628     return true;
629   }
630 
631   QuicStreamCount advertised_max_incoming_bidirectional_streams =
632       GetAdvertisedMaxIncomingBidirectionalStreams();
633   if (advertised_max_incoming_bidirectional_streams == 0 ||
634       stream_id > QuicUtils::GetFirstBidirectionalStreamId(
635                       transport_version(), Perspective::IS_CLIENT) +
636                       QuicUtils::StreamIdDelta(transport_version()) *
637                           (advertised_max_incoming_bidirectional_streams - 1)) {
638     connection()->CloseConnection(
639         QUIC_INVALID_STREAM_ID,
640         "PRIORITY_UPDATE frame received for invalid stream.",
641         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
642     return false;
643   }
644 
645   if (MaybeSetStreamPriority(stream_id, QuicStreamPriority(priority))) {
646     return true;
647   }
648 
649   if (IsClosedStream(stream_id)) {
650     return true;
651   }
652 
653   buffered_stream_priorities_[stream_id] = priority;
654 
655   if (buffered_stream_priorities_.size() >
656       10 * max_open_incoming_bidirectional_streams()) {
657     // This should never happen, because |buffered_stream_priorities_| should
658     // only contain entries for streams that are allowed to be open by the peer
659     // but have not been opened yet.
660     std::string error_message =
661         absl::StrCat("Too many stream priority values buffered: ",
662                      buffered_stream_priorities_.size(),
663                      ", which should not exceed the incoming stream limit of ",
664                      max_open_incoming_bidirectional_streams());
665     QUIC_BUG(quic_bug_10360_2) << error_message;
666     connection()->CloseConnection(
667         QUIC_INTERNAL_ERROR, error_message,
668         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
669     return false;
670   }
671 
672   return true;
673 }
674 
ProcessHeaderData(const struct iovec & iov)675 size_t QuicSpdySession::ProcessHeaderData(const struct iovec& iov) {
676   QUIC_BUG_IF(quic_bug_12477_4, destruction_indicator_ != 123456789)
677       << "QuicSpdyStream use after free. " << destruction_indicator_
678       << QuicStackTrace();
679   return h2_deframer_.ProcessInput(static_cast<char*>(iov.iov_base),
680                                    iov.iov_len);
681 }
682 
WriteHeadersOnHeadersStream(QuicStreamId id,Http2HeaderBlock headers,bool fin,const spdy::SpdyStreamPrecedence & precedence,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)683 size_t QuicSpdySession::WriteHeadersOnHeadersStream(
684     QuicStreamId id, Http2HeaderBlock headers, bool fin,
685     const spdy::SpdyStreamPrecedence& precedence,
686     quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
687         ack_listener) {
688   QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
689 
690   return WriteHeadersOnHeadersStreamImpl(
691       id, std::move(headers), fin,
692       /* parent_stream_id = */ 0,
693       Spdy3PriorityToHttp2Weight(precedence.spdy3_priority()),
694       /* exclusive = */ false, std::move(ack_listener));
695 }
696 
WritePriority(QuicStreamId stream_id,QuicStreamId parent_stream_id,int weight,bool exclusive)697 size_t QuicSpdySession::WritePriority(QuicStreamId stream_id,
698                                       QuicStreamId parent_stream_id, int weight,
699                                       bool exclusive) {
700   QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
701   SpdyPriorityIR priority_frame(stream_id, parent_stream_id, weight, exclusive);
702   SpdySerializedFrame frame(spdy_framer_.SerializeFrame(priority_frame));
703   headers_stream()->WriteOrBufferData(
704       absl::string_view(frame.data(), frame.size()), false, nullptr);
705   return frame.size();
706 }
707 
WriteHttp3PriorityUpdate(QuicStreamId stream_id,HttpStreamPriority priority)708 void QuicSpdySession::WriteHttp3PriorityUpdate(QuicStreamId stream_id,
709                                                HttpStreamPriority priority) {
710   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
711 
712   send_control_stream_->WritePriorityUpdate(stream_id, priority);
713 }
714 
OnHttp3GoAway(uint64_t id)715 void QuicSpdySession::OnHttp3GoAway(uint64_t id) {
716   QUIC_BUG_IF(quic_bug_12477_5, !version().UsesHttp3())
717       << "HTTP/3 GOAWAY received on version " << version();
718 
719   if (last_received_http3_goaway_id_.has_value() &&
720       id > last_received_http3_goaway_id_.value()) {
721     CloseConnectionWithDetails(
722         QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS,
723         absl::StrCat("GOAWAY received with ID ", id,
724                      " greater than previously received ID ",
725                      last_received_http3_goaway_id_.value()));
726     return;
727   }
728   last_received_http3_goaway_id_ = id;
729 
730   if (perspective() == Perspective::IS_SERVER) {
731     // TODO(b/151749109): Cancel server pushes with push ID larger than |id|.
732     return;
733   }
734 
735   // QuicStreamId is uint32_t.  Casting to this narrower type is well-defined
736   // and preserves the lower 32 bits.  Both IsBidirectionalStreamId() and
737   // IsIncomingStream() give correct results, because their return value is
738   // determined by the least significant two bits.
739   QuicStreamId stream_id = static_cast<QuicStreamId>(id);
740   if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) ||
741       IsIncomingStream(stream_id)) {
742     CloseConnectionWithDetails(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID,
743                                "GOAWAY with invalid stream ID");
744     return;
745   }
746 
747   // TODO(b/161252736): Cancel client requests with ID larger than |id|.
748   // If |id| is larger than numeric_limits<QuicStreamId>::max(), then use
749   // max() instead of downcast value.
750 }
751 
OnStreamsBlockedFrame(const QuicStreamsBlockedFrame & frame)752 bool QuicSpdySession::OnStreamsBlockedFrame(
753     const QuicStreamsBlockedFrame& frame) {
754   if (!QuicSession::OnStreamsBlockedFrame(frame)) {
755     return false;
756   }
757 
758   // The peer asked for stream space more than this implementation has. Send
759   // goaway.
760   if (perspective() == Perspective::IS_SERVER &&
761       frame.stream_count >= QuicUtils::GetMaxStreamCount()) {
762     QUICHE_DCHECK_EQ(frame.stream_count, QuicUtils::GetMaxStreamCount());
763     SendHttp3GoAway(QUIC_PEER_GOING_AWAY, "stream count too large");
764   }
765   return true;
766 }
767 
SendHttp3GoAway(QuicErrorCode error_code,const std::string & reason)768 void QuicSpdySession::SendHttp3GoAway(QuicErrorCode error_code,
769                                       const std::string& reason) {
770   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
771   if (!IsEncryptionEstablished()) {
772     QUIC_CODE_COUNT(quic_h3_goaway_before_encryption_established);
773     connection()->CloseConnection(
774         error_code, reason,
775         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
776     return;
777   }
778   QuicStreamId stream_id;
779 
780   stream_id = QuicUtils::GetMaxClientInitiatedBidirectionalStreamId(
781       transport_version());
782   if (last_sent_http3_goaway_id_.has_value() &&
783       last_sent_http3_goaway_id_.value() <= stream_id) {
784     // Do not send GOAWAY frame with a higher id, because it is forbidden.
785     // Do not send one with same stream id as before, since frames on the
786     // control stream are guaranteed to be processed in order.
787     return;
788   }
789 
790   send_control_stream_->SendGoAway(stream_id);
791   last_sent_http3_goaway_id_ = stream_id;
792 }
793 
WritePushPromise(QuicStreamId original_stream_id,QuicStreamId promised_stream_id,Http2HeaderBlock headers)794 void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id,
795                                        QuicStreamId promised_stream_id,
796                                        Http2HeaderBlock headers) {
797   if (perspective() == Perspective::IS_CLIENT) {
798     QUIC_BUG(quic_bug_10360_4) << "Client shouldn't send PUSH_PROMISE";
799     return;
800   }
801 
802   if (VersionUsesHttp3(transport_version())) {
803     QUIC_BUG(quic_bug_12477_6)
804         << "Support for server push over HTTP/3 has been removed.";
805     return;
806   }
807 
808   SpdyPushPromiseIR push_promise(original_stream_id, promised_stream_id,
809                                  std::move(headers));
810   // PUSH_PROMISE must not be the last frame sent out, at least followed by
811   // response headers.
812   push_promise.set_fin(false);
813 
814   SpdySerializedFrame frame(spdy_framer_.SerializeFrame(push_promise));
815   headers_stream()->WriteOrBufferData(
816       absl::string_view(frame.data(), frame.size()), false, nullptr);
817 }
818 
SendInitialData()819 void QuicSpdySession::SendInitialData() {
820   if (!VersionUsesHttp3(transport_version())) {
821     return;
822   }
823   QuicConnection::ScopedPacketFlusher flusher(connection());
824   send_control_stream_->MaybeSendSettingsFrame();
825 }
826 
qpack_encoder()827 QpackEncoder* QuicSpdySession::qpack_encoder() {
828   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
829 
830   return qpack_encoder_.get();
831 }
832 
qpack_decoder()833 QpackDecoder* QuicSpdySession::qpack_decoder() {
834   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
835 
836   return qpack_decoder_.get();
837 }
838 
OnStreamCreated(QuicSpdyStream * stream)839 void QuicSpdySession::OnStreamCreated(QuicSpdyStream* stream) {
840   auto it = buffered_stream_priorities_.find(stream->id());
841   if (it == buffered_stream_priorities_.end()) {
842     return;
843   }
844 
845   stream->SetPriority(QuicStreamPriority(it->second));
846   buffered_stream_priorities_.erase(it);
847 }
848 
GetOrCreateSpdyDataStream(const QuicStreamId stream_id)849 QuicSpdyStream* QuicSpdySession::GetOrCreateSpdyDataStream(
850     const QuicStreamId stream_id) {
851   QuicStream* stream = GetOrCreateStream(stream_id);
852   if (stream && stream->is_static()) {
853     QUIC_BUG(quic_bug_10360_5)
854         << "GetOrCreateSpdyDataStream returns static stream " << stream_id
855         << " in version " << transport_version() << "\n"
856         << QuicStackTrace();
857     connection()->CloseConnection(
858         QUIC_INVALID_STREAM_ID,
859         absl::StrCat("stream ", stream_id, " is static"),
860         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
861     return nullptr;
862   }
863   return static_cast<QuicSpdyStream*>(stream);
864 }
865 
OnNewEncryptionKeyAvailable(EncryptionLevel level,std::unique_ptr<QuicEncrypter> encrypter)866 void QuicSpdySession::OnNewEncryptionKeyAvailable(
867     EncryptionLevel level, std::unique_ptr<QuicEncrypter> encrypter) {
868   QuicSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
869   if (IsEncryptionEstablished()) {
870     // Send H3 SETTINGs once encryption is established.
871     SendInitialData();
872   }
873 }
874 
ShouldNegotiateWebTransport()875 bool QuicSpdySession::ShouldNegotiateWebTransport() { return false; }
876 
ShouldValidateWebTransportVersion() const877 bool QuicSpdySession::ShouldValidateWebTransportVersion() const { return true; }
878 
WillNegotiateWebTransport()879 bool QuicSpdySession::WillNegotiateWebTransport() {
880   return LocalHttpDatagramSupport() != HttpDatagramSupport::kNone &&
881          version().UsesHttp3() && ShouldNegotiateWebTransport();
882 }
883 
884 // True if there are open HTTP requests.
ShouldKeepConnectionAlive() const885 bool QuicSpdySession::ShouldKeepConnectionAlive() const {
886   QUICHE_DCHECK(VersionUsesHttp3(transport_version()) ||
887                 0u == pending_streams_size());
888   return GetNumActiveStreams() + pending_streams_size() > 0;
889 }
890 
UsesPendingStreamForFrame(QuicFrameType type,QuicStreamId stream_id) const891 bool QuicSpdySession::UsesPendingStreamForFrame(QuicFrameType type,
892                                                 QuicStreamId stream_id) const {
893   // Pending streams can only be used to handle unidirectional stream with
894   // STREAM & RESET_STREAM frames in IETF QUIC.
895   return VersionUsesHttp3(transport_version()) &&
896          (type == STREAM_FRAME || type == RST_STREAM_FRAME) &&
897          QuicUtils::GetStreamType(stream_id, perspective(),
898                                   IsIncomingStream(stream_id),
899                                   version()) == READ_UNIDIRECTIONAL;
900 }
901 
WriteHeadersOnHeadersStreamImpl(QuicStreamId id,spdy::Http2HeaderBlock headers,bool fin,QuicStreamId parent_stream_id,int weight,bool exclusive,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)902 size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl(
903     QuicStreamId id, spdy::Http2HeaderBlock headers, bool fin,
904     QuicStreamId parent_stream_id, int weight, bool exclusive,
905     quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
906         ack_listener) {
907   QUICHE_DCHECK(!VersionUsesHttp3(transport_version()));
908 
909   const QuicByteCount uncompressed_size = headers.TotalBytesUsed();
910   SpdyHeadersIR headers_frame(id, std::move(headers));
911   headers_frame.set_fin(fin);
912   if (perspective() == Perspective::IS_CLIENT) {
913     headers_frame.set_has_priority(true);
914     headers_frame.set_parent_stream_id(parent_stream_id);
915     headers_frame.set_weight(weight);
916     headers_frame.set_exclusive(exclusive);
917   }
918   SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame));
919   headers_stream()->WriteOrBufferData(
920       absl::string_view(frame.data(), frame.size()), false,
921       std::move(ack_listener));
922 
923   // Calculate compressed header block size without framing overhead.
924   QuicByteCount compressed_size = frame.size();
925   compressed_size -= spdy::kFrameHeaderSize;
926   if (perspective() == Perspective::IS_CLIENT) {
927     // Exclusive bit and Stream Dependency are four bytes, weight is one more.
928     compressed_size -= 5;
929   }
930 
931   LogHeaderCompressionRatioHistogram(
932       /* using_qpack = */ false,
933       /* is_sent = */ true, compressed_size, uncompressed_size);
934 
935   return frame.size();
936 }
937 
OnPromiseHeaderList(QuicStreamId,QuicStreamId,size_t,const QuicHeaderList &)938 void QuicSpdySession::OnPromiseHeaderList(
939     QuicStreamId /*stream_id*/, QuicStreamId /*promised_stream_id*/,
940     size_t /*frame_len*/, const QuicHeaderList& /*header_list*/) {
941   std::string error =
942       "OnPromiseHeaderList should be overridden in client code.";
943   QUIC_BUG(quic_bug_10360_6) << error;
944   connection()->CloseConnection(QUIC_INTERNAL_ERROR, error,
945                                 ConnectionCloseBehavior::SILENT_CLOSE);
946 }
947 
ResumeApplicationState(ApplicationState * cached_state)948 bool QuicSpdySession::ResumeApplicationState(ApplicationState* cached_state) {
949   QUICHE_DCHECK_EQ(perspective(), Perspective::IS_CLIENT);
950   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
951 
952   SettingsFrame out;
953   if (!HttpDecoder::DecodeSettings(
954           reinterpret_cast<char*>(cached_state->data()), cached_state->size(),
955           &out)) {
956     return false;
957   }
958 
959   if (debug_visitor_ != nullptr) {
960     debug_visitor_->OnSettingsFrameResumed(out);
961   }
962   QUICHE_DCHECK(streams_waiting_for_settings_.empty());
963   for (const auto& setting : out.values) {
964     OnSetting(setting.first, setting.second);
965   }
966   return true;
967 }
968 
OnAlpsData(const uint8_t * alps_data,size_t alps_length)969 absl::optional<std::string> QuicSpdySession::OnAlpsData(
970     const uint8_t* alps_data, size_t alps_length) {
971   AlpsFrameDecoder alps_frame_decoder(this);
972   HttpDecoder decoder(&alps_frame_decoder);
973   decoder.ProcessInput(reinterpret_cast<const char*>(alps_data), alps_length);
974   if (alps_frame_decoder.error_detail()) {
975     return alps_frame_decoder.error_detail();
976   }
977 
978   if (decoder.error() != QUIC_NO_ERROR) {
979     return decoder.error_detail();
980   }
981 
982   if (!decoder.AtFrameBoundary()) {
983     return "incomplete HTTP/3 frame";
984   }
985 
986   return absl::nullopt;
987 }
988 
OnAcceptChFrameReceivedViaAlps(const AcceptChFrame & frame)989 void QuicSpdySession::OnAcceptChFrameReceivedViaAlps(
990     const AcceptChFrame& frame) {
991   if (debug_visitor_) {
992     debug_visitor_->OnAcceptChFrameReceivedViaAlps(frame);
993   }
994 }
995 
OnSettingsFrame(const SettingsFrame & frame)996 bool QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) {
997   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
998   if (debug_visitor_ != nullptr) {
999     debug_visitor_->OnSettingsFrameReceived(frame);
1000   }
1001   for (const auto& setting : frame.values) {
1002     if (!OnSetting(setting.first, setting.second)) {
1003       return false;
1004     }
1005   }
1006   for (QuicStreamId stream_id : streams_waiting_for_settings_) {
1007     QUICHE_DCHECK(ShouldBufferRequestsUntilSettings());
1008     QuicSpdyStream* stream = GetOrCreateSpdyDataStream(stream_id);
1009     if (stream == nullptr) {
1010       // The stream may no longer exist, since it is possible for a stream to
1011       // get reset while waiting for the SETTINGS frame.
1012       continue;
1013     }
1014     stream->OnDataAvailable();
1015   }
1016   streams_waiting_for_settings_.clear();
1017   return true;
1018 }
1019 
OnSettingsFrameViaAlps(const SettingsFrame & frame)1020 absl::optional<std::string> QuicSpdySession::OnSettingsFrameViaAlps(
1021     const SettingsFrame& frame) {
1022   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1023 
1024   if (debug_visitor_ != nullptr) {
1025     debug_visitor_->OnSettingsFrameReceivedViaAlps(frame);
1026   }
1027   for (const auto& setting : frame.values) {
1028     if (!OnSetting(setting.first, setting.second)) {
1029       // Do not bother adding the setting identifier or value to the error
1030       // message, because OnSetting() already closed the connection, therefore
1031       // the error message will be ignored.
1032       return "error parsing setting";
1033     }
1034   }
1035   return absl::nullopt;
1036 }
1037 
VerifySettingIsZeroOrOne(uint64_t id,uint64_t value)1038 bool QuicSpdySession::VerifySettingIsZeroOrOne(uint64_t id, uint64_t value) {
1039   if (value == 0 || value == 1) {
1040     return true;
1041   }
1042   std::string error_details = absl::StrCat(
1043       "Received ",
1044       H3SettingsToString(static_cast<Http3AndQpackSettingsIdentifiers>(id)),
1045       " with invalid value ", value);
1046   QUIC_PEER_BUG(bad received setting) << ENDPOINT << error_details;
1047   CloseConnectionWithDetails(QUIC_HTTP_INVALID_SETTING_VALUE, error_details);
1048   return false;
1049 }
1050 
OnSetting(uint64_t id,uint64_t value)1051 bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) {
1052   any_settings_received_ = true;
1053 
1054   if (VersionUsesHttp3(transport_version())) {
1055     // SETTINGS frame received on the control stream.
1056     switch (id) {
1057       case SETTINGS_QPACK_MAX_TABLE_CAPACITY: {
1058         QUIC_DVLOG(1)
1059             << ENDPOINT
1060             << "SETTINGS_QPACK_MAX_TABLE_CAPACITY received with value "
1061             << value;
1062         // Communicate |value| to encoder, because it is used for encoding
1063         // Required Insert Count.
1064         if (!qpack_encoder_->SetMaximumDynamicTableCapacity(value)) {
1065           CloseConnectionWithDetails(
1066               was_zero_rtt_rejected()
1067                   ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
1068                   : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
1069               absl::StrCat(was_zero_rtt_rejected()
1070                                ? "Server rejected 0-RTT, aborting because "
1071                                : "",
1072                            "Server sent an SETTINGS_QPACK_MAX_TABLE_CAPACITY: ",
1073                            value, " while current value is: ",
1074                            qpack_encoder_->MaximumDynamicTableCapacity()));
1075           return false;
1076         }
1077         // However, limit the dynamic table capacity to
1078         // |qpack_maximum_dynamic_table_capacity_|.
1079         qpack_encoder_->SetDynamicTableCapacity(
1080             std::min(value, qpack_maximum_dynamic_table_capacity_));
1081         break;
1082       }
1083       case SETTINGS_MAX_FIELD_SECTION_SIZE:
1084         QUIC_DVLOG(1) << ENDPOINT
1085                       << "SETTINGS_MAX_FIELD_SECTION_SIZE received with value "
1086                       << value;
1087         if (max_outbound_header_list_size_ !=
1088                 std::numeric_limits<size_t>::max() &&
1089             max_outbound_header_list_size_ > value) {
1090           CloseConnectionWithDetails(
1091               was_zero_rtt_rejected()
1092                   ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
1093                   : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
1094               absl::StrCat(was_zero_rtt_rejected()
1095                                ? "Server rejected 0-RTT, aborting because "
1096                                : "",
1097                            "Server sent an SETTINGS_MAX_FIELD_SECTION_SIZE: ",
1098                            value, " which reduces current value: ",
1099                            max_outbound_header_list_size_));
1100           return false;
1101         }
1102         max_outbound_header_list_size_ = value;
1103         break;
1104       case SETTINGS_QPACK_BLOCKED_STREAMS: {
1105         QUIC_DVLOG(1) << ENDPOINT
1106                       << "SETTINGS_QPACK_BLOCKED_STREAMS received with value "
1107                       << value;
1108         if (!qpack_encoder_->SetMaximumBlockedStreams(value)) {
1109           CloseConnectionWithDetails(
1110               was_zero_rtt_rejected()
1111                   ? QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH
1112                   : QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH,
1113               absl::StrCat(was_zero_rtt_rejected()
1114                                ? "Server rejected 0-RTT, aborting because "
1115                                : "",
1116                            "Server sent an SETTINGS_QPACK_BLOCKED_STREAMS: ",
1117                            value, " which reduces current value: ",
1118                            qpack_encoder_->maximum_blocked_streams()));
1119           return false;
1120         }
1121         break;
1122       }
1123       case SETTINGS_ENABLE_CONNECT_PROTOCOL: {
1124         QUIC_DVLOG(1) << ENDPOINT
1125                       << "SETTINGS_ENABLE_CONNECT_PROTOCOL received with value "
1126                       << value;
1127         if (!VerifySettingIsZeroOrOne(id, value)) {
1128           return false;
1129         }
1130         if (perspective() == Perspective::IS_CLIENT) {
1131           allow_extended_connect_ = value != 0;
1132         }
1133         break;
1134       }
1135       case spdy::SETTINGS_ENABLE_PUSH:
1136         ABSL_FALLTHROUGH_INTENDED;
1137       case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
1138         ABSL_FALLTHROUGH_INTENDED;
1139       case spdy::SETTINGS_INITIAL_WINDOW_SIZE:
1140         ABSL_FALLTHROUGH_INTENDED;
1141       case spdy::SETTINGS_MAX_FRAME_SIZE:
1142         CloseConnectionWithDetails(
1143             QUIC_HTTP_RECEIVE_SPDY_SETTING,
1144             absl::StrCat("received HTTP/2 specific setting in HTTP/3 session: ",
1145                          id));
1146         return false;
1147       case SETTINGS_H3_DATAGRAM_DRAFT04: {
1148         HttpDatagramSupport local_http_datagram_support =
1149             LocalHttpDatagramSupport();
1150         if (local_http_datagram_support != HttpDatagramSupport::kDraft04 &&
1151             local_http_datagram_support !=
1152                 HttpDatagramSupport::kRfcAndDraft04) {
1153           break;
1154         }
1155         QUIC_DVLOG(1) << ENDPOINT
1156                       << "SETTINGS_H3_DATAGRAM_DRAFT04 received with value "
1157                       << value;
1158         if (!version().UsesHttp3()) {
1159           break;
1160         }
1161         if (!VerifySettingIsZeroOrOne(id, value)) {
1162           return false;
1163         }
1164         if (value && http_datagram_support_ != HttpDatagramSupport::kRfc) {
1165           // If both RFC 9297 and draft-04 are supported, we use the RFC. This
1166           // is implemented by ignoring SETTINGS_H3_DATAGRAM_DRAFT04 when we've
1167           // already parsed SETTINGS_H3_DATAGRAM.
1168           http_datagram_support_ = HttpDatagramSupport::kDraft04;
1169         }
1170         break;
1171       }
1172       case SETTINGS_H3_DATAGRAM: {
1173         HttpDatagramSupport local_http_datagram_support =
1174             LocalHttpDatagramSupport();
1175         if (local_http_datagram_support != HttpDatagramSupport::kRfc &&
1176             local_http_datagram_support !=
1177                 HttpDatagramSupport::kRfcAndDraft04) {
1178           break;
1179         }
1180         QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_H3_DATAGRAM received with value "
1181                       << value;
1182         if (!version().UsesHttp3()) {
1183           break;
1184         }
1185         if (!VerifySettingIsZeroOrOne(id, value)) {
1186           return false;
1187         }
1188         if (value) {
1189           http_datagram_support_ = HttpDatagramSupport::kRfc;
1190         }
1191         break;
1192       }
1193       case SETTINGS_WEBTRANS_DRAFT00:
1194         if (!WillNegotiateWebTransport()) {
1195           break;
1196         }
1197         QUIC_DVLOG(1) << ENDPOINT
1198                       << "SETTINGS_ENABLE_WEBTRANSPORT received with value "
1199                       << value;
1200         if (!VerifySettingIsZeroOrOne(id, value)) {
1201           return false;
1202         }
1203         peer_supports_webtransport_ = (value == 1);
1204         if (perspective() == Perspective::IS_CLIENT && value == 1) {
1205           allow_extended_connect_ = true;
1206         }
1207         break;
1208       default:
1209         QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id
1210                       << " received with value " << value;
1211         // Ignore unknown settings.
1212         break;
1213     }
1214     return true;
1215   }
1216 
1217   // SETTINGS frame received on the headers stream.
1218   switch (id) {
1219     case spdy::SETTINGS_HEADER_TABLE_SIZE:
1220       QUIC_DVLOG(1) << ENDPOINT
1221                     << "SETTINGS_HEADER_TABLE_SIZE received with value "
1222                     << value;
1223       spdy_framer_.UpdateHeaderEncoderTableSize(
1224           std::min<uint64_t>(value, kHpackEncoderDynamicTableSizeLimit));
1225       break;
1226     case spdy::SETTINGS_ENABLE_PUSH:
1227       if (perspective() == Perspective::IS_SERVER) {
1228         // See rfc7540, Section 6.5.2.
1229         if (value > 1) {
1230           QUIC_DLOG(ERROR) << ENDPOINT << "Invalid value " << value
1231                            << " received for SETTINGS_ENABLE_PUSH.";
1232           if (IsConnected()) {
1233             CloseConnectionWithDetails(
1234                 QUIC_INVALID_HEADERS_STREAM_DATA,
1235                 absl::StrCat("Invalid value for SETTINGS_ENABLE_PUSH: ",
1236                              value));
1237           }
1238           return true;
1239         }
1240         QUIC_DVLOG(1) << ENDPOINT << "SETTINGS_ENABLE_PUSH received with value "
1241                       << value << ", ignoring.";
1242         break;
1243       } else {
1244         QUIC_DLOG(ERROR)
1245             << ENDPOINT
1246             << "Invalid SETTINGS_ENABLE_PUSH received by client with value "
1247             << value;
1248         if (IsConnected()) {
1249           CloseConnectionWithDetails(
1250               QUIC_INVALID_HEADERS_STREAM_DATA,
1251               absl::StrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
1252         }
1253       }
1254       break;
1255     case spdy::SETTINGS_MAX_HEADER_LIST_SIZE:
1256       QUIC_DVLOG(1) << ENDPOINT
1257                     << "SETTINGS_MAX_HEADER_LIST_SIZE received with value "
1258                     << value;
1259       max_outbound_header_list_size_ = value;
1260       break;
1261     default:
1262       QUIC_DLOG(ERROR) << ENDPOINT << "Unknown setting identifier " << id
1263                        << " received with value " << value;
1264       if (IsConnected()) {
1265         CloseConnectionWithDetails(
1266             QUIC_INVALID_HEADERS_STREAM_DATA,
1267             absl::StrCat("Unsupported field of HTTP/2 SETTINGS frame: ", id));
1268       }
1269   }
1270   return true;
1271 }
1272 
ShouldReleaseHeadersStreamSequencerBuffer()1273 bool QuicSpdySession::ShouldReleaseHeadersStreamSequencerBuffer() {
1274   return false;
1275 }
1276 
OnHeaders(SpdyStreamId stream_id,bool has_priority,const spdy::SpdyStreamPrecedence & precedence,bool fin)1277 void QuicSpdySession::OnHeaders(SpdyStreamId stream_id, bool has_priority,
1278                                 const spdy::SpdyStreamPrecedence& precedence,
1279                                 bool fin) {
1280   if (has_priority) {
1281     if (perspective() == Perspective::IS_CLIENT) {
1282       CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
1283                                  "Server must not send priorities.");
1284       return;
1285     }
1286     OnStreamHeadersPriority(stream_id, precedence);
1287   } else {
1288     if (perspective() == Perspective::IS_SERVER) {
1289       CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
1290                                  "Client must send priorities.");
1291       return;
1292     }
1293   }
1294   QUICHE_DCHECK_EQ(QuicUtils::GetInvalidStreamId(transport_version()),
1295                    stream_id_);
1296   QUICHE_DCHECK_EQ(QuicUtils::GetInvalidStreamId(transport_version()),
1297                    promised_stream_id_);
1298   stream_id_ = stream_id;
1299   fin_ = fin;
1300 }
1301 
OnPushPromise(SpdyStreamId stream_id,SpdyStreamId promised_stream_id)1302 void QuicSpdySession::OnPushPromise(SpdyStreamId stream_id,
1303                                     SpdyStreamId promised_stream_id) {
1304   QUICHE_DCHECK_EQ(QuicUtils::GetInvalidStreamId(transport_version()),
1305                    stream_id_);
1306   QUICHE_DCHECK_EQ(QuicUtils::GetInvalidStreamId(transport_version()),
1307                    promised_stream_id_);
1308   stream_id_ = stream_id;
1309   promised_stream_id_ = promised_stream_id;
1310 }
1311 
1312 // TODO (wangyix): Why is SpdyStreamId used instead of QuicStreamId?
1313 // This occurs in many places in this file.
OnPriority(SpdyStreamId stream_id,const spdy::SpdyStreamPrecedence & precedence)1314 void QuicSpdySession::OnPriority(SpdyStreamId stream_id,
1315                                  const spdy::SpdyStreamPrecedence& precedence) {
1316   if (perspective() == Perspective::IS_CLIENT) {
1317     CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA,
1318                                "Server must not send PRIORITY frames.");
1319     return;
1320   }
1321   OnPriorityFrame(stream_id, precedence);
1322 }
1323 
OnHeaderList(const QuicHeaderList & header_list)1324 void QuicSpdySession::OnHeaderList(const QuicHeaderList& header_list) {
1325   QUIC_DVLOG(1) << ENDPOINT << "Received header list for stream " << stream_id_
1326                 << ": " << header_list.DebugString();
1327   // This code path is only executed for push promise in IETF QUIC.
1328   if (VersionUsesHttp3(transport_version())) {
1329     QUICHE_DCHECK(promised_stream_id_ !=
1330                   QuicUtils::GetInvalidStreamId(transport_version()));
1331   }
1332   if (promised_stream_id_ ==
1333       QuicUtils::GetInvalidStreamId(transport_version())) {
1334     OnStreamHeaderList(stream_id_, fin_, frame_len_, header_list);
1335   } else {
1336     OnPromiseHeaderList(stream_id_, promised_stream_id_, frame_len_,
1337                         header_list);
1338   }
1339   // Reset state for the next frame.
1340   promised_stream_id_ = QuicUtils::GetInvalidStreamId(transport_version());
1341   stream_id_ = QuicUtils::GetInvalidStreamId(transport_version());
1342   fin_ = false;
1343   frame_len_ = 0;
1344 }
1345 
OnCompressedFrameSize(size_t frame_len)1346 void QuicSpdySession::OnCompressedFrameSize(size_t frame_len) {
1347   frame_len_ += frame_len;
1348 }
1349 
CloseConnectionWithDetails(QuicErrorCode error,const std::string & details)1350 void QuicSpdySession::CloseConnectionWithDetails(QuicErrorCode error,
1351                                                  const std::string& details) {
1352   connection()->CloseConnection(
1353       error, details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
1354 }
1355 
HasActiveRequestStreams() const1356 bool QuicSpdySession::HasActiveRequestStreams() const {
1357   return GetNumActiveStreams() + num_draining_streams() > 0;
1358 }
1359 
ProcessPendingStream(PendingStream * pending)1360 QuicStream* QuicSpdySession::ProcessPendingStream(PendingStream* pending) {
1361   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1362   QUICHE_DCHECK(connection()->connected());
1363   struct iovec iov;
1364   if (!pending->sequencer()->GetReadableRegion(&iov)) {
1365     // The first byte hasn't been received yet.
1366     return nullptr;
1367   }
1368 
1369   QuicDataReader reader(static_cast<char*>(iov.iov_base), iov.iov_len);
1370   uint8_t stream_type_length = reader.PeekVarInt62Length();
1371   uint64_t stream_type = 0;
1372   if (!reader.ReadVarInt62(&stream_type)) {
1373     if (pending->sequencer()->NumBytesBuffered() ==
1374         pending->sequencer()->close_offset()) {
1375       // Stream received FIN but there are not enough bytes for stream type.
1376       // Mark all bytes consumed in order to close stream.
1377       pending->MarkConsumed(pending->sequencer()->close_offset());
1378     }
1379     return nullptr;
1380   }
1381   pending->MarkConsumed(stream_type_length);
1382 
1383   switch (stream_type) {
1384     case kControlStream: {  // HTTP/3 control stream.
1385       if (receive_control_stream_) {
1386         CloseConnectionOnDuplicateHttp3UnidirectionalStreams("Control");
1387         return nullptr;
1388       }
1389       auto receive_stream =
1390           std::make_unique<QuicReceiveControlStream>(pending, this);
1391       receive_control_stream_ = receive_stream.get();
1392       ActivateStream(std::move(receive_stream));
1393       QUIC_DVLOG(1) << ENDPOINT << "Receive Control stream is created";
1394       if (debug_visitor_ != nullptr) {
1395         debug_visitor_->OnPeerControlStreamCreated(
1396             receive_control_stream_->id());
1397       }
1398       return receive_control_stream_;
1399     }
1400     case kServerPushStream: {  // Push Stream.
1401       CloseConnectionWithDetails(QUIC_HTTP_RECEIVE_SERVER_PUSH,
1402                                  "Received server push stream");
1403       return nullptr;
1404     }
1405     case kQpackEncoderStream: {  // QPACK encoder stream.
1406       if (qpack_encoder_receive_stream_) {
1407         CloseConnectionOnDuplicateHttp3UnidirectionalStreams("QPACK encoder");
1408         return nullptr;
1409       }
1410       auto encoder_receive = std::make_unique<QpackReceiveStream>(
1411           pending, this, qpack_decoder_->encoder_stream_receiver());
1412       qpack_encoder_receive_stream_ = encoder_receive.get();
1413       ActivateStream(std::move(encoder_receive));
1414       QUIC_DVLOG(1) << ENDPOINT << "Receive QPACK Encoder stream is created";
1415       if (debug_visitor_ != nullptr) {
1416         debug_visitor_->OnPeerQpackEncoderStreamCreated(
1417             qpack_encoder_receive_stream_->id());
1418       }
1419       return qpack_encoder_receive_stream_;
1420     }
1421     case kQpackDecoderStream: {  // QPACK decoder stream.
1422       if (qpack_decoder_receive_stream_) {
1423         CloseConnectionOnDuplicateHttp3UnidirectionalStreams("QPACK decoder");
1424         return nullptr;
1425       }
1426       auto decoder_receive = std::make_unique<QpackReceiveStream>(
1427           pending, this, qpack_encoder_->decoder_stream_receiver());
1428       qpack_decoder_receive_stream_ = decoder_receive.get();
1429       ActivateStream(std::move(decoder_receive));
1430       QUIC_DVLOG(1) << ENDPOINT << "Receive QPACK Decoder stream is created";
1431       if (debug_visitor_ != nullptr) {
1432         debug_visitor_->OnPeerQpackDecoderStreamCreated(
1433             qpack_decoder_receive_stream_->id());
1434       }
1435       return qpack_decoder_receive_stream_;
1436     }
1437     case kWebTransportUnidirectionalStream: {
1438       // Note that this checks whether WebTransport is enabled on the receiver
1439       // side, as we may receive WebTransport streams before peer's SETTINGS are
1440       // received.
1441       // TODO(b/184156476): consider whether this means we should drop buffered
1442       // streams if we don't receive indication of WebTransport support.
1443       if (!WillNegotiateWebTransport()) {
1444         // Treat as unknown stream type.
1445         break;
1446       }
1447       QUIC_DVLOG(1) << ENDPOINT << "Created an incoming WebTransport stream "
1448                     << pending->id();
1449       auto stream_owned =
1450           std::make_unique<WebTransportHttp3UnidirectionalStream>(pending,
1451                                                                   this);
1452       WebTransportHttp3UnidirectionalStream* stream = stream_owned.get();
1453       ActivateStream(std::move(stream_owned));
1454       return stream;
1455     }
1456     default:
1457       break;
1458   }
1459   MaybeSendStopSendingFrame(
1460       pending->id(),
1461       QuicResetStreamError::FromInternal(QUIC_STREAM_STREAM_CREATION_ERROR));
1462   pending->StopReading();
1463   return nullptr;
1464 }
1465 
MaybeInitializeHttp3UnidirectionalStreams()1466 void QuicSpdySession::MaybeInitializeHttp3UnidirectionalStreams() {
1467   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1468   if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
1469     auto send_control = std::make_unique<QuicSendControlStream>(
1470         GetNextOutgoingUnidirectionalStreamId(), this, settings_);
1471     send_control_stream_ = send_control.get();
1472     ActivateStream(std::move(send_control));
1473     if (debug_visitor_) {
1474       debug_visitor_->OnControlStreamCreated(send_control_stream_->id());
1475     }
1476   }
1477 
1478   if (!qpack_decoder_send_stream_ &&
1479       CanOpenNextOutgoingUnidirectionalStream()) {
1480     auto decoder_send = std::make_unique<QpackSendStream>(
1481         GetNextOutgoingUnidirectionalStreamId(), this, kQpackDecoderStream);
1482     qpack_decoder_send_stream_ = decoder_send.get();
1483     ActivateStream(std::move(decoder_send));
1484     qpack_decoder_->set_qpack_stream_sender_delegate(
1485         qpack_decoder_send_stream_);
1486     if (debug_visitor_) {
1487       debug_visitor_->OnQpackDecoderStreamCreated(
1488           qpack_decoder_send_stream_->id());
1489     }
1490   }
1491 
1492   if (!qpack_encoder_send_stream_ &&
1493       CanOpenNextOutgoingUnidirectionalStream()) {
1494     auto encoder_send = std::make_unique<QpackSendStream>(
1495         GetNextOutgoingUnidirectionalStreamId(), this, kQpackEncoderStream);
1496     qpack_encoder_send_stream_ = encoder_send.get();
1497     ActivateStream(std::move(encoder_send));
1498     qpack_encoder_->set_qpack_stream_sender_delegate(
1499         qpack_encoder_send_stream_);
1500     if (debug_visitor_) {
1501       debug_visitor_->OnQpackEncoderStreamCreated(
1502           qpack_encoder_send_stream_->id());
1503     }
1504   }
1505 }
1506 
BeforeConnectionCloseSent()1507 void QuicSpdySession::BeforeConnectionCloseSent() {
1508   if (!VersionUsesHttp3(transport_version()) || !IsEncryptionEstablished()) {
1509     return;
1510   }
1511 
1512   QUICHE_DCHECK_EQ(perspective(), Perspective::IS_SERVER);
1513 
1514   QuicStreamId stream_id =
1515       GetLargestPeerCreatedStreamId(/*unidirectional = */ false);
1516 
1517   if (stream_id == QuicUtils::GetInvalidStreamId(transport_version())) {
1518     // No client-initiated bidirectional streams received yet.
1519     // Send 0 to let client know that all requests can be retried.
1520     stream_id = 0;
1521   } else {
1522     // Tell client that streams starting with the next after the largest
1523     // received one can be retried.
1524     stream_id += QuicUtils::StreamIdDelta(transport_version());
1525   }
1526   if (last_sent_http3_goaway_id_.has_value() &&
1527       last_sent_http3_goaway_id_.value() <= stream_id) {
1528     // Do not send GOAWAY frame with a higher id, because it is forbidden.
1529     // Do not send one with same stream id as before, since frames on the
1530     // control stream are guaranteed to be processed in order.
1531     return;
1532   }
1533 
1534   send_control_stream_->SendGoAway(stream_id);
1535   last_sent_http3_goaway_id_ = stream_id;
1536 }
1537 
OnCanCreateNewOutgoingStream(bool unidirectional)1538 void QuicSpdySession::OnCanCreateNewOutgoingStream(bool unidirectional) {
1539   if (unidirectional && VersionUsesHttp3(transport_version())) {
1540     MaybeInitializeHttp3UnidirectionalStreams();
1541   }
1542 }
1543 
goaway_received() const1544 bool QuicSpdySession::goaway_received() const {
1545   return VersionUsesHttp3(transport_version())
1546              ? last_received_http3_goaway_id_.has_value()
1547              : transport_goaway_received();
1548 }
1549 
goaway_sent() const1550 bool QuicSpdySession::goaway_sent() const {
1551   return VersionUsesHttp3(transport_version())
1552              ? last_sent_http3_goaway_id_.has_value()
1553              : transport_goaway_sent();
1554 }
1555 
CloseConnectionOnDuplicateHttp3UnidirectionalStreams(absl::string_view type)1556 void QuicSpdySession::CloseConnectionOnDuplicateHttp3UnidirectionalStreams(
1557     absl::string_view type) {
1558   QUIC_PEER_BUG(quic_peer_bug_10360_9) << absl::StrCat(
1559       "Received a duplicate ", type, " stream: Closing connection.");
1560   CloseConnectionWithDetails(QUIC_HTTP_DUPLICATE_UNIDIRECTIONAL_STREAM,
1561                              absl::StrCat(type, " stream is received twice."));
1562 }
1563 
1564 // static
LogHeaderCompressionRatioHistogram(bool using_qpack,bool is_sent,QuicByteCount compressed,QuicByteCount uncompressed)1565 void QuicSpdySession::LogHeaderCompressionRatioHistogram(
1566     bool using_qpack, bool is_sent, QuicByteCount compressed,
1567     QuicByteCount uncompressed) {
1568   if (compressed <= 0 || uncompressed <= 0) {
1569     return;
1570   }
1571 
1572   int ratio = 100 * (compressed) / (uncompressed);
1573   if (ratio < 1) {
1574     ratio = 1;
1575   } else if (ratio > 200) {
1576     ratio = 200;
1577   }
1578 
1579   // Note that when using histogram macros in Chromium, the histogram name must
1580   // be the same across calls for any given call site.
1581   if (using_qpack) {
1582     if (is_sent) {
1583       QUIC_HISTOGRAM_COUNTS("QuicSession.HeaderCompressionRatioQpackSent",
1584                             ratio, 1, 200, 200,
1585                             "Header compression ratio as percentage for sent "
1586                             "headers using QPACK.");
1587     } else {
1588       QUIC_HISTOGRAM_COUNTS("QuicSession.HeaderCompressionRatioQpackReceived",
1589                             ratio, 1, 200, 200,
1590                             "Header compression ratio as percentage for "
1591                             "received headers using QPACK.");
1592     }
1593   } else {
1594     if (is_sent) {
1595       QUIC_HISTOGRAM_COUNTS("QuicSession.HeaderCompressionRatioHpackSent",
1596                             ratio, 1, 200, 200,
1597                             "Header compression ratio as percentage for sent "
1598                             "headers using HPACK.");
1599     } else {
1600       QUIC_HISTOGRAM_COUNTS("QuicSession.HeaderCompressionRatioHpackReceived",
1601                             ratio, 1, 200, 200,
1602                             "Header compression ratio as percentage for "
1603                             "received headers using HPACK.");
1604     }
1605   }
1606 }
1607 
SendHttp3Datagram(QuicStreamId stream_id,absl::string_view payload)1608 MessageStatus QuicSpdySession::SendHttp3Datagram(QuicStreamId stream_id,
1609                                                  absl::string_view payload) {
1610   if (!SupportsH3Datagram()) {
1611     QUIC_BUG(send http datagram too early)
1612         << "Refusing to send HTTP Datagram before SETTINGS received";
1613     return MESSAGE_STATUS_INTERNAL_ERROR;
1614   }
1615   // Stream ID is sent divided by four as per the specification.
1616   uint64_t stream_id_to_write = stream_id / kHttpDatagramStreamIdDivisor;
1617   size_t slice_length =
1618       QuicDataWriter::GetVarInt62Len(stream_id_to_write) + payload.length();
1619   quiche::QuicheBuffer buffer(
1620       connection()->helper()->GetStreamSendBufferAllocator(), slice_length);
1621   QuicDataWriter writer(slice_length, buffer.data());
1622   if (!writer.WriteVarInt62(stream_id_to_write)) {
1623     QUIC_BUG(h3 datagram stream ID write fail)
1624         << "Failed to write HTTP/3 datagram stream ID";
1625     return MESSAGE_STATUS_INTERNAL_ERROR;
1626   }
1627   if (!writer.WriteBytes(payload.data(), payload.length())) {
1628     QUIC_BUG(h3 datagram payload write fail)
1629         << "Failed to write HTTP/3 datagram payload";
1630     return MESSAGE_STATUS_INTERNAL_ERROR;
1631   }
1632 
1633   quiche::QuicheMemSlice slice(std::move(buffer));
1634   return datagram_queue()->SendOrQueueDatagram(std::move(slice));
1635 }
1636 
SetMaxDatagramTimeInQueueForStreamId(QuicStreamId,QuicTime::Delta max_time_in_queue)1637 void QuicSpdySession::SetMaxDatagramTimeInQueueForStreamId(
1638     QuicStreamId /*stream_id*/, QuicTime::Delta max_time_in_queue) {
1639   // TODO(b/184598230): implement this in a way that works for multiple sessions
1640   // on a same connection.
1641   datagram_queue()->SetMaxTimeInQueue(max_time_in_queue);
1642 }
1643 
OnMessageReceived(absl::string_view message)1644 void QuicSpdySession::OnMessageReceived(absl::string_view message) {
1645   QuicSession::OnMessageReceived(message);
1646   if (!SupportsH3Datagram()) {
1647     QUIC_DLOG(INFO) << "Ignoring unexpected received HTTP/3 datagram";
1648     return;
1649   }
1650   QuicDataReader reader(message);
1651   uint64_t stream_id64;
1652   if (!reader.ReadVarInt62(&stream_id64)) {
1653     QUIC_DLOG(ERROR) << "Failed to parse stream ID in received HTTP/3 datagram";
1654     return;
1655   }
1656   // Stream ID is sent divided by four as per the specification.
1657   if (stream_id64 >
1658       std::numeric_limits<QuicStreamId>::max() / kHttpDatagramStreamIdDivisor) {
1659     CloseConnectionWithDetails(
1660         QUIC_HTTP_FRAME_ERROR,
1661         absl::StrCat("Received HTTP Datagram with invalid quarter stream ID ",
1662                      stream_id64));
1663     return;
1664   }
1665   stream_id64 *= kHttpDatagramStreamIdDivisor;
1666   QuicStreamId stream_id = static_cast<QuicStreamId>(stream_id64);
1667   QuicSpdyStream* stream =
1668       static_cast<QuicSpdyStream*>(GetActiveStream(stream_id));
1669   if (stream == nullptr) {
1670     QUIC_DLOG(INFO) << "Received HTTP/3 datagram for unknown stream ID "
1671                     << stream_id;
1672     // TODO(b/181256914) buffer HTTP/3 datagrams with unknown stream IDs for a
1673     // short period of time in case they were reordered.
1674     return;
1675   }
1676   stream->OnDatagramReceived(&reader);
1677 }
1678 
SupportsWebTransport()1679 bool QuicSpdySession::SupportsWebTransport() {
1680   return WillNegotiateWebTransport() && SupportsH3Datagram() &&
1681          peer_supports_webtransport_ &&
1682          (!GetQuicReloadableFlag(quic_verify_request_headers_2) ||
1683           allow_extended_connect_);
1684 }
1685 
SupportsH3Datagram() const1686 bool QuicSpdySession::SupportsH3Datagram() const {
1687   return http_datagram_support_ != HttpDatagramSupport::kNone;
1688 }
1689 
GetWebTransportSession(WebTransportSessionId id)1690 WebTransportHttp3* QuicSpdySession::GetWebTransportSession(
1691     WebTransportSessionId id) {
1692   if (!SupportsWebTransport()) {
1693     return nullptr;
1694   }
1695   if (!IsValidWebTransportSessionId(id, version())) {
1696     return nullptr;
1697   }
1698   QuicSpdyStream* connect_stream = GetOrCreateSpdyDataStream(id);
1699   if (connect_stream == nullptr) {
1700     return nullptr;
1701   }
1702   return connect_stream->web_transport();
1703 }
1704 
ShouldProcessIncomingRequests()1705 bool QuicSpdySession::ShouldProcessIncomingRequests() {
1706   if (!ShouldBufferRequestsUntilSettings()) {
1707     return true;
1708   }
1709 
1710   return any_settings_received_;
1711 }
1712 
OnStreamWaitingForClientSettings(QuicStreamId id)1713 void QuicSpdySession::OnStreamWaitingForClientSettings(QuicStreamId id) {
1714   QUICHE_DCHECK(ShouldBufferRequestsUntilSettings());
1715   QUICHE_DCHECK(QuicUtils::IsBidirectionalStreamId(id, version()));
1716   streams_waiting_for_settings_.insert(id);
1717 }
1718 
AssociateIncomingWebTransportStreamWithSession(WebTransportSessionId session_id,QuicStreamId stream_id)1719 void QuicSpdySession::AssociateIncomingWebTransportStreamWithSession(
1720     WebTransportSessionId session_id, QuicStreamId stream_id) {
1721   if (QuicUtils::IsOutgoingStreamId(version(), stream_id, perspective())) {
1722     QUIC_BUG(AssociateIncomingWebTransportStreamWithSession got outgoing stream)
1723         << ENDPOINT
1724         << "AssociateIncomingWebTransportStreamWithSession() got an outgoing "
1725            "stream ID: "
1726         << stream_id;
1727     return;
1728   }
1729   WebTransportHttp3* session = GetWebTransportSession(session_id);
1730   if (session != nullptr) {
1731     QUIC_DVLOG(1) << ENDPOINT
1732                   << "Successfully associated incoming WebTransport stream "
1733                   << stream_id << " with session ID " << session_id;
1734 
1735     session->AssociateStream(stream_id);
1736     return;
1737   }
1738   // Evict the oldest streams until we are under the limit.
1739   while (buffered_streams_.size() >= kMaxUnassociatedWebTransportStreams) {
1740     QUIC_DVLOG(1) << ENDPOINT << "Removing stream "
1741                   << buffered_streams_.front().stream_id
1742                   << " from buffered streams as the queue is full.";
1743     ResetStream(buffered_streams_.front().stream_id,
1744                 QUIC_STREAM_WEBTRANSPORT_BUFFERED_STREAMS_LIMIT_EXCEEDED);
1745     buffered_streams_.pop_front();
1746   }
1747   QUIC_DVLOG(1) << ENDPOINT << "Received a WebTransport stream " << stream_id
1748                 << " for session ID " << session_id
1749                 << " but cannot associate it; buffering instead.";
1750   buffered_streams_.push_back(
1751       BufferedWebTransportStream{session_id, stream_id});
1752 }
1753 
ProcessBufferedWebTransportStreamsForSession(WebTransportHttp3 * session)1754 void QuicSpdySession::ProcessBufferedWebTransportStreamsForSession(
1755     WebTransportHttp3* session) {
1756   const WebTransportSessionId session_id = session->id();
1757   QUIC_DVLOG(1) << "Processing buffered WebTransport streams for "
1758                 << session_id;
1759   auto it = buffered_streams_.begin();
1760   while (it != buffered_streams_.end()) {
1761     if (it->session_id == session_id) {
1762       QUIC_DVLOG(1) << "Unbuffered and associated WebTransport stream "
1763                     << it->stream_id << " with session " << it->session_id;
1764       session->AssociateStream(it->stream_id);
1765       it = buffered_streams_.erase(it);
1766     } else {
1767       it++;
1768     }
1769   }
1770 }
1771 
1772 WebTransportHttp3UnidirectionalStream*
CreateOutgoingUnidirectionalWebTransportStream(WebTransportHttp3 * session)1773 QuicSpdySession::CreateOutgoingUnidirectionalWebTransportStream(
1774     WebTransportHttp3* session) {
1775   if (!CanOpenNextOutgoingUnidirectionalStream()) {
1776     return nullptr;
1777   }
1778 
1779   QuicStreamId stream_id = GetNextOutgoingUnidirectionalStreamId();
1780   auto stream_owned = std::make_unique<WebTransportHttp3UnidirectionalStream>(
1781       stream_id, this, session->id());
1782   WebTransportHttp3UnidirectionalStream* stream = stream_owned.get();
1783   ActivateStream(std::move(stream_owned));
1784   stream->WritePreamble();
1785   session->AssociateStream(stream_id);
1786   return stream;
1787 }
1788 
CreateOutgoingBidirectionalWebTransportStream(WebTransportHttp3 * session)1789 QuicSpdyStream* QuicSpdySession::CreateOutgoingBidirectionalWebTransportStream(
1790     WebTransportHttp3* session) {
1791   QuicSpdyStream* stream = CreateOutgoingBidirectionalStream();
1792   if (stream == nullptr) {
1793     return nullptr;
1794   }
1795   QuicStreamId stream_id = stream->id();
1796   stream->ConvertToWebTransportDataStream(session->id());
1797   if (stream->web_transport_stream() == nullptr) {
1798     // An error in ConvertToWebTransportDataStream() would result in
1799     // CONNECTION_CLOSE, thus we don't need to do anything here.
1800     return nullptr;
1801   }
1802   session->AssociateStream(stream_id);
1803   return stream;
1804 }
1805 
OnDatagramProcessed(absl::optional<MessageStatus>)1806 void QuicSpdySession::OnDatagramProcessed(
1807     absl::optional<MessageStatus> /*status*/) {
1808   // TODO(b/184598230): make this work with multiple datagram flows.
1809 }
1810 
OnDatagramProcessed(absl::optional<MessageStatus> status)1811 void QuicSpdySession::DatagramObserver::OnDatagramProcessed(
1812     absl::optional<MessageStatus> status) {
1813   session_->OnDatagramProcessed(status);
1814 }
1815 
LocalHttpDatagramSupport()1816 HttpDatagramSupport QuicSpdySession::LocalHttpDatagramSupport() {
1817   return HttpDatagramSupport::kNone;
1818 }
1819 
HttpDatagramSupportToString(HttpDatagramSupport http_datagram_support)1820 std::string HttpDatagramSupportToString(
1821     HttpDatagramSupport http_datagram_support) {
1822   switch (http_datagram_support) {
1823     case HttpDatagramSupport::kNone:
1824       return "None";
1825     case HttpDatagramSupport::kDraft04:
1826       return "Draft04";
1827     case HttpDatagramSupport::kRfc:
1828       return "Rfc";
1829     case HttpDatagramSupport::kRfcAndDraft04:
1830       return "RfcAndDraft04";
1831   }
1832   return absl::StrCat("Unknown(", static_cast<int>(http_datagram_support), ")");
1833 }
1834 
operator <<(std::ostream & os,const HttpDatagramSupport & http_datagram_support)1835 std::ostream& operator<<(std::ostream& os,
1836                          const HttpDatagramSupport& http_datagram_support) {
1837   os << HttpDatagramSupportToString(http_datagram_support);
1838   return os;
1839 }
1840 
1841 // Must not be called after Initialize().
set_allow_extended_connect(bool allow_extended_connect)1842 void QuicSpdySession::set_allow_extended_connect(bool allow_extended_connect) {
1843   QUIC_BUG_IF(extended connect wrong version,
1844               !GetQuicReloadableFlag(quic_verify_request_headers_2) ||
1845                   !VersionUsesHttp3(transport_version()))
1846       << "Try to enable/disable extended CONNECT in Google QUIC";
1847   QUIC_BUG_IF(extended connect on client,
1848               !GetQuicReloadableFlag(quic_verify_request_headers_2) ||
1849                   perspective() == Perspective::IS_CLIENT)
1850       << "Enabling/disabling extended CONNECT on the client side has no effect";
1851   if (ShouldNegotiateWebTransport()) {
1852     QUIC_BUG_IF(disable extended connect, !allow_extended_connect)
1853         << "Disabling extended CONNECT with web transport enabled has no "
1854            "effect.";
1855     return;
1856   }
1857   allow_extended_connect_ = allow_extended_connect;
1858 }
1859 
1860 #undef ENDPOINT  // undef for jumbo builds
1861 
1862 }  // namespace quic
1863