xref: /aosp_15_r20/external/cronet/net/websockets/websocket_basic_stream.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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 #ifndef NET_WEBSOCKETS_WEBSOCKET_BASIC_STREAM_H_
6 #define NET_WEBSOCKETS_WEBSOCKET_BASIC_STREAM_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #include "base/containers/queue.h"
16 #include "base/containers/span.h"
17 #include "base/memory/scoped_refptr.h"
18 #include "base/time/time.h"
19 #include "net/base/completion_once_callback.h"
20 #include "net/base/net_export.h"
21 #include "net/log/net_log_with_source.h"
22 #include "net/traffic_annotation/network_traffic_annotation.h"
23 #include "net/websockets/websocket_frame.h"
24 #include "net/websockets/websocket_frame_parser.h"
25 #include "net/websockets/websocket_stream.h"
26 
27 namespace base {
28 class TimeTicks;
29 }  // namespace base
30 
31 namespace net {
32 
33 class ClientSocketHandle;
34 class DrainableIOBuffer;
35 class GrowableIOBuffer;
36 class IOBuffer;
37 class IOBufferWithSize;
38 struct WebSocketFrame;
39 struct WebSocketFrameChunk;
40 struct NetworkTrafficAnnotationTag;
41 
42 // Implementation of WebSocketStream for non-multiplexed ws:// connections (or
43 // the physical side of a multiplexed ws:// connection).
44 //
45 // Please update the traffic annotations in the websocket_basic_stream.cc and
46 // websocket_stream.cc if the class is used for any communication with Google.
47 // In such a case, annotation should be passed from the callers to this class
48 // and a local annotation can not be used anymore.
49 class NET_EXPORT_PRIVATE WebSocketBasicStream final : public WebSocketStream {
50  public:
51   typedef WebSocketMaskingKey (*WebSocketMaskingKeyGeneratorFunction)();
52 
53   enum class BufferSize : uint8_t {
54     kSmall,
55     kLarge,
56   };
57 
58   // A class that calculates whether the associated WebSocketBasicStream
59   // should use a small buffer or large buffer, given the timing information
60   // or Read calls. This class is public for testing.
61   class NET_EXPORT_PRIVATE BufferSizeManager final {
62    public:
63     BufferSizeManager();
64     BufferSizeManager(const BufferSizeManager&) = delete;
65     BufferSizeManager& operator=(const BufferSizeManager&) = delete;
66     ~BufferSizeManager();
67 
68     // Called when the associated WebSocketBasicStream starts reading data
69     // into a buffer.
70     void OnRead(base::TimeTicks now);
71 
72     // Called when the Read operation completes. `size` must be positive.
73     void OnReadComplete(base::TimeTicks now, int size);
74 
75     // Returns the appropriate buffer size the associated WebSocketBasicStream
76     // should use.
buffer_size()77     BufferSize buffer_size() const { return buffer_size_; }
78 
79     // Set the rolling average window for tests.
set_window_for_test(size_t size)80     void set_window_for_test(size_t size) { rolling_average_window_ = size; }
81 
82    private:
83     // This keeps the best read buffer size.
84     BufferSize buffer_size_ = BufferSize::kSmall;
85 
86     // The number of results to calculate the throughput. This is a variable so
87     // that unittests can set other values.
88     size_t rolling_average_window_ = 100;
89 
90     // This keeps the timestamps to calculate the throughput.
91     base::queue<base::TimeTicks> read_start_timestamps_;
92 
93     // The sum of the last few read size.
94     int rolling_byte_total_ = 0;
95 
96     // This keeps the read size.
97     base::queue<int> recent_read_sizes_;
98   };
99 
100   // Adapter that allows WebSocketBasicStream to use
101   // either a TCP/IP or TLS socket, or an HTTP/2 stream.
102   class Adapter {
103    public:
104     virtual ~Adapter() = default;
105     virtual int Read(IOBuffer* buf,
106                      int buf_len,
107                      CompletionOnceCallback callback) = 0;
108     virtual int Write(
109         IOBuffer* buf,
110         int buf_len,
111         CompletionOnceCallback callback,
112         const NetworkTrafficAnnotationTag& traffic_annotation) = 0;
113     virtual void Disconnect() = 0;
114     virtual bool is_initialized() const = 0;
115   };
116 
117   // This class should not normally be constructed directly; see
118   // WebSocketStream::CreateAndConnectStream() and
119   // WebSocketBasicHandshakeStream::Upgrade().
120   WebSocketBasicStream(std::unique_ptr<Adapter> connection,
121                        const scoped_refptr<GrowableIOBuffer>& http_read_buffer,
122                        const std::string& sub_protocol,
123                        const std::string& extensions,
124                        const NetLogWithSource& net_log);
125 
126   // The destructor has to make sure the connection is closed when we finish so
127   // that it does not get returned to the pool.
128   ~WebSocketBasicStream() override;
129 
130   // WebSocketStream implementation.
131   int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
132                  CompletionOnceCallback callback) override;
133 
134   int WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
135                   CompletionOnceCallback callback) override;
136 
137   void Close() override;
138 
139   std::string GetSubProtocol() const override;
140 
141   std::string GetExtensions() const override;
142 
143   const NetLogWithSource& GetNetLogWithSource() const override;
144 
145   ////////////////////////////////////////////////////////////////////////////
146   // Methods for testing only.
147 
148   static std::unique_ptr<WebSocketBasicStream>
149   CreateWebSocketBasicStreamForTesting(
150       std::unique_ptr<ClientSocketHandle> connection,
151       const scoped_refptr<GrowableIOBuffer>& http_read_buffer,
152       const std::string& sub_protocol,
153       const std::string& extensions,
154       const NetLogWithSource& net_log,
155       WebSocketMaskingKeyGeneratorFunction key_generator_function);
156 
157  private:
158   // Reads until socket read returns asynchronously or returns error.
159   // If returns ERR_IO_PENDING, then |read_callback_| will be called with result
160   // later.
161   int ReadEverything(std::vector<std::unique_ptr<WebSocketFrame>>* frames);
162 
163   // Called when a read completes. Parses the result, tries to read more.
164   // Might call |read_callback_|.
165   void OnReadComplete(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
166                       int result);
167 
168   // Writes until |buffer| is fully drained (in which case returns OK) or a
169   // socket write returns asynchronously or returns an error.  If returns
170   // ERR_IO_PENDING, then |write_callback_| will be called with result later.
171   int WriteEverything(const scoped_refptr<DrainableIOBuffer>& buffer);
172 
173   // Called when a write completes.  Tries to write more.
174   // Might call |write_callback_|.
175   void OnWriteComplete(const scoped_refptr<DrainableIOBuffer>& buffer,
176                        int result);
177 
178   // Attempts to parse the output of a read as WebSocket frames. On success,
179   // returns OK and places the frame(s) in |frames|.
180   int HandleReadResult(int result,
181                        std::vector<std::unique_ptr<WebSocketFrame>>* frames);
182 
183   // Converts the chunks in |frame_chunks| into frames and writes them to
184   // |frames|. |frame_chunks| is destroyed in the process. Returns
185   // ERR_WS_PROTOCOL_ERROR if an invalid chunk was found. If one or more frames
186   // was added to |frames|, then returns OK, otherwise returns ERR_IO_PENDING.
187   int ConvertChunksToFrames(
188       std::vector<std::unique_ptr<WebSocketFrameChunk>>* frame_chunks,
189       std::vector<std::unique_ptr<WebSocketFrame>>* frames);
190 
191   // Converts a |chunk| to a |frame|. |*frame| should be NULL on entry to this
192   // method. If |chunk| is an incomplete control frame, or an empty middle
193   // frame, then |*frame| may still be NULL on exit. If an invalid control frame
194   // is found, returns ERR_WS_PROTOCOL_ERROR and the stream is no longer
195   // usable. Otherwise returns OK (even if frame is still NULL).
196   int ConvertChunkToFrame(std::unique_ptr<WebSocketFrameChunk> chunk,
197                           std::unique_ptr<WebSocketFrame>* frame);
198 
199   // Creates a frame based on the value of |is_final_chunk|, |data| and
200   // |current_frame_header_|. Clears |current_frame_header_| if |is_final_chunk|
201   // is true. |data| may be NULL if the frame has an empty payload. A frame in
202   // the middle of a message with no data is not useful; in this case the
203   // returned frame will be NULL. Otherwise, |current_frame_header_->opcode| is
204   // set to Continuation after use if it was Text or Binary, in accordance with
205   // WebSocket RFC6455 section 5.4.
206   std::unique_ptr<WebSocketFrame> CreateFrame(bool is_final_chunk,
207                                               base::span<const char> data);
208 
209   // Adds |data_buffer| to the end of |incomplete_control_frame_body_|, applying
210   // bounds checks.
211   void AddToIncompleteControlFrameBody(base::span<const char> data);
212 
213   // Storage for pending reads.
214   scoped_refptr<IOBufferWithSize> read_buffer_;
215 
216   // The best read buffer size for the current throughput.
217   size_t target_read_buffer_size_;
218 
219   // The connection, wrapped in a ClientSocketHandle so that we can prevent it
220   // from being returned to the pool.
221   std::unique_ptr<Adapter> connection_;
222 
223   // Frame header for the frame currently being received. Only non-NULL while we
224   // are processing the frame. If the frame arrives in multiple chunks, it can
225   // remain non-NULL until additional chunks arrive. If the header of the frame
226   // was invalid, this is set to NULL, the channel is failed, and subsequent
227   // chunks of the same frame will be ignored.
228   std::unique_ptr<WebSocketFrameHeader> current_frame_header_;
229 
230   // Although it should rarely happen in practice, a control frame can arrive
231   // broken into chunks. This variable provides storage for a partial control
232   // frame until the rest arrives. It will be empty the rest of the time.
233   std::vector<char> incomplete_control_frame_body_;
234   // Storage for payload of combined (see |incomplete_control_frame_body_|)
235   // control frame.
236   std::vector<char> complete_control_frame_body_;
237 
238   // Only used during handshake. Some data may be left in this buffer after the
239   // handshake, in which case it will be picked up during the first call to
240   // ReadFrames(). The type is GrowableIOBuffer for compatibility with
241   // net::HttpStreamParser, which is used to parse the handshake.
242   scoped_refptr<GrowableIOBuffer> http_read_buffer_;
243   // Flag to keep above buffer until next ReadFrames() after decoding.
244   bool is_http_read_buffer_decoded_ = false;
245 
246   // This keeps the current parse state (including any incomplete headers) and
247   // parses frames.
248   WebSocketFrameParser parser_;
249 
250   // The negotated sub-protocol, or empty for none.
251   const std::string sub_protocol_;
252 
253   // The extensions negotiated with the remote server.
254   const std::string extensions_;
255 
256   NetLogWithSource net_log_;
257 
258   // This is used for adaptive read buffer size.
259   BufferSizeManager buffer_size_manager_;
260 
261   // This keeps the current read buffer size.
262   BufferSize buffer_size_ = buffer_size_manager_.buffer_size();
263 
264   // This can be overridden in tests to make the output deterministic. We don't
265   // use a Callback here because a function pointer is faster and good enough
266   // for our purposes.
267   WebSocketMaskingKeyGeneratorFunction generate_websocket_masking_key_;
268 
269   // User callback saved for asynchronous writes and reads.
270   CompletionOnceCallback write_callback_;
271   CompletionOnceCallback read_callback_;
272 };
273 
274 }  // namespace net
275 
276 #endif  // NET_WEBSOCKETS_WEBSOCKET_BASIC_STREAM_H_
277