xref: /aosp_15_r20/external/cronet/net/websockets/websocket_basic_stream.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_basic_stream.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <algorithm>
11*6777b538SAndroid Build Coastguard Worker #include <limits>
12*6777b538SAndroid Build Coastguard Worker #include <ostream>
13*6777b538SAndroid Build Coastguard Worker #include <utility>
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
22*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
24*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/socket/client_socket_handle.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/traffic_annotation/network_traffic_annotation.h"
28*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_basic_stream_adapters.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_errors.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_frame.h"
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker namespace net {
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker namespace {
35*6777b538SAndroid Build Coastguard Worker 
36*6777b538SAndroid Build Coastguard Worker // Please refer to the comment in class header if the usage changes.
37*6777b538SAndroid Build Coastguard Worker constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
38*6777b538SAndroid Build Coastguard Worker     net::DefineNetworkTrafficAnnotation("websocket_basic_stream", R"(
39*6777b538SAndroid Build Coastguard Worker       semantics {
40*6777b538SAndroid Build Coastguard Worker         sender: "WebSocket Basic Stream"
41*6777b538SAndroid Build Coastguard Worker         description:
42*6777b538SAndroid Build Coastguard Worker           "Implementation of WebSocket API from web content (a page the user "
43*6777b538SAndroid Build Coastguard Worker           "visits)."
44*6777b538SAndroid Build Coastguard Worker         trigger: "Website calls the WebSocket API."
45*6777b538SAndroid Build Coastguard Worker         data:
46*6777b538SAndroid Build Coastguard Worker           "Any data provided by web content, masked and framed in accordance "
47*6777b538SAndroid Build Coastguard Worker           "with RFC6455."
48*6777b538SAndroid Build Coastguard Worker         destination: OTHER
49*6777b538SAndroid Build Coastguard Worker         destination_other:
50*6777b538SAndroid Build Coastguard Worker           "The address that the website has chosen to communicate to."
51*6777b538SAndroid Build Coastguard Worker       }
52*6777b538SAndroid Build Coastguard Worker       policy {
53*6777b538SAndroid Build Coastguard Worker         cookies_allowed: YES
54*6777b538SAndroid Build Coastguard Worker         cookies_store: "user"
55*6777b538SAndroid Build Coastguard Worker         setting: "These requests cannot be disabled."
56*6777b538SAndroid Build Coastguard Worker         policy_exception_justification:
57*6777b538SAndroid Build Coastguard Worker           "Not implemented. WebSocket is a core web platform API."
58*6777b538SAndroid Build Coastguard Worker       }
59*6777b538SAndroid Build Coastguard Worker       comments:
60*6777b538SAndroid Build Coastguard Worker         "The browser will never add cookies to a WebSocket message. But the "
61*6777b538SAndroid Build Coastguard Worker         "handshake that was performed when the WebSocket connection was "
62*6777b538SAndroid Build Coastguard Worker         "established may have contained cookies."
63*6777b538SAndroid Build Coastguard Worker       )");
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker // This uses type uint64_t to match the definition of
66*6777b538SAndroid Build Coastguard Worker // WebSocketFrameHeader::payload_length in websocket_frame.h.
67*6777b538SAndroid Build Coastguard Worker constexpr uint64_t kMaxControlFramePayload = 125;
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker // The number of bytes to attempt to read at a time. It's used only for high
70*6777b538SAndroid Build Coastguard Worker // throughput connections.
71*6777b538SAndroid Build Coastguard Worker // TODO(ricea): See if there is a better number or algorithm to fulfill our
72*6777b538SAndroid Build Coastguard Worker // requirements:
73*6777b538SAndroid Build Coastguard Worker //  1. We would like to use minimal memory on low-bandwidth or idle connections
74*6777b538SAndroid Build Coastguard Worker //  2. We would like to read as close to line speed as possible on
75*6777b538SAndroid Build Coastguard Worker //     high-bandwidth connections
76*6777b538SAndroid Build Coastguard Worker //  3. We can't afford to cause jank on the IO thread by copying large buffers
77*6777b538SAndroid Build Coastguard Worker //     around
78*6777b538SAndroid Build Coastguard Worker //  4. We would like to hit any sweet-spots that might exist in terms of network
79*6777b538SAndroid Build Coastguard Worker //     packet sizes / encryption block sizes / IPC alignment issues, etc.
80*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
81*6777b538SAndroid Build Coastguard Worker constexpr size_t kLargeReadBufferSize = 32 * 1024;
82*6777b538SAndroid Build Coastguard Worker #else
83*6777b538SAndroid Build Coastguard Worker // |2^n - delta| is better than 2^n on Linux. See crrev.com/c/1792208.
84*6777b538SAndroid Build Coastguard Worker constexpr size_t kLargeReadBufferSize = 131000;
85*6777b538SAndroid Build Coastguard Worker #endif
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker // The number of bytes to attempt to read at a time. It's set as an initial read
88*6777b538SAndroid Build Coastguard Worker // buffer size and used for low throughput connections.
89*6777b538SAndroid Build Coastguard Worker constexpr size_t kSmallReadBufferSize = 1000;
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker // The threshold to decide whether to switch the read buffer size.
92*6777b538SAndroid Build Coastguard Worker constexpr double kThresholdInBytesPerSecond = 1200 * 1000;
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker // Returns the total serialized size of |frames|. This function assumes that
95*6777b538SAndroid Build Coastguard Worker // |frames| will be serialized with mask field. This function forces the
96*6777b538SAndroid Build Coastguard Worker // masked bit of the frames on.
CalculateSerializedSizeAndTurnOnMaskBit(std::vector<std::unique_ptr<WebSocketFrame>> * frames)97*6777b538SAndroid Build Coastguard Worker int CalculateSerializedSizeAndTurnOnMaskBit(
98*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames) {
99*6777b538SAndroid Build Coastguard Worker   constexpr uint64_t kMaximumTotalSize = std::numeric_limits<int>::max();
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   uint64_t total_size = 0;
102*6777b538SAndroid Build Coastguard Worker   for (const auto& frame : *frames) {
103*6777b538SAndroid Build Coastguard Worker     // Force the masked bit on.
104*6777b538SAndroid Build Coastguard Worker     frame->header.masked = true;
105*6777b538SAndroid Build Coastguard Worker     // We enforce flow control so the renderer should never be able to force us
106*6777b538SAndroid Build Coastguard Worker     // to cache anywhere near 2GB of frames.
107*6777b538SAndroid Build Coastguard Worker     uint64_t frame_size = frame->header.payload_length +
108*6777b538SAndroid Build Coastguard Worker                           GetWebSocketFrameHeaderSize(frame->header);
109*6777b538SAndroid Build Coastguard Worker     CHECK_LE(frame_size, kMaximumTotalSize - total_size)
110*6777b538SAndroid Build Coastguard Worker         << "Aborting to prevent overflow";
111*6777b538SAndroid Build Coastguard Worker     total_size += frame_size;
112*6777b538SAndroid Build Coastguard Worker   }
113*6777b538SAndroid Build Coastguard Worker   return static_cast<int>(total_size);
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker 
NetLogBufferSizeParam(int buffer_size)116*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogBufferSizeParam(int buffer_size) {
117*6777b538SAndroid Build Coastguard Worker   base::Value::Dict dict;
118*6777b538SAndroid Build Coastguard Worker   dict.Set("read_buffer_size_in_bytes", buffer_size);
119*6777b538SAndroid Build Coastguard Worker   return dict;
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker 
NetLogFrameHeaderParam(const WebSocketFrameHeader * header)122*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogFrameHeaderParam(const WebSocketFrameHeader* header) {
123*6777b538SAndroid Build Coastguard Worker   base::Value::Dict dict;
124*6777b538SAndroid Build Coastguard Worker   dict.Set("final", header->final);
125*6777b538SAndroid Build Coastguard Worker   dict.Set("reserved1", header->reserved1);
126*6777b538SAndroid Build Coastguard Worker   dict.Set("reserved2", header->reserved2);
127*6777b538SAndroid Build Coastguard Worker   dict.Set("reserved3", header->reserved3);
128*6777b538SAndroid Build Coastguard Worker   dict.Set("opcode", header->opcode);
129*6777b538SAndroid Build Coastguard Worker   dict.Set("masked", header->masked);
130*6777b538SAndroid Build Coastguard Worker   dict.Set("payload_length", static_cast<double>(header->payload_length));
131*6777b538SAndroid Build Coastguard Worker   return dict;
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker }  // namespace
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker WebSocketBasicStream::BufferSizeManager::BufferSizeManager() = default;
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker WebSocketBasicStream::BufferSizeManager::~BufferSizeManager() = default;
139*6777b538SAndroid Build Coastguard Worker 
OnRead(base::TimeTicks now)140*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::BufferSizeManager::OnRead(base::TimeTicks now) {
141*6777b538SAndroid Build Coastguard Worker   read_start_timestamps_.push(now);
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker 
OnReadComplete(base::TimeTicks now,int size)144*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::BufferSizeManager::OnReadComplete(
145*6777b538SAndroid Build Coastguard Worker     base::TimeTicks now,
146*6777b538SAndroid Build Coastguard Worker     int size) {
147*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(size, 0);
148*6777b538SAndroid Build Coastguard Worker   // This cannot overflow because the result is at most
149*6777b538SAndroid Build Coastguard Worker   // kLargeReadBufferSize*rolling_average_window_.
150*6777b538SAndroid Build Coastguard Worker   rolling_byte_total_ += size;
151*6777b538SAndroid Build Coastguard Worker   recent_read_sizes_.push(size);
152*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(read_start_timestamps_.size(), rolling_average_window_);
153*6777b538SAndroid Build Coastguard Worker   if (read_start_timestamps_.size() == rolling_average_window_) {
154*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(read_start_timestamps_.size(), recent_read_sizes_.size());
155*6777b538SAndroid Build Coastguard Worker     base::TimeDelta duration = now - read_start_timestamps_.front();
156*6777b538SAndroid Build Coastguard Worker     base::TimeDelta threshold_duration =
157*6777b538SAndroid Build Coastguard Worker         base::Seconds(rolling_byte_total_ / kThresholdInBytesPerSecond);
158*6777b538SAndroid Build Coastguard Worker     read_start_timestamps_.pop();
159*6777b538SAndroid Build Coastguard Worker     rolling_byte_total_ -= recent_read_sizes_.front();
160*6777b538SAndroid Build Coastguard Worker     recent_read_sizes_.pop();
161*6777b538SAndroid Build Coastguard Worker     if (threshold_duration < duration) {
162*6777b538SAndroid Build Coastguard Worker       buffer_size_ = BufferSize::kSmall;
163*6777b538SAndroid Build Coastguard Worker     } else {
164*6777b538SAndroid Build Coastguard Worker       buffer_size_ = BufferSize::kLarge;
165*6777b538SAndroid Build Coastguard Worker     }
166*6777b538SAndroid Build Coastguard Worker   }
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker 
WebSocketBasicStream(std::unique_ptr<Adapter> connection,const scoped_refptr<GrowableIOBuffer> & http_read_buffer,const std::string & sub_protocol,const std::string & extensions,const NetLogWithSource & net_log)169*6777b538SAndroid Build Coastguard Worker WebSocketBasicStream::WebSocketBasicStream(
170*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<Adapter> connection,
171*6777b538SAndroid Build Coastguard Worker     const scoped_refptr<GrowableIOBuffer>& http_read_buffer,
172*6777b538SAndroid Build Coastguard Worker     const std::string& sub_protocol,
173*6777b538SAndroid Build Coastguard Worker     const std::string& extensions,
174*6777b538SAndroid Build Coastguard Worker     const NetLogWithSource& net_log)
175*6777b538SAndroid Build Coastguard Worker     : read_buffer_(
176*6777b538SAndroid Build Coastguard Worker           base::MakeRefCounted<IOBufferWithSize>(kSmallReadBufferSize)),
177*6777b538SAndroid Build Coastguard Worker       target_read_buffer_size_(read_buffer_->size()),
178*6777b538SAndroid Build Coastguard Worker       connection_(std::move(connection)),
179*6777b538SAndroid Build Coastguard Worker       http_read_buffer_(http_read_buffer),
180*6777b538SAndroid Build Coastguard Worker       sub_protocol_(sub_protocol),
181*6777b538SAndroid Build Coastguard Worker       extensions_(extensions),
182*6777b538SAndroid Build Coastguard Worker       net_log_(net_log),
183*6777b538SAndroid Build Coastguard Worker       generate_websocket_masking_key_(&GenerateWebSocketMaskingKey) {
184*6777b538SAndroid Build Coastguard Worker   // http_read_buffer_ should not be set if it contains no data.
185*6777b538SAndroid Build Coastguard Worker   if (http_read_buffer_.get() && http_read_buffer_->offset() == 0)
186*6777b538SAndroid Build Coastguard Worker     http_read_buffer_ = nullptr;
187*6777b538SAndroid Build Coastguard Worker   DCHECK(connection_->is_initialized());
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker 
~WebSocketBasicStream()190*6777b538SAndroid Build Coastguard Worker WebSocketBasicStream::~WebSocketBasicStream() { Close(); }
191*6777b538SAndroid Build Coastguard Worker 
ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>> * frames,CompletionOnceCallback callback)192*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::ReadFrames(
193*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames,
194*6777b538SAndroid Build Coastguard Worker     CompletionOnceCallback callback) {
195*6777b538SAndroid Build Coastguard Worker   read_callback_ = std::move(callback);
196*6777b538SAndroid Build Coastguard Worker   complete_control_frame_body_.clear();
197*6777b538SAndroid Build Coastguard Worker   if (http_read_buffer_ && is_http_read_buffer_decoded_) {
198*6777b538SAndroid Build Coastguard Worker     http_read_buffer_.reset();
199*6777b538SAndroid Build Coastguard Worker   }
200*6777b538SAndroid Build Coastguard Worker   return ReadEverything(frames);
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker 
WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>> * frames,CompletionOnceCallback callback)203*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::WriteFrames(
204*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames,
205*6777b538SAndroid Build Coastguard Worker     CompletionOnceCallback callback) {
206*6777b538SAndroid Build Coastguard Worker   // This function always concatenates all frames into a single buffer.
207*6777b538SAndroid Build Coastguard Worker   // TODO(ricea): Investigate whether it would be better in some cases to
208*6777b538SAndroid Build Coastguard Worker   // perform multiple writes with smaller buffers.
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker   write_callback_ = std::move(callback);
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker   // First calculate the size of the buffer we need to allocate.
213*6777b538SAndroid Build Coastguard Worker   int total_size = CalculateSerializedSizeAndTurnOnMaskBit(frames);
214*6777b538SAndroid Build Coastguard Worker   auto combined_buffer = base::MakeRefCounted<IOBufferWithSize>(total_size);
215*6777b538SAndroid Build Coastguard Worker 
216*6777b538SAndroid Build Coastguard Worker   char* dest = combined_buffer->data();
217*6777b538SAndroid Build Coastguard Worker   int remaining_size = total_size;
218*6777b538SAndroid Build Coastguard Worker   for (const auto& frame : *frames) {
219*6777b538SAndroid Build Coastguard Worker     net_log_.AddEvent(net::NetLogEventType::WEBSOCKET_SENT_FRAME_HEADER,
220*6777b538SAndroid Build Coastguard Worker                       [&] { return NetLogFrameHeaderParam(&frame->header); });
221*6777b538SAndroid Build Coastguard Worker     WebSocketMaskingKey mask = generate_websocket_masking_key_();
222*6777b538SAndroid Build Coastguard Worker     int result =
223*6777b538SAndroid Build Coastguard Worker         WriteWebSocketFrameHeader(frame->header, &mask, dest, remaining_size);
224*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_INVALID_ARGUMENT, result)
225*6777b538SAndroid Build Coastguard Worker         << "WriteWebSocketFrameHeader() says that " << remaining_size
226*6777b538SAndroid Build Coastguard Worker         << " is not enough to write the header in. This should not happen.";
227*6777b538SAndroid Build Coastguard Worker     CHECK_GE(result, 0) << "Potentially security-critical check failed";
228*6777b538SAndroid Build Coastguard Worker     dest += result;
229*6777b538SAndroid Build Coastguard Worker     remaining_size -= result;
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker     CHECK_LE(frame->header.payload_length,
232*6777b538SAndroid Build Coastguard Worker              static_cast<uint64_t>(remaining_size));
233*6777b538SAndroid Build Coastguard Worker     const int frame_size = static_cast<int>(frame->header.payload_length);
234*6777b538SAndroid Build Coastguard Worker     if (frame_size > 0) {
235*6777b538SAndroid Build Coastguard Worker       const char* const frame_data = frame->payload;
236*6777b538SAndroid Build Coastguard Worker       std::copy(frame_data, frame_data + frame_size, dest);
237*6777b538SAndroid Build Coastguard Worker       MaskWebSocketFramePayload(mask, 0, dest, frame_size);
238*6777b538SAndroid Build Coastguard Worker       dest += frame_size;
239*6777b538SAndroid Build Coastguard Worker       remaining_size -= frame_size;
240*6777b538SAndroid Build Coastguard Worker     }
241*6777b538SAndroid Build Coastguard Worker   }
242*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(0, remaining_size) << "Buffer size calculation was wrong; "
243*6777b538SAndroid Build Coastguard Worker                                << remaining_size << " bytes left over.";
244*6777b538SAndroid Build Coastguard Worker   auto drainable_buffer = base::MakeRefCounted<DrainableIOBuffer>(
245*6777b538SAndroid Build Coastguard Worker       std::move(combined_buffer), total_size);
246*6777b538SAndroid Build Coastguard Worker   return WriteEverything(drainable_buffer);
247*6777b538SAndroid Build Coastguard Worker }
248*6777b538SAndroid Build Coastguard Worker 
Close()249*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::Close() {
250*6777b538SAndroid Build Coastguard Worker   connection_->Disconnect();
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker 
GetSubProtocol() const253*6777b538SAndroid Build Coastguard Worker std::string WebSocketBasicStream::GetSubProtocol() const {
254*6777b538SAndroid Build Coastguard Worker   return sub_protocol_;
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker 
GetExtensions() const257*6777b538SAndroid Build Coastguard Worker std::string WebSocketBasicStream::GetExtensions() const { return extensions_; }
258*6777b538SAndroid Build Coastguard Worker 
GetNetLogWithSource() const259*6777b538SAndroid Build Coastguard Worker const NetLogWithSource& WebSocketBasicStream::GetNetLogWithSource() const {
260*6777b538SAndroid Build Coastguard Worker   return net_log_;
261*6777b538SAndroid Build Coastguard Worker }
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker /*static*/
264*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketBasicStream>
CreateWebSocketBasicStreamForTesting(std::unique_ptr<ClientSocketHandle> connection,const scoped_refptr<GrowableIOBuffer> & http_read_buffer,const std::string & sub_protocol,const std::string & extensions,const NetLogWithSource & net_log,WebSocketMaskingKeyGeneratorFunction key_generator_function)265*6777b538SAndroid Build Coastguard Worker WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
266*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<ClientSocketHandle> connection,
267*6777b538SAndroid Build Coastguard Worker     const scoped_refptr<GrowableIOBuffer>& http_read_buffer,
268*6777b538SAndroid Build Coastguard Worker     const std::string& sub_protocol,
269*6777b538SAndroid Build Coastguard Worker     const std::string& extensions,
270*6777b538SAndroid Build Coastguard Worker     const NetLogWithSource& net_log,
271*6777b538SAndroid Build Coastguard Worker     WebSocketMaskingKeyGeneratorFunction key_generator_function) {
272*6777b538SAndroid Build Coastguard Worker   auto stream = std::make_unique<WebSocketBasicStream>(
273*6777b538SAndroid Build Coastguard Worker       std::make_unique<WebSocketClientSocketHandleAdapter>(
274*6777b538SAndroid Build Coastguard Worker           std::move(connection)),
275*6777b538SAndroid Build Coastguard Worker       http_read_buffer, sub_protocol, extensions, net_log);
276*6777b538SAndroid Build Coastguard Worker   stream->generate_websocket_masking_key_ = key_generator_function;
277*6777b538SAndroid Build Coastguard Worker   return stream;
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker 
ReadEverything(std::vector<std::unique_ptr<WebSocketFrame>> * frames)280*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::ReadEverything(
281*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames) {
282*6777b538SAndroid Build Coastguard Worker   DCHECK(frames->empty());
283*6777b538SAndroid Build Coastguard Worker 
284*6777b538SAndroid Build Coastguard Worker   // If there is data left over after parsing the HTTP headers, attempt to parse
285*6777b538SAndroid Build Coastguard Worker   // it as WebSocket frames.
286*6777b538SAndroid Build Coastguard Worker   if (http_read_buffer_.get() && !is_http_read_buffer_decoded_) {
287*6777b538SAndroid Build Coastguard Worker     DCHECK_GE(http_read_buffer_->offset(), 0);
288*6777b538SAndroid Build Coastguard Worker     is_http_read_buffer_decoded_ = true;
289*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrameChunk>> frame_chunks;
290*6777b538SAndroid Build Coastguard Worker     if (!parser_.Decode(http_read_buffer_->StartOfBuffer(),
291*6777b538SAndroid Build Coastguard Worker                         http_read_buffer_->offset(), &frame_chunks))
292*6777b538SAndroid Build Coastguard Worker       return WebSocketErrorToNetError(parser_.websocket_error());
293*6777b538SAndroid Build Coastguard Worker     if (!frame_chunks.empty()) {
294*6777b538SAndroid Build Coastguard Worker       int result = ConvertChunksToFrames(&frame_chunks, frames);
295*6777b538SAndroid Build Coastguard Worker       if (result != ERR_IO_PENDING)
296*6777b538SAndroid Build Coastguard Worker         return result;
297*6777b538SAndroid Build Coastguard Worker     }
298*6777b538SAndroid Build Coastguard Worker   }
299*6777b538SAndroid Build Coastguard Worker 
300*6777b538SAndroid Build Coastguard Worker   // Run until socket stops giving us data or we get some frames.
301*6777b538SAndroid Build Coastguard Worker   while (true) {
302*6777b538SAndroid Build Coastguard Worker     if (buffer_size_manager_.buffer_size() != buffer_size_) {
303*6777b538SAndroid Build Coastguard Worker       read_buffer_ = base::MakeRefCounted<IOBufferWithSize>(
304*6777b538SAndroid Build Coastguard Worker           buffer_size_manager_.buffer_size() == BufferSize::kSmall
305*6777b538SAndroid Build Coastguard Worker               ? kSmallReadBufferSize
306*6777b538SAndroid Build Coastguard Worker               : kLargeReadBufferSize);
307*6777b538SAndroid Build Coastguard Worker       buffer_size_ = buffer_size_manager_.buffer_size();
308*6777b538SAndroid Build Coastguard Worker       net_log_.AddEvent(
309*6777b538SAndroid Build Coastguard Worker           net::NetLogEventType::WEBSOCKET_READ_BUFFER_SIZE_CHANGED,
310*6777b538SAndroid Build Coastguard Worker           [&] { return NetLogBufferSizeParam(read_buffer_->size()); });
311*6777b538SAndroid Build Coastguard Worker     }
312*6777b538SAndroid Build Coastguard Worker     buffer_size_manager_.OnRead(base::TimeTicks::Now());
313*6777b538SAndroid Build Coastguard Worker 
314*6777b538SAndroid Build Coastguard Worker     // base::Unretained(this) here is safe because net::Socket guarantees not to
315*6777b538SAndroid Build Coastguard Worker     // call any callbacks after Disconnect(), which we call from the destructor.
316*6777b538SAndroid Build Coastguard Worker     // The caller of ReadEverything() is required to keep |frames| valid.
317*6777b538SAndroid Build Coastguard Worker     int result = connection_->Read(
318*6777b538SAndroid Build Coastguard Worker         read_buffer_.get(), read_buffer_->size(),
319*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&WebSocketBasicStream::OnReadComplete,
320*6777b538SAndroid Build Coastguard Worker                        base::Unretained(this), base::Unretained(frames)));
321*6777b538SAndroid Build Coastguard Worker     if (result == ERR_IO_PENDING)
322*6777b538SAndroid Build Coastguard Worker       return result;
323*6777b538SAndroid Build Coastguard Worker     result = HandleReadResult(result, frames);
324*6777b538SAndroid Build Coastguard Worker     if (result != ERR_IO_PENDING)
325*6777b538SAndroid Build Coastguard Worker       return result;
326*6777b538SAndroid Build Coastguard Worker     DCHECK(frames->empty());
327*6777b538SAndroid Build Coastguard Worker   }
328*6777b538SAndroid Build Coastguard Worker }
329*6777b538SAndroid Build Coastguard Worker 
OnReadComplete(std::vector<std::unique_ptr<WebSocketFrame>> * frames,int result)330*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::OnReadComplete(
331*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames,
332*6777b538SAndroid Build Coastguard Worker     int result) {
333*6777b538SAndroid Build Coastguard Worker   result = HandleReadResult(result, frames);
334*6777b538SAndroid Build Coastguard Worker   if (result == ERR_IO_PENDING)
335*6777b538SAndroid Build Coastguard Worker     result = ReadEverything(frames);
336*6777b538SAndroid Build Coastguard Worker   if (result != ERR_IO_PENDING)
337*6777b538SAndroid Build Coastguard Worker     std::move(read_callback_).Run(result);
338*6777b538SAndroid Build Coastguard Worker }
339*6777b538SAndroid Build Coastguard Worker 
WriteEverything(const scoped_refptr<DrainableIOBuffer> & buffer)340*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::WriteEverything(
341*6777b538SAndroid Build Coastguard Worker     const scoped_refptr<DrainableIOBuffer>& buffer) {
342*6777b538SAndroid Build Coastguard Worker   while (buffer->BytesRemaining() > 0) {
343*6777b538SAndroid Build Coastguard Worker     // The use of base::Unretained() here is safe because on destruction we
344*6777b538SAndroid Build Coastguard Worker     // disconnect the socket, preventing any further callbacks.
345*6777b538SAndroid Build Coastguard Worker     int result = connection_->Write(
346*6777b538SAndroid Build Coastguard Worker         buffer.get(), buffer->BytesRemaining(),
347*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&WebSocketBasicStream::OnWriteComplete,
348*6777b538SAndroid Build Coastguard Worker                        base::Unretained(this), buffer),
349*6777b538SAndroid Build Coastguard Worker         kTrafficAnnotation);
350*6777b538SAndroid Build Coastguard Worker     if (result > 0) {
351*6777b538SAndroid Build Coastguard Worker       buffer->DidConsume(result);
352*6777b538SAndroid Build Coastguard Worker     } else {
353*6777b538SAndroid Build Coastguard Worker       return result;
354*6777b538SAndroid Build Coastguard Worker     }
355*6777b538SAndroid Build Coastguard Worker   }
356*6777b538SAndroid Build Coastguard Worker   return OK;
357*6777b538SAndroid Build Coastguard Worker }
358*6777b538SAndroid Build Coastguard Worker 
OnWriteComplete(const scoped_refptr<DrainableIOBuffer> & buffer,int result)359*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::OnWriteComplete(
360*6777b538SAndroid Build Coastguard Worker     const scoped_refptr<DrainableIOBuffer>& buffer,
361*6777b538SAndroid Build Coastguard Worker     int result) {
362*6777b538SAndroid Build Coastguard Worker   if (result < 0) {
363*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, result);
364*6777b538SAndroid Build Coastguard Worker     std::move(write_callback_).Run(result);
365*6777b538SAndroid Build Coastguard Worker     return;
366*6777b538SAndroid Build Coastguard Worker   }
367*6777b538SAndroid Build Coastguard Worker 
368*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(0, result);
369*6777b538SAndroid Build Coastguard Worker 
370*6777b538SAndroid Build Coastguard Worker   buffer->DidConsume(result);
371*6777b538SAndroid Build Coastguard Worker   result = WriteEverything(buffer);
372*6777b538SAndroid Build Coastguard Worker   if (result != ERR_IO_PENDING)
373*6777b538SAndroid Build Coastguard Worker     std::move(write_callback_).Run(result);
374*6777b538SAndroid Build Coastguard Worker }
375*6777b538SAndroid Build Coastguard Worker 
HandleReadResult(int result,std::vector<std::unique_ptr<WebSocketFrame>> * frames)376*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::HandleReadResult(
377*6777b538SAndroid Build Coastguard Worker     int result,
378*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames) {
379*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(ERR_IO_PENDING, result);
380*6777b538SAndroid Build Coastguard Worker   DCHECK(frames->empty());
381*6777b538SAndroid Build Coastguard Worker   if (result < 0)
382*6777b538SAndroid Build Coastguard Worker     return result;
383*6777b538SAndroid Build Coastguard Worker   if (result == 0)
384*6777b538SAndroid Build Coastguard Worker     return ERR_CONNECTION_CLOSED;
385*6777b538SAndroid Build Coastguard Worker 
386*6777b538SAndroid Build Coastguard Worker   buffer_size_manager_.OnReadComplete(base::TimeTicks::Now(), result);
387*6777b538SAndroid Build Coastguard Worker 
388*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<WebSocketFrameChunk>> frame_chunks;
389*6777b538SAndroid Build Coastguard Worker   if (!parser_.Decode(read_buffer_->data(), result, &frame_chunks))
390*6777b538SAndroid Build Coastguard Worker     return WebSocketErrorToNetError(parser_.websocket_error());
391*6777b538SAndroid Build Coastguard Worker   if (frame_chunks.empty())
392*6777b538SAndroid Build Coastguard Worker     return ERR_IO_PENDING;
393*6777b538SAndroid Build Coastguard Worker   return ConvertChunksToFrames(&frame_chunks, frames);
394*6777b538SAndroid Build Coastguard Worker }
395*6777b538SAndroid Build Coastguard Worker 
ConvertChunksToFrames(std::vector<std::unique_ptr<WebSocketFrameChunk>> * frame_chunks,std::vector<std::unique_ptr<WebSocketFrame>> * frames)396*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::ConvertChunksToFrames(
397*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrameChunk>>* frame_chunks,
398*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<WebSocketFrame>>* frames) {
399*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame_chunks->size(); ++i) {
400*6777b538SAndroid Build Coastguard Worker     auto& chunk = (*frame_chunks)[i];
401*6777b538SAndroid Build Coastguard Worker     DCHECK(chunk == frame_chunks->back() || chunk->final_chunk)
402*6777b538SAndroid Build Coastguard Worker         << "Only last chunk can have |final_chunk| set to be false.";
403*6777b538SAndroid Build Coastguard Worker     if (const auto& header = chunk->header) {
404*6777b538SAndroid Build Coastguard Worker       net_log_.AddEvent(net::NetLogEventType::WEBSOCKET_RECV_FRAME_HEADER,
405*6777b538SAndroid Build Coastguard Worker                         [&] { return NetLogFrameHeaderParam(header.get()); });
406*6777b538SAndroid Build Coastguard Worker     }
407*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<WebSocketFrame> frame;
408*6777b538SAndroid Build Coastguard Worker     int result = ConvertChunkToFrame(std::move(chunk), &frame);
409*6777b538SAndroid Build Coastguard Worker     if (result != OK)
410*6777b538SAndroid Build Coastguard Worker       return result;
411*6777b538SAndroid Build Coastguard Worker     if (frame)
412*6777b538SAndroid Build Coastguard Worker       frames->push_back(std::move(frame));
413*6777b538SAndroid Build Coastguard Worker   }
414*6777b538SAndroid Build Coastguard Worker   frame_chunks->clear();
415*6777b538SAndroid Build Coastguard Worker   if (frames->empty())
416*6777b538SAndroid Build Coastguard Worker     return ERR_IO_PENDING;
417*6777b538SAndroid Build Coastguard Worker   return OK;
418*6777b538SAndroid Build Coastguard Worker }
419*6777b538SAndroid Build Coastguard Worker 
ConvertChunkToFrame(std::unique_ptr<WebSocketFrameChunk> chunk,std::unique_ptr<WebSocketFrame> * frame)420*6777b538SAndroid Build Coastguard Worker int WebSocketBasicStream::ConvertChunkToFrame(
421*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<WebSocketFrameChunk> chunk,
422*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<WebSocketFrame>* frame) {
423*6777b538SAndroid Build Coastguard Worker   DCHECK(frame->get() == nullptr);
424*6777b538SAndroid Build Coastguard Worker   bool is_first_chunk = false;
425*6777b538SAndroid Build Coastguard Worker   if (chunk->header) {
426*6777b538SAndroid Build Coastguard Worker     DCHECK(current_frame_header_ == nullptr)
427*6777b538SAndroid Build Coastguard Worker         << "Received the header for a new frame without notification that "
428*6777b538SAndroid Build Coastguard Worker         << "the previous frame was complete (bug in WebSocketFrameParser?)";
429*6777b538SAndroid Build Coastguard Worker     is_first_chunk = true;
430*6777b538SAndroid Build Coastguard Worker     current_frame_header_.swap(chunk->header);
431*6777b538SAndroid Build Coastguard Worker   }
432*6777b538SAndroid Build Coastguard Worker   DCHECK(current_frame_header_) << "Unexpected header-less chunk received "
433*6777b538SAndroid Build Coastguard Worker                                 << "(final_chunk = " << chunk->final_chunk
434*6777b538SAndroid Build Coastguard Worker                                 << ", payload size = " << chunk->payload.size()
435*6777b538SAndroid Build Coastguard Worker                                 << ") (bug in WebSocketFrameParser?)";
436*6777b538SAndroid Build Coastguard Worker   const bool is_final_chunk = chunk->final_chunk;
437*6777b538SAndroid Build Coastguard Worker   const WebSocketFrameHeader::OpCode opcode = current_frame_header_->opcode;
438*6777b538SAndroid Build Coastguard Worker   if (WebSocketFrameHeader::IsKnownControlOpCode(opcode)) {
439*6777b538SAndroid Build Coastguard Worker     bool protocol_error = false;
440*6777b538SAndroid Build Coastguard Worker     if (!current_frame_header_->final) {
441*6777b538SAndroid Build Coastguard Worker       DVLOG(1) << "WebSocket protocol error. Control frame, opcode=" << opcode
442*6777b538SAndroid Build Coastguard Worker                << " received with FIN bit unset.";
443*6777b538SAndroid Build Coastguard Worker       protocol_error = true;
444*6777b538SAndroid Build Coastguard Worker     }
445*6777b538SAndroid Build Coastguard Worker     if (current_frame_header_->payload_length > kMaxControlFramePayload) {
446*6777b538SAndroid Build Coastguard Worker       DVLOG(1) << "WebSocket protocol error. Control frame, opcode=" << opcode
447*6777b538SAndroid Build Coastguard Worker                << ", payload_length=" << current_frame_header_->payload_length
448*6777b538SAndroid Build Coastguard Worker                << " exceeds maximum payload length for a control message.";
449*6777b538SAndroid Build Coastguard Worker       protocol_error = true;
450*6777b538SAndroid Build Coastguard Worker     }
451*6777b538SAndroid Build Coastguard Worker     if (protocol_error) {
452*6777b538SAndroid Build Coastguard Worker       current_frame_header_.reset();
453*6777b538SAndroid Build Coastguard Worker       return ERR_WS_PROTOCOL_ERROR;
454*6777b538SAndroid Build Coastguard Worker     }
455*6777b538SAndroid Build Coastguard Worker 
456*6777b538SAndroid Build Coastguard Worker     if (!is_final_chunk) {
457*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << "Encountered a split control frame, opcode " << opcode;
458*6777b538SAndroid Build Coastguard Worker       AddToIncompleteControlFrameBody(chunk->payload);
459*6777b538SAndroid Build Coastguard Worker       return OK;
460*6777b538SAndroid Build Coastguard Worker     }
461*6777b538SAndroid Build Coastguard Worker 
462*6777b538SAndroid Build Coastguard Worker     if (!incomplete_control_frame_body_.empty()) {
463*6777b538SAndroid Build Coastguard Worker       DVLOG(2) << "Rejoining a split control frame, opcode " << opcode;
464*6777b538SAndroid Build Coastguard Worker       AddToIncompleteControlFrameBody(chunk->payload);
465*6777b538SAndroid Build Coastguard Worker       DCHECK(is_final_chunk);
466*6777b538SAndroid Build Coastguard Worker       DCHECK(complete_control_frame_body_.empty());
467*6777b538SAndroid Build Coastguard Worker       complete_control_frame_body_ = std::move(incomplete_control_frame_body_);
468*6777b538SAndroid Build Coastguard Worker       *frame = CreateFrame(is_final_chunk, complete_control_frame_body_);
469*6777b538SAndroid Build Coastguard Worker       return OK;
470*6777b538SAndroid Build Coastguard Worker     }
471*6777b538SAndroid Build Coastguard Worker   }
472*6777b538SAndroid Build Coastguard Worker 
473*6777b538SAndroid Build Coastguard Worker   // Apply basic sanity checks to the |payload_length| field from the frame
474*6777b538SAndroid Build Coastguard Worker   // header. A check for exact equality can only be used when the whole frame
475*6777b538SAndroid Build Coastguard Worker   // arrives in one chunk.
476*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(current_frame_header_->payload_length,
477*6777b538SAndroid Build Coastguard Worker             base::checked_cast<uint64_t>(chunk->payload.size()));
478*6777b538SAndroid Build Coastguard Worker   DCHECK(!is_first_chunk || !is_final_chunk ||
479*6777b538SAndroid Build Coastguard Worker          current_frame_header_->payload_length ==
480*6777b538SAndroid Build Coastguard Worker              base::checked_cast<uint64_t>(chunk->payload.size()));
481*6777b538SAndroid Build Coastguard Worker 
482*6777b538SAndroid Build Coastguard Worker   // Convert the chunk to a complete frame.
483*6777b538SAndroid Build Coastguard Worker   *frame = CreateFrame(is_final_chunk, chunk->payload);
484*6777b538SAndroid Build Coastguard Worker   return OK;
485*6777b538SAndroid Build Coastguard Worker }
486*6777b538SAndroid Build Coastguard Worker 
CreateFrame(bool is_final_chunk,base::span<const char> data)487*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketFrame> WebSocketBasicStream::CreateFrame(
488*6777b538SAndroid Build Coastguard Worker     bool is_final_chunk,
489*6777b538SAndroid Build Coastguard Worker     base::span<const char> data) {
490*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<WebSocketFrame> result_frame;
491*6777b538SAndroid Build Coastguard Worker   const bool is_final_chunk_in_message =
492*6777b538SAndroid Build Coastguard Worker       is_final_chunk && current_frame_header_->final;
493*6777b538SAndroid Build Coastguard Worker   const WebSocketFrameHeader::OpCode opcode = current_frame_header_->opcode;
494*6777b538SAndroid Build Coastguard Worker   // Empty frames convey no useful information unless they are the first frame
495*6777b538SAndroid Build Coastguard Worker   // (containing the type and flags) or have the "final" bit set.
496*6777b538SAndroid Build Coastguard Worker   if (is_final_chunk_in_message || data.size() > 0 ||
497*6777b538SAndroid Build Coastguard Worker       current_frame_header_->opcode !=
498*6777b538SAndroid Build Coastguard Worker           WebSocketFrameHeader::kOpCodeContinuation) {
499*6777b538SAndroid Build Coastguard Worker     result_frame = std::make_unique<WebSocketFrame>(opcode);
500*6777b538SAndroid Build Coastguard Worker     result_frame->header.CopyFrom(*current_frame_header_);
501*6777b538SAndroid Build Coastguard Worker     result_frame->header.final = is_final_chunk_in_message;
502*6777b538SAndroid Build Coastguard Worker     result_frame->header.payload_length = data.size();
503*6777b538SAndroid Build Coastguard Worker     result_frame->payload = data.data();
504*6777b538SAndroid Build Coastguard Worker     // Ensure that opcodes Text and Binary are only used for the first frame in
505*6777b538SAndroid Build Coastguard Worker     // the message. Also clear the reserved bits.
506*6777b538SAndroid Build Coastguard Worker     // TODO(ricea): If a future extension requires the reserved bits to be
507*6777b538SAndroid Build Coastguard Worker     // retained on continuation frames, make this behaviour conditional on a
508*6777b538SAndroid Build Coastguard Worker     // flag set at construction time.
509*6777b538SAndroid Build Coastguard Worker     if (!is_final_chunk && WebSocketFrameHeader::IsKnownDataOpCode(opcode)) {
510*6777b538SAndroid Build Coastguard Worker       current_frame_header_->opcode = WebSocketFrameHeader::kOpCodeContinuation;
511*6777b538SAndroid Build Coastguard Worker       current_frame_header_->reserved1 = false;
512*6777b538SAndroid Build Coastguard Worker       current_frame_header_->reserved2 = false;
513*6777b538SAndroid Build Coastguard Worker       current_frame_header_->reserved3 = false;
514*6777b538SAndroid Build Coastguard Worker     }
515*6777b538SAndroid Build Coastguard Worker   }
516*6777b538SAndroid Build Coastguard Worker   // Make sure that a frame header is not applied to any chunks that do not
517*6777b538SAndroid Build Coastguard Worker   // belong to it.
518*6777b538SAndroid Build Coastguard Worker   if (is_final_chunk)
519*6777b538SAndroid Build Coastguard Worker     current_frame_header_.reset();
520*6777b538SAndroid Build Coastguard Worker   return result_frame;
521*6777b538SAndroid Build Coastguard Worker }
522*6777b538SAndroid Build Coastguard Worker 
AddToIncompleteControlFrameBody(base::span<const char> data)523*6777b538SAndroid Build Coastguard Worker void WebSocketBasicStream::AddToIncompleteControlFrameBody(
524*6777b538SAndroid Build Coastguard Worker     base::span<const char> data) {
525*6777b538SAndroid Build Coastguard Worker   if (data.empty()) {
526*6777b538SAndroid Build Coastguard Worker     return;
527*6777b538SAndroid Build Coastguard Worker   }
528*6777b538SAndroid Build Coastguard Worker   incomplete_control_frame_body_.insert(incomplete_control_frame_body_.end(),
529*6777b538SAndroid Build Coastguard Worker                                         data.begin(), data.end());
530*6777b538SAndroid Build Coastguard Worker   // This method checks for oversize control frames above, so as long as
531*6777b538SAndroid Build Coastguard Worker   // the frame parser is working correctly, this won't overflow. If a bug
532*6777b538SAndroid Build Coastguard Worker   // does cause it to overflow, it will CHECK() in
533*6777b538SAndroid Build Coastguard Worker   // AddToIncompleteControlFrameBody() without writing outside the buffer.
534*6777b538SAndroid Build Coastguard Worker   CHECK_LE(incomplete_control_frame_body_.size(), kMaxControlFramePayload)
535*6777b538SAndroid Build Coastguard Worker       << "Control frame body larger than frame header indicates; frame parser "
536*6777b538SAndroid Build Coastguard Worker          "bug?";
537*6777b538SAndroid Build Coastguard Worker }
538*6777b538SAndroid Build Coastguard Worker 
539*6777b538SAndroid Build Coastguard Worker }  // namespace net
540