1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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.
9 #include "net/websockets/websocket_basic_stream.h"
11 #include <string.h> // for memcpy() and memset().
15 #include "base/basictypes.h"
16 #include "base/big_endian.h"
17 #include "base/port.h"
18 #include "net/base/capturing_net_log.h"
19 #include "net/base/test_completion_callback.h"
20 #include "net/socket/socket_test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
26 #define WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(name, value) \
27 const char k##name[] = value; \
28 const size_t k##name##Size = arraysize(k##name) - 1;
30 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(SampleFrame
, "\x81\x06Sample");
31 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
33 "\x81\x7F\x00\x00\x00\x00\x7F\xFF\xFF\xFF"
34 "chromiunum ad pasco per loca insanis pullum manducat frumenti");
35 const size_t kLargeFrameHeaderSize
= 10;
36 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(MultipleFrames
,
37 "\x81\x01X\x81\x01Y\x81\x01Z");
38 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFirstFrame
, "\x01\x00");
39 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyMiddleFrame
, "\x00\x00");
40 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalTextFrame
, "\x81\x00");
41 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalContinuationFrame
,
43 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(ValidPong
, "\x8A\x00");
44 // This frame encodes a payload length of 7 in two bytes, which is always
46 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(InvalidFrame
,
47 "\x81\x7E\x00\x07Invalid");
48 // Control frames must have the FIN bit set. This one does not.
49 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(PingFrameWithoutFin
, "\x09\x00");
50 // Control frames must have a payload of 125 bytes or less. This one has
51 // a payload of 126 bytes.
52 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
54 "\x8a\x7e\x00\x7eZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
55 "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
56 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(CloseFrame
,
57 "\x88\x09\x03\xe8occludo");
58 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(WriteFrame
,
59 "\x81\x85\x00\x00\x00\x00Write");
60 WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(MaskedEmptyPong
,
61 "\x8A\x80\x00\x00\x00\x00");
62 const WebSocketMaskingKey kNulMaskingKey
= {{'\0', '\0', '\0', '\0'}};
63 const WebSocketMaskingKey kNonNulMaskingKey
= {
64 {'\x0d', '\x1b', '\x06', '\x17'}};
66 // A masking key generator function which generates the identity mask,
68 WebSocketMaskingKey
GenerateNulMaskingKey() { return kNulMaskingKey
; }
70 // A masking key generation function which generates a fixed masking key with no
72 WebSocketMaskingKey
GenerateNonNulMaskingKey() { return kNonNulMaskingKey
; }
74 // Base class for WebSocketBasicStream test fixtures.
75 class WebSocketBasicStreamTest
: public ::testing::Test
{
77 scoped_ptr
<WebSocketBasicStream
> stream_
;
78 CapturingNetLog net_log_
;
81 // A subclass of StaticSocketDataProvider modified to require that all data
82 // expected to be read or written actually is.
83 class StrictStaticSocketDataProvider
: public StaticSocketDataProvider
{
85 StrictStaticSocketDataProvider(MockRead
* reads
,
90 : StaticSocketDataProvider(reads
, reads_count
, writes
, writes_count
),
91 strict_mode_(strict_mode
) {}
93 ~StrictStaticSocketDataProvider() override
{
95 EXPECT_EQ(read_count(), read_index());
96 EXPECT_EQ(write_count(), write_index());
101 const bool strict_mode_
;
104 // A fixture for tests which only perform normal socket operations.
105 class WebSocketBasicStreamSocketTest
: public WebSocketBasicStreamTest
{
107 WebSocketBasicStreamSocketTest()
109 pool_(1, 1, &histograms_
, &factory_
),
110 generator_(&GenerateNulMaskingKey
),
111 expect_all_io_to_complete_(true) {}
113 virtual ~WebSocketBasicStreamSocketTest() {
114 // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so
115 // should be destroyed first.
119 scoped_ptr
<ClientSocketHandle
> MakeTransportSocket(MockRead reads
[],
122 size_t writes_count
) {
123 socket_data_
.reset(new StrictStaticSocketDataProvider(
124 reads
, reads_count
, writes
, writes_count
, expect_all_io_to_complete_
));
125 socket_data_
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
126 factory_
.AddSocketDataProvider(socket_data_
.get());
128 scoped_ptr
<ClientSocketHandle
> transport_socket(new ClientSocketHandle
);
129 scoped_refptr
<MockTransportSocketParams
> params
;
130 transport_socket
->Init("a",
133 CompletionCallback(),
135 bound_net_log_
.bound());
136 return transport_socket
.Pass();
139 void SetHttpReadBuffer(const char* data
, size_t size
) {
140 http_read_buffer_
= new GrowableIOBuffer
;
141 http_read_buffer_
->SetCapacity(size
);
142 memcpy(http_read_buffer_
->data(), data
, size
);
143 http_read_buffer_
->set_offset(size
);
146 void CreateStream(MockRead reads
[],
149 size_t writes_count
) {
150 stream_
= WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
151 MakeTransportSocket(reads
, reads_count
, writes
, writes_count
),
159 void CreateReadOnly(MockRead (&reads
)[N
]) {
160 CreateStream(reads
, N
, NULL
, 0);
163 void CreateNullStream() { CreateStream(NULL
, 0, NULL
, 0); }
165 scoped_ptr
<SocketDataProvider
> socket_data_
;
166 MockClientSocketFactory factory_
;
167 ClientSocketPoolHistograms histograms_
;
168 MockTransportClientSocketPool pool_
;
169 CapturingBoundNetLog(bound_net_log_
);
170 ScopedVector
<WebSocketFrame
> frames_
;
171 TestCompletionCallback cb_
;
172 scoped_refptr
<GrowableIOBuffer
> http_read_buffer_
;
173 std::string sub_protocol_
;
174 std::string extensions_
;
175 WebSocketBasicStream::WebSocketMaskingKeyGeneratorFunction generator_
;
176 bool expect_all_io_to_complete_
;
179 // A test fixture for the common case of tests that only perform a single read.
180 class WebSocketBasicStreamSocketSingleReadTest
181 : public WebSocketBasicStreamSocketTest
{
183 void CreateRead(const MockRead
& read
) {
185 CreateStream(reads_
, 1U, NULL
, 0);
191 // A test fixture for tests that perform chunked reads.
192 class WebSocketBasicStreamSocketChunkedReadTest
193 : public WebSocketBasicStreamSocketTest
{
195 // Specify the behaviour if there aren't enough chunks to use all the data. If
196 // LAST_FRAME_BIG is specified, then the rest of the data will be
197 // put in the last chunk. If LAST_FRAME_NOT_BIG is specified, then the last
198 // frame will be no bigger than the rest of the frames (but it can be smaller,
199 // if not enough data remains).
200 enum LastFrameBehaviour
{
205 // Prepares a read from |data| of |data_size|, split into |number_of_chunks|,
206 // each of |chunk_size| (except that the last chunk may be larger or
207 // smaller). All reads must be either SYNCHRONOUS or ASYNC (not a mixture),
208 // and errors cannot be simulated. Once data is exhausted, further reads will
209 // return 0 (ie. connection closed).
210 void CreateChunkedRead(IoMode mode
,
214 int number_of_chunks
,
215 LastFrameBehaviour last_frame_behaviour
) {
216 reads_
.reset(new MockRead
[number_of_chunks
]);
217 const char* start
= data
;
218 for (int i
= 0; i
< number_of_chunks
; ++i
) {
219 int len
= chunk_size
;
220 const bool is_last_chunk
= (i
== number_of_chunks
- 1);
221 if ((last_frame_behaviour
== LAST_FRAME_BIG
&& is_last_chunk
) ||
222 static_cast<int>(data
+ data_size
- start
) < len
) {
223 len
= static_cast<int>(data
+ data_size
- start
);
225 reads_
[i
] = MockRead(mode
, start
, len
);
228 CreateStream(reads_
.get(), number_of_chunks
, NULL
, 0);
231 scoped_ptr
<MockRead
[]> reads_
;
234 // Test fixture for write tests.
235 class WebSocketBasicStreamSocketWriteTest
236 : public WebSocketBasicStreamSocketTest
{
238 // All write tests use the same frame, so it is easiest to create it during
240 virtual void SetUp() override
{ PrepareWriteFrame(); }
242 // Creates a WebSocketFrame with a wire format matching kWriteFrame and adds
244 void PrepareWriteFrame() {
245 scoped_ptr
<WebSocketFrame
> frame(
246 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText
));
247 const size_t payload_size
=
248 kWriteFrameSize
- (WebSocketFrameHeader::kBaseHeaderSize
+
249 WebSocketFrameHeader::kMaskingKeyLength
);
250 frame
->data
= new IOBuffer(payload_size
);
251 memcpy(frame
->data
->data(),
252 kWriteFrame
+ kWriteFrameSize
- payload_size
,
254 WebSocketFrameHeader
& header
= frame
->header
;
256 header
.masked
= true;
257 header
.payload_length
= payload_size
;
258 frames_
.push_back(frame
.release());
261 // Creates a stream that expects the listed writes.
263 void CreateWriteOnly(MockWrite (&writes
)[N
]) {
264 CreateStream(NULL
, 0, writes
, N
);
268 TEST_F(WebSocketBasicStreamSocketTest
, ConstructionWorks
) {
272 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncReadWorks
) {
273 CreateRead(MockRead(SYNCHRONOUS
, kSampleFrame
, kSampleFrameSize
));
274 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
275 EXPECT_EQ(OK
, result
);
276 ASSERT_EQ(1U, frames_
.size());
277 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
278 EXPECT_TRUE(frames_
[0]->header
.final
);
281 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncReadWorks
) {
282 CreateRead(MockRead(ASYNC
, kSampleFrame
, kSampleFrameSize
));
283 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
284 ASSERT_EQ(ERR_IO_PENDING
, result
);
285 EXPECT_EQ(OK
, cb_
.WaitForResult());
286 ASSERT_EQ(1U, frames_
.size());
287 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
288 // Don't repeat all the tests from SyncReadWorks; just enough to be sure the
289 // frame was really read.
292 // ReadFrames will not return a frame whose header has not been wholly received.
293 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, HeaderFragmentedSync
) {
295 SYNCHRONOUS
, kSampleFrame
, kSampleFrameSize
, 1, 2, LAST_FRAME_BIG
);
296 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
297 EXPECT_EQ(OK
, result
);
298 ASSERT_EQ(1U, frames_
.size());
299 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
302 // The same behaviour applies to asynchronous reads.
303 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, HeaderFragmentedAsync
) {
305 ASYNC
, kSampleFrame
, kSampleFrameSize
, 1, 2, LAST_FRAME_BIG
);
306 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
307 ASSERT_EQ(ERR_IO_PENDING
, result
);
308 EXPECT_EQ(OK
, cb_
.WaitForResult());
309 ASSERT_EQ(1U, frames_
.size());
310 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
313 // If it receives an incomplete header in a synchronous call, then has to wait
314 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING.
315 TEST_F(WebSocketBasicStreamSocketTest
, HeaderFragmentedSyncAsync
) {
316 MockRead reads
[] = {MockRead(SYNCHRONOUS
, kSampleFrame
, 1),
317 MockRead(ASYNC
, kSampleFrame
+ 1, kSampleFrameSize
- 1)};
318 CreateReadOnly(reads
);
319 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
320 ASSERT_EQ(ERR_IO_PENDING
, result
);
321 EXPECT_EQ(OK
, cb_
.WaitForResult());
322 ASSERT_EQ(1U, frames_
.size());
323 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
326 // An extended header should also return ERR_IO_PENDING if it is not completely
328 TEST_F(WebSocketBasicStreamSocketTest
, FragmentedLargeHeader
) {
330 MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
- 1),
331 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
)};
332 CreateReadOnly(reads
);
333 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
336 // A frame that does not arrive in a single read should be broken into separate
338 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, LargeFrameFirstChunk
) {
339 CreateRead(MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kPartialLargeFrameSize
));
340 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
341 ASSERT_EQ(1U, frames_
.size());
342 EXPECT_FALSE(frames_
[0]->header
.final
);
343 EXPECT_EQ(kPartialLargeFrameSize
- kLargeFrameHeaderSize
,
344 static_cast<size_t>(frames_
[0]->header
.payload_length
));
347 // If only the header of a data frame arrives, we should receive a frame with a
348 // zero-size payload.
349 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, HeaderOnlyChunk
) {
350 CreateRead(MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
));
352 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
353 ASSERT_EQ(1U, frames_
.size());
354 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
355 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
356 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
359 // If the header and the body of a data frame arrive seperately, we should see
360 // them as separate frames.
361 TEST_F(WebSocketBasicStreamSocketTest
, HeaderBodySeparated
) {
363 MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
),
365 kPartialLargeFrame
+ kLargeFrameHeaderSize
,
366 kPartialLargeFrameSize
- kLargeFrameHeaderSize
)};
367 CreateReadOnly(reads
);
368 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
369 ASSERT_EQ(1U, frames_
.size());
370 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
371 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
373 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
374 EXPECT_EQ(OK
, cb_
.WaitForResult());
375 ASSERT_EQ(1U, frames_
.size());
376 EXPECT_EQ(kPartialLargeFrameSize
- kLargeFrameHeaderSize
,
377 frames_
[0]->header
.payload_length
);
378 EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation
,
379 frames_
[0]->header
.opcode
);
382 // Every frame has a header with a correct payload_length field.
383 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, LargeFrameTwoChunks
) {
384 const size_t kChunkSize
= 16;
385 CreateChunkedRead(ASYNC
,
387 kPartialLargeFrameSize
,
391 TestCompletionCallback cb
[2];
393 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
394 EXPECT_EQ(OK
, cb
[0].WaitForResult());
395 ASSERT_EQ(1U, frames_
.size());
396 EXPECT_EQ(kChunkSize
- kLargeFrameHeaderSize
,
397 frames_
[0]->header
.payload_length
);
400 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
401 EXPECT_EQ(OK
, cb
[1].WaitForResult());
402 ASSERT_EQ(1U, frames_
.size());
403 EXPECT_EQ(kChunkSize
, frames_
[0]->header
.payload_length
);
406 // Only the final frame of a fragmented message has |final| bit set.
407 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, OnlyFinalChunkIsFinal
) {
408 static const size_t kFirstChunkSize
= 4;
409 CreateChunkedRead(ASYNC
,
415 TestCompletionCallback cb
[2];
417 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
418 EXPECT_EQ(OK
, cb
[0].WaitForResult());
419 ASSERT_EQ(1U, frames_
.size());
420 ASSERT_FALSE(frames_
[0]->header
.final
);
423 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
424 EXPECT_EQ(OK
, cb
[1].WaitForResult());
425 ASSERT_EQ(1U, frames_
.size());
426 ASSERT_TRUE(frames_
[0]->header
.final
);
429 // All frames after the first have their opcode changed to Continuation.
430 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, ContinuationOpCodeUsed
) {
431 const size_t kFirstChunkSize
= 3;
432 const int kChunkCount
= 3;
433 // The input data is one frame with opcode Text, which arrives in three
435 CreateChunkedRead(ASYNC
,
441 TestCompletionCallback cb
[kChunkCount
];
443 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
444 EXPECT_EQ(OK
, cb
[0].WaitForResult());
445 ASSERT_EQ(1U, frames_
.size());
446 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
448 // This test uses a loop to verify that the opcode for every frames generated
449 // after the first is converted to Continuation.
450 for (int i
= 1; i
< kChunkCount
; ++i
) {
452 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[i
].callback()));
453 EXPECT_EQ(OK
, cb
[i
].WaitForResult());
454 ASSERT_EQ(1U, frames_
.size());
455 EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation
,
456 frames_
[0]->header
.opcode
);
460 // Multiple frames that arrive together should be parsed correctly.
461 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, ThreeFramesTogether
) {
462 CreateRead(MockRead(SYNCHRONOUS
, kMultipleFrames
, kMultipleFramesSize
));
464 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
465 ASSERT_EQ(3U, frames_
.size());
466 EXPECT_TRUE(frames_
[0]->header
.final
);
467 EXPECT_TRUE(frames_
[1]->header
.final
);
468 EXPECT_TRUE(frames_
[2]->header
.final
);
471 // ERR_CONNECTION_CLOSED must be returned on close.
472 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncClose
) {
473 CreateRead(MockRead(SYNCHRONOUS
, "", 0));
475 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
476 stream_
->ReadFrames(&frames_
, cb_
.callback()));
479 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncClose
) {
480 CreateRead(MockRead(ASYNC
, "", 0));
482 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
483 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
486 // The result should be the same if the socket returns
487 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established
488 // connection; a Read of size 0 is the expected behaviour. The key point of this
489 // test is to confirm that ReadFrames() behaviour is identical in both cases.
490 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncCloseWithErr
) {
491 CreateRead(MockRead(SYNCHRONOUS
, ERR_CONNECTION_CLOSED
));
493 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
494 stream_
->ReadFrames(&frames_
, cb_
.callback()));
497 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncCloseWithErr
) {
498 CreateRead(MockRead(ASYNC
, ERR_CONNECTION_CLOSED
));
500 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
501 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
504 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncErrorsPassedThrough
) {
505 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that
506 // WebSocketBasicStream gives no special handling to.
507 CreateRead(MockRead(SYNCHRONOUS
, ERR_INSUFFICIENT_RESOURCES
));
509 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES
,
510 stream_
->ReadFrames(&frames_
, cb_
.callback()));
513 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncErrorsPassedThrough
) {
514 CreateRead(MockRead(ASYNC
, ERR_INSUFFICIENT_RESOURCES
));
516 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
517 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES
, cb_
.WaitForResult());
520 // If we get a frame followed by a close, we should receive them separately.
521 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, CloseAfterFrame
) {
522 // The chunk size equals the data size, so the second chunk is 0 size, closing
524 CreateChunkedRead(SYNCHRONOUS
,
531 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
532 EXPECT_EQ(1U, frames_
.size());
534 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
535 stream_
->ReadFrames(&frames_
, cb_
.callback()));
538 // Synchronous close after an async frame header is handled by a different code
540 TEST_F(WebSocketBasicStreamSocketTest
, AsyncCloseAfterIncompleteHeader
) {
541 MockRead reads
[] = {MockRead(ASYNC
, kSampleFrame
, 1U),
542 MockRead(SYNCHRONOUS
, "", 0)};
543 CreateReadOnly(reads
);
545 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
546 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
549 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a
550 // slightly different code path.
551 TEST_F(WebSocketBasicStreamSocketTest
, AsyncErrCloseAfterIncompleteHeader
) {
552 MockRead reads
[] = {MockRead(ASYNC
, kSampleFrame
, 1U),
553 MockRead(SYNCHRONOUS
, ERR_CONNECTION_CLOSED
)};
554 CreateReadOnly(reads
);
556 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
557 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
560 // An empty first frame is not ignored.
561 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, EmptyFirstFrame
) {
562 CreateRead(MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
));
564 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
565 ASSERT_EQ(1U, frames_
.size());
566 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
567 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
570 // An empty frame in the middle of a message is ignored.
571 TEST_F(WebSocketBasicStreamSocketTest
, EmptyMiddleFrame
) {
573 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
574 MockRead(SYNCHRONOUS
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
575 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
)};
576 CreateReadOnly(reads
);
578 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
579 EXPECT_EQ(1U, frames_
.size());
581 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
584 // An empty frame in the middle of a message that arrives separately is still
586 TEST_F(WebSocketBasicStreamSocketTest
, EmptyMiddleFrameAsync
) {
588 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
589 MockRead(ASYNC
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
590 // We include a pong message to verify the middle frame was actually
592 MockRead(ASYNC
, kValidPong
, kValidPongSize
)};
593 CreateReadOnly(reads
);
595 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
596 EXPECT_EQ(1U, frames_
.size());
598 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
599 EXPECT_EQ(OK
, cb_
.WaitForResult());
600 ASSERT_EQ(1U, frames_
.size());
601 EXPECT_EQ(WebSocketFrameHeader::kOpCodePong
, frames_
[0]->header
.opcode
);
604 // An empty final frame is not ignored.
605 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, EmptyFinalFrame
) {
607 MockRead(SYNCHRONOUS
, kEmptyFinalTextFrame
, kEmptyFinalTextFrameSize
));
609 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
610 ASSERT_EQ(1U, frames_
.size());
611 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
612 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
615 // An empty middle frame is ignored with a final frame present.
616 TEST_F(WebSocketBasicStreamSocketTest
, ThreeFrameEmptyMessage
) {
618 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
619 MockRead(SYNCHRONOUS
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
620 MockRead(SYNCHRONOUS
,
621 kEmptyFinalContinuationFrame
,
622 kEmptyFinalContinuationFrameSize
)};
623 CreateReadOnly(reads
);
625 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
626 ASSERT_EQ(1U, frames_
.size());
627 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
629 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
630 ASSERT_EQ(1U, frames_
.size());
631 EXPECT_TRUE(frames_
[0]->header
.final
);
634 // If there was a frame read at the same time as the response headers (and the
635 // handshake succeeded), then we should parse it.
636 TEST_F(WebSocketBasicStreamSocketTest
, HttpReadBufferIsUsed
) {
637 SetHttpReadBuffer(kSampleFrame
, kSampleFrameSize
);
640 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
641 ASSERT_EQ(1U, frames_
.size());
642 ASSERT_TRUE(frames_
[0]->data
.get());
643 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
646 // Check that a frame whose header partially arrived at the end of the response
647 // headers works correctly.
648 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
649 PartialFrameHeaderInHttpResponse
) {
650 SetHttpReadBuffer(kSampleFrame
, 1);
651 CreateRead(MockRead(ASYNC
, kSampleFrame
+ 1, kSampleFrameSize
- 1));
653 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
654 EXPECT_EQ(OK
, cb_
.WaitForResult());
655 ASSERT_EQ(1U, frames_
.size());
656 ASSERT_TRUE(frames_
[0]->data
.get());
657 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
658 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
661 // Check that a control frame which partially arrives at the end of the response
662 // headers works correctly.
663 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
664 PartialControlFrameInHttpResponse
) {
665 const size_t kPartialFrameBytes
= 3;
666 SetHttpReadBuffer(kCloseFrame
, kPartialFrameBytes
);
667 CreateRead(MockRead(ASYNC
,
668 kCloseFrame
+ kPartialFrameBytes
,
669 kCloseFrameSize
- kPartialFrameBytes
));
671 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
672 EXPECT_EQ(OK
, cb_
.WaitForResult());
673 ASSERT_EQ(1U, frames_
.size());
674 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
675 EXPECT_EQ(kCloseFrameSize
- 2, frames_
[0]->header
.payload_length
);
678 memcmp(frames_
[0]->data
->data(), kCloseFrame
+ 2, kCloseFrameSize
- 2));
681 // Check that a control frame which partially arrives at the end of the response
682 // headers works correctly. Synchronous version (unlikely in practice).
683 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
684 PartialControlFrameInHttpResponseSync
) {
685 const size_t kPartialFrameBytes
= 3;
686 SetHttpReadBuffer(kCloseFrame
, kPartialFrameBytes
);
687 CreateRead(MockRead(SYNCHRONOUS
,
688 kCloseFrame
+ kPartialFrameBytes
,
689 kCloseFrameSize
- kPartialFrameBytes
));
691 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
692 ASSERT_EQ(1U, frames_
.size());
693 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
696 // Check that an invalid frame results in an error.
697 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncInvalidFrame
) {
698 CreateRead(MockRead(SYNCHRONOUS
, kInvalidFrame
, kInvalidFrameSize
));
700 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
701 stream_
->ReadFrames(&frames_
, cb_
.callback()));
704 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncInvalidFrame
) {
705 CreateRead(MockRead(ASYNC
, kInvalidFrame
, kInvalidFrameSize
));
707 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
708 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
, cb_
.WaitForResult());
711 // A control frame without a FIN flag is invalid and should not be passed
712 // through to higher layers. RFC6455 5.5 "All control frames ... MUST NOT be
714 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, ControlFrameWithoutFin
) {
716 MockRead(SYNCHRONOUS
, kPingFrameWithoutFin
, kPingFrameWithoutFinSize
));
718 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
719 stream_
->ReadFrames(&frames_
, cb_
.callback()));
720 EXPECT_TRUE(frames_
.empty());
723 // A control frame over 125 characters is invalid. RFC6455 5.5 "All control
724 // frames MUST have a payload length of 125 bytes or less". Since we use a
725 // 125-byte buffer to assemble fragmented control frames, we need to detect this
726 // error before attempting to assemble the fragments.
727 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, OverlongControlFrame
) {
728 CreateRead(MockRead(SYNCHRONOUS
, k126BytePong
, k126BytePongSize
));
730 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
731 stream_
->ReadFrames(&frames_
, cb_
.callback()));
732 EXPECT_TRUE(frames_
.empty());
735 // A control frame over 125 characters should still be rejected if it is split
736 // into multiple chunks.
737 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, SplitOverlongControlFrame
) {
738 const size_t kFirstChunkSize
= 16;
739 expect_all_io_to_complete_
= false;
740 CreateChunkedRead(SYNCHRONOUS
,
747 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
748 stream_
->ReadFrames(&frames_
, cb_
.callback()));
749 EXPECT_TRUE(frames_
.empty());
752 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
,
753 AsyncSplitOverlongControlFrame
) {
754 const size_t kFirstChunkSize
= 16;
755 expect_all_io_to_complete_
= false;
756 CreateChunkedRead(ASYNC
,
763 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
764 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
, cb_
.WaitForResult());
765 // The caller should not call ReadFrames() again after receiving an error
766 // other than ERR_IO_PENDING.
767 EXPECT_TRUE(frames_
.empty());
770 // In the synchronous case, ReadFrames assembles the whole control frame before
772 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, SyncControlFrameAssembly
) {
773 const size_t kChunkSize
= 3;
775 SYNCHRONOUS
, kCloseFrame
, kCloseFrameSize
, kChunkSize
, 3, LAST_FRAME_BIG
);
777 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
778 ASSERT_EQ(1U, frames_
.size());
779 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
782 // In the asynchronous case, the callback is not called until the control frame
783 // has been completely assembled.
784 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, AsyncControlFrameAssembly
) {
785 const size_t kChunkSize
= 3;
787 ASYNC
, kCloseFrame
, kCloseFrameSize
, kChunkSize
, 3, LAST_FRAME_BIG
);
789 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
790 EXPECT_EQ(OK
, cb_
.WaitForResult());
791 ASSERT_EQ(1U, frames_
.size());
792 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
795 // A frame with a 1MB payload that has to be read in chunks.
796 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, OneMegFrame
) {
797 // This should be equal to the definition of kReadBufferSize in
798 // websocket_basic_stream.cc.
799 const int kReadBufferSize
= 32 * 1024;
800 const uint64 kPayloadSize
= 1 << 20;
801 const size_t kWireSize
= kPayloadSize
+ kLargeFrameHeaderSize
;
802 const size_t kExpectedFrameCount
=
803 (kWireSize
+ kReadBufferSize
- 1) / kReadBufferSize
;
804 scoped_ptr
<char[]> big_frame(new char[kWireSize
]);
805 memcpy(big_frame
.get(), "\x81\x7F", 2);
806 base::WriteBigEndian(big_frame
.get() + 2, kPayloadSize
);
807 memset(big_frame
.get() + kLargeFrameHeaderSize
, 'A', kPayloadSize
);
809 CreateChunkedRead(ASYNC
,
816 for (size_t frame
= 0; frame
< kExpectedFrameCount
; ++frame
) {
818 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
819 EXPECT_EQ(OK
, cb_
.WaitForResult());
820 ASSERT_EQ(1U, frames_
.size());
821 size_t expected_payload_size
= kReadBufferSize
;
823 expected_payload_size
= kReadBufferSize
- kLargeFrameHeaderSize
;
824 } else if (frame
== kExpectedFrameCount
- 1) {
825 expected_payload_size
= kLargeFrameHeaderSize
;
827 EXPECT_EQ(expected_payload_size
, frames_
[0]->header
.payload_length
);
831 // A frame with reserved flag(s) set that arrives in chunks should only have the
832 // reserved flag(s) set on the first chunk when split.
833 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, ReservedFlagCleared
) {
834 static const char kReservedFlagFrame
[] = "\x41\x05Hello";
835 const size_t kReservedFlagFrameSize
= arraysize(kReservedFlagFrame
) - 1;
836 const size_t kChunkSize
= 5;
838 CreateChunkedRead(ASYNC
,
840 kReservedFlagFrameSize
,
845 TestCompletionCallback cb
[2];
846 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
847 EXPECT_EQ(OK
, cb
[0].WaitForResult());
848 ASSERT_EQ(1U, frames_
.size());
849 EXPECT_TRUE(frames_
[0]->header
.reserved1
);
852 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
853 EXPECT_EQ(OK
, cb
[1].WaitForResult());
854 ASSERT_EQ(1U, frames_
.size());
855 EXPECT_FALSE(frames_
[0]->header
.reserved1
);
858 // Check that writing a frame all at once works.
859 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteAtOnce
) {
860 MockWrite writes
[] = {MockWrite(SYNCHRONOUS
, kWriteFrame
, kWriteFrameSize
)};
861 CreateWriteOnly(writes
);
863 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
866 // Check that completely async writing works.
867 TEST_F(WebSocketBasicStreamSocketWriteTest
, AsyncWriteAtOnce
) {
868 MockWrite writes
[] = {MockWrite(ASYNC
, kWriteFrame
, kWriteFrameSize
)};
869 CreateWriteOnly(writes
);
871 ASSERT_EQ(ERR_IO_PENDING
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
872 EXPECT_EQ(OK
, cb_
.WaitForResult());
875 // Check that writing a frame to an extremely full kernel buffer (so that it
876 // ends up being sent in bits) works. The WriteFrames() callback should not be
877 // called until all parts have been written.
878 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteInBits
) {
879 MockWrite writes
[] = {MockWrite(SYNCHRONOUS
, kWriteFrame
, 4),
880 MockWrite(ASYNC
, kWriteFrame
+ 4, 4),
881 MockWrite(ASYNC
, kWriteFrame
+ 8, kWriteFrameSize
- 8)};
882 CreateWriteOnly(writes
);
884 ASSERT_EQ(ERR_IO_PENDING
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
885 EXPECT_EQ(OK
, cb_
.WaitForResult());
888 // Check that writing a Pong frame with a NULL body works.
889 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteNullPong
) {
890 MockWrite writes
[] = {
891 MockWrite(SYNCHRONOUS
, kMaskedEmptyPong
, kMaskedEmptyPongSize
)};
892 CreateWriteOnly(writes
);
894 scoped_ptr
<WebSocketFrame
> frame(
895 new WebSocketFrame(WebSocketFrameHeader::kOpCodePong
));
896 WebSocketFrameHeader
& header
= frame
->header
;
898 header
.masked
= true;
899 header
.payload_length
= 0;
900 ScopedVector
<WebSocketFrame
> frames
;
901 frames
.push_back(frame
.release());
902 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames
, cb_
.callback()));
905 // Check that writing with a non-NULL mask works correctly.
906 TEST_F(WebSocketBasicStreamSocketTest
, WriteNonNulMask
) {
907 std::string masked_frame
= std::string("\x81\x88");
908 masked_frame
+= std::string(kNonNulMaskingKey
.key
, 4);
909 masked_frame
+= "jiggered";
910 MockWrite writes
[] = {
911 MockWrite(SYNCHRONOUS
, masked_frame
.data(), masked_frame
.size())};
912 generator_
= &GenerateNonNulMaskingKey
;
913 CreateStream(NULL
, 0, writes
, arraysize(writes
));
915 scoped_ptr
<WebSocketFrame
> frame(
916 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText
));
917 const std::string unmasked_payload
= "graphics";
918 const size_t payload_size
= unmasked_payload
.size();
919 frame
->data
= new IOBuffer(payload_size
);
920 memcpy(frame
->data
->data(), unmasked_payload
.data(), payload_size
);
921 WebSocketFrameHeader
& header
= frame
->header
;
923 header
.masked
= true;
924 header
.payload_length
= payload_size
;
925 frames_
.push_back(frame
.release());
927 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
930 TEST_F(WebSocketBasicStreamSocketTest
, GetExtensionsWorks
) {
931 extensions_
= "inflate-uuencode";
934 EXPECT_EQ("inflate-uuencode", stream_
->GetExtensions());
937 TEST_F(WebSocketBasicStreamSocketTest
, GetSubProtocolWorks
) {
938 sub_protocol_
= "cyberchat";
941 EXPECT_EQ("cyberchat", stream_
->GetSubProtocol());