xref: /aosp_15_r20/external/cronet/net/websockets/websocket_basic_stream_test.cc (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 // Tests for WebSocketBasicStream. Note that we do not attempt to verify that
6 // frame parsing itself functions correctly, as that is covered by the
7 // WebSocketFrameParser tests.
8 
9 #include "net/websockets/websocket_basic_stream.h"
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>  // for memcpy() and memset().
14 
15 #include <iterator>
16 #include <optional>
17 #include <string_view>
18 #include <utility>
19 
20 #include "base/containers/heap_array.h"
21 #include "base/containers/span.h"
22 #include "base/numerics/byte_conversions.h"
23 #include "base/strings/string_piece.h"
24 #include "base/time/time.h"
25 #include "net/base/io_buffer.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/network_anonymization_key.h"
28 #include "net/base/privacy_mode.h"
29 #include "net/base/request_priority.h"
30 #include "net/base/test_completion_callback.h"
31 #include "net/dns/public/secure_dns_policy.h"
32 #include "net/socket/client_socket_handle.h"
33 #include "net/socket/client_socket_pool.h"
34 #include "net/socket/connect_job.h"
35 #include "net/socket/socket_tag.h"
36 #include "net/socket/socket_test_util.h"
37 #include "net/test/gtest_util.h"
38 #include "net/test/test_with_task_environment.h"
39 #include "net/traffic_annotation/network_traffic_annotation.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "url/scheme_host_port.h"
43 #include "url/url_constants.h"
44 
45 using net::test::IsError;
46 using net::test::IsOk;
47 
48 namespace net {
49 namespace {
50 
51 #define WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(name, value) \
52   const char k##name[] = value;                                  \
53   const size_t k##name##Size = std::size(k##name) - 1
54 
55 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(SampleFrame, "\x81\x06Sample");
56 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
57     PartialLargeFrame,
58     "\x81\x7F\x00\x00\x00\x00\x7F\xFF\xFF\xFF"
59     "chromiunum ad pasco per loca insanis pullum manducat frumenti");
60 constexpr size_t kLargeFrameHeaderSize = 10;
61 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(MultipleFrames,
62                                             "\x81\x01X\x81\x01Y\x81\x01Z");
63 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFirstFrame, "\x01\x00");
64 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyMiddleFrame, "\x00\x00");
65 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalTextFrame, "\x81\x00");
66 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalContinuationFrame,
67                                             "\x80\x00");
68 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(ValidPong, "\x8A\x00");
69 // This frame encodes a payload length of 7 in two bytes, which is always
70 // invalid.
71 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(InvalidFrame,
72                                             "\x81\x7E\x00\x07Invalid");
73 // Control frames must have the FIN bit set. This one does not.
74 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(PingFrameWithoutFin, "\x09\x00");
75 // Control frames must have a payload of 125 bytes or less. This one has
76 // a payload of 126 bytes.
77 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
78     126BytePong,
79     "\x8a\x7e\x00\x7eZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
80     "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
81 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(CloseFrame,
82                                             "\x88\x09\x03\xe8occludo");
83 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(WriteFrame,
84                                             "\x81\x85\x00\x00\x00\x00Write");
85 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(MaskedEmptyPong,
86                                             "\x8A\x80\x00\x00\x00\x00");
87 constexpr WebSocketMaskingKey kNulMaskingKey = {{'\0', '\0', '\0', '\0'}};
88 constexpr WebSocketMaskingKey kNonNulMaskingKey = {
89     {'\x0d', '\x1b', '\x06', '\x17'}};
90 
91 // A masking key generator function which generates the identity mask,
92 // ie. "\0\0\0\0".
GenerateNulMaskingKey()93 WebSocketMaskingKey GenerateNulMaskingKey() {
94   return kNulMaskingKey;
95 }
96 
97 // A masking key generation function which generates a fixed masking key with no
98 // nul characters.
GenerateNonNulMaskingKey()99 WebSocketMaskingKey GenerateNonNulMaskingKey() {
100   return kNonNulMaskingKey;
101 }
102 
103 // A subclass of StaticSocketDataProvider modified to require that all data
104 // expected to be read or written actually is.
105 class StrictStaticSocketDataProvider : public StaticSocketDataProvider {
106  public:
StrictStaticSocketDataProvider(base::span<const MockRead> reads,base::span<const MockWrite> writes,bool strict_mode)107   StrictStaticSocketDataProvider(base::span<const MockRead> reads,
108                                  base::span<const MockWrite> writes,
109                                  bool strict_mode)
110       : StaticSocketDataProvider(reads, writes), strict_mode_(strict_mode) {}
111 
~StrictStaticSocketDataProvider()112   ~StrictStaticSocketDataProvider() override {
113     if (strict_mode_) {
114       EXPECT_EQ(read_count(), read_index());
115       EXPECT_EQ(write_count(), write_index());
116     }
117   }
118 
119  private:
120   const bool strict_mode_;
121 };
122 
123 // A fixture for tests which only perform normal socket operations.
124 class WebSocketBasicStreamSocketTest : public TestWithTaskEnvironment {
125  protected:
WebSocketBasicStreamSocketTest()126   WebSocketBasicStreamSocketTest()
127       : common_connect_job_params_(
128             &factory_,
129             /*host_resolver=*/nullptr,
130             /*http_auth_cache=*/nullptr,
131             /*http_auth_handler_factory=*/nullptr,
132             /*spdy_session_pool=*/nullptr,
133             /*quic_supported_versions=*/nullptr,
134             /*quic_session_pool=*/nullptr,
135             /*proxy_delegate=*/nullptr,
136             /*http_user_agent_settings=*/nullptr,
137             /*ssl_client_context=*/nullptr,
138             /*socket_performance_watcher_factory=*/nullptr,
139             /*network_quality_estimator=*/nullptr,
140             /*net_log=*/nullptr,
141             /*websocket_endpoint_lock_manager=*/nullptr,
142             /*http_server_properties*/ nullptr,
143             /*alpn_protos=*/nullptr,
144             /*application_settings=*/nullptr,
145             /*ignore_certificate_errors=*/nullptr,
146             /*early_data_enabled=*/nullptr),
147         pool_(1, 1, &common_connect_job_params_),
148         generator_(&GenerateNulMaskingKey) {}
149 
~WebSocketBasicStreamSocketTest()150   ~WebSocketBasicStreamSocketTest() override {
151     // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so
152     // should be destroyed first.
153     stream_.reset();
154   }
155 
MakeTransportSocket(base::span<const MockRead> reads,base::span<const MockWrite> writes)156   std::unique_ptr<ClientSocketHandle> MakeTransportSocket(
157       base::span<const MockRead> reads,
158       base::span<const MockWrite> writes) {
159     socket_data_ = std::make_unique<StrictStaticSocketDataProvider>(
160         reads, writes, expect_all_io_to_complete_);
161     socket_data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
162     factory_.AddSocketDataProvider(socket_data_.get());
163 
164     auto transport_socket = std::make_unique<ClientSocketHandle>();
165     scoped_refptr<ClientSocketPool::SocketParams> null_params;
166     ClientSocketPool::GroupId group_id(
167         url::SchemeHostPort(url::kHttpScheme, "a", 80),
168         PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
169         SecureDnsPolicy::kAllow, /*disable_cert_network_fetches=*/false);
170     transport_socket->Init(
171         group_id, null_params, std::nullopt /* proxy_annotation_tag */, MEDIUM,
172         SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
173         CompletionOnceCallback(), ClientSocketPool::ProxyAuthCallback(), &pool_,
174         NetLogWithSource());
175     return transport_socket;
176   }
177 
SetHttpReadBuffer(const char * data,size_t size)178   void SetHttpReadBuffer(const char* data, size_t size) {
179     http_read_buffer_ = base::MakeRefCounted<GrowableIOBuffer>();
180     http_read_buffer_->SetCapacity(size);
181     memcpy(http_read_buffer_->data(), data, size);
182     http_read_buffer_->set_offset(size);
183   }
184 
CreateStream(base::span<const MockRead> reads,base::span<const MockWrite> writes)185   void CreateStream(base::span<const MockRead> reads,
186                     base::span<const MockWrite> writes) {
187     stream_ = WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
188         MakeTransportSocket(reads, writes), http_read_buffer_, sub_protocol_,
189         extensions_, net_log_, generator_);
190   }
191 
192   std::unique_ptr<SocketDataProvider> socket_data_;
193   MockClientSocketFactory factory_;
194   const CommonConnectJobParams common_connect_job_params_;
195   MockTransportClientSocketPool pool_;
196   std::vector<std::unique_ptr<WebSocketFrame>> frames_;
197   TestCompletionCallback cb_;
198   scoped_refptr<GrowableIOBuffer> http_read_buffer_;
199   std::string sub_protocol_;
200   std::string extensions_;
201   NetLogWithSource net_log_;
202   WebSocketBasicStream::WebSocketMaskingKeyGeneratorFunction generator_;
203   bool expect_all_io_to_complete_ = true;
204   std::unique_ptr<WebSocketBasicStream> stream_;
205 };
206 
207 // A test fixture for the common case of tests that only perform a single read.
208 class WebSocketBasicStreamSocketSingleReadTest
209     : public WebSocketBasicStreamSocketTest {
210  protected:
CreateRead(const MockRead & read)211   void CreateRead(const MockRead& read) {
212     reads_[0] = read;
213     CreateStream(reads_, base::span<MockWrite>());
214   }
215 
216   MockRead reads_[1];
217 };
218 
219 // A test fixture for tests that perform chunked reads.
220 class WebSocketBasicStreamSocketChunkedReadTest
221     : public WebSocketBasicStreamSocketTest {
222  protected:
223   // Specify the behaviour if there aren't enough chunks to use all the data. If
224   // LAST_FRAME_BIG is specified, then the rest of the data will be
225   // put in the last chunk. If LAST_FRAME_NOT_BIG is specified, then the last
226   // frame will be no bigger than the rest of the frames (but it can be smaller,
227   // if not enough data remains).
228   enum LastFrameBehaviour { LAST_FRAME_BIG, LAST_FRAME_NOT_BIG };
229 
230   // Prepares a read from |data| of |data_size|, split into |number_of_chunks|,
231   // each of |chunk_size| (except that the last chunk may be larger or
232   // smaller). All reads must be either SYNCHRONOUS or ASYNC (not a mixture),
233   // and errors cannot be simulated. Once data is exhausted, further reads will
234   // return 0 (ie. connection closed).
CreateChunkedRead(IoMode mode,const char data[],size_t data_size,int chunk_size,size_t number_of_chunks,LastFrameBehaviour last_frame_behaviour)235   void CreateChunkedRead(IoMode mode,
236                          const char data[],
237                          size_t data_size,
238                          int chunk_size,
239                          size_t number_of_chunks,
240                          LastFrameBehaviour last_frame_behaviour) {
241     reads_.clear();
242     const char* start = data;
243     for (size_t i = 0; i < number_of_chunks; ++i) {
244       int len = chunk_size;
245       const bool is_last_chunk = (i == number_of_chunks - 1);
246       if ((last_frame_behaviour == LAST_FRAME_BIG && is_last_chunk) ||
247           static_cast<int>(data + data_size - start) < len) {
248         len = static_cast<int>(data + data_size - start);
249       }
250       reads_.emplace_back(mode, start, len);
251       start += len;
252     }
253     CreateStream(reads_, base::span<MockWrite>());
254   }
255 
256   std::vector<MockRead> reads_;
257 };
258 
259 // Test fixture for write tests.
260 class WebSocketBasicStreamSocketWriteTest
261     : public WebSocketBasicStreamSocketTest {
262  protected:
263   // All write tests use the same frame, so it is easiest to create it during
264   // test creation.
SetUp()265   void SetUp() override { PrepareWriteFrame(); }
266 
267   // Creates a WebSocketFrame with a wire format matching kWriteFrame and adds
268   // it to |frames_|.
PrepareWriteFrame()269   void PrepareWriteFrame() {
270     auto frame =
271         std::make_unique<WebSocketFrame>(WebSocketFrameHeader::kOpCodeText);
272     const size_t payload_size =
273         kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize +
274                            WebSocketFrameHeader::kMaskingKeyLength);
275     auto buffer = base::MakeRefCounted<IOBufferWithSize>(payload_size);
276     frame_buffers_.push_back(buffer);
277     memcpy(buffer->data(), kWriteFrame + kWriteFrameSize - payload_size,
278            payload_size);
279     frame->payload = buffer->data();
280     WebSocketFrameHeader& header = frame->header;
281     header.final = true;
282     header.masked = true;
283     header.payload_length = payload_size;
284     frames_.push_back(std::move(frame));
285   }
286 
287   // TODO(yoichio): Make this type std::vector<std::string>.
288   std::vector<scoped_refptr<IOBuffer>> frame_buffers_;
289 };
290 
291 // A test fixture for tests that perform read buffer size switching.
292 class WebSocketBasicStreamSwitchTest : public WebSocketBasicStreamSocketTest {
293  protected:
294   // This is used to specify the read start/end time.
MicrosecondsFromStart(int microseconds)295   base::TimeTicks MicrosecondsFromStart(int microseconds) {
296     static const base::TimeTicks kStartPoint =
297         base::TimeTicks::UnixEpoch() + base::Seconds(60);
298     return kStartPoint + base::Microseconds(microseconds);
299   }
300 
301   WebSocketBasicStream::BufferSizeManager buffer_size_manager_;
302 };
303 
TEST_F(WebSocketBasicStreamSocketTest,ConstructionWorks)304 TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) {
305   CreateStream(base::span<MockRead>(), base::span<MockWrite>());
306 }
307 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,SyncReadWorks)308 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncReadWorks) {
309   CreateRead(MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize));
310   int result = stream_->ReadFrames(&frames_, cb_.callback());
311   EXPECT_THAT(result, IsOk());
312   ASSERT_EQ(1U, frames_.size());
313   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
314   EXPECT_TRUE(frames_[0]->header.final);
315 }
316 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,AsyncReadWorks)317 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncReadWorks) {
318   CreateRead(MockRead(ASYNC, kSampleFrame, kSampleFrameSize));
319   int result = stream_->ReadFrames(&frames_, cb_.callback());
320   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
321   EXPECT_THAT(cb_.WaitForResult(), IsOk());
322   ASSERT_EQ(1U, frames_.size());
323   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
324   // Don't repeat all the tests from SyncReadWorks; just enough to be sure the
325   // frame was really read.
326 }
327 
328 // ReadFrames will not return a frame whose header has not been wholly received.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,HeaderFragmentedSync)329 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedSync) {
330   CreateChunkedRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize, 1, 2,
331                     LAST_FRAME_BIG);
332   int result = stream_->ReadFrames(&frames_, cb_.callback());
333   EXPECT_THAT(result, IsOk());
334   ASSERT_EQ(1U, frames_.size());
335   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
336 }
337 
338 // The same behaviour applies to asynchronous reads.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,HeaderFragmentedAsync)339 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedAsync) {
340   CreateChunkedRead(ASYNC, kSampleFrame, kSampleFrameSize, 1, 2,
341                     LAST_FRAME_BIG);
342   int result = stream_->ReadFrames(&frames_, cb_.callback());
343   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
344   EXPECT_THAT(cb_.WaitForResult(), IsOk());
345   ASSERT_EQ(1U, frames_.size());
346   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
347 }
348 
349 // If it receives an incomplete header in a synchronous call, then has to wait
350 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING.
TEST_F(WebSocketBasicStreamSocketTest,HeaderFragmentedSyncAsync)351 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) {
352   MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1),
353                       MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)};
354   CreateStream(reads, base::span<MockWrite>());
355   int result = stream_->ReadFrames(&frames_, cb_.callback());
356   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
357   EXPECT_THAT(cb_.WaitForResult(), IsOk());
358   ASSERT_EQ(1U, frames_.size());
359   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
360 }
361 
362 // An extended header should also return ERR_IO_PENDING if it is not completely
363 // received.
TEST_F(WebSocketBasicStreamSocketTest,FragmentedLargeHeader)364 TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) {
365   MockRead reads[] = {
366       MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1),
367       MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
368   CreateStream(reads, base::span<MockWrite>());
369   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
370               IsError(ERR_IO_PENDING));
371 }
372 
373 // A frame that does not arrive in a single read should be broken into separate
374 // frames.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,LargeFrameFirstChunk)375 TEST_F(WebSocketBasicStreamSocketSingleReadTest, LargeFrameFirstChunk) {
376   CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize));
377   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
378   ASSERT_EQ(1U, frames_.size());
379   EXPECT_FALSE(frames_[0]->header.final);
380   EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize,
381             static_cast<size_t>(frames_[0]->header.payload_length));
382 }
383 
384 // If only the header of a data frame arrives, we should receive a frame with a
385 // zero-size payload.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,HeaderOnlyChunk)386 TEST_F(WebSocketBasicStreamSocketSingleReadTest, HeaderOnlyChunk) {
387   CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize));
388 
389   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
390   ASSERT_EQ(1U, frames_.size());
391   EXPECT_EQ(nullptr, frames_[0]->payload);
392   EXPECT_EQ(0U, frames_[0]->header.payload_length);
393   EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
394 }
395 
396 // If the header and the body of a data frame arrive seperately, we should see
397 // them as separate frames.
TEST_F(WebSocketBasicStreamSocketTest,HeaderBodySeparated)398 TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparated) {
399   MockRead reads[] = {
400       MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize),
401       MockRead(ASYNC, kPartialLargeFrame + kLargeFrameHeaderSize,
402                kPartialLargeFrameSize - kLargeFrameHeaderSize)};
403   CreateStream(reads, base::span<MockWrite>());
404   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
405   ASSERT_EQ(1U, frames_.size());
406   EXPECT_EQ(nullptr, frames_[0]->payload);
407   EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
408   frames_.clear();
409   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
410               IsError(ERR_IO_PENDING));
411   EXPECT_THAT(cb_.WaitForResult(), IsOk());
412   ASSERT_EQ(1U, frames_.size());
413   EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize,
414             frames_[0]->header.payload_length);
415   EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
416             frames_[0]->header.opcode);
417 }
418 
419 // Every frame has a header with a correct payload_length field.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,LargeFrameTwoChunks)420 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, LargeFrameTwoChunks) {
421   constexpr size_t kChunkSize = 16;
422   CreateChunkedRead(ASYNC, kPartialLargeFrame, kPartialLargeFrameSize,
423                     kChunkSize, 2, LAST_FRAME_NOT_BIG);
424   TestCompletionCallback cb[2];
425 
426   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
427               IsError(ERR_IO_PENDING));
428   EXPECT_THAT(cb[0].WaitForResult(), IsOk());
429   ASSERT_EQ(1U, frames_.size());
430   EXPECT_EQ(kChunkSize - kLargeFrameHeaderSize,
431             frames_[0]->header.payload_length);
432 
433   frames_.clear();
434   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
435               IsError(ERR_IO_PENDING));
436   EXPECT_THAT(cb[1].WaitForResult(), IsOk());
437   ASSERT_EQ(1U, frames_.size());
438   EXPECT_EQ(kChunkSize, frames_[0]->header.payload_length);
439 }
440 
441 // Only the final frame of a fragmented message has |final| bit set.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,OnlyFinalChunkIsFinal)442 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OnlyFinalChunkIsFinal) {
443   static constexpr size_t kFirstChunkSize = 4;
444   CreateChunkedRead(ASYNC, kSampleFrame, kSampleFrameSize, kFirstChunkSize, 2,
445                     LAST_FRAME_BIG);
446   TestCompletionCallback cb[2];
447 
448   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
449               IsError(ERR_IO_PENDING));
450   EXPECT_THAT(cb[0].WaitForResult(), IsOk());
451   ASSERT_EQ(1U, frames_.size());
452   ASSERT_FALSE(frames_[0]->header.final);
453 
454   frames_.clear();
455   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
456               IsError(ERR_IO_PENDING));
457   EXPECT_THAT(cb[1].WaitForResult(), IsOk());
458   ASSERT_EQ(1U, frames_.size());
459   ASSERT_TRUE(frames_[0]->header.final);
460 }
461 
462 // All frames after the first have their opcode changed to Continuation.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,ContinuationOpCodeUsed)463 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ContinuationOpCodeUsed) {
464   constexpr size_t kFirstChunkSize = 3;
465   constexpr int kChunkCount = 3;
466   // The input data is one frame with opcode Text, which arrives in three
467   // separate chunks.
468   CreateChunkedRead(ASYNC, kSampleFrame, kSampleFrameSize, kFirstChunkSize,
469                     kChunkCount, LAST_FRAME_BIG);
470   TestCompletionCallback cb[kChunkCount];
471 
472   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
473               IsError(ERR_IO_PENDING));
474   EXPECT_THAT(cb[0].WaitForResult(), IsOk());
475   ASSERT_EQ(1U, frames_.size());
476   EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
477 
478   // This test uses a loop to verify that the opcode for every frames generated
479   // after the first is converted to Continuation.
480   for (int i = 1; i < kChunkCount; ++i) {
481     frames_.clear();
482     ASSERT_THAT(stream_->ReadFrames(&frames_, cb[i].callback()),
483                 IsError(ERR_IO_PENDING));
484     EXPECT_THAT(cb[i].WaitForResult(), IsOk());
485     ASSERT_EQ(1U, frames_.size());
486     EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
487               frames_[0]->header.opcode);
488   }
489 }
490 
491 // Multiple frames that arrive together should be parsed correctly.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,ThreeFramesTogether)492 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ThreeFramesTogether) {
493   CreateRead(MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize));
494 
495   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
496   ASSERT_EQ(3U, frames_.size());
497   EXPECT_TRUE(frames_[0]->header.final);
498   EXPECT_TRUE(frames_[1]->header.final);
499   EXPECT_TRUE(frames_[2]->header.final);
500 }
501 
502 // ERR_CONNECTION_CLOSED must be returned on close.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,SyncClose)503 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncClose) {
504   CreateRead(MockRead(SYNCHRONOUS, "", 0));
505 
506   EXPECT_EQ(ERR_CONNECTION_CLOSED,
507             stream_->ReadFrames(&frames_, cb_.callback()));
508 }
509 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,AsyncClose)510 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncClose) {
511   CreateRead(MockRead(ASYNC, "", 0));
512 
513   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
514               IsError(ERR_IO_PENDING));
515   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
516 }
517 
518 // The result should be the same if the socket returns
519 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established
520 // connection; a Read of size 0 is the expected behaviour. The key point of this
521 // test is to confirm that ReadFrames() behaviour is identical in both cases.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,SyncCloseWithErr)522 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncCloseWithErr) {
523   CreateRead(MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED));
524 
525   EXPECT_EQ(ERR_CONNECTION_CLOSED,
526             stream_->ReadFrames(&frames_, cb_.callback()));
527 }
528 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,AsyncCloseWithErr)529 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncCloseWithErr) {
530   CreateRead(MockRead(ASYNC, ERR_CONNECTION_CLOSED));
531 
532   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
533               IsError(ERR_IO_PENDING));
534   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
535 }
536 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,SyncErrorsPassedThrough)537 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncErrorsPassedThrough) {
538   // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that
539   // WebSocketBasicStream gives no special handling to.
540   CreateRead(MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES));
541 
542   EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES,
543             stream_->ReadFrames(&frames_, cb_.callback()));
544 }
545 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,AsyncErrorsPassedThrough)546 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncErrorsPassedThrough) {
547   CreateRead(MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES));
548 
549   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
550               IsError(ERR_IO_PENDING));
551   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_INSUFFICIENT_RESOURCES));
552 }
553 
554 // If we get a frame followed by a close, we should receive them separately.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,CloseAfterFrame)555 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, CloseAfterFrame) {
556   // The chunk size equals the data size, so the second chunk is 0 size, closing
557   // the connection.
558   CreateChunkedRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize,
559                     kSampleFrameSize, 2, LAST_FRAME_NOT_BIG);
560 
561   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
562   EXPECT_EQ(1U, frames_.size());
563   frames_.clear();
564   EXPECT_EQ(ERR_CONNECTION_CLOSED,
565             stream_->ReadFrames(&frames_, cb_.callback()));
566 }
567 
568 // Synchronous close after an async frame header is handled by a different code
569 // path.
TEST_F(WebSocketBasicStreamSocketTest,AsyncCloseAfterIncompleteHeader)570 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) {
571   MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U),
572                       MockRead(SYNCHRONOUS, "", 0)};
573   CreateStream(reads, base::span<MockWrite>());
574 
575   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
576               IsError(ERR_IO_PENDING));
577   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
578 }
579 
580 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a
581 // slightly different code path.
TEST_F(WebSocketBasicStreamSocketTest,AsyncErrCloseAfterIncompleteHeader)582 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) {
583   MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U),
584                       MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)};
585   CreateStream(reads, base::span<MockWrite>());
586 
587   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
588               IsError(ERR_IO_PENDING));
589   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
590 }
591 
592 // An empty first frame is not ignored.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,EmptyFirstFrame)593 TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFirstFrame) {
594   CreateRead(MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize));
595 
596   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
597   ASSERT_EQ(1U, frames_.size());
598   EXPECT_EQ(nullptr, frames_[0]->payload);
599   EXPECT_EQ(0U, frames_[0]->header.payload_length);
600 }
601 
602 // An empty frame in the middle of a message is ignored.
TEST_F(WebSocketBasicStreamSocketTest,EmptyMiddleFrame)603 TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrame) {
604   MockRead reads[] = {
605       MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
606       MockRead(SYNCHRONOUS, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
607       MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
608   CreateStream(reads, base::span<MockWrite>());
609 
610   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
611   EXPECT_EQ(1U, frames_.size());
612   frames_.clear();
613   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
614               IsError(ERR_IO_PENDING));
615 }
616 
617 // An empty frame in the middle of a message that arrives separately is still
618 // ignored.
TEST_F(WebSocketBasicStreamSocketTest,EmptyMiddleFrameAsync)619 TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrameAsync) {
620   MockRead reads[] = {
621       MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
622       MockRead(ASYNC, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
623       // We include a pong message to verify the middle frame was actually
624       // processed.
625       MockRead(ASYNC, kValidPong, kValidPongSize)};
626   CreateStream(reads, base::span<MockWrite>());
627 
628   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
629   EXPECT_EQ(1U, frames_.size());
630   frames_.clear();
631   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
632               IsError(ERR_IO_PENDING));
633   EXPECT_THAT(cb_.WaitForResult(), IsOk());
634   ASSERT_EQ(1U, frames_.size());
635   EXPECT_EQ(WebSocketFrameHeader::kOpCodePong, frames_[0]->header.opcode);
636 }
637 
638 // An empty final frame is not ignored.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,EmptyFinalFrame)639 TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFinalFrame) {
640   CreateRead(
641       MockRead(SYNCHRONOUS, kEmptyFinalTextFrame, kEmptyFinalTextFrameSize));
642 
643   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
644   ASSERT_EQ(1U, frames_.size());
645   EXPECT_EQ(nullptr, frames_[0]->payload);
646   EXPECT_EQ(0U, frames_[0]->header.payload_length);
647 }
648 
649 // An empty middle frame is ignored with a final frame present.
TEST_F(WebSocketBasicStreamSocketTest,ThreeFrameEmptyMessage)650 TEST_F(WebSocketBasicStreamSocketTest, ThreeFrameEmptyMessage) {
651   MockRead reads[] = {
652       MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
653       MockRead(SYNCHRONOUS, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
654       MockRead(SYNCHRONOUS, kEmptyFinalContinuationFrame,
655                kEmptyFinalContinuationFrameSize)};
656   CreateStream(reads, base::span<MockWrite>());
657 
658   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
659   ASSERT_EQ(1U, frames_.size());
660   EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
661   frames_.clear();
662   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
663   ASSERT_EQ(1U, frames_.size());
664   EXPECT_TRUE(frames_[0]->header.final);
665 }
666 
667 // If there was a frame read at the same time as the response headers (and the
668 // handshake succeeded), then we should parse it.
TEST_F(WebSocketBasicStreamSocketTest,HttpReadBufferIsUsed)669 TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) {
670   SetHttpReadBuffer(kSampleFrame, kSampleFrameSize);
671   CreateStream(base::span<MockRead>(), base::span<MockWrite>());
672 
673   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
674   ASSERT_EQ(1U, frames_.size());
675   ASSERT_TRUE(frames_[0]->payload);
676   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
677 }
678 
679 // Check that a frame whose header partially arrived at the end of the response
680 // headers works correctly.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,PartialFrameHeaderInHttpResponse)681 TEST_F(WebSocketBasicStreamSocketSingleReadTest,
682        PartialFrameHeaderInHttpResponse) {
683   SetHttpReadBuffer(kSampleFrame, 1);
684   CreateRead(MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1));
685 
686   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
687               IsError(ERR_IO_PENDING));
688   EXPECT_THAT(cb_.WaitForResult(), IsOk());
689   ASSERT_EQ(1U, frames_.size());
690   ASSERT_TRUE(frames_[0]->payload);
691   EXPECT_EQ(UINT64_C(6), frames_[0]->header.payload_length);
692   EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
693 }
694 
695 // Check that a control frame which partially arrives at the end of the response
696 // headers works correctly.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,PartialControlFrameInHttpResponse)697 TEST_F(WebSocketBasicStreamSocketSingleReadTest,
698        PartialControlFrameInHttpResponse) {
699   constexpr size_t kPartialFrameBytes = 3;
700   SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes);
701   CreateRead(MockRead(ASYNC, kCloseFrame + kPartialFrameBytes,
702                       kCloseFrameSize - kPartialFrameBytes));
703 
704   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
705               IsError(ERR_IO_PENDING));
706   EXPECT_THAT(cb_.WaitForResult(), IsOk());
707   ASSERT_EQ(1U, frames_.size());
708   EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
709   EXPECT_EQ(kCloseFrameSize - 2, frames_[0]->header.payload_length);
710   EXPECT_EQ(std::string(frames_[0]->payload, kCloseFrameSize - 2),
711             std::string(kCloseFrame + 2, kCloseFrameSize - 2));
712 }
713 
714 // Check that a control frame which partially arrives at the end of the response
715 // headers works correctly. Synchronous version (unlikely in practice).
TEST_F(WebSocketBasicStreamSocketSingleReadTest,PartialControlFrameInHttpResponseSync)716 TEST_F(WebSocketBasicStreamSocketSingleReadTest,
717        PartialControlFrameInHttpResponseSync) {
718   constexpr size_t kPartialFrameBytes = 3;
719   SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes);
720   CreateRead(MockRead(SYNCHRONOUS, kCloseFrame + kPartialFrameBytes,
721                       kCloseFrameSize - kPartialFrameBytes));
722 
723   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
724   ASSERT_EQ(1U, frames_.size());
725   EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
726 }
727 
728 // Check that an invalid frame results in an error.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,SyncInvalidFrame)729 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncInvalidFrame) {
730   CreateRead(MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize));
731 
732   EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
733             stream_->ReadFrames(&frames_, cb_.callback()));
734 }
735 
TEST_F(WebSocketBasicStreamSocketSingleReadTest,AsyncInvalidFrame)736 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncInvalidFrame) {
737   CreateRead(MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize));
738 
739   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
740               IsError(ERR_IO_PENDING));
741   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_WS_PROTOCOL_ERROR));
742 }
743 
744 // A control frame without a FIN flag is invalid and should not be passed
745 // through to higher layers. RFC6455 5.5 "All control frames ... MUST NOT be
746 // fragmented."
TEST_F(WebSocketBasicStreamSocketSingleReadTest,ControlFrameWithoutFin)747 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ControlFrameWithoutFin) {
748   CreateRead(
749       MockRead(SYNCHRONOUS, kPingFrameWithoutFin, kPingFrameWithoutFinSize));
750 
751   EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
752             stream_->ReadFrames(&frames_, cb_.callback()));
753   EXPECT_TRUE(frames_.empty());
754 }
755 
756 // A control frame over 125 characters is invalid. RFC6455 5.5 "All control
757 // frames MUST have a payload length of 125 bytes or less". Since we use a
758 // 125-byte buffer to assemble fragmented control frames, we need to detect this
759 // error before attempting to assemble the fragments.
TEST_F(WebSocketBasicStreamSocketSingleReadTest,OverlongControlFrame)760 TEST_F(WebSocketBasicStreamSocketSingleReadTest, OverlongControlFrame) {
761   CreateRead(MockRead(SYNCHRONOUS, k126BytePong, k126BytePongSize));
762 
763   EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
764             stream_->ReadFrames(&frames_, cb_.callback()));
765   EXPECT_TRUE(frames_.empty());
766 }
767 
768 // A control frame over 125 characters should still be rejected if it is split
769 // into multiple chunks.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,SplitOverlongControlFrame)770 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SplitOverlongControlFrame) {
771   constexpr size_t kFirstChunkSize = 16;
772   expect_all_io_to_complete_ = false;
773   CreateChunkedRead(SYNCHRONOUS, k126BytePong, k126BytePongSize,
774                     kFirstChunkSize, 2, LAST_FRAME_BIG);
775 
776   EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
777             stream_->ReadFrames(&frames_, cb_.callback()));
778   EXPECT_TRUE(frames_.empty());
779 }
780 
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,AsyncSplitOverlongControlFrame)781 TEST_F(WebSocketBasicStreamSocketChunkedReadTest,
782        AsyncSplitOverlongControlFrame) {
783   constexpr size_t kFirstChunkSize = 16;
784   expect_all_io_to_complete_ = false;
785   CreateChunkedRead(ASYNC, k126BytePong, k126BytePongSize, kFirstChunkSize, 2,
786                     LAST_FRAME_BIG);
787 
788   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
789               IsError(ERR_IO_PENDING));
790   EXPECT_THAT(cb_.WaitForResult(), IsError(ERR_WS_PROTOCOL_ERROR));
791   // The caller should not call ReadFrames() again after receiving an error
792   // other than ERR_IO_PENDING.
793   EXPECT_TRUE(frames_.empty());
794 }
795 
796 // In the synchronous case, ReadFrames assembles the whole control frame before
797 // returning.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,SyncControlFrameAssembly)798 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SyncControlFrameAssembly) {
799   constexpr size_t kChunkSize = 3;
800   CreateChunkedRead(SYNCHRONOUS, kCloseFrame, kCloseFrameSize, kChunkSize, 3,
801                     LAST_FRAME_BIG);
802 
803   EXPECT_THAT(stream_->ReadFrames(&frames_, cb_.callback()), IsOk());
804   ASSERT_EQ(1U, frames_.size());
805   EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
806 }
807 
808 // In the asynchronous case, the callback is not called until the control frame
809 // has been completely assembled.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,AsyncControlFrameAssembly)810 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, AsyncControlFrameAssembly) {
811   constexpr size_t kChunkSize = 3;
812   CreateChunkedRead(ASYNC, kCloseFrame, kCloseFrameSize, kChunkSize, 3,
813                     LAST_FRAME_BIG);
814 
815   ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
816               IsError(ERR_IO_PENDING));
817   EXPECT_THAT(cb_.WaitForResult(), IsOk());
818   ASSERT_EQ(1U, frames_.size());
819   EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
820 }
821 
822 // A frame with a 1MB payload that has to be read in chunks.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,OneMegFrame)823 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OneMegFrame) {
824   // This should be equal to the definition of kSmallReadBufferFrame in
825   // websocket_basic_stream.cc.
826   constexpr int kReadBufferSize = 1000;
827   constexpr uint64_t kPayloadSize = 1 << 20;
828   constexpr size_t kWireSize = kPayloadSize + kLargeFrameHeaderSize;
829   constexpr size_t kExpectedFrameCount =
830       (kWireSize + kReadBufferSize - 1) / kReadBufferSize;
831 
832   auto big_frame = base::HeapArray<uint8_t>::WithSize(kWireSize);
833   auto [extended_header, payload] =
834       big_frame.as_span().split_at(kLargeFrameHeaderSize);
835 
836   {
837     auto [header, extended_payload_length] = extended_header.split_at<2u>();
838     header.copy_from(base::as_byte_span({'\x81', '\x7F'}));
839     extended_payload_length.copy_from(base::U64ToBigEndian(kPayloadSize));
840   }
841 
842   std::ranges::fill(payload, 'A');
843 
844   CreateChunkedRead(ASYNC, reinterpret_cast<char*>(big_frame.data()),
845                     big_frame.size(), kReadBufferSize, kExpectedFrameCount,
846                     LAST_FRAME_BIG);
847 
848   for (size_t frame = 0; frame < kExpectedFrameCount; ++frame) {
849     frames_.clear();
850     ASSERT_THAT(stream_->ReadFrames(&frames_, cb_.callback()),
851                 IsError(ERR_IO_PENDING));
852     EXPECT_THAT(cb_.WaitForResult(), IsOk());
853     ASSERT_EQ(1U, frames_.size());
854     size_t expected_payload_size = kReadBufferSize;
855     if (frame == 0) {
856       expected_payload_size = kReadBufferSize - kLargeFrameHeaderSize;
857     } else if (frame == kExpectedFrameCount - 1) {
858       expected_payload_size =
859           kWireSize - kReadBufferSize * (kExpectedFrameCount - 1);
860     }
861     EXPECT_EQ(expected_payload_size, frames_[0]->header.payload_length);
862   }
863 }
864 
865 // A frame with reserved flag(s) set that arrives in chunks should only have the
866 // reserved flag(s) set on the first chunk when split.
TEST_F(WebSocketBasicStreamSocketChunkedReadTest,ReservedFlagCleared)867 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ReservedFlagCleared) {
868   static constexpr char kReservedFlagFrame[] = "\x41\x05Hello";
869   constexpr size_t kReservedFlagFrameSize = std::size(kReservedFlagFrame) - 1;
870   constexpr size_t kChunkSize = 5;
871 
872   CreateChunkedRead(ASYNC, kReservedFlagFrame, kReservedFlagFrameSize,
873                     kChunkSize, 2, LAST_FRAME_BIG);
874 
875   TestCompletionCallback cb[2];
876   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[0].callback()),
877               IsError(ERR_IO_PENDING));
878   EXPECT_THAT(cb[0].WaitForResult(), IsOk());
879   ASSERT_EQ(1U, frames_.size());
880   EXPECT_TRUE(frames_[0]->header.reserved1);
881 
882   frames_.clear();
883   ASSERT_THAT(stream_->ReadFrames(&frames_, cb[1].callback()),
884               IsError(ERR_IO_PENDING));
885   EXPECT_THAT(cb[1].WaitForResult(), IsOk());
886   ASSERT_EQ(1U, frames_.size());
887   EXPECT_FALSE(frames_[0]->header.reserved1);
888 }
889 
890 // Check that writing a frame all at once works.
TEST_F(WebSocketBasicStreamSocketWriteTest,WriteAtOnce)891 TEST_F(WebSocketBasicStreamSocketWriteTest, WriteAtOnce) {
892   MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)};
893   CreateStream(base::span<MockRead>(), writes);
894 
895   EXPECT_THAT(stream_->WriteFrames(&frames_, cb_.callback()), IsOk());
896 }
897 
898 // Check that completely async writing works.
TEST_F(WebSocketBasicStreamSocketWriteTest,AsyncWriteAtOnce)899 TEST_F(WebSocketBasicStreamSocketWriteTest, AsyncWriteAtOnce) {
900   MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)};
901   CreateStream(base::span<MockRead>(), writes);
902 
903   ASSERT_THAT(stream_->WriteFrames(&frames_, cb_.callback()),
904               IsError(ERR_IO_PENDING));
905   EXPECT_THAT(cb_.WaitForResult(), IsOk());
906 }
907 
908 // Check that writing a frame to an extremely full kernel buffer (so that it
909 // ends up being sent in bits) works. The WriteFrames() callback should not be
910 // called until all parts have been written.
TEST_F(WebSocketBasicStreamSocketWriteTest,WriteInBits)911 TEST_F(WebSocketBasicStreamSocketWriteTest, WriteInBits) {
912   MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4),
913                         MockWrite(ASYNC, kWriteFrame + 4, 4),
914                         MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)};
915   CreateStream(base::span<MockRead>(), writes);
916 
917   ASSERT_THAT(stream_->WriteFrames(&frames_, cb_.callback()),
918               IsError(ERR_IO_PENDING));
919   EXPECT_THAT(cb_.WaitForResult(), IsOk());
920 }
921 
922 // Check that writing a Pong frame with a nullptr body works.
TEST_F(WebSocketBasicStreamSocketWriteTest,WriteNullptrPong)923 TEST_F(WebSocketBasicStreamSocketWriteTest, WriteNullptrPong) {
924   MockWrite writes[] = {
925       MockWrite(SYNCHRONOUS, kMaskedEmptyPong, kMaskedEmptyPongSize)};
926   CreateStream(base::span<MockRead>(), writes);
927 
928   auto frame =
929       std::make_unique<WebSocketFrame>(WebSocketFrameHeader::kOpCodePong);
930   WebSocketFrameHeader& header = frame->header;
931   header.final = true;
932   header.masked = true;
933   header.payload_length = 0;
934   std::vector<std::unique_ptr<WebSocketFrame>> frames;
935   frames.push_back(std::move(frame));
936   EXPECT_THAT(stream_->WriteFrames(&frames, cb_.callback()), IsOk());
937 }
938 
939 // Check that writing with a non-nullptr mask works correctly.
TEST_F(WebSocketBasicStreamSocketTest,WriteNonNulMask)940 TEST_F(WebSocketBasicStreamSocketTest, WriteNonNulMask) {
941   std::string masked_frame = std::string("\x81\x88");
942   masked_frame += std::string(std::begin(kNonNulMaskingKey.key),
943                               std::end(kNonNulMaskingKey.key));
944   masked_frame += "jiggered";
945   MockWrite writes[] = {
946       MockWrite(SYNCHRONOUS, masked_frame.data(), masked_frame.size())};
947   generator_ = &GenerateNonNulMaskingKey;
948   CreateStream(base::span<MockRead>(), writes);
949 
950   auto frame =
951       std::make_unique<WebSocketFrame>(WebSocketFrameHeader::kOpCodeText);
952   const std::string unmasked_payload = "graphics";
953   const size_t payload_size = unmasked_payload.size();
954   auto buffer = base::MakeRefCounted<IOBufferWithSize>(payload_size);
955   memcpy(buffer->data(), unmasked_payload.data(), payload_size);
956   frame->payload = buffer->data();
957   WebSocketFrameHeader& header = frame->header;
958   header.final = true;
959   header.masked = true;
960   header.payload_length = payload_size;
961   frames_.push_back(std::move(frame));
962 
963   EXPECT_THAT(stream_->WriteFrames(&frames_, cb_.callback()), IsOk());
964 }
965 
TEST_F(WebSocketBasicStreamSocketTest,GetExtensionsWorks)966 TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) {
967   extensions_ = "inflate-uuencode";
968   CreateStream(base::span<MockRead>(), base::span<MockWrite>());
969 
970   EXPECT_EQ("inflate-uuencode", stream_->GetExtensions());
971 }
972 
TEST_F(WebSocketBasicStreamSocketTest,GetSubProtocolWorks)973 TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) {
974   sub_protocol_ = "cyberchat";
975   CreateStream(base::span<MockRead>(), base::span<MockWrite>());
976 
977   EXPECT_EQ("cyberchat", stream_->GetSubProtocol());
978 }
979 
980 // Check that the read buffer size initialization works correctly.
TEST_F(WebSocketBasicStreamSwitchTest,GetInitialReadBufferSize)981 TEST_F(WebSocketBasicStreamSwitchTest, GetInitialReadBufferSize) {
982   EXPECT_EQ(buffer_size_manager_.buffer_size(),
983             WebSocketBasicStream::BufferSize::kSmall);
984   buffer_size_manager_.OnRead(MicrosecondsFromStart(0));
985   EXPECT_EQ(buffer_size_manager_.buffer_size(),
986             WebSocketBasicStream::BufferSize::kSmall);
987 }
988 
989 // Check that the case where the start time and the end time are the same.
TEST_F(WebSocketBasicStreamSwitchTest,ZeroSecondRead)990 TEST_F(WebSocketBasicStreamSwitchTest, ZeroSecondRead) {
991   buffer_size_manager_.set_window_for_test(1);
992   buffer_size_manager_.OnRead(MicrosecondsFromStart(0));
993   buffer_size_manager_.OnReadComplete(MicrosecondsFromStart(0), 1000);
994   EXPECT_EQ(buffer_size_manager_.buffer_size(),
995             WebSocketBasicStream::BufferSize::kLarge);
996 }
997 
998 // Check that the read buffer size is switched for high throughput connection.
TEST_F(WebSocketBasicStreamSwitchTest,CheckSwitch)999 TEST_F(WebSocketBasicStreamSwitchTest, CheckSwitch) {
1000   buffer_size_manager_.set_window_for_test(4);
1001   // It tests the case where 4000 bytes data is read in 2000 ms. In this case,
1002   // the read buffer size should be switched to the large one.
1003   buffer_size_manager_.OnRead(MicrosecondsFromStart(0));
1004   buffer_size_manager_.OnReadComplete(MicrosecondsFromStart(200), 1000);
1005   buffer_size_manager_.OnRead(MicrosecondsFromStart(800));
1006   buffer_size_manager_.OnReadComplete(MicrosecondsFromStart(1000), 1000);
1007   buffer_size_manager_.OnRead(MicrosecondsFromStart(1300));
1008   buffer_size_manager_.OnReadComplete(MicrosecondsFromStart(1500), 1000);
1009   buffer_size_manager_.OnRead(MicrosecondsFromStart(1800));
1010   buffer_size_manager_.OnReadComplete(MicrosecondsFromStart(2000), 1000);
1011   EXPECT_EQ(buffer_size_manager_.buffer_size(),
1012             WebSocketBasicStream::BufferSize::kLarge);
1013 }
1014 
1015 }  // namespace
1016 }  // namespace net
1017