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