xref: /aosp_15_r20/external/cronet/net/quic/quic_chromium_client_stream.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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