• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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_stream.h"
6 
7 #include <limits>
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <utility>
12 
13 #include "absl/base/macros.h"
14 #include "absl/strings/numbers.h"
15 #include "absl/strings/str_cat.h"
16 #include "absl/strings/string_view.h"
17 #include "quiche/http2/http2_constants.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_spdy_session.h"
22 #include "quiche/quic/core/http/spdy_utils.h"
23 #include "quiche/quic/core/http/web_transport_http3.h"
24 #include "quiche/quic/core/qpack/qpack_decoder.h"
25 #include "quiche/quic/core/qpack/qpack_encoder.h"
26 #include "quiche/quic/core/quic_error_codes.h"
27 #include "quiche/quic/core/quic_stream_priority.h"
28 #include "quiche/quic/core/quic_types.h"
29 #include "quiche/quic/core/quic_utils.h"
30 #include "quiche/quic/core/quic_versions.h"
31 #include "quiche/quic/core/quic_write_blocked_list.h"
32 #include "quiche/quic/core/web_transport_interface.h"
33 #include "quiche/quic/platform/api/quic_bug_tracker.h"
34 #include "quiche/quic/platform/api/quic_flag_utils.h"
35 #include "quiche/quic/platform/api/quic_flags.h"
36 #include "quiche/quic/platform/api/quic_logging.h"
37 #include "quiche/quic/platform/api/quic_testvalue.h"
38 #include "quiche/common/capsule.h"
39 #include "quiche/common/platform/api/quiche_flag_utils.h"
40 #include "quiche/common/platform/api/quiche_logging.h"
41 #include "quiche/common/quiche_mem_slice_storage.h"
42 #include "quiche/common/quiche_text_utils.h"
43 #include "quiche/spdy/core/spdy_protocol.h"
44 
45 using ::quiche::Capsule;
46 using ::quiche::CapsuleType;
47 using ::spdy::Http2HeaderBlock;
48 
49 namespace quic {
50 
51 // Visitor of HttpDecoder that passes data frame to QuicSpdyStream and closes
52 // the connection on unexpected frames.
53 class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor {
54  public:
HttpDecoderVisitor(QuicSpdyStream * stream)55   explicit HttpDecoderVisitor(QuicSpdyStream* stream) : stream_(stream) {}
56   HttpDecoderVisitor(const HttpDecoderVisitor&) = delete;
57   HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete;
58 
OnError(HttpDecoder * decoder)59   void OnError(HttpDecoder* decoder) override {
60     stream_->OnUnrecoverableError(decoder->error(), decoder->error_detail());
61   }
62 
OnMaxPushIdFrame()63   bool OnMaxPushIdFrame() override {
64     CloseConnectionOnWrongFrame("Max Push Id");
65     return false;
66   }
67 
OnGoAwayFrame(const GoAwayFrame &)68   bool OnGoAwayFrame(const GoAwayFrame& /*frame*/) override {
69     CloseConnectionOnWrongFrame("Goaway");
70     return false;
71   }
72 
OnSettingsFrameStart(QuicByteCount)73   bool OnSettingsFrameStart(QuicByteCount /*header_length*/) override {
74     CloseConnectionOnWrongFrame("Settings");
75     return false;
76   }
77 
OnSettingsFrame(const SettingsFrame &)78   bool OnSettingsFrame(const SettingsFrame& /*frame*/) override {
79     CloseConnectionOnWrongFrame("Settings");
80     return false;
81   }
82 
OnDataFrameStart(QuicByteCount header_length,QuicByteCount payload_length)83   bool OnDataFrameStart(QuicByteCount header_length,
84                         QuicByteCount payload_length) override {
85     return stream_->OnDataFrameStart(header_length, payload_length);
86   }
87 
OnDataFramePayload(absl::string_view payload)88   bool OnDataFramePayload(absl::string_view payload) override {
89     QUICHE_DCHECK(!payload.empty());
90     return stream_->OnDataFramePayload(payload);
91   }
92 
OnDataFrameEnd()93   bool OnDataFrameEnd() override { return stream_->OnDataFrameEnd(); }
94 
OnHeadersFrameStart(QuicByteCount header_length,QuicByteCount payload_length)95   bool OnHeadersFrameStart(QuicByteCount header_length,
96                            QuicByteCount payload_length) override {
97     if (!VersionUsesHttp3(stream_->transport_version())) {
98       CloseConnectionOnWrongFrame("Headers");
99       return false;
100     }
101     return stream_->OnHeadersFrameStart(header_length, payload_length);
102   }
103 
OnHeadersFramePayload(absl::string_view payload)104   bool OnHeadersFramePayload(absl::string_view payload) override {
105     QUICHE_DCHECK(!payload.empty());
106     if (!VersionUsesHttp3(stream_->transport_version())) {
107       CloseConnectionOnWrongFrame("Headers");
108       return false;
109     }
110     return stream_->OnHeadersFramePayload(payload);
111   }
112 
OnHeadersFrameEnd()113   bool OnHeadersFrameEnd() override {
114     if (!VersionUsesHttp3(stream_->transport_version())) {
115       CloseConnectionOnWrongFrame("Headers");
116       return false;
117     }
118     return stream_->OnHeadersFrameEnd();
119   }
120 
OnPriorityUpdateFrameStart(QuicByteCount)121   bool OnPriorityUpdateFrameStart(QuicByteCount /*header_length*/) override {
122     CloseConnectionOnWrongFrame("Priority update");
123     return false;
124   }
125 
OnPriorityUpdateFrame(const PriorityUpdateFrame &)126   bool OnPriorityUpdateFrame(const PriorityUpdateFrame& /*frame*/) override {
127     CloseConnectionOnWrongFrame("Priority update");
128     return false;
129   }
130 
OnAcceptChFrameStart(QuicByteCount)131   bool OnAcceptChFrameStart(QuicByteCount /*header_length*/) override {
132     CloseConnectionOnWrongFrame("ACCEPT_CH");
133     return false;
134   }
135 
OnAcceptChFrame(const AcceptChFrame &)136   bool OnAcceptChFrame(const AcceptChFrame& /*frame*/) override {
137     CloseConnectionOnWrongFrame("ACCEPT_CH");
138     return false;
139   }
140 
OnWebTransportStreamFrameType(QuicByteCount header_length,WebTransportSessionId session_id)141   void OnWebTransportStreamFrameType(
142       QuicByteCount header_length, WebTransportSessionId session_id) override {
143     stream_->OnWebTransportStreamFrameType(header_length, session_id);
144   }
145 
OnUnknownFrameStart(uint64_t frame_type,QuicByteCount header_length,QuicByteCount payload_length)146   bool OnUnknownFrameStart(uint64_t frame_type, QuicByteCount header_length,
147                            QuicByteCount payload_length) override {
148     return stream_->OnUnknownFrameStart(frame_type, header_length,
149                                         payload_length);
150   }
151 
OnUnknownFramePayload(absl::string_view payload)152   bool OnUnknownFramePayload(absl::string_view payload) override {
153     return stream_->OnUnknownFramePayload(payload);
154   }
155 
OnUnknownFrameEnd()156   bool OnUnknownFrameEnd() override { return stream_->OnUnknownFrameEnd(); }
157 
158  private:
CloseConnectionOnWrongFrame(absl::string_view frame_type)159   void CloseConnectionOnWrongFrame(absl::string_view frame_type) {
160     stream_->OnUnrecoverableError(
161         QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM,
162         absl::StrCat(frame_type, " frame received on data stream"));
163   }
164 
165   QuicSpdyStream* stream_;
166 };
167 
168 #define ENDPOINT                                                   \
169   (session()->perspective() == Perspective::IS_SERVER ? "Server: " \
170                                                       : "Client:"  \
171                                                         " ")
172 
QuicSpdyStream(QuicStreamId id,QuicSpdySession * spdy_session,StreamType type)173 QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session,
174                                StreamType type)
175     : QuicStream(id, spdy_session, /*is_static=*/false, type),
176       spdy_session_(spdy_session),
177       on_body_available_called_because_sequencer_is_closed_(false),
178       visitor_(nullptr),
179       blocked_on_decoding_headers_(false),
180       headers_decompressed_(false),
181       header_list_size_limit_exceeded_(false),
182       headers_payload_length_(0),
183       trailers_decompressed_(false),
184       trailers_consumed_(false),
185       http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)),
186       decoder_(http_decoder_visitor_.get()),
187       sequencer_offset_(0),
188       is_decoder_processing_input_(false),
189       ack_listener_(nullptr),
190       last_sent_priority_(
191           QuicStreamPriority::Default(spdy_session->priority_type())) {
192   QUICHE_DCHECK_EQ(session()->connection(), spdy_session->connection());
193   QUICHE_DCHECK_EQ(transport_version(), spdy_session->transport_version());
194   QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id));
195   QUICHE_DCHECK_EQ(0u, sequencer()->NumBytesConsumed());
196   // If headers are sent on the headers stream, then do not receive any
197   // callbacks from the sequencer until headers are complete.
198   if (!VersionUsesHttp3(transport_version())) {
199     sequencer()->SetBlockedUntilFlush();
200   }
201 
202   if (VersionUsesHttp3(transport_version())) {
203     sequencer()->set_level_triggered(true);
204   }
205 
206   spdy_session_->OnStreamCreated(this);
207 }
208 
QuicSpdyStream(PendingStream * pending,QuicSpdySession * spdy_session)209 QuicSpdyStream::QuicSpdyStream(PendingStream* pending,
210                                QuicSpdySession* spdy_session)
211     : QuicStream(pending, spdy_session, /*is_static=*/false),
212       spdy_session_(spdy_session),
213       on_body_available_called_because_sequencer_is_closed_(false),
214       visitor_(nullptr),
215       blocked_on_decoding_headers_(false),
216       headers_decompressed_(false),
217       header_list_size_limit_exceeded_(false),
218       headers_payload_length_(0),
219       trailers_decompressed_(false),
220       trailers_consumed_(false),
221       http_decoder_visitor_(std::make_unique<HttpDecoderVisitor>(this)),
222       decoder_(http_decoder_visitor_.get()),
223       sequencer_offset_(sequencer()->NumBytesConsumed()),
224       is_decoder_processing_input_(false),
225       ack_listener_(nullptr),
226       last_sent_priority_(
227           QuicStreamPriority::Default(spdy_session->priority_type())) {
228   QUICHE_DCHECK_EQ(session()->connection(), spdy_session->connection());
229   QUICHE_DCHECK_EQ(transport_version(), spdy_session->transport_version());
230   QUICHE_DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id()));
231   // If headers are sent on the headers stream, then do not receive any
232   // callbacks from the sequencer until headers are complete.
233   if (!VersionUsesHttp3(transport_version())) {
234     sequencer()->SetBlockedUntilFlush();
235   }
236 
237   if (VersionUsesHttp3(transport_version())) {
238     sequencer()->set_level_triggered(true);
239   }
240 
241   spdy_session_->OnStreamCreated(this);
242 }
243 
~QuicSpdyStream()244 QuicSpdyStream::~QuicSpdyStream() {}
245 
WriteHeaders(Http2HeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)246 size_t QuicSpdyStream::WriteHeaders(
247     Http2HeaderBlock header_block, bool fin,
248     quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
249         ack_listener) {
250   if (!AssertNotWebTransportDataStream("writing headers")) {
251     return 0;
252   }
253 
254   QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
255 
256   MaybeProcessSentWebTransportHeaders(header_block);
257 
258   if (web_transport_ != nullptr &&
259       spdy_session_->perspective() == Perspective::IS_SERVER &&
260       spdy_session_->SupportedWebTransportVersion() ==
261           WebTransportHttp3Version::kDraft02) {
262     header_block["sec-webtransport-http3-draft"] = "draft02";
263   }
264 
265   size_t bytes_written =
266       WriteHeadersImpl(std::move(header_block), fin, std::move(ack_listener));
267   if (!VersionUsesHttp3(transport_version()) && fin) {
268     // If HEADERS are sent on the headers stream, then |fin_sent_| needs to be
269     // set and write side needs to be closed without actually sending a FIN on
270     // this stream.
271     // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent.
272     SetFinSent();
273     CloseWriteSide();
274   }
275 
276   if (web_transport_ != nullptr &&
277       session()->perspective() == Perspective::IS_CLIENT) {
278     WriteGreaseCapsule();
279     if (spdy_session_->http_datagram_support() ==
280         HttpDatagramSupport::kDraft04) {
281       // Send a REGISTER_DATAGRAM_NO_CONTEXT capsule to support servers that
282       // are running draft-ietf-masque-h3-datagram-04 or -05.
283       uint64_t capsule_type = 0xff37a2;  // REGISTER_DATAGRAM_NO_CONTEXT
284       constexpr unsigned char capsule_data[4] = {
285           0x80, 0xff, 0x7c, 0x00,  // WEBTRANSPORT datagram format type
286       };
287       WriteCapsule(Capsule::Unknown(
288           capsule_type,
289           absl::string_view(reinterpret_cast<const char*>(capsule_data),
290                             sizeof(capsule_data))));
291       WriteGreaseCapsule();
292     }
293   }
294 
295   if (connect_ip_visitor_ != nullptr) {
296     connect_ip_visitor_->OnHeadersWritten();
297   }
298 
299   return bytes_written;
300 }
301 
WriteOrBufferBody(absl::string_view data,bool fin)302 void QuicSpdyStream::WriteOrBufferBody(absl::string_view data, bool fin) {
303   if (!AssertNotWebTransportDataStream("writing body data")) {
304     return;
305   }
306   if (!VersionUsesHttp3(transport_version()) || data.length() == 0) {
307     WriteOrBufferData(data, fin, nullptr);
308     return;
309   }
310   QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
311 
312   const bool success =
313       WriteDataFrameHeader(data.length(), /*force_write=*/true);
314   QUICHE_DCHECK(success);
315 
316   // Write body.
317   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id()
318                   << " is writing DATA frame payload of length "
319                   << data.length() << " with fin " << fin;
320   WriteOrBufferData(data, fin, nullptr);
321 }
322 
WriteTrailers(Http2HeaderBlock trailer_block,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)323 size_t QuicSpdyStream::WriteTrailers(
324     Http2HeaderBlock trailer_block,
325     quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
326         ack_listener) {
327   if (fin_sent()) {
328     QUIC_BUG(quic_bug_10410_1)
329         << "Trailers cannot be sent after a FIN, on stream " << id();
330     return 0;
331   }
332 
333   if (!VersionUsesHttp3(transport_version())) {
334     // The header block must contain the final offset for this stream, as the
335     // trailers may be processed out of order at the peer.
336     const QuicStreamOffset final_offset =
337         stream_bytes_written() + BufferedDataBytes();
338     QUIC_DLOG(INFO) << ENDPOINT << "Inserting trailer: ("
339                     << kFinalOffsetHeaderKey << ", " << final_offset << ")";
340     trailer_block.insert(
341         std::make_pair(kFinalOffsetHeaderKey, absl::StrCat(final_offset)));
342   }
343 
344   // Write the trailing headers with a FIN, and close stream for writing:
345   // trailers are the last thing to be sent on a stream.
346   const bool kFin = true;
347   size_t bytes_written =
348       WriteHeadersImpl(std::move(trailer_block), kFin, std::move(ack_listener));
349 
350   // If trailers are sent on the headers stream, then |fin_sent_| needs to be
351   // set without actually sending a FIN on this stream.
352   if (!VersionUsesHttp3(transport_version())) {
353     SetFinSent();
354 
355     // Also, write side of this stream needs to be closed.  However, only do
356     // this if there is no more buffered data, otherwise it will never be sent.
357     if (BufferedDataBytes() == 0) {
358       CloseWriteSide();
359     }
360   }
361 
362   return bytes_written;
363 }
364 
WritevBody(const struct iovec * iov,int count,bool fin)365 QuicConsumedData QuicSpdyStream::WritevBody(const struct iovec* iov, int count,
366                                             bool fin) {
367   quiche::QuicheMemSliceStorage storage(
368       iov, count,
369       session()->connection()->helper()->GetStreamSendBufferAllocator(),
370       GetQuicFlag(quic_send_buffer_max_data_slice_size));
371   return WriteBodySlices(storage.ToSpan(), fin);
372 }
373 
WriteDataFrameHeader(QuicByteCount data_length,bool force_write)374 bool QuicSpdyStream::WriteDataFrameHeader(QuicByteCount data_length,
375                                           bool force_write) {
376   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
377   QUICHE_DCHECK_GT(data_length, 0u);
378   quiche::QuicheBuffer header = HttpEncoder::SerializeDataFrameHeader(
379       data_length,
380       spdy_session_->connection()->helper()->GetStreamSendBufferAllocator());
381   const bool can_write = CanWriteNewDataAfterData(header.size());
382   if (!can_write && !force_write) {
383     return false;
384   }
385 
386   if (spdy_session_->debug_visitor()) {
387     spdy_session_->debug_visitor()->OnDataFrameSent(id(), data_length);
388   }
389 
390   unacked_frame_headers_offsets_.Add(
391       send_buffer().stream_offset(),
392       send_buffer().stream_offset() + header.size());
393   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id()
394                   << " is writing DATA frame header of length "
395                   << header.size();
396   if (can_write) {
397     // Save one copy and allocation if send buffer can accomodate the header.
398     quiche::QuicheMemSlice header_slice(std::move(header));
399     WriteMemSlices(absl::MakeSpan(&header_slice, 1), false);
400   } else {
401     QUICHE_DCHECK(force_write);
402     WriteOrBufferData(header.AsStringView(), false, nullptr);
403   }
404   return true;
405 }
406 
WriteBodySlices(absl::Span<quiche::QuicheMemSlice> slices,bool fin)407 QuicConsumedData QuicSpdyStream::WriteBodySlices(
408     absl::Span<quiche::QuicheMemSlice> slices, bool fin) {
409   if (!VersionUsesHttp3(transport_version()) || slices.empty()) {
410     return WriteMemSlices(slices, fin);
411   }
412 
413   QuicConnection::ScopedPacketFlusher flusher(spdy_session_->connection());
414   const QuicByteCount data_size = MemSliceSpanTotalSize(slices);
415   if (!WriteDataFrameHeader(data_size, /*force_write=*/false)) {
416     return {0, false};
417   }
418 
419   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id()
420                   << " is writing DATA frame payload of length " << data_size;
421   return WriteMemSlices(slices, fin);
422 }
423 
Readv(const struct iovec * iov,size_t iov_len)424 size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) {
425   QUICHE_DCHECK(FinishedReadingHeaders());
426   if (!VersionUsesHttp3(transport_version())) {
427     return sequencer()->Readv(iov, iov_len);
428   }
429   size_t bytes_read = 0;
430   sequencer()->MarkConsumed(body_manager_.ReadBody(iov, iov_len, &bytes_read));
431 
432   return bytes_read;
433 }
434 
GetReadableRegions(iovec * iov,size_t iov_len) const435 int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const {
436   QUICHE_DCHECK(FinishedReadingHeaders());
437   if (!VersionUsesHttp3(transport_version())) {
438     return sequencer()->GetReadableRegions(iov, iov_len);
439   }
440   return body_manager_.PeekBody(iov, iov_len);
441 }
442 
MarkConsumed(size_t num_bytes)443 void QuicSpdyStream::MarkConsumed(size_t num_bytes) {
444   QUICHE_DCHECK(FinishedReadingHeaders());
445   if (!VersionUsesHttp3(transport_version())) {
446     sequencer()->MarkConsumed(num_bytes);
447     return;
448   }
449 
450   sequencer()->MarkConsumed(body_manager_.OnBodyConsumed(num_bytes));
451 }
452 
IsDoneReading() const453 bool QuicSpdyStream::IsDoneReading() const {
454   bool done_reading_headers = FinishedReadingHeaders();
455   bool done_reading_body = sequencer()->IsClosed();
456   bool done_reading_trailers = FinishedReadingTrailers();
457   return done_reading_headers && done_reading_body && done_reading_trailers;
458 }
459 
HasBytesToRead() const460 bool QuicSpdyStream::HasBytesToRead() const {
461   if (!VersionUsesHttp3(transport_version())) {
462     return sequencer()->HasBytesToRead();
463   }
464   return body_manager_.HasBytesToRead();
465 }
466 
ReadableBytes() const467 QuicByteCount QuicSpdyStream::ReadableBytes() const {
468   if (!VersionUsesHttp3(transport_version())) {
469     return sequencer()->ReadableBytes();
470   }
471   return body_manager_.ReadableBytes();
472 }
473 
MarkTrailersConsumed()474 void QuicSpdyStream::MarkTrailersConsumed() { trailers_consumed_ = true; }
475 
total_body_bytes_read() const476 uint64_t QuicSpdyStream::total_body_bytes_read() const {
477   if (VersionUsesHttp3(transport_version())) {
478     return body_manager_.total_body_bytes_received();
479   }
480   return sequencer()->NumBytesConsumed();
481 }
482 
ConsumeHeaderList()483 void QuicSpdyStream::ConsumeHeaderList() {
484   header_list_.Clear();
485 
486   if (!FinishedReadingHeaders()) {
487     return;
488   }
489 
490   if (!VersionUsesHttp3(transport_version())) {
491     sequencer()->SetUnblocked();
492     return;
493   }
494 
495   if (body_manager_.HasBytesToRead()) {
496     HandleBodyAvailable();
497     return;
498   }
499 
500   if (sequencer()->IsClosed() &&
501       !on_body_available_called_because_sequencer_is_closed_) {
502     on_body_available_called_because_sequencer_is_closed_ = true;
503     HandleBodyAvailable();
504   }
505 }
506 
OnStreamHeadersPriority(const spdy::SpdyStreamPrecedence & precedence)507 void QuicSpdyStream::OnStreamHeadersPriority(
508     const spdy::SpdyStreamPrecedence& precedence) {
509   QUICHE_DCHECK_EQ(Perspective::IS_SERVER,
510                    session()->connection()->perspective());
511   if (session()->priority_type() != QuicPriorityType::kHttp) {
512     return;
513   }
514   SetPriority(QuicStreamPriority(HttpStreamPriority{
515       precedence.spdy3_priority(), HttpStreamPriority::kDefaultIncremental}));
516 }
517 
OnStreamHeaderList(bool fin,size_t frame_len,const QuicHeaderList & header_list)518 void QuicSpdyStream::OnStreamHeaderList(bool fin, size_t frame_len,
519                                         const QuicHeaderList& header_list) {
520   if (!spdy_session()->user_agent_id().has_value()) {
521     std::string uaid;
522     for (const auto& kv : header_list) {
523       if (quiche::QuicheTextUtils::ToLower(kv.first) == kUserAgentHeaderName) {
524         uaid = kv.second;
525         break;
526       }
527     }
528     spdy_session()->SetUserAgentId(std::move(uaid));
529   }
530 
531   // TODO(b/134706391): remove |fin| argument.
532   // When using Google QUIC, an empty header list indicates that the size limit
533   // has been exceeded.
534   // When using IETF QUIC, there is an explicit signal from
535   // QpackDecodedHeadersAccumulator.
536   if ((VersionUsesHttp3(transport_version()) &&
537        header_list_size_limit_exceeded_) ||
538       (!VersionUsesHttp3(transport_version()) && header_list.empty())) {
539     OnHeadersTooLarge();
540     if (IsDoneReading()) {
541       return;
542     }
543   }
544   if (!NextHeaderIsTrailer()) {
545     OnInitialHeadersComplete(fin, frame_len, header_list);
546   } else {
547     OnTrailingHeadersComplete(fin, frame_len, header_list);
548   }
549 }
550 
OnHeadersDecoded(QuicHeaderList headers,bool header_list_size_limit_exceeded)551 void QuicSpdyStream::OnHeadersDecoded(QuicHeaderList headers,
552                                       bool header_list_size_limit_exceeded) {
553   header_list_size_limit_exceeded_ = header_list_size_limit_exceeded;
554   qpack_decoded_headers_accumulator_.reset();
555 
556   QuicSpdySession::LogHeaderCompressionRatioHistogram(
557       /* using_qpack = */ true,
558       /* is_sent = */ false, headers.compressed_header_bytes(),
559       headers.uncompressed_header_bytes());
560 
561   Http3DebugVisitor* const debug_visitor = spdy_session()->debug_visitor();
562   if (debug_visitor) {
563     debug_visitor->OnHeadersDecoded(id(), headers);
564   }
565 
566   OnStreamHeaderList(/* fin = */ false, headers_payload_length_, headers);
567 
568   if (blocked_on_decoding_headers_) {
569     blocked_on_decoding_headers_ = false;
570     // Continue decoding HTTP/3 frames.
571     OnDataAvailable();
572   }
573 }
574 
OnHeaderDecodingError(QuicErrorCode error_code,absl::string_view error_message)575 void QuicSpdyStream::OnHeaderDecodingError(QuicErrorCode error_code,
576                                            absl::string_view error_message) {
577   qpack_decoded_headers_accumulator_.reset();
578 
579   std::string connection_close_error_message = absl::StrCat(
580       "Error decoding ", headers_decompressed_ ? "trailers" : "headers",
581       " on stream ", id(), ": ", error_message);
582   OnUnrecoverableError(error_code, connection_close_error_message);
583 }
584 
MaybeSendPriorityUpdateFrame()585 void QuicSpdyStream::MaybeSendPriorityUpdateFrame() {
586   if (!VersionUsesHttp3(transport_version()) ||
587       session()->perspective() != Perspective::IS_CLIENT) {
588     return;
589   }
590   if (spdy_session_->priority_type() != QuicPriorityType::kHttp) {
591     return;
592   }
593 
594   if (last_sent_priority_ == priority()) {
595     return;
596   }
597   last_sent_priority_ = priority();
598 
599   spdy_session_->WriteHttp3PriorityUpdate(id(), priority().http());
600 }
601 
OnHeadersTooLarge()602 void QuicSpdyStream::OnHeadersTooLarge() { Reset(QUIC_HEADERS_TOO_LARGE); }
603 
OnInitialHeadersComplete(bool fin,size_t,const QuicHeaderList & header_list)604 void QuicSpdyStream::OnInitialHeadersComplete(
605     bool fin, size_t /*frame_len*/, const QuicHeaderList& header_list) {
606   // TODO(b/134706391): remove |fin| argument.
607   headers_decompressed_ = true;
608   header_list_ = header_list;
609   bool header_too_large = VersionUsesHttp3(transport_version())
610                               ? header_list_size_limit_exceeded_
611                               : header_list.empty();
612   if (!AreHeaderFieldValuesValid(header_list)) {
613     OnInvalidHeaders();
614     return;
615   }
616   // Validate request headers if it did not exceed size limit. If it did,
617   // OnHeadersTooLarge() should have already handled it previously.
618   if (!header_too_large && !ValidateReceivedHeaders(header_list)) {
619     QUIC_CODE_COUNT_N(quic_validate_request_header, 1, 2);
620     QUICHE_DCHECK(!invalid_request_details().empty())
621         << "ValidatedRequestHeaders() returns false without populating "
622            "invalid_request_details_";
623     if (GetQuicReloadableFlag(quic_act_upon_invalid_header)) {
624       QUIC_RELOADABLE_FLAG_COUNT(quic_act_upon_invalid_header);
625       OnInvalidHeaders();
626       return;
627     }
628   }
629   QUIC_CODE_COUNT_N(quic_validate_request_header, 2, 2);
630 
631   if (!header_too_large) {
632     MaybeProcessReceivedWebTransportHeaders();
633   }
634 
635   if (VersionUsesHttp3(transport_version())) {
636     if (fin) {
637       OnStreamFrame(QuicStreamFrame(id(), /* fin = */ true,
638                                     highest_received_byte_offset(),
639                                     absl::string_view()));
640     }
641     return;
642   }
643 
644   if (fin && !rst_sent()) {
645     OnStreamFrame(
646         QuicStreamFrame(id(), fin, /* offset = */ 0, absl::string_view()));
647   }
648   if (FinishedReadingHeaders()) {
649     sequencer()->SetUnblocked();
650   }
651 }
652 
CopyAndValidateTrailers(const QuicHeaderList & header_list,bool expect_final_byte_offset,size_t * final_byte_offset,spdy::Http2HeaderBlock * trailers)653 bool QuicSpdyStream::CopyAndValidateTrailers(const QuicHeaderList& header_list,
654                                              bool expect_final_byte_offset,
655                                              size_t* final_byte_offset,
656                                              spdy::Http2HeaderBlock* trailers) {
657   return SpdyUtils::CopyAndValidateTrailers(
658       header_list, expect_final_byte_offset, final_byte_offset, trailers);
659 }
660 
OnTrailingHeadersComplete(bool fin,size_t,const QuicHeaderList & header_list)661 void QuicSpdyStream::OnTrailingHeadersComplete(
662     bool fin, size_t /*frame_len*/, const QuicHeaderList& header_list) {
663   // TODO(b/134706391): remove |fin| argument.
664   QUICHE_DCHECK(!trailers_decompressed_);
665   if (!VersionUsesHttp3(transport_version()) && fin_received()) {
666     QUIC_DLOG(INFO) << ENDPOINT
667                     << "Received Trailers after FIN, on stream: " << id();
668     stream_delegate()->OnStreamError(QUIC_INVALID_HEADERS_STREAM_DATA,
669                                      "Trailers after fin");
670     return;
671   }
672 
673   if (!VersionUsesHttp3(transport_version()) && !fin) {
674     QUIC_DLOG(INFO) << ENDPOINT
675                     << "Trailers must have FIN set, on stream: " << id();
676     stream_delegate()->OnStreamError(QUIC_INVALID_HEADERS_STREAM_DATA,
677                                      "Fin missing from trailers");
678     return;
679   }
680 
681   size_t final_byte_offset = 0;
682   const bool expect_final_byte_offset = !VersionUsesHttp3(transport_version());
683   if (!CopyAndValidateTrailers(header_list, expect_final_byte_offset,
684                                &final_byte_offset, &received_trailers_)) {
685     QUIC_DLOG(ERROR) << ENDPOINT << "Trailers for stream " << id()
686                      << " are malformed.";
687     stream_delegate()->OnStreamError(QUIC_INVALID_HEADERS_STREAM_DATA,
688                                      "Trailers are malformed");
689     return;
690   }
691   trailers_decompressed_ = true;
692   if (fin) {
693     const QuicStreamOffset offset = VersionUsesHttp3(transport_version())
694                                         ? highest_received_byte_offset()
695                                         : final_byte_offset;
696     OnStreamFrame(QuicStreamFrame(id(), fin, offset, absl::string_view()));
697   }
698 }
699 
OnPriorityFrame(const spdy::SpdyStreamPrecedence & precedence)700 void QuicSpdyStream::OnPriorityFrame(
701     const spdy::SpdyStreamPrecedence& precedence) {
702   QUICHE_DCHECK_EQ(Perspective::IS_SERVER,
703                    session()->connection()->perspective());
704   if (session()->priority_type() != QuicPriorityType::kHttp) {
705     return;
706   }
707   SetPriority(QuicStreamPriority(HttpStreamPriority{
708       precedence.spdy3_priority(), HttpStreamPriority::kDefaultIncremental}));
709 }
710 
OnStreamReset(const QuicRstStreamFrame & frame)711 void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) {
712   if (web_transport_data_ != nullptr) {
713     WebTransportStreamVisitor* webtransport_visitor =
714         web_transport_data_->adapter.visitor();
715     if (webtransport_visitor != nullptr) {
716       webtransport_visitor->OnResetStreamReceived(
717           Http3ErrorToWebTransportOrDefault(frame.ietf_error_code));
718     }
719     QuicStream::OnStreamReset(frame);
720     return;
721   }
722 
723   if (VersionUsesHttp3(transport_version()) && !fin_received() &&
724       spdy_session_->qpack_decoder()) {
725     spdy_session_->qpack_decoder()->OnStreamReset(id());
726     qpack_decoded_headers_accumulator_.reset();
727   }
728 
729   if (VersionUsesHttp3(transport_version()) ||
730       frame.error_code != QUIC_STREAM_NO_ERROR) {
731     QuicStream::OnStreamReset(frame);
732     return;
733   }
734 
735   QUIC_DVLOG(1) << ENDPOINT
736                 << "Received QUIC_STREAM_NO_ERROR, not discarding response";
737   set_rst_received(true);
738   MaybeIncreaseHighestReceivedOffset(frame.byte_offset);
739   set_stream_error(frame.error());
740   CloseWriteSide();
741 }
742 
ResetWithError(QuicResetStreamError error)743 void QuicSpdyStream::ResetWithError(QuicResetStreamError error) {
744   if (VersionUsesHttp3(transport_version()) && !fin_received() &&
745       spdy_session_->qpack_decoder() && web_transport_data_ == nullptr) {
746     spdy_session_->qpack_decoder()->OnStreamReset(id());
747     qpack_decoded_headers_accumulator_.reset();
748   }
749 
750   QuicStream::ResetWithError(error);
751 }
752 
OnStopSending(QuicResetStreamError error)753 bool QuicSpdyStream::OnStopSending(QuicResetStreamError error) {
754   if (web_transport_data_ != nullptr) {
755     WebTransportStreamVisitor* visitor = web_transport_data_->adapter.visitor();
756     if (visitor != nullptr) {
757       visitor->OnStopSendingReceived(
758           Http3ErrorToWebTransportOrDefault(error.ietf_application_code()));
759     }
760   }
761 
762   return QuicStream::OnStopSending(error);
763 }
764 
OnWriteSideInDataRecvdState()765 void QuicSpdyStream::OnWriteSideInDataRecvdState() {
766   if (web_transport_data_ != nullptr) {
767     WebTransportStreamVisitor* visitor = web_transport_data_->adapter.visitor();
768     if (visitor != nullptr) {
769       visitor->OnWriteSideInDataRecvdState();
770     }
771   }
772 
773   QuicStream::OnWriteSideInDataRecvdState();
774 }
775 
OnDataAvailable()776 void QuicSpdyStream::OnDataAvailable() {
777   if (!VersionUsesHttp3(transport_version())) {
778     // Sequencer must be blocked until headers are consumed.
779     QUICHE_DCHECK(FinishedReadingHeaders());
780   }
781 
782   if (!VersionUsesHttp3(transport_version())) {
783     HandleBodyAvailable();
784     return;
785   }
786 
787   if (web_transport_data_ != nullptr) {
788     web_transport_data_->adapter.OnDataAvailable();
789     return;
790   }
791 
792   if (!spdy_session()->ShouldProcessIncomingRequests()) {
793     spdy_session()->OnStreamWaitingForClientSettings(id());
794     return;
795   }
796 
797   if (is_decoder_processing_input_) {
798     // Let the outermost nested OnDataAvailable() call do the work.
799     return;
800   }
801 
802   if (blocked_on_decoding_headers_) {
803     return;
804   }
805 
806   if (spdy_session_->SupportsWebTransport()) {
807     // We do this here, since at this point, we have passed the
808     // ShouldProcessIncomingRequests() check above, meaning we know for a fact
809     // if we should be parsing WEBTRANSPORT_STREAM or not.
810     decoder_.EnableWebTransportStreamParsing();
811   }
812 
813   iovec iov;
814   while (session()->connection()->connected() && !reading_stopped() &&
815          decoder_.error() == QUIC_NO_ERROR) {
816     QUICHE_DCHECK_GE(sequencer_offset_, sequencer()->NumBytesConsumed());
817     if (!sequencer()->PeekRegion(sequencer_offset_, &iov)) {
818       break;
819     }
820 
821     QUICHE_DCHECK(!sequencer()->IsClosed());
822     is_decoder_processing_input_ = true;
823     QuicByteCount processed_bytes = decoder_.ProcessInput(
824         reinterpret_cast<const char*>(iov.iov_base), iov.iov_len);
825     is_decoder_processing_input_ = false;
826     if (!session()->connection()->connected()) {
827       return;
828     }
829     sequencer_offset_ += processed_bytes;
830     if (blocked_on_decoding_headers_) {
831       return;
832     }
833     if (web_transport_data_ != nullptr) {
834       return;
835     }
836   }
837 
838   // Do not call HandleBodyAvailable() until headers are consumed.
839   if (!FinishedReadingHeaders()) {
840     return;
841   }
842 
843   if (body_manager_.HasBytesToRead()) {
844     HandleBodyAvailable();
845     return;
846   }
847 
848   if (sequencer()->IsClosed() &&
849       !on_body_available_called_because_sequencer_is_closed_) {
850     on_body_available_called_because_sequencer_is_closed_ = true;
851     HandleBodyAvailable();
852   }
853 }
854 
OnClose()855 void QuicSpdyStream::OnClose() {
856   QuicStream::OnClose();
857 
858   qpack_decoded_headers_accumulator_.reset();
859 
860   if (visitor_) {
861     Visitor* visitor = visitor_;
862     // Calling Visitor::OnClose() may result the destruction of the visitor,
863     // so we need to ensure we don't call it again.
864     visitor_ = nullptr;
865     visitor->OnClose(this);
866   }
867 
868   if (web_transport_ != nullptr) {
869     web_transport_->OnConnectStreamClosing();
870   }
871   if (web_transport_data_ != nullptr) {
872     WebTransportHttp3* web_transport =
873         spdy_session_->GetWebTransportSession(web_transport_data_->session_id);
874     if (web_transport == nullptr) {
875       // Since there is no guaranteed destruction order for streams, the session
876       // could be already removed from the stream map by the time we reach here.
877       QUIC_DLOG(WARNING) << ENDPOINT << "WebTransport stream " << id()
878                          << " attempted to notify parent session "
879                          << web_transport_data_->session_id
880                          << ", but the session could not be found.";
881       return;
882     }
883     web_transport->OnStreamClosed(id());
884   }
885 }
886 
OnCanWrite()887 void QuicSpdyStream::OnCanWrite() {
888   QuicStream::OnCanWrite();
889 
890   // Trailers (and hence a FIN) may have been sent ahead of queued body bytes.
891   if (!HasBufferedData() && fin_sent()) {
892     CloseWriteSide();
893   }
894 }
895 
FinishedReadingHeaders() const896 bool QuicSpdyStream::FinishedReadingHeaders() const {
897   return headers_decompressed_ && header_list_.empty();
898 }
899 
ParseHeaderStatusCode(const Http2HeaderBlock & header,int * status_code)900 bool QuicSpdyStream::ParseHeaderStatusCode(const Http2HeaderBlock& header,
901                                            int* status_code) {
902   Http2HeaderBlock::const_iterator it = header.find(spdy::kHttp2StatusHeader);
903   if (it == header.end()) {
904     return false;
905   }
906   const absl::string_view status(it->second);
907   return ParseHeaderStatusCode(status, status_code);
908 }
909 
ParseHeaderStatusCode(absl::string_view status,int * status_code)910 bool QuicSpdyStream::ParseHeaderStatusCode(absl::string_view status,
911                                            int* status_code) {
912   if (status.size() != 3) {
913     return false;
914   }
915   // First character must be an integer in range [1,5].
916   if (status[0] < '1' || status[0] > '5') {
917     return false;
918   }
919   // The remaining two characters must be integers.
920   if (!isdigit(status[1]) || !isdigit(status[2])) {
921     return false;
922   }
923   return absl::SimpleAtoi(status, status_code);
924 }
925 
FinishedReadingTrailers() const926 bool QuicSpdyStream::FinishedReadingTrailers() const {
927   // If no further trailing headers are expected, and the decompressed trailers
928   // (if any) have been consumed, then reading of trailers is finished.
929   if (!fin_received()) {
930     return false;
931   } else if (!trailers_decompressed_) {
932     return true;
933   } else {
934     return trailers_consumed_;
935   }
936 }
937 
OnDataFrameStart(QuicByteCount header_length,QuicByteCount payload_length)938 bool QuicSpdyStream::OnDataFrameStart(QuicByteCount header_length,
939                                       QuicByteCount payload_length) {
940   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
941 
942   if (spdy_session_->debug_visitor()) {
943     spdy_session_->debug_visitor()->OnDataFrameReceived(id(), payload_length);
944   }
945 
946   if (!headers_decompressed_ || trailers_decompressed_) {
947     QUICHE_LOG(INFO) << ENDPOINT << "stream_id: " << id()
948                      << ", headers_decompressed: "
949                      << (headers_decompressed_ ? "true" : "false")
950                      << ", trailers_decompressed: "
951                      << (trailers_decompressed_ ? "true" : "false")
952                      << ", NumBytesConsumed: "
953                      << sequencer()->NumBytesConsumed()
954                      << ", total_body_bytes_received: "
955                      << body_manager_.total_body_bytes_received()
956                      << ", header_length: " << header_length
957                      << ", payload_length: " << payload_length;
958     stream_delegate()->OnStreamError(
959         QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
960         "Unexpected DATA frame received.");
961     return false;
962   }
963 
964   sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
965 
966   return true;
967 }
968 
OnDataFramePayload(absl::string_view payload)969 bool QuicSpdyStream::OnDataFramePayload(absl::string_view payload) {
970   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
971 
972   body_manager_.OnBody(payload);
973 
974   return true;
975 }
976 
OnDataFrameEnd()977 bool QuicSpdyStream::OnDataFrameEnd() {
978   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
979 
980   QUIC_DVLOG(1) << ENDPOINT
981                 << "Reaches the end of a data frame. Total bytes received are "
982                 << body_manager_.total_body_bytes_received();
983   return true;
984 }
985 
OnStreamFrameAcked(QuicStreamOffset offset,QuicByteCount data_length,bool fin_acked,QuicTime::Delta ack_delay_time,QuicTime receive_timestamp,QuicByteCount * newly_acked_length)986 bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset,
987                                         QuicByteCount data_length,
988                                         bool fin_acked,
989                                         QuicTime::Delta ack_delay_time,
990                                         QuicTime receive_timestamp,
991                                         QuicByteCount* newly_acked_length) {
992   const bool new_data_acked = QuicStream::OnStreamFrameAcked(
993       offset, data_length, fin_acked, ack_delay_time, receive_timestamp,
994       newly_acked_length);
995 
996   const QuicByteCount newly_acked_header_length =
997       GetNumFrameHeadersInInterval(offset, data_length);
998   QUICHE_DCHECK_LE(newly_acked_header_length, *newly_acked_length);
999   unacked_frame_headers_offsets_.Difference(offset, offset + data_length);
1000   if (ack_listener_ != nullptr && new_data_acked) {
1001     ack_listener_->OnPacketAcked(
1002         *newly_acked_length - newly_acked_header_length, ack_delay_time);
1003   }
1004   return new_data_acked;
1005 }
1006 
OnStreamFrameRetransmitted(QuicStreamOffset offset,QuicByteCount data_length,bool fin_retransmitted)1007 void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
1008                                                 QuicByteCount data_length,
1009                                                 bool fin_retransmitted) {
1010   QuicStream::OnStreamFrameRetransmitted(offset, data_length,
1011                                          fin_retransmitted);
1012 
1013   const QuicByteCount retransmitted_header_length =
1014       GetNumFrameHeadersInInterval(offset, data_length);
1015   QUICHE_DCHECK_LE(retransmitted_header_length, data_length);
1016 
1017   if (ack_listener_ != nullptr) {
1018     ack_listener_->OnPacketRetransmitted(data_length -
1019                                          retransmitted_header_length);
1020   }
1021 }
1022 
GetNumFrameHeadersInInterval(QuicStreamOffset offset,QuicByteCount data_length) const1023 QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval(
1024     QuicStreamOffset offset, QuicByteCount data_length) const {
1025   QuicByteCount header_acked_length = 0;
1026   QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length);
1027   newly_acked.Intersection(unacked_frame_headers_offsets_);
1028   for (const auto& interval : newly_acked) {
1029     header_acked_length += interval.Length();
1030   }
1031   return header_acked_length;
1032 }
1033 
OnHeadersFrameStart(QuicByteCount header_length,QuicByteCount payload_length)1034 bool QuicSpdyStream::OnHeadersFrameStart(QuicByteCount header_length,
1035                                          QuicByteCount payload_length) {
1036   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1037   QUICHE_DCHECK(!qpack_decoded_headers_accumulator_);
1038 
1039   if (spdy_session_->debug_visitor()) {
1040     spdy_session_->debug_visitor()->OnHeadersFrameReceived(id(),
1041                                                            payload_length);
1042   }
1043 
1044   headers_payload_length_ = payload_length;
1045 
1046   if (trailers_decompressed_) {
1047     QUICHE_LOG(INFO) << ENDPOINT << "stream_id: " << id()
1048                      << ", headers_decompressed: "
1049                      << (headers_decompressed_ ? "true" : "false")
1050                      << ", NumBytesConsumed: "
1051                      << sequencer()->NumBytesConsumed()
1052                      << ", total_body_bytes_received: "
1053                      << body_manager_.total_body_bytes_received();
1054     stream_delegate()->OnStreamError(
1055         QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
1056         "HEADERS frame received after trailing HEADERS.");
1057     return false;
1058   }
1059 
1060   sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
1061 
1062   qpack_decoded_headers_accumulator_ =
1063       std::make_unique<QpackDecodedHeadersAccumulator>(
1064           id(), spdy_session_->qpack_decoder(), this,
1065           spdy_session_->max_inbound_header_list_size());
1066 
1067   return true;
1068 }
1069 
OnHeadersFramePayload(absl::string_view payload)1070 bool QuicSpdyStream::OnHeadersFramePayload(absl::string_view payload) {
1071   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1072 
1073   if (!qpack_decoded_headers_accumulator_) {
1074     QUIC_BUG(b215142466_OnHeadersFramePayload);
1075     OnHeaderDecodingError(QUIC_INTERNAL_ERROR,
1076                           "qpack_decoded_headers_accumulator_ is nullptr");
1077     return false;
1078   }
1079 
1080   qpack_decoded_headers_accumulator_->Decode(payload);
1081 
1082   // |qpack_decoded_headers_accumulator_| is reset if an error is detected.
1083   if (!qpack_decoded_headers_accumulator_) {
1084     return false;
1085   }
1086 
1087   sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size()));
1088   return true;
1089 }
1090 
OnHeadersFrameEnd()1091 bool QuicSpdyStream::OnHeadersFrameEnd() {
1092   QUICHE_DCHECK(VersionUsesHttp3(transport_version()));
1093 
1094   if (!qpack_decoded_headers_accumulator_) {
1095     QUIC_BUG(b215142466_OnHeadersFrameEnd);
1096     OnHeaderDecodingError(QUIC_INTERNAL_ERROR,
1097                           "qpack_decoded_headers_accumulator_ is nullptr");
1098     return false;
1099   }
1100 
1101   qpack_decoded_headers_accumulator_->EndHeaderBlock();
1102 
1103   // If decoding is complete or an error is detected, then
1104   // |qpack_decoded_headers_accumulator_| is already reset.
1105   if (qpack_decoded_headers_accumulator_) {
1106     blocked_on_decoding_headers_ = true;
1107     return false;
1108   }
1109 
1110   return !sequencer()->IsClosed() && !reading_stopped();
1111 }
1112 
OnWebTransportStreamFrameType(QuicByteCount header_length,WebTransportSessionId session_id)1113 void QuicSpdyStream::OnWebTransportStreamFrameType(
1114     QuicByteCount header_length, WebTransportSessionId session_id) {
1115   QUIC_DVLOG(1) << ENDPOINT << " Received WEBTRANSPORT_STREAM on stream "
1116                 << id() << " for session " << session_id;
1117   QuicStreamOffset offset = sequencer()->NumBytesConsumed();
1118   sequencer()->MarkConsumed(header_length);
1119 
1120   std::optional<WebTransportHttp3Version> version =
1121       spdy_session_->SupportedWebTransportVersion();
1122   QUICHE_DCHECK(version.has_value());
1123   if (version == WebTransportHttp3Version::kDraft02) {
1124     if (headers_payload_length_ > 0 || headers_decompressed_) {
1125       std::string error =
1126           absl::StrCat("Stream ", id(),
1127                        " attempted to convert itself into a WebTransport data "
1128                        "stream, but it already has HTTP data on it");
1129       QUIC_PEER_BUG(WEBTRANSPORT_STREAM received on HTTP request)
1130           << ENDPOINT << error;
1131       OnUnrecoverableError(QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
1132                            error);
1133       return;
1134     }
1135   } else {
1136     if (offset > 0) {
1137       std::string error =
1138           absl::StrCat("Stream ", id(),
1139                        " received WEBTRANSPORT_STREAM at a non-zero offset");
1140       QUIC_DLOG(ERROR) << ENDPOINT << error;
1141       OnUnrecoverableError(QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
1142                            error);
1143       return;
1144     }
1145   }
1146 
1147   if (QuicUtils::IsOutgoingStreamId(spdy_session_->version(), id(),
1148                                     spdy_session_->perspective())) {
1149     std::string error = absl::StrCat(
1150         "Stream ", id(),
1151         " attempted to convert itself into a WebTransport data stream, but "
1152         "only the initiator of the stream can do that");
1153     QUIC_PEER_BUG(WEBTRANSPORT_STREAM received on outgoing request)
1154         << ENDPOINT << error;
1155     OnUnrecoverableError(QUIC_HTTP_INVALID_FRAME_SEQUENCE_ON_SPDY_STREAM,
1156                          error);
1157     return;
1158   }
1159 
1160   QUICHE_DCHECK(web_transport_ == nullptr);
1161   web_transport_data_ =
1162       std::make_unique<WebTransportDataStream>(this, session_id);
1163   spdy_session_->AssociateIncomingWebTransportStreamWithSession(session_id,
1164                                                                 id());
1165 }
1166 
OnUnknownFrameStart(uint64_t frame_type,QuicByteCount header_length,QuicByteCount payload_length)1167 bool QuicSpdyStream::OnUnknownFrameStart(uint64_t frame_type,
1168                                          QuicByteCount header_length,
1169                                          QuicByteCount payload_length) {
1170   if (spdy_session_->debug_visitor()) {
1171     spdy_session_->debug_visitor()->OnUnknownFrameReceived(id(), frame_type,
1172                                                            payload_length);
1173   }
1174   spdy_session_->OnUnknownFrameStart(id(), frame_type, header_length,
1175                                      payload_length);
1176 
1177   // Consume the frame header.
1178   QUIC_DVLOG(1) << ENDPOINT << "Consuming " << header_length
1179                 << " byte long frame header of frame of unknown type "
1180                 << frame_type << ".";
1181   sequencer()->MarkConsumed(body_manager_.OnNonBody(header_length));
1182   return true;
1183 }
1184 
OnUnknownFramePayload(absl::string_view payload)1185 bool QuicSpdyStream::OnUnknownFramePayload(absl::string_view payload) {
1186   spdy_session_->OnUnknownFramePayload(id(), payload);
1187 
1188   // Consume the frame payload.
1189   QUIC_DVLOG(1) << ENDPOINT << "Consuming " << payload.size()
1190                 << " bytes of payload of frame of unknown type.";
1191   sequencer()->MarkConsumed(body_manager_.OnNonBody(payload.size()));
1192   return true;
1193 }
1194 
OnUnknownFrameEnd()1195 bool QuicSpdyStream::OnUnknownFrameEnd() { return true; }
1196 
WriteHeadersImpl(spdy::Http2HeaderBlock header_block,bool fin,quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)1197 size_t QuicSpdyStream::WriteHeadersImpl(
1198     spdy::Http2HeaderBlock header_block, bool fin,
1199     quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
1200         ack_listener) {
1201   if (!VersionUsesHttp3(transport_version())) {
1202     return spdy_session_->WriteHeadersOnHeadersStream(
1203         id(), std::move(header_block), fin,
1204         spdy::SpdyStreamPrecedence(priority().http().urgency),
1205         std::move(ack_listener));
1206   }
1207 
1208   // Encode header list.
1209   QuicByteCount encoder_stream_sent_byte_count;
1210   std::string encoded_headers =
1211       spdy_session_->qpack_encoder()->EncodeHeaderList(
1212           id(), header_block, &encoder_stream_sent_byte_count);
1213 
1214   if (spdy_session_->debug_visitor()) {
1215     spdy_session_->debug_visitor()->OnHeadersFrameSent(id(), header_block);
1216   }
1217 
1218   // Write HEADERS frame.
1219   std::string headers_frame_header =
1220       HttpEncoder::SerializeHeadersFrameHeader(encoded_headers.size());
1221   unacked_frame_headers_offsets_.Add(
1222       send_buffer().stream_offset(),
1223       send_buffer().stream_offset() + headers_frame_header.length());
1224 
1225   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id()
1226                   << " is writing HEADERS frame header of length "
1227                   << headers_frame_header.length() << ", and payload of length "
1228                   << encoded_headers.length() << " with fin " << fin;
1229   WriteOrBufferData(absl::StrCat(headers_frame_header, encoded_headers), fin,
1230                     /*ack_listener=*/nullptr);
1231 
1232   QuicSpdySession::LogHeaderCompressionRatioHistogram(
1233       /* using_qpack = */ true,
1234       /* is_sent = */ true,
1235       encoded_headers.size() + encoder_stream_sent_byte_count,
1236       header_block.TotalBytesUsed());
1237 
1238   return encoded_headers.size();
1239 }
1240 
CanWriteNewBodyData(QuicByteCount write_size) const1241 bool QuicSpdyStream::CanWriteNewBodyData(QuicByteCount write_size) const {
1242   QUICHE_DCHECK_NE(0u, write_size);
1243   if (!VersionUsesHttp3(transport_version())) {
1244     return CanWriteNewData();
1245   }
1246 
1247   return CanWriteNewDataAfterData(
1248       HttpEncoder::GetDataFrameHeaderLength(write_size));
1249 }
1250 
MaybeProcessReceivedWebTransportHeaders()1251 void QuicSpdyStream::MaybeProcessReceivedWebTransportHeaders() {
1252   if (!spdy_session_->SupportsWebTransport()) {
1253     return;
1254   }
1255   if (session()->perspective() != Perspective::IS_SERVER) {
1256     return;
1257   }
1258   QUICHE_DCHECK(IsValidWebTransportSessionId(id(), version()));
1259 
1260   std::string method;
1261   std::string protocol;
1262   for (const auto& [header_name, header_value] : header_list_) {
1263     if (header_name == ":method") {
1264       if (!method.empty() || header_value.empty()) {
1265         return;
1266       }
1267       method = header_value;
1268     }
1269     if (header_name == ":protocol") {
1270       if (!protocol.empty() || header_value.empty()) {
1271         return;
1272       }
1273       protocol = header_value;
1274     }
1275     if (header_name == "datagram-flow-id") {
1276       QUIC_DLOG(ERROR) << ENDPOINT
1277                        << "Rejecting WebTransport due to unexpected "
1278                           "Datagram-Flow-Id header";
1279       return;
1280     }
1281   }
1282 
1283   if (method != "CONNECT" || protocol != "webtransport") {
1284     return;
1285   }
1286 
1287   web_transport_ =
1288       std::make_unique<WebTransportHttp3>(spdy_session_, this, id());
1289 }
1290 
MaybeProcessSentWebTransportHeaders(spdy::Http2HeaderBlock & headers)1291 void QuicSpdyStream::MaybeProcessSentWebTransportHeaders(
1292     spdy::Http2HeaderBlock& headers) {
1293   if (!spdy_session_->SupportsWebTransport()) {
1294     return;
1295   }
1296   if (session()->perspective() != Perspective::IS_CLIENT) {
1297     return;
1298   }
1299   QUICHE_DCHECK(IsValidWebTransportSessionId(id(), version()));
1300 
1301   const auto method_it = headers.find(":method");
1302   const auto protocol_it = headers.find(":protocol");
1303   if (method_it == headers.end() || protocol_it == headers.end()) {
1304     return;
1305   }
1306   if (method_it->second != "CONNECT" && protocol_it->second != "webtransport") {
1307     return;
1308   }
1309 
1310   if (spdy_session_->SupportedWebTransportVersion() ==
1311       WebTransportHttp3Version::kDraft02) {
1312     headers["sec-webtransport-http3-draft02"] = "1";
1313   }
1314 
1315   web_transport_ =
1316       std::make_unique<WebTransportHttp3>(spdy_session_, this, id());
1317 }
1318 
OnCanWriteNewData()1319 void QuicSpdyStream::OnCanWriteNewData() {
1320   if (web_transport_data_ != nullptr) {
1321     web_transport_data_->adapter.OnCanWriteNewData();
1322   }
1323 }
1324 
AssertNotWebTransportDataStream(absl::string_view operation)1325 bool QuicSpdyStream::AssertNotWebTransportDataStream(
1326     absl::string_view operation) {
1327   if (web_transport_data_ != nullptr) {
1328     QUIC_BUG(Invalid operation on WebTransport stream)
1329         << "Attempted to " << operation << " on WebTransport data stream "
1330         << id() << " associated with session "
1331         << web_transport_data_->session_id;
1332     OnUnrecoverableError(QUIC_INTERNAL_ERROR,
1333                          absl::StrCat("Attempted to ", operation,
1334                                       " on WebTransport data stream"));
1335     return false;
1336   }
1337   return true;
1338 }
1339 
ConvertToWebTransportDataStream(WebTransportSessionId session_id)1340 void QuicSpdyStream::ConvertToWebTransportDataStream(
1341     WebTransportSessionId session_id) {
1342   if (send_buffer().stream_offset() != 0) {
1343     QUIC_BUG(Sending WEBTRANSPORT_STREAM when data already sent)
1344         << "Attempted to send a WEBTRANSPORT_STREAM frame when other data has "
1345            "already been sent on the stream.";
1346     OnUnrecoverableError(QUIC_INTERNAL_ERROR,
1347                          "Attempted to send a WEBTRANSPORT_STREAM frame when "
1348                          "other data has already been sent on the stream.");
1349     return;
1350   }
1351 
1352   std::string header =
1353       HttpEncoder::SerializeWebTransportStreamFrameHeader(session_id);
1354   if (header.empty()) {
1355     QUIC_BUG(Failed to serialize WEBTRANSPORT_STREAM)
1356         << "Failed to serialize a WEBTRANSPORT_STREAM frame.";
1357     OnUnrecoverableError(QUIC_INTERNAL_ERROR,
1358                          "Failed to serialize a WEBTRANSPORT_STREAM frame.");
1359     return;
1360   }
1361 
1362   WriteOrBufferData(header, /*fin=*/false, nullptr);
1363   web_transport_data_ =
1364       std::make_unique<WebTransportDataStream>(this, session_id);
1365   QUIC_DVLOG(1) << ENDPOINT << "Successfully opened WebTransport data stream "
1366                 << id() << " for session " << session_id;
1367 }
1368 
WebTransportDataStream(QuicSpdyStream * stream,WebTransportSessionId session_id)1369 QuicSpdyStream::WebTransportDataStream::WebTransportDataStream(
1370     QuicSpdyStream* stream, WebTransportSessionId session_id)
1371     : session_id(session_id),
1372       adapter(stream->spdy_session_, stream, stream->sequencer()) {}
1373 
HandleReceivedDatagram(absl::string_view payload)1374 void QuicSpdyStream::HandleReceivedDatagram(absl::string_view payload) {
1375   if (datagram_visitor_ == nullptr) {
1376     QUIC_DLOG(ERROR) << ENDPOINT << "Received datagram without any visitor";
1377     return;
1378   }
1379   datagram_visitor_->OnHttp3Datagram(id(), payload);
1380 }
1381 
OnCapsule(const Capsule & capsule)1382 bool QuicSpdyStream::OnCapsule(const Capsule& capsule) {
1383   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " received capsule "
1384                   << capsule;
1385   if (!headers_decompressed_) {
1386     QUIC_PEER_BUG(capsule before headers)
1387         << ENDPOINT << "Stream " << id() << " received capsule " << capsule
1388         << " before headers";
1389     return false;
1390   }
1391   if (web_transport_ != nullptr && web_transport_->close_received()) {
1392     QUIC_PEER_BUG(capsule after close)
1393         << ENDPOINT << "Stream " << id() << " received capsule " << capsule
1394         << " after CLOSE_WEBTRANSPORT_SESSION.";
1395     return false;
1396   }
1397   switch (capsule.capsule_type()) {
1398     case CapsuleType::DATAGRAM:
1399       HandleReceivedDatagram(capsule.datagram_capsule().http_datagram_payload);
1400       return true;
1401     case CapsuleType::LEGACY_DATAGRAM:
1402       HandleReceivedDatagram(
1403           capsule.legacy_datagram_capsule().http_datagram_payload);
1404       return true;
1405     case CapsuleType::LEGACY_DATAGRAM_WITHOUT_CONTEXT:
1406       HandleReceivedDatagram(capsule.legacy_datagram_without_context_capsule()
1407                                  .http_datagram_payload);
1408       return true;
1409     case CapsuleType::CLOSE_WEBTRANSPORT_SESSION:
1410       if (web_transport_ == nullptr) {
1411         QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
1412                          << " for a non-WebTransport stream.";
1413         return false;
1414       }
1415       web_transport_->OnCloseReceived(
1416           capsule.close_web_transport_session_capsule().error_code,
1417           capsule.close_web_transport_session_capsule().error_message);
1418       return true;
1419     case CapsuleType::DRAIN_WEBTRANSPORT_SESSION:
1420       if (web_transport_ == nullptr) {
1421         QUIC_DLOG(ERROR) << ENDPOINT << "Received capsule " << capsule
1422                          << " for a non-WebTransport stream.";
1423         return false;
1424       }
1425       web_transport_->OnDrainSessionReceived();
1426       return true;
1427     case CapsuleType::ADDRESS_ASSIGN:
1428       if (connect_ip_visitor_ == nullptr) {
1429         return true;
1430       }
1431       return connect_ip_visitor_->OnAddressAssignCapsule(
1432           capsule.address_assign_capsule());
1433     case CapsuleType::ADDRESS_REQUEST:
1434       if (connect_ip_visitor_ == nullptr) {
1435         return true;
1436       }
1437       return connect_ip_visitor_->OnAddressRequestCapsule(
1438           capsule.address_request_capsule());
1439     case CapsuleType::ROUTE_ADVERTISEMENT:
1440       if (connect_ip_visitor_ == nullptr) {
1441         return true;
1442       }
1443       return connect_ip_visitor_->OnRouteAdvertisementCapsule(
1444           capsule.route_advertisement_capsule());
1445 
1446     // Ignore WebTransport over HTTP/2 capsules.
1447     case CapsuleType::WT_RESET_STREAM:
1448     case CapsuleType::WT_STOP_SENDING:
1449     case CapsuleType::WT_STREAM:
1450     case CapsuleType::WT_STREAM_WITH_FIN:
1451     case CapsuleType::WT_MAX_STREAM_DATA:
1452     case CapsuleType::WT_MAX_STREAMS_BIDI:
1453     case CapsuleType::WT_MAX_STREAMS_UNIDI:
1454       return true;
1455   }
1456   if (datagram_visitor_) {
1457     datagram_visitor_->OnUnknownCapsule(id(), capsule.unknown_capsule());
1458   }
1459   return true;
1460 }
1461 
OnCapsuleParseFailure(absl::string_view error_message)1462 void QuicSpdyStream::OnCapsuleParseFailure(absl::string_view error_message) {
1463   QUIC_DLOG(ERROR) << ENDPOINT << "Capsule parse failure: " << error_message;
1464   Reset(QUIC_BAD_APPLICATION_PAYLOAD);
1465 }
1466 
WriteCapsule(const Capsule & capsule,bool fin)1467 void QuicSpdyStream::WriteCapsule(const Capsule& capsule, bool fin) {
1468   QUIC_DLOG(INFO) << ENDPOINT << "Stream " << id() << " sending capsule "
1469                   << capsule;
1470   quiche::QuicheBuffer serialized_capsule = SerializeCapsule(
1471       capsule,
1472       spdy_session_->connection()->helper()->GetStreamSendBufferAllocator());
1473   QUICHE_DCHECK_GT(serialized_capsule.size(), 0u);
1474   WriteOrBufferBody(serialized_capsule.AsStringView(), /*fin=*/fin);
1475 }
1476 
WriteGreaseCapsule()1477 void QuicSpdyStream::WriteGreaseCapsule() {
1478   // GREASE capsulde IDs have a form of 41 * N + 23.
1479   QuicRandom* random = spdy_session_->connection()->random_generator();
1480   uint64_t type = random->InsecureRandUint64() >> 4;
1481   type = (type / 41) * 41 + 23;
1482   QUICHE_DCHECK_EQ((type - 23) % 41, 0u);
1483 
1484   constexpr size_t kMaxLength = 64;
1485   size_t length = random->InsecureRandUint64() % kMaxLength;
1486   std::string bytes(length, '\0');
1487   random->InsecureRandBytes(&bytes[0], bytes.size());
1488   Capsule capsule = Capsule::Unknown(type, bytes);
1489   WriteCapsule(capsule, /*fin=*/false);
1490 }
1491 
SendHttp3Datagram(absl::string_view payload)1492 MessageStatus QuicSpdyStream::SendHttp3Datagram(absl::string_view payload) {
1493   return spdy_session_->SendHttp3Datagram(id(), payload);
1494 }
1495 
RegisterHttp3DatagramVisitor(Http3DatagramVisitor * visitor)1496 void QuicSpdyStream::RegisterHttp3DatagramVisitor(
1497     Http3DatagramVisitor* visitor) {
1498   if (visitor == nullptr) {
1499     QUIC_BUG(null datagram visitor)
1500         << ENDPOINT << "Null datagram visitor for stream ID " << id();
1501     return;
1502   }
1503   QUIC_DLOG(INFO) << ENDPOINT << "Registering datagram visitor with stream ID "
1504                   << id();
1505 
1506   if (datagram_visitor_ != nullptr) {
1507     QUIC_BUG(h3 datagram double registration)
1508         << ENDPOINT
1509         << "Attempted to doubly register HTTP/3 datagram with stream ID "
1510         << id();
1511     return;
1512   }
1513   datagram_visitor_ = visitor;
1514   QUICHE_DCHECK(!capsule_parser_);
1515   capsule_parser_ = std::make_unique<quiche::CapsuleParser>(this);
1516 }
1517 
UnregisterHttp3DatagramVisitor()1518 void QuicSpdyStream::UnregisterHttp3DatagramVisitor() {
1519   if (datagram_visitor_ == nullptr) {
1520     QUIC_BUG(datagram visitor empty during unregistration)
1521         << ENDPOINT << "Cannot unregister datagram visitor for stream ID "
1522         << id();
1523     return;
1524   }
1525   QUIC_DLOG(INFO) << ENDPOINT << "Unregistering datagram visitor for stream ID "
1526                   << id();
1527   datagram_visitor_ = nullptr;
1528 }
1529 
ReplaceHttp3DatagramVisitor(Http3DatagramVisitor * visitor)1530 void QuicSpdyStream::ReplaceHttp3DatagramVisitor(
1531     Http3DatagramVisitor* visitor) {
1532   QUIC_BUG_IF(h3 datagram unknown move, datagram_visitor_ == nullptr)
1533       << "Attempted to move missing datagram visitor on HTTP/3 stream ID "
1534       << id();
1535   datagram_visitor_ = visitor;
1536 }
1537 
RegisterConnectIpVisitor(ConnectIpVisitor * visitor)1538 void QuicSpdyStream::RegisterConnectIpVisitor(ConnectIpVisitor* visitor) {
1539   if (visitor == nullptr) {
1540     QUIC_BUG(null connect - ip visitor)
1541         << ENDPOINT << "Null connect-ip visitor for stream ID " << id();
1542     return;
1543   }
1544   QUIC_DLOG(INFO) << ENDPOINT
1545                   << "Registering CONNECT-IP visitor with stream ID " << id();
1546 
1547   if (connect_ip_visitor_ != nullptr) {
1548     QUIC_BUG(connect - ip double registration)
1549         << ENDPOINT << "Attempted to doubly register CONNECT-IP with stream ID "
1550         << id();
1551     return;
1552   }
1553   connect_ip_visitor_ = visitor;
1554 }
1555 
UnregisterConnectIpVisitor()1556 void QuicSpdyStream::UnregisterConnectIpVisitor() {
1557   if (connect_ip_visitor_ == nullptr) {
1558     QUIC_BUG(connect - ip visitor empty during unregistration)
1559         << ENDPOINT << "Cannot unregister CONNECT-IP visitor for stream ID "
1560         << id();
1561     return;
1562   }
1563   QUIC_DLOG(INFO) << ENDPOINT
1564                   << "Unregistering CONNECT-IP visitor for stream ID " << id();
1565   connect_ip_visitor_ = nullptr;
1566 }
1567 
ReplaceConnectIpVisitor(ConnectIpVisitor * visitor)1568 void QuicSpdyStream::ReplaceConnectIpVisitor(ConnectIpVisitor* visitor) {
1569   QUIC_BUG_IF(connect - ip unknown move, connect_ip_visitor_ == nullptr)
1570       << "Attempted to move missing CONNECT-IP visitor on HTTP/3 stream ID "
1571       << id();
1572   connect_ip_visitor_ = visitor;
1573 }
1574 
SetMaxDatagramTimeInQueue(QuicTime::Delta max_time_in_queue)1575 void QuicSpdyStream::SetMaxDatagramTimeInQueue(
1576     QuicTime::Delta max_time_in_queue) {
1577   spdy_session_->SetMaxDatagramTimeInQueueForStreamId(id(), max_time_in_queue);
1578 }
1579 
OnDatagramReceived(QuicDataReader * reader)1580 void QuicSpdyStream::OnDatagramReceived(QuicDataReader* reader) {
1581   if (!headers_decompressed_) {
1582     QUIC_DLOG(INFO) << "Dropping datagram received before headers on stream ID "
1583                     << id();
1584     return;
1585   }
1586   HandleReceivedDatagram(reader->ReadRemainingPayload());
1587 }
1588 
GetMaxDatagramSize() const1589 QuicByteCount QuicSpdyStream::GetMaxDatagramSize() const {
1590   QuicByteCount prefix_size = 0;
1591   switch (spdy_session_->http_datagram_support()) {
1592     case HttpDatagramSupport::kDraft04:
1593     case HttpDatagramSupport::kRfc:
1594       prefix_size =
1595           QuicDataWriter::GetVarInt62Len(id() / kHttpDatagramStreamIdDivisor);
1596       break;
1597     case HttpDatagramSupport::kNone:
1598     case HttpDatagramSupport::kRfcAndDraft04:
1599       QUIC_BUG(GetMaxDatagramSize called with no datagram support)
1600           << "GetMaxDatagramSize() called when no HTTP/3 datagram support has "
1601              "been negotiated.  Support value: "
1602           << spdy_session_->http_datagram_support();
1603       break;
1604   }
1605   // If the logic above fails, use the largest possible value as the safe one.
1606   if (prefix_size == 0) {
1607     prefix_size = 8;
1608   }
1609 
1610   QuicByteCount max_datagram_size =
1611       session()->GetGuaranteedLargestMessagePayload();
1612   if (max_datagram_size < prefix_size) {
1613     QUIC_BUG(max_datagram_size smaller than prefix_size)
1614         << "GetGuaranteedLargestMessagePayload() returned a datagram size that "
1615            "is not sufficient to fit stream ID into it.";
1616     return 0;
1617   }
1618   return max_datagram_size - prefix_size;
1619 }
1620 
HandleBodyAvailable()1621 void QuicSpdyStream::HandleBodyAvailable() {
1622   if (!capsule_parser_) {
1623     OnBodyAvailable();
1624     return;
1625   }
1626   while (body_manager_.HasBytesToRead()) {
1627     iovec iov;
1628     int num_iov = GetReadableRegions(&iov, /*iov_len=*/1);
1629     if (num_iov == 0) {
1630       break;
1631     }
1632     if (!capsule_parser_->IngestCapsuleFragment(absl::string_view(
1633             reinterpret_cast<const char*>(iov.iov_base), iov.iov_len))) {
1634       break;
1635     }
1636     MarkConsumed(iov.iov_len);
1637   }
1638   // If we received a FIN, make sure that there isn't a partial capsule buffered
1639   // in the capsule parser.
1640   if (sequencer()->IsClosed()) {
1641     capsule_parser_->ErrorIfThereIsRemainingBufferedData();
1642     if (web_transport_ != nullptr) {
1643       web_transport_->OnConnectStreamFinReceived();
1644     }
1645     OnFinRead();
1646   }
1647 }
1648 
1649 namespace {
1650 
1651 // Return true if |c| is not allowed in an HTTP/3 wire-encoded header and
1652 // pseudo-header names according to
1653 // https://datatracker.ietf.org/doc/html/draft-ietf-quic-http#section-4.1.1 and
1654 // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-semantics-19#section-5.6.2
IsInvalidHeaderNameCharacter(unsigned char c)1655 constexpr bool IsInvalidHeaderNameCharacter(unsigned char c) {
1656   if (c == '!' || c == '|' || c == '~' || c == '*' || c == '+' || c == '-' ||
1657       c == '.' ||
1658       // #, $, %, &, '
1659       (c >= '#' && c <= '\'') ||
1660       // [0-9], :
1661       (c >= '0' && c <= ':') ||
1662       // ^, _, `, [a-z]
1663       (c >= '^' && c <= 'z')) {
1664     return false;
1665   }
1666   return true;
1667 }
1668 
1669 // Return true if `name` is invalid because it contains a disallowed character.
HeaderNameHasInvalidCharacter(absl::string_view name)1670 bool HeaderNameHasInvalidCharacter(absl::string_view name) {
1671   const bool colon_invalid =
1672       GetQuicReloadableFlag(quic_colon_invalid_in_header_name);
1673   if (colon_invalid) {
1674     QUICHE_RELOADABLE_FLAG_COUNT(quic_colon_invalid_in_header_name);
1675   }
1676 
1677   if (name.empty()) {
1678     return false;
1679   }
1680 
1681   // Remove leading colon of pseudo-headers.
1682   // This is the only position where colon is allowed.
1683   if (name[0] == ':') {
1684     name.remove_prefix(1);
1685   }
1686 
1687   if (std::find(name.begin(), name.end(), ':') != name.end()) {
1688     // Header name contains colon (other than optional leading colon of
1689     // pseudo-headers), which is invalid.
1690     QUICHE_CODE_COUNT(quic_colon_in_header_name);
1691     if (colon_invalid) {
1692       return true;
1693     }
1694   }
1695 
1696   return std::any_of(name.begin(), name.end(), IsInvalidHeaderNameCharacter);
1697 }
1698 
1699 }  // namespace
1700 
ValidateReceivedHeaders(const QuicHeaderList & header_list)1701 bool QuicSpdyStream::ValidateReceivedHeaders(
1702     const QuicHeaderList& header_list) {
1703   bool force_fail_validation = false;
1704   AdjustTestValue("quic::QuicSpdyStream::request_header_validation_adjust",
1705                   &force_fail_validation);
1706   if (force_fail_validation) {
1707     invalid_request_details_ =
1708         "request_header_validation_adjust force failed the validation.";
1709     QUIC_DLOG(ERROR) << invalid_request_details_;
1710     return false;
1711   }
1712   bool is_response = false;
1713   for (const std::pair<std::string, std::string>& pair : header_list) {
1714     const std::string& name = pair.first;
1715     if (HeaderNameHasInvalidCharacter(name)) {
1716       invalid_request_details_ =
1717           absl::StrCat("Invalid character in header name ", name);
1718       QUIC_DLOG(ERROR) << invalid_request_details_;
1719       return false;
1720     }
1721     if (name == ":status") {
1722       is_response = !pair.second.empty();
1723     }
1724     if (is_response && name == "host") {
1725       // Host header is allowed in response.
1726       continue;
1727     }
1728     if (http2::GetInvalidHttp2HeaderSet().contains(name)) {
1729       invalid_request_details_ = absl::StrCat(name, " header is not allowed");
1730       QUIC_DLOG(ERROR) << invalid_request_details_;
1731       return false;
1732     }
1733   }
1734   return true;
1735 }
1736 
set_invalid_request_details(std::string invalid_request_details)1737 void QuicSpdyStream::set_invalid_request_details(
1738     std::string invalid_request_details) {
1739   QUIC_BUG_IF(
1740       empty invalid request detail,
1741       !invalid_request_details_.empty() || invalid_request_details.empty());
1742   invalid_request_details_ = std::move(invalid_request_details);
1743 }
1744 
AreHeaderFieldValuesValid(const QuicHeaderList & header_list) const1745 bool QuicSpdyStream::AreHeaderFieldValuesValid(
1746     const QuicHeaderList& header_list) const {
1747   if (!VersionUsesHttp3(transport_version())) {
1748     return true;
1749   }
1750   // According to https://www.rfc-editor.org/rfc/rfc9114.html#section-10.3
1751   // "[...] HTTP/3 can transport field values that are not valid. While most
1752   // values that can be encoded will not alter field parsing, carriage return
1753   // (ASCII 0x0d), line feed (ASCII 0x0a), and the null character (ASCII 0x00)
1754   // might be exploited by an attacker if they are translated verbatim. Any
1755   // request or response that contains a character not permitted in a field
1756   // value MUST be treated as malformed.
1757   // [...]"
1758   for (const std::pair<std::string, std::string>& pair : header_list) {
1759     const std::string& value = pair.second;
1760     for (const auto c : value) {
1761       if (c == '\0' || c == '\n' || c == '\r') {
1762         return false;
1763       }
1764     }
1765   }
1766   return true;
1767 }
1768 
OnInvalidHeaders()1769 void QuicSpdyStream::OnInvalidHeaders() { Reset(QUIC_BAD_APPLICATION_PAYLOAD); }
1770 
CloseReadSide()1771 void QuicSpdyStream::CloseReadSide() {
1772   QuicStream::CloseReadSide();
1773 
1774   // QuicStream::CloseReadSide() releases buffered read data from
1775   // QuicStreamSequencer, invalidating every reference held by `body_manager_`.
1776   body_manager_.Clear();
1777 }
1778 
1779 #undef ENDPOINT  // undef for jumbo builds
1780 }  // namespace quic
1781