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