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