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 // The base class for streams which deliver data to/from an application. 6 // In each direction, the data on such a stream first contains compressed 7 // headers then body data. 8 9 #ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_H_ 10 #define QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_H_ 11 12 #include <sys/types.h> 13 14 #include <cstddef> 15 #include <list> 16 #include <memory> 17 #include <string> 18 19 #include "absl/base/attributes.h" 20 #include "absl/strings/string_view.h" 21 #include "absl/types/span.h" 22 #include "quiche/quic/core/http/http_decoder.h" 23 #include "quiche/quic/core/http/http_encoder.h" 24 #include "quiche/quic/core/http/quic_header_list.h" 25 #include "quiche/quic/core/http/quic_spdy_stream_body_manager.h" 26 #include "quiche/quic/core/http/web_transport_stream_adapter.h" 27 #include "quiche/quic/core/qpack/qpack_decoded_headers_accumulator.h" 28 #include "quiche/quic/core/quic_error_codes.h" 29 #include "quiche/quic/core/quic_packets.h" 30 #include "quiche/quic/core/quic_session.h" 31 #include "quiche/quic/core/quic_stream.h" 32 #include "quiche/quic/core/quic_stream_priority.h" 33 #include "quiche/quic/core/quic_stream_sequencer.h" 34 #include "quiche/quic/core/quic_types.h" 35 #include "quiche/quic/core/web_transport_interface.h" 36 #include "quiche/quic/platform/api/quic_export.h" 37 #include "quiche/quic/platform/api/quic_flags.h" 38 #include "quiche/quic/platform/api/quic_socket_address.h" 39 #include "quiche/common/capsule.h" 40 #include "quiche/common/platform/api/quiche_mem_slice.h" 41 #include "quiche/spdy/core/http2_header_block.h" 42 #include "quiche/spdy/core/spdy_framer.h" 43 44 namespace quic { 45 46 namespace test { 47 class QuicSpdyStreamPeer; 48 class QuicStreamPeer; 49 } // namespace test 50 51 class QuicSpdySession; 52 class WebTransportHttp3; 53 54 // A QUIC stream that can send and receive HTTP2 (SPDY) headers. 55 class QUICHE_EXPORT QuicSpdyStream 56 : public QuicStream, 57 public quiche::CapsuleParser::Visitor, 58 public QpackDecodedHeadersAccumulator::Visitor { 59 public: 60 // Visitor receives callbacks from the stream. 61 class QUICHE_EXPORT Visitor { 62 public: Visitor()63 Visitor() {} 64 Visitor(const Visitor&) = delete; 65 Visitor& operator=(const Visitor&) = delete; 66 67 // Called when the stream is closed. 68 virtual void OnClose(QuicSpdyStream* stream) = 0; 69 70 protected: ~Visitor()71 virtual ~Visitor() {} 72 }; 73 74 QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session, 75 StreamType type); 76 QuicSpdyStream(PendingStream* pending, QuicSpdySession* spdy_session); 77 QuicSpdyStream(const QuicSpdyStream&) = delete; 78 QuicSpdyStream& operator=(const QuicSpdyStream&) = delete; 79 ~QuicSpdyStream() override; 80 81 // QuicStream implementation 82 void OnClose() override; 83 84 // Override to maybe close the write side after writing. 85 void OnCanWrite() override; 86 87 // Called by the session when headers with a priority have been received 88 // for this stream. This method will only be called for server streams. 89 virtual void OnStreamHeadersPriority( 90 const spdy::SpdyStreamPrecedence& precedence); 91 92 // Called by the session when decompressed headers have been completely 93 // delivered to this stream. If |fin| is true, then this stream 94 // should be closed; no more data will be sent by the peer. 95 virtual void OnStreamHeaderList(bool fin, size_t frame_len, 96 const QuicHeaderList& header_list); 97 98 // Called by the session when a PRIORITY frame has been been received for this 99 // stream. This method will only be called for server streams. 100 void OnPriorityFrame(const spdy::SpdyStreamPrecedence& precedence); 101 102 // Override the base class to not discard response when receiving 103 // QUIC_STREAM_NO_ERROR. 104 void OnStreamReset(const QuicRstStreamFrame& frame) override; 105 void ResetWithError(QuicResetStreamError error) override; 106 bool OnStopSending(QuicResetStreamError error) override; 107 108 // Called by the sequencer when new data is available. Decodes the data and 109 // calls OnBodyAvailable() to pass to the upper layer. 110 void OnDataAvailable() override; 111 112 // Called in OnDataAvailable() after it finishes the decoding job. 113 virtual void OnBodyAvailable() = 0; 114 115 // Writes the headers contained in |header_block| on the dedicated headers 116 // stream or on this stream, depending on VersionUsesHttp3(). Returns the 117 // number of bytes sent, including data sent on the encoder stream when using 118 // QPACK. 119 virtual size_t WriteHeaders( 120 spdy::Http2HeaderBlock header_block, bool fin, 121 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> 122 ack_listener); 123 124 // Sends |data| to the peer, or buffers if it can't be sent immediately. 125 virtual void WriteOrBufferBody(absl::string_view data, bool fin); 126 127 // Writes the trailers contained in |trailer_block| on the dedicated headers 128 // stream or on this stream, depending on VersionUsesHttp3(). Trailers will 129 // always have the FIN flag set. Returns the number of bytes sent, including 130 // data sent on the encoder stream when using QPACK. 131 virtual size_t WriteTrailers( 132 spdy::Http2HeaderBlock trailer_block, 133 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> 134 ack_listener); 135 136 // Override to report newly acked bytes via ack_listener_. 137 bool OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, 138 bool fin_acked, QuicTime::Delta ack_delay_time, 139 QuicTime receive_timestamp, 140 QuicByteCount* newly_acked_length) override; 141 142 // Override to report bytes retransmitted via ack_listener_. 143 void OnStreamFrameRetransmitted(QuicStreamOffset offset, 144 QuicByteCount data_length, 145 bool fin_retransmitted) override; 146 147 // Does the same thing as WriteOrBufferBody except this method takes iovec 148 // as the data input. Right now it only calls WritevData. 149 QuicConsumedData WritevBody(const struct iovec* iov, int count, bool fin); 150 151 // Does the same thing as WriteOrBufferBody except this method takes 152 // memslicespan as the data input. Right now it only calls WriteMemSlices. 153 QuicConsumedData WriteBodySlices(absl::Span<quiche::QuicheMemSlice> slices, 154 bool fin); 155 156 // Marks the trailers as consumed. This applies to the case where this object 157 // receives headers and trailers as QuicHeaderLists via calls to 158 // OnStreamHeaderList(). Trailer data will be consumed from the sequencer only 159 // once all body data has been consumed. 160 void MarkTrailersConsumed(); 161 162 // Clears |header_list_|. 163 void ConsumeHeaderList(); 164 165 // This block of functions wraps the sequencer's functions of the same 166 // name. These methods return uncompressed data until that has 167 // been fully processed. Then they simply delegate to the sequencer. 168 virtual size_t Readv(const struct iovec* iov, size_t iov_len); 169 virtual int GetReadableRegions(iovec* iov, size_t iov_len) const; 170 void MarkConsumed(size_t num_bytes); 171 172 // Returns true if header contains a valid 3-digit status and parse the status 173 // code to |status_code|. 174 static bool ParseHeaderStatusCode(const spdy::Http2HeaderBlock& header, 175 int* status_code); 176 // Returns true if status_value (associated with :status) contains a valid 177 // 3-digit status and parse the status code to |status_code|. 178 static bool ParseHeaderStatusCode(absl::string_view status_value, 179 int* status_code); 180 181 // Returns true when headers, data and trailers all are read. 182 bool IsDoneReading() const; 183 // For IETF QUIC, bytes-to-read/readable-bytes only concern body (not headers 184 // or trailers). For gQUIC, they refer to all the bytes in the sequencer. 185 bool HasBytesToRead() const; 186 QuicByteCount ReadableBytes() const; 187 set_visitor(Visitor * visitor)188 void set_visitor(Visitor* visitor) { visitor_ = visitor; } 189 headers_decompressed()190 bool headers_decompressed() const { return headers_decompressed_; } 191 192 // Returns total amount of body bytes that have been read. 193 uint64_t total_body_bytes_read() const; 194 header_list()195 const QuicHeaderList& header_list() const { return header_list_; } 196 trailers_decompressed()197 bool trailers_decompressed() const { return trailers_decompressed_; } 198 199 // Returns whatever trailers have been received for this stream. received_trailers()200 const spdy::Http2HeaderBlock& received_trailers() const { 201 return received_trailers_; 202 } 203 204 // Returns true if headers have been fully read and consumed. 205 bool FinishedReadingHeaders() const; 206 207 // Returns true if FIN has been received and either trailers have been fully 208 // read and consumed or there are no trailers. 209 bool FinishedReadingTrailers() const; 210 211 // Returns true if the sequencer has delivered the FIN, and no more body bytes 212 // will be available. IsSequencerClosed()213 bool IsSequencerClosed() { return sequencer()->IsClosed(); } 214 215 // QpackDecodedHeadersAccumulator::Visitor implementation. 216 void OnHeadersDecoded(QuicHeaderList headers, 217 bool header_list_size_limit_exceeded) override; 218 void OnHeaderDecodingError(QuicErrorCode error_code, 219 absl::string_view error_message) override; 220 spdy_session()221 QuicSpdySession* spdy_session() const { return spdy_session_; } 222 223 // Send PRIORITY_UPDATE frame and update |last_sent_priority_| if 224 // |last_sent_priority_| is different from current priority. 225 void MaybeSendPriorityUpdateFrame() override; 226 227 // Returns the WebTransport session owned by this stream, if one exists. web_transport()228 WebTransportHttp3* web_transport() { return web_transport_.get(); } 229 230 // Returns the WebTransport data stream associated with this QUIC stream, or 231 // null if this is not a WebTransport data stream. web_transport_stream()232 WebTransportStream* web_transport_stream() { 233 if (web_transport_data_ == nullptr) { 234 return nullptr; 235 } 236 return &web_transport_data_->adapter; 237 } 238 239 // Sends a WEBTRANSPORT_STREAM frame and sets up the appropriate metadata. 240 void ConvertToWebTransportDataStream(WebTransportSessionId session_id); 241 242 void OnCanWriteNewData() override; 243 244 // If this stream is a WebTransport data stream, closes the connection with an 245 // error, and returns false. 246 bool AssertNotWebTransportDataStream(absl::string_view operation); 247 248 // Indicates whether a call to WriteBodySlices will be successful and not 249 // rejected due to buffer being full. |write_size| must be non-zero. 250 bool CanWriteNewBodyData(QuicByteCount write_size) const; 251 252 // From CapsuleParser::Visitor. 253 bool OnCapsule(const quiche::Capsule& capsule) override; 254 void OnCapsuleParseFailure(absl::string_view error_message) override; 255 256 // Sends an HTTP/3 datagram. The stream ID is not part of |payload|. Virtual 257 // to allow mocking in tests. 258 virtual MessageStatus SendHttp3Datagram(absl::string_view payload); 259 260 class QUICHE_EXPORT Http3DatagramVisitor { 261 public: ~Http3DatagramVisitor()262 virtual ~Http3DatagramVisitor() {} 263 264 // Called when an HTTP/3 datagram is received. |payload| does not contain 265 // the stream ID. 266 virtual void OnHttp3Datagram(QuicStreamId stream_id, 267 absl::string_view payload) = 0; 268 269 // Called when a Capsule with an unknown type is received. 270 virtual void OnUnknownCapsule(QuicStreamId stream_id, 271 const quiche::UnknownCapsule& capsule) = 0; 272 }; 273 274 // Registers |visitor| to receive HTTP/3 datagrams and enables Capsule 275 // Protocol by registering a CapsuleParser. |visitor| must be valid until a 276 // corresponding call to UnregisterHttp3DatagramVisitor. 277 void RegisterHttp3DatagramVisitor(Http3DatagramVisitor* visitor); 278 279 // Unregisters an HTTP/3 datagram visitor. Must only be called after a call to 280 // RegisterHttp3DatagramVisitor. 281 void UnregisterHttp3DatagramVisitor(); 282 283 // Replaces the current HTTP/3 datagram visitor with a different visitor. 284 // Mainly meant to be used by the visitors' move operators. 285 void ReplaceHttp3DatagramVisitor(Http3DatagramVisitor* visitor); 286 287 class QUICHE_EXPORT ConnectIpVisitor { 288 public: ~ConnectIpVisitor()289 virtual ~ConnectIpVisitor() {} 290 291 virtual bool OnAddressAssignCapsule( 292 const quiche::AddressAssignCapsule& capsule) = 0; 293 virtual bool OnAddressRequestCapsule( 294 const quiche::AddressRequestCapsule& capsule) = 0; 295 virtual bool OnRouteAdvertisementCapsule( 296 const quiche::RouteAdvertisementCapsule& capsule) = 0; 297 virtual void OnHeadersWritten() = 0; 298 }; 299 300 // Registers |visitor| to receive CONNECT-IP capsules. |visitor| must be 301 // valid until a corresponding call to UnregisterConnectIpVisitor. 302 void RegisterConnectIpVisitor(ConnectIpVisitor* visitor); 303 304 // Unregisters a CONNECT-IP visitor. Must only be called after a call to 305 // RegisterConnectIpVisitor. 306 void UnregisterConnectIpVisitor(); 307 308 // Replaces the current CONNECT-IP visitor with a different visitor. 309 // Mainly meant to be used by the visitors' move operators. 310 void ReplaceConnectIpVisitor(ConnectIpVisitor* visitor); 311 312 // Sets max datagram time in queue. 313 void SetMaxDatagramTimeInQueue(QuicTime::Delta max_time_in_queue); 314 315 void OnDatagramReceived(QuicDataReader* reader); 316 317 QuicByteCount GetMaxDatagramSize() const; 318 319 // Writes |capsule| onto the DATA stream. 320 void WriteCapsule(const quiche::Capsule& capsule, bool fin = false); 321 322 void WriteGreaseCapsule(); 323 invalid_request_details()324 const std::string& invalid_request_details() const { 325 return invalid_request_details_; 326 } 327 328 protected: 329 // Called when the received headers are too large. By default this will 330 // reset the stream. 331 virtual void OnHeadersTooLarge(); 332 333 virtual void OnInitialHeadersComplete(bool fin, size_t frame_len, 334 const QuicHeaderList& header_list); 335 virtual void OnTrailingHeadersComplete(bool fin, size_t frame_len, 336 const QuicHeaderList& header_list); 337 virtual size_t WriteHeadersImpl( 338 spdy::Http2HeaderBlock header_block, bool fin, 339 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> 340 ack_listener); 341 342 virtual bool CopyAndValidateTrailers(const QuicHeaderList& header_list, 343 bool expect_final_byte_offset, 344 size_t* final_byte_offset, 345 spdy::Http2HeaderBlock* trailers); 346 visitor()347 Visitor* visitor() { return visitor_; } 348 set_headers_decompressed(bool val)349 void set_headers_decompressed(bool val) { headers_decompressed_ = val; } 350 set_ack_listener(quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener)351 void set_ack_listener( 352 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> 353 ack_listener) { 354 ack_listener_ = std::move(ack_listener); 355 } 356 357 void OnWriteSideInDataRecvdState() override; 358 359 virtual bool ValidateReceivedHeaders(const QuicHeaderList& header_list); 360 // TODO(b/202433856) Merge AreHeaderFieldValueValid into 361 // ValidateReceivedHeaders once all flags guarding the behavior of 362 // ValidateReceivedHeaders has been rolled out. 363 virtual bool AreHeaderFieldValuesValid( 364 const QuicHeaderList& header_list) const; 365 366 // Reset stream upon invalid request headers. 367 virtual void OnInvalidHeaders(); 368 369 void set_invalid_request_details(std::string invalid_request_details); 370 371 // Called by HttpDecoderVisitor. 372 virtual bool OnDataFrameStart(QuicByteCount header_length, 373 QuicByteCount payload_length); 374 375 void CloseReadSide() override; 376 377 private: 378 friend class test::QuicSpdyStreamPeer; 379 friend class test::QuicStreamPeer; 380 friend class QuicStreamUtils; 381 class HttpDecoderVisitor; 382 383 struct QUICHE_EXPORT WebTransportDataStream { 384 WebTransportDataStream(QuicSpdyStream* stream, 385 WebTransportSessionId session_id); 386 387 WebTransportSessionId session_id; 388 WebTransportStreamAdapter adapter; 389 }; 390 391 // Called by HttpDecoderVisitor. 392 bool OnDataFramePayload(absl::string_view payload); 393 bool OnDataFrameEnd(); 394 bool OnHeadersFrameStart(QuicByteCount header_length, 395 QuicByteCount payload_length); 396 bool OnHeadersFramePayload(absl::string_view payload); 397 bool OnHeadersFrameEnd(); 398 void OnWebTransportStreamFrameType(QuicByteCount header_length, 399 WebTransportSessionId session_id); 400 bool OnUnknownFrameStart(uint64_t frame_type, QuicByteCount header_length, 401 QuicByteCount payload_length); 402 bool OnUnknownFramePayload(absl::string_view payload); 403 bool OnUnknownFrameEnd(); 404 405 // Given the interval marked by [|offset|, |offset| + |data_length|), return 406 // the number of frame header bytes contained in it. 407 QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset, 408 QuicByteCount data_length) const; 409 410 void MaybeProcessSentWebTransportHeaders(spdy::Http2HeaderBlock& headers); 411 void MaybeProcessReceivedWebTransportHeaders(); 412 413 // Writes HTTP/3 DATA frame header. If |force_write| is true, use 414 // WriteOrBufferData if send buffer cannot accomodate the header + data. 415 ABSL_MUST_USE_RESULT bool WriteDataFrameHeader(QuicByteCount data_length, 416 bool force_write); 417 418 // Simply calls OnBodyAvailable() unless capsules are in use, in which case 419 // pass the capsule fragments to the capsule manager. 420 void HandleBodyAvailable(); 421 422 // Called when a datagram frame or capsule is received. 423 void HandleReceivedDatagram(absl::string_view payload); 424 425 // Whether the next received header is trailer or not. NextHeaderIsTrailer()426 virtual bool NextHeaderIsTrailer() const { return headers_decompressed_; } 427 428 QuicSpdySession* spdy_session_; 429 430 bool on_body_available_called_because_sequencer_is_closed_; 431 432 Visitor* visitor_; 433 434 // True if read side processing is blocked while waiting for callback from 435 // QPACK decoder. 436 bool blocked_on_decoding_headers_; 437 // True if the headers have been completely decompressed. 438 bool headers_decompressed_; 439 // True if uncompressed headers or trailers exceed maximum allowed size 440 // advertised to peer via SETTINGS_MAX_HEADER_LIST_SIZE. 441 bool header_list_size_limit_exceeded_; 442 // Contains a copy of the decompressed header (name, value) pairs until they 443 // are consumed via Readv. 444 QuicHeaderList header_list_; 445 // Length of most recently received HEADERS frame payload. 446 QuicByteCount headers_payload_length_; 447 448 // True if the trailers have been completely decompressed. 449 bool trailers_decompressed_; 450 // True if the trailers have been consumed. 451 bool trailers_consumed_; 452 453 // The parsed trailers received from the peer. 454 spdy::Http2HeaderBlock received_trailers_; 455 456 // Headers accumulator for decoding HEADERS frame payload. 457 std::unique_ptr<QpackDecodedHeadersAccumulator> 458 qpack_decoded_headers_accumulator_; 459 // Visitor of the HttpDecoder. 460 std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_; 461 // HttpDecoder for processing raw incoming stream frames. 462 HttpDecoder decoder_; 463 // Object that manages references to DATA frame payload fragments buffered by 464 // the sequencer and calculates how much data should be marked consumed with 465 // the sequencer each time new stream data is processed. 466 QuicSpdyStreamBodyManager body_manager_; 467 468 std::unique_ptr<quiche::CapsuleParser> capsule_parser_; 469 470 // Sequencer offset keeping track of how much data HttpDecoder has processed. 471 // Initial value is zero for fresh streams, or sequencer()->NumBytesConsumed() 472 // at time of construction if a PendingStream is converted to account for the 473 // length of the unidirectional stream type at the beginning of the stream. 474 QuicStreamOffset sequencer_offset_; 475 476 // True when inside an HttpDecoder::ProcessInput() call. 477 // Used for detecting reentrancy. 478 bool is_decoder_processing_input_; 479 480 // Ack listener of this stream, and it is notified when any of written bytes 481 // are acked or retransmitted. 482 quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener_; 483 484 // Offset of unacked frame headers. 485 QuicIntervalSet<QuicStreamOffset> unacked_frame_headers_offsets_; 486 487 // Priority parameters sent in the last PRIORITY_UPDATE frame, or default 488 // values defined by RFC9218 if no PRIORITY_UPDATE frame has been sent. 489 QuicStreamPriority last_sent_priority_; 490 491 // If this stream is a WebTransport extended CONNECT stream, contains the 492 // WebTransport session associated with this stream. 493 std::unique_ptr<WebTransportHttp3> web_transport_; 494 495 // If this stream is a WebTransport data stream, |web_transport_data_| 496 // contains all of the associated metadata. 497 std::unique_ptr<WebTransportDataStream> web_transport_data_; 498 499 // HTTP/3 Datagram support. 500 Http3DatagramVisitor* datagram_visitor_ = nullptr; 501 // CONNECT-IP support. 502 ConnectIpVisitor* connect_ip_visitor_ = nullptr; 503 504 // Empty if the headers are valid. 505 std::string invalid_request_details_; 506 }; 507 508 } // namespace quic 509 510 #endif // QUICHE_QUIC_CORE_HTTP_QUIC_SPDY_STREAM_H_ 511