1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // NOTE: This code is not shared between Google and Chrome. 6 7 #ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_ 8 #define NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_ 9 10 #include <stddef.h> 11 12 #include <memory> 13 #include <string_view> 14 #include <vector> 15 16 #include "base/containers/circular_deque.h" 17 #include "base/functional/callback_forward.h" 18 #include "base/memory/raw_ptr.h" 19 #include "base/time/time.h" 20 #include "net/base/completion_once_callback.h" 21 #include "net/base/idempotency.h" 22 #include "net/base/ip_endpoint.h" 23 #include "net/base/net_export.h" 24 #include "net/base/upload_data_stream.h" 25 #include "net/http/http_request_info.h" 26 #include "net/http/http_response_info.h" 27 #include "net/http/http_stream.h" 28 #include "net/log/net_log_with_source.h" 29 #include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream.h" 30 #include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h" 31 #include "net/traffic_annotation/network_traffic_annotation.h" 32 33 namespace quic { 34 class QuicSpdyClientSessionBase; 35 } // namespace quic 36 namespace net { 37 38 // A client-initiated ReliableQuicStream. Instances of this class 39 // are owned by the QuicClientSession which created them. 40 class NET_EXPORT_PRIVATE QuicChromiumClientStream 41 : public quic::QuicSpdyStream { 42 public: 43 // Wrapper for interacting with the session in a restricted fashion. 44 class NET_EXPORT_PRIVATE Handle { 45 public: 46 Handle(const Handle&) = delete; 47 Handle& operator=(const Handle&) = delete; 48 49 ~Handle(); 50 51 // Returns true if the stream is still connected. IsOpen()52 bool IsOpen() { return stream_ != nullptr; } 53 54 // Reads initial or 103 Early Hints headers into |header_block| and returns 55 // the length of the HEADERS frame which contained them. If headers are not 56 // available, returns ERR_IO_PENDING and will invoke |callback| 57 // asynchronously when the headers arrive. 58 // TODO(rch): Invoke |callback| when there is a stream or connection error 59 // instead of calling OnClose() or OnError(). 60 int ReadInitialHeaders(spdy::Http2HeaderBlock* header_block, 61 CompletionOnceCallback callback); 62 63 // Reads at most |buffer_len| bytes of body into |buffer| and returns the 64 // number of bytes read. If body is not available, returns ERR_IO_PENDING 65 // and will invoke |callback| asynchronously when data arrive. 66 // TODO(rch): Invoke |callback| when there is a stream or connection error 67 // instead of calling OnClose() or OnError(). 68 int ReadBody(IOBuffer* buffer, 69 int buffer_len, 70 CompletionOnceCallback callback); 71 72 // Reads trailing headers into |header_block| and returns the length of 73 // the HEADERS frame which contained them. If headers are not available, 74 // returns ERR_IO_PENDING and will invoke |callback| asynchronously when 75 // the headers arrive. 76 // TODO(rch): Invoke |callback| when there is a stream or connection error 77 // instead of calling OnClose() or OnError(). 78 int ReadTrailingHeaders(spdy::Http2HeaderBlock* header_block, 79 CompletionOnceCallback callback); 80 81 // Writes |header_block| to the peer. Closes the write side if |fin| is 82 // true. If non-null, |ack_notifier_delegate| will be notified when the 83 // headers are ACK'd by the peer. Returns a net error code if there is 84 // an error writing the headers, or the number of bytes written on 85 // success. Will not return ERR_IO_PENDING. 86 int WriteHeaders( 87 spdy::Http2HeaderBlock header_block, 88 bool fin, 89 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> 90 ack_notifier_delegate); 91 92 // Writes |data| to the peer. Closes the write side if |fin| is true. 93 // If the data could not be written immediately, returns ERR_IO_PENDING 94 // and invokes |callback| asynchronously when the write completes. 95 int WriteStreamData(std::string_view data, 96 bool fin, 97 CompletionOnceCallback callback); 98 99 // Same as WriteStreamData except it writes data from a vector of IOBuffers, 100 // with the length of each buffer at the corresponding index in |lengths|. 101 int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers, 102 const std::vector<int>& lengths, 103 bool fin, 104 CompletionOnceCallback callback); 105 106 // Writes |packet| to server by constructing a UDP payload from 107 // packet and sending the datagram on the stream. 108 int WriteConnectUdpPayload(absl::string_view packet); 109 110 // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes 111 // read. 112 int Read(IOBuffer* buf, int buf_len); 113 114 // Called to notify the stream when the final incoming data is read. 115 void OnFinRead(); 116 117 // Prevents the connection from migrating to a cellular network while this 118 // stream is open. 119 void DisableConnectionMigrationToCellularNetwork(); 120 121 // Sets the precedence of the stream to |priority|. 122 void SetPriority(const quic::QuicStreamPriority& priority); 123 124 // Sends a RST_STREAM frame to the peer and closes the streams. 125 void Reset(quic::QuicRstStreamErrorCode error_code); 126 127 // Registers |visitor| to receive HTTP/3 datagrams on the stream. 128 void RegisterHttp3DatagramVisitor(Http3DatagramVisitor* visitor); 129 130 // Unregisters an HTTP/3 datagram visitor. 131 void UnregisterHttp3DatagramVisitor(); 132 133 quic::QuicStreamId id() const; 134 quic::QuicErrorCode connection_error() const; 135 quic::QuicRstStreamErrorCode stream_error() const; 136 uint64_t connection_wire_error() const; 137 uint64_t ietf_application_error() const; 138 bool fin_sent() const; 139 bool fin_received() const; 140 uint64_t stream_bytes_read() const; 141 uint64_t stream_bytes_written() const; 142 size_t NumBytesConsumed() const; 143 bool HasBytesToRead() const; 144 bool IsDoneReading() const; 145 bool IsFirstStream() const; 146 first_early_hints_time()147 base::TimeTicks first_early_hints_time() const { 148 return first_early_hints_time_; 149 } 150 headers_received_start_time()151 base::TimeTicks headers_received_start_time() const { 152 return headers_received_start_time_; 153 } 154 155 // TODO(rch): Move this test-only method to a peer, or else remove. 156 bool can_migrate_to_cellular_network(); 157 158 const NetLogWithSource& net_log() const; 159 160 // Sets the idempotency of the request. 161 void SetRequestIdempotency(Idempotency idempotency); 162 // Returns the idempotency of the request. 163 Idempotency GetRequestIdempotency() const; 164 165 // Returns the largest payload that will fit into a single MESSAGE frame at 166 // any point during the connection. This assumes the version and 167 // connection ID lengths do not change. Returns zero if the stream or 168 // session are closed. 169 quic::QuicPacketLength GetGuaranteedLargestMessagePayload() const; 170 171 private: 172 friend class QuicChromiumClientStream; 173 174 // Constucts a new Handle for |stream|. 175 explicit Handle(QuicChromiumClientStream* stream); 176 177 // Methods invoked by the stream. 178 void OnEarlyHintsAvailable(); 179 void OnInitialHeadersAvailable(); 180 void OnTrailingHeadersAvailable(); 181 void OnDataAvailable(); 182 void OnCanWrite(); 183 void OnClose(); 184 void OnError(int error); 185 186 // Invokes async IO callbacks because of |error|. 187 void InvokeCallbacksOnClose(int error); 188 189 // Saves various fields from the stream before the stream goes away. 190 void SaveState(); 191 192 void SetCallback(CompletionOnceCallback new_callback, 193 CompletionOnceCallback* callback); 194 195 void ResetAndRun(CompletionOnceCallback callback, int rv); 196 197 int HandleIOComplete(int rv); 198 199 raw_ptr<QuicChromiumClientStream> stream_; // Unowned. 200 201 bool may_invoke_callbacks_ = true; // True when callbacks may be invoked. 202 203 // Callback to be invoked when ReadInitialHeaders completes asynchronously. 204 CompletionOnceCallback read_headers_callback_; 205 // Provided by the owner of this handle when ReadInitialHeaders is called. 206 raw_ptr<spdy::Http2HeaderBlock> read_headers_buffer_ = nullptr; 207 208 // Callback to be invoked when ReadBody completes asynchronously. 209 CompletionOnceCallback read_body_callback_; 210 raw_ptr<IOBuffer, DanglingUntriaged> read_body_buffer_; 211 int read_body_buffer_len_ = 0; 212 213 // Callback to be invoked when WriteStreamData or WritevStreamData completes 214 // asynchronously. 215 CompletionOnceCallback write_callback_; 216 217 quic::QuicStreamId id_; 218 quic::QuicErrorCode connection_error_; 219 quic::QuicRstStreamErrorCode stream_error_; 220 uint64_t connection_wire_error_ = 0; 221 uint64_t ietf_application_error_ = 0; 222 bool fin_sent_; 223 bool fin_received_; 224 uint64_t stream_bytes_read_; 225 uint64_t stream_bytes_written_; 226 bool is_done_reading_; 227 bool is_first_stream_; 228 size_t num_bytes_consumed_; 229 Idempotency idempotency_ = DEFAULT_IDEMPOTENCY; 230 231 int net_error_ = ERR_UNEXPECTED; 232 233 NetLogWithSource net_log_; 234 235 // The time at which the first 103 Early Hints response is received. 236 base::TimeTicks first_early_hints_time_; 237 238 base::TimeTicks headers_received_start_time_; 239 240 base::WeakPtrFactory<Handle> weak_factory_{this}; 241 }; 242 243 QuicChromiumClientStream( 244 quic::QuicStreamId id, 245 quic::QuicSpdyClientSessionBase* session, 246 quic::StreamType type, 247 const NetLogWithSource& net_log, 248 const NetworkTrafficAnnotationTag& traffic_annotation); 249 QuicChromiumClientStream( 250 quic::PendingStream* pending, 251 quic::QuicSpdyClientSessionBase* session, 252 const NetLogWithSource& net_log, 253 const NetworkTrafficAnnotationTag& traffic_annotation); 254 255 QuicChromiumClientStream(const QuicChromiumClientStream&) = delete; 256 QuicChromiumClientStream& operator=(const QuicChromiumClientStream&) = delete; 257 258 ~QuicChromiumClientStream() override; 259 260 // quic::QuicSpdyStream 261 void OnInitialHeadersComplete( 262 bool fin, 263 size_t frame_len, 264 const quic::QuicHeaderList& header_list) override; 265 void OnTrailingHeadersComplete( 266 bool fin, 267 size_t frame_len, 268 const quic::QuicHeaderList& header_list) override; 269 void OnBodyAvailable() override; 270 void OnClose() override; 271 void OnCanWrite() override; 272 size_t WriteHeaders( 273 spdy::Http2HeaderBlock header_block, 274 bool fin, 275 quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface> 276 ack_listener) override; 277 278 // While the server's set_priority shouldn't be called externally, the creator 279 // of client-side streams should be able to set the priority. 280 using quic::QuicSpdyStream::SetPriority; 281 282 // Writes |data| to the peer and closes the write side if |fin| is true. 283 // Returns true if the data have been fully written. If the data was not fully 284 // written, returns false and OnCanWrite() will be invoked later. 285 bool WriteStreamData(std::string_view data, bool fin); 286 // Same as WriteStreamData except it writes data from a vector of IOBuffers, 287 // with the length of each buffer at the corresponding index in |lengths|. 288 bool WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers, 289 const std::vector<int>& lengths, 290 bool fin); 291 292 // Creates a new Handle for this stream. Must only be called once. 293 std::unique_ptr<QuicChromiumClientStream::Handle> CreateHandle(); 294 295 // Clears |handle_| from this stream. 296 void ClearHandle(); 297 298 // Notifies the stream handle of error, but doesn't close the stream. 299 void OnError(int error); 300 301 // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes read. 302 int Read(IOBuffer* buf, int buf_len); 303 net_log()304 const NetLogWithSource& net_log() const { return net_log_; } 305 306 // Prevents this stream from migrating to a cellular network. May be reset 307 // when connection migrates to a cellular network. 308 void DisableConnectionMigrationToCellularNetwork(); 309 can_migrate_to_cellular_network()310 bool can_migrate_to_cellular_network() { 311 return can_migrate_to_cellular_network_; 312 } 313 314 // True if the underlying QUIC session supports HTTP/3 Datagrams. 315 bool SupportsH3Datagram() const; 316 317 // Returns the largest payload that will fit into a single MESSAGE frame at 318 // any point during the connection. This assumes the version and 319 // connection ID lengths do not change. Returns zero if the stream or 320 // session are closed. 321 quic::QuicPacketLength GetGuaranteedLargestMessagePayload() const; 322 323 // True if this stream is the first data stream created on this session. 324 bool IsFirstStream(); 325 326 int DeliverEarlyHints(spdy::Http2HeaderBlock* header_block); 327 328 int DeliverInitialHeaders(spdy::Http2HeaderBlock* header_block); 329 330 bool DeliverTrailingHeaders(spdy::Http2HeaderBlock* header_block, 331 int* frame_len); 332 333 static constexpr char kHttp3DatagramDroppedHistogram[] = 334 "Net.QuicChromiumClientStream." 335 "Http3DatagramDroppedOnWriteConnectUdpPayload"; 336 337 using quic::QuicSpdyStream::HasBufferedData; 338 using quic::QuicStream::sequencer; 339 340 private: 341 void NotifyHandleOfInitialHeadersAvailableLater(); 342 void NotifyHandleOfInitialHeadersAvailable(); 343 void NotifyHandleOfTrailingHeadersAvailableLater(); 344 void NotifyHandleOfTrailingHeadersAvailable(); 345 void NotifyHandleOfDataAvailableLater(); 346 void NotifyHandleOfDataAvailable(); 347 348 NetLogWithSource net_log_; 349 raw_ptr<Handle> handle_ = nullptr; 350 351 // True when initial headers have been sent. 352 bool initial_headers_sent_ = false; 353 354 raw_ptr<quic::QuicSpdyClientSessionBase> session_; 355 quic::QuicTransportVersion quic_version_; 356 357 // Set to false if this stream should not be migrated to a cellular network 358 // during connection migration. 359 bool can_migrate_to_cellular_network_ = true; 360 361 // True if non-informational (non-1xx) initial headers have arrived. 362 bool initial_headers_arrived_ = false; 363 // True if non-informational (non-1xx) initial headers have been delivered to 364 // the handle. 365 bool headers_delivered_ = false; 366 // Stores the initial header until they are delivered to the handle. 367 spdy::Http2HeaderBlock initial_headers_; 368 // Length of the HEADERS frame containing initial headers. 369 size_t initial_headers_frame_len_ = 0; 370 371 // Length of the HEADERS frame containing trailing headers. 372 size_t trailing_headers_frame_len_ = 0; 373 374 struct EarlyHints { EarlyHintsEarlyHints375 EarlyHints(spdy::Http2HeaderBlock headers, size_t frame_len) 376 : headers(std::move(headers)), frame_len(frame_len) {} 377 EarlyHints(EarlyHints&& other) = default; 378 EarlyHints& operator=(EarlyHints&& other) = default; 379 EarlyHints(const EarlyHints& other) = delete; 380 EarlyHints& operator=(const EarlyHints& other) = delete; 381 382 spdy::Http2HeaderBlock headers; 383 size_t frame_len = 0; 384 }; 385 base::circular_deque<EarlyHints> early_hints_; 386 387 base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_{this}; 388 }; 389 390 } // namespace net 391 392 #endif // NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_ 393