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