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