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