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/test_completion_callback.h"
19 #include "net/log/capturing_net_log.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()
108 : pool_(1, 1, &factory_
),
109 generator_(&GenerateNulMaskingKey
),
110 expect_all_io_to_complete_(true) {}
112 ~WebSocketBasicStreamSocketTest() override
{
113 // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so
114 // should be destroyed first.
118 scoped_ptr
<ClientSocketHandle
> MakeTransportSocket(MockRead reads
[],
121 size_t writes_count
) {
122 socket_data_
.reset(new StrictStaticSocketDataProvider(
123 reads
, reads_count
, writes
, writes_count
, expect_all_io_to_complete_
));
124 socket_data_
->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
125 factory_
.AddSocketDataProvider(socket_data_
.get());
127 scoped_ptr
<ClientSocketHandle
> transport_socket(new ClientSocketHandle
);
128 scoped_refptr
<MockTransportSocketParams
> params
;
129 transport_socket
->Init("a",
132 CompletionCallback(),
134 bound_net_log_
.bound());
135 return transport_socket
.Pass();
138 void SetHttpReadBuffer(const char* data
, size_t size
) {
139 http_read_buffer_
= new GrowableIOBuffer
;
140 http_read_buffer_
->SetCapacity(size
);
141 memcpy(http_read_buffer_
->data(), data
, size
);
142 http_read_buffer_
->set_offset(size
);
145 void CreateStream(MockRead reads
[],
148 size_t writes_count
) {
149 stream_
= WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
150 MakeTransportSocket(reads
, reads_count
, writes
, writes_count
),
158 void CreateReadOnly(MockRead (&reads
)[N
]) {
159 CreateStream(reads
, N
, NULL
, 0);
162 void CreateNullStream() { CreateStream(NULL
, 0, NULL
, 0); }
164 scoped_ptr
<SocketDataProvider
> socket_data_
;
165 MockClientSocketFactory factory_
;
166 MockTransportClientSocketPool pool_
;
167 CapturingBoundNetLog(bound_net_log_
);
168 ScopedVector
<WebSocketFrame
> frames_
;
169 TestCompletionCallback cb_
;
170 scoped_refptr
<GrowableIOBuffer
> http_read_buffer_
;
171 std::string sub_protocol_
;
172 std::string extensions_
;
173 WebSocketBasicStream::WebSocketMaskingKeyGeneratorFunction generator_
;
174 bool expect_all_io_to_complete_
;
177 // A test fixture for the common case of tests that only perform a single read.
178 class WebSocketBasicStreamSocketSingleReadTest
179 : public WebSocketBasicStreamSocketTest
{
181 void CreateRead(const MockRead
& read
) {
183 CreateStream(reads_
, 1U, NULL
, 0);
189 // A test fixture for tests that perform chunked reads.
190 class WebSocketBasicStreamSocketChunkedReadTest
191 : public WebSocketBasicStreamSocketTest
{
193 // Specify the behaviour if there aren't enough chunks to use all the data. If
194 // LAST_FRAME_BIG is specified, then the rest of the data will be
195 // put in the last chunk. If LAST_FRAME_NOT_BIG is specified, then the last
196 // frame will be no bigger than the rest of the frames (but it can be smaller,
197 // if not enough data remains).
198 enum LastFrameBehaviour
{
203 // Prepares a read from |data| of |data_size|, split into |number_of_chunks|,
204 // each of |chunk_size| (except that the last chunk may be larger or
205 // smaller). All reads must be either SYNCHRONOUS or ASYNC (not a mixture),
206 // and errors cannot be simulated. Once data is exhausted, further reads will
207 // return 0 (ie. connection closed).
208 void CreateChunkedRead(IoMode mode
,
212 int number_of_chunks
,
213 LastFrameBehaviour last_frame_behaviour
) {
214 reads_
.reset(new MockRead
[number_of_chunks
]);
215 const char* start
= data
;
216 for (int i
= 0; i
< number_of_chunks
; ++i
) {
217 int len
= chunk_size
;
218 const bool is_last_chunk
= (i
== number_of_chunks
- 1);
219 if ((last_frame_behaviour
== LAST_FRAME_BIG
&& is_last_chunk
) ||
220 static_cast<int>(data
+ data_size
- start
) < len
) {
221 len
= static_cast<int>(data
+ data_size
- start
);
223 reads_
[i
] = MockRead(mode
, start
, len
);
226 CreateStream(reads_
.get(), number_of_chunks
, NULL
, 0);
229 scoped_ptr
<MockRead
[]> reads_
;
232 // Test fixture for write tests.
233 class WebSocketBasicStreamSocketWriteTest
234 : public WebSocketBasicStreamSocketTest
{
236 // All write tests use the same frame, so it is easiest to create it during
238 void SetUp() override
{ PrepareWriteFrame(); }
240 // Creates a WebSocketFrame with a wire format matching kWriteFrame and adds
242 void PrepareWriteFrame() {
243 scoped_ptr
<WebSocketFrame
> frame(
244 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText
));
245 const size_t payload_size
=
246 kWriteFrameSize
- (WebSocketFrameHeader::kBaseHeaderSize
+
247 WebSocketFrameHeader::kMaskingKeyLength
);
248 frame
->data
= new IOBuffer(payload_size
);
249 memcpy(frame
->data
->data(),
250 kWriteFrame
+ kWriteFrameSize
- payload_size
,
252 WebSocketFrameHeader
& header
= frame
->header
;
254 header
.masked
= true;
255 header
.payload_length
= payload_size
;
256 frames_
.push_back(frame
.release());
259 // Creates a stream that expects the listed writes.
261 void CreateWriteOnly(MockWrite (&writes
)[N
]) {
262 CreateStream(NULL
, 0, writes
, N
);
266 TEST_F(WebSocketBasicStreamSocketTest
, ConstructionWorks
) {
270 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncReadWorks
) {
271 CreateRead(MockRead(SYNCHRONOUS
, kSampleFrame
, kSampleFrameSize
));
272 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
273 EXPECT_EQ(OK
, result
);
274 ASSERT_EQ(1U, frames_
.size());
275 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
276 EXPECT_TRUE(frames_
[0]->header
.final
);
279 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncReadWorks
) {
280 CreateRead(MockRead(ASYNC
, kSampleFrame
, kSampleFrameSize
));
281 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
282 ASSERT_EQ(ERR_IO_PENDING
, result
);
283 EXPECT_EQ(OK
, cb_
.WaitForResult());
284 ASSERT_EQ(1U, frames_
.size());
285 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
286 // Don't repeat all the tests from SyncReadWorks; just enough to be sure the
287 // frame was really read.
290 // ReadFrames will not return a frame whose header has not been wholly received.
291 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, HeaderFragmentedSync
) {
293 SYNCHRONOUS
, kSampleFrame
, kSampleFrameSize
, 1, 2, LAST_FRAME_BIG
);
294 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
295 EXPECT_EQ(OK
, result
);
296 ASSERT_EQ(1U, frames_
.size());
297 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
300 // The same behaviour applies to asynchronous reads.
301 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, HeaderFragmentedAsync
) {
303 ASYNC
, kSampleFrame
, kSampleFrameSize
, 1, 2, LAST_FRAME_BIG
);
304 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
305 ASSERT_EQ(ERR_IO_PENDING
, result
);
306 EXPECT_EQ(OK
, cb_
.WaitForResult());
307 ASSERT_EQ(1U, frames_
.size());
308 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
311 // If it receives an incomplete header in a synchronous call, then has to wait
312 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING.
313 TEST_F(WebSocketBasicStreamSocketTest
, HeaderFragmentedSyncAsync
) {
314 MockRead reads
[] = {MockRead(SYNCHRONOUS
, kSampleFrame
, 1),
315 MockRead(ASYNC
, kSampleFrame
+ 1, kSampleFrameSize
- 1)};
316 CreateReadOnly(reads
);
317 int result
= stream_
->ReadFrames(&frames_
, cb_
.callback());
318 ASSERT_EQ(ERR_IO_PENDING
, result
);
319 EXPECT_EQ(OK
, cb_
.WaitForResult());
320 ASSERT_EQ(1U, frames_
.size());
321 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
324 // An extended header should also return ERR_IO_PENDING if it is not completely
326 TEST_F(WebSocketBasicStreamSocketTest
, FragmentedLargeHeader
) {
328 MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
- 1),
329 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
)};
330 CreateReadOnly(reads
);
331 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
334 // A frame that does not arrive in a single read should be broken into separate
336 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, LargeFrameFirstChunk
) {
337 CreateRead(MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kPartialLargeFrameSize
));
338 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
339 ASSERT_EQ(1U, frames_
.size());
340 EXPECT_FALSE(frames_
[0]->header
.final
);
341 EXPECT_EQ(kPartialLargeFrameSize
- kLargeFrameHeaderSize
,
342 static_cast<size_t>(frames_
[0]->header
.payload_length
));
345 // If only the header of a data frame arrives, we should receive a frame with a
346 // zero-size payload.
347 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, HeaderOnlyChunk
) {
348 CreateRead(MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
));
350 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
351 ASSERT_EQ(1U, frames_
.size());
352 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
353 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
354 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
357 // If the header and the body of a data frame arrive seperately, we should see
358 // them as separate frames.
359 TEST_F(WebSocketBasicStreamSocketTest
, HeaderBodySeparated
) {
361 MockRead(SYNCHRONOUS
, kPartialLargeFrame
, kLargeFrameHeaderSize
),
363 kPartialLargeFrame
+ kLargeFrameHeaderSize
,
364 kPartialLargeFrameSize
- kLargeFrameHeaderSize
)};
365 CreateReadOnly(reads
);
366 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
367 ASSERT_EQ(1U, frames_
.size());
368 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
369 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
371 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
372 EXPECT_EQ(OK
, cb_
.WaitForResult());
373 ASSERT_EQ(1U, frames_
.size());
374 EXPECT_EQ(kPartialLargeFrameSize
- kLargeFrameHeaderSize
,
375 frames_
[0]->header
.payload_length
);
376 EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation
,
377 frames_
[0]->header
.opcode
);
380 // Every frame has a header with a correct payload_length field.
381 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, LargeFrameTwoChunks
) {
382 const size_t kChunkSize
= 16;
383 CreateChunkedRead(ASYNC
,
385 kPartialLargeFrameSize
,
389 TestCompletionCallback cb
[2];
391 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
392 EXPECT_EQ(OK
, cb
[0].WaitForResult());
393 ASSERT_EQ(1U, frames_
.size());
394 EXPECT_EQ(kChunkSize
- kLargeFrameHeaderSize
,
395 frames_
[0]->header
.payload_length
);
398 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
399 EXPECT_EQ(OK
, cb
[1].WaitForResult());
400 ASSERT_EQ(1U, frames_
.size());
401 EXPECT_EQ(kChunkSize
, frames_
[0]->header
.payload_length
);
404 // Only the final frame of a fragmented message has |final| bit set.
405 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, OnlyFinalChunkIsFinal
) {
406 static const size_t kFirstChunkSize
= 4;
407 CreateChunkedRead(ASYNC
,
413 TestCompletionCallback cb
[2];
415 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
416 EXPECT_EQ(OK
, cb
[0].WaitForResult());
417 ASSERT_EQ(1U, frames_
.size());
418 ASSERT_FALSE(frames_
[0]->header
.final
);
421 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
422 EXPECT_EQ(OK
, cb
[1].WaitForResult());
423 ASSERT_EQ(1U, frames_
.size());
424 ASSERT_TRUE(frames_
[0]->header
.final
);
427 // All frames after the first have their opcode changed to Continuation.
428 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, ContinuationOpCodeUsed
) {
429 const size_t kFirstChunkSize
= 3;
430 const int kChunkCount
= 3;
431 // The input data is one frame with opcode Text, which arrives in three
433 CreateChunkedRead(ASYNC
,
439 TestCompletionCallback cb
[kChunkCount
];
441 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
442 EXPECT_EQ(OK
, cb
[0].WaitForResult());
443 ASSERT_EQ(1U, frames_
.size());
444 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
446 // This test uses a loop to verify that the opcode for every frames generated
447 // after the first is converted to Continuation.
448 for (int i
= 1; i
< kChunkCount
; ++i
) {
450 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[i
].callback()));
451 EXPECT_EQ(OK
, cb
[i
].WaitForResult());
452 ASSERT_EQ(1U, frames_
.size());
453 EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation
,
454 frames_
[0]->header
.opcode
);
458 // Multiple frames that arrive together should be parsed correctly.
459 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, ThreeFramesTogether
) {
460 CreateRead(MockRead(SYNCHRONOUS
, kMultipleFrames
, kMultipleFramesSize
));
462 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
463 ASSERT_EQ(3U, frames_
.size());
464 EXPECT_TRUE(frames_
[0]->header
.final
);
465 EXPECT_TRUE(frames_
[1]->header
.final
);
466 EXPECT_TRUE(frames_
[2]->header
.final
);
469 // ERR_CONNECTION_CLOSED must be returned on close.
470 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncClose
) {
471 CreateRead(MockRead(SYNCHRONOUS
, "", 0));
473 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
474 stream_
->ReadFrames(&frames_
, cb_
.callback()));
477 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncClose
) {
478 CreateRead(MockRead(ASYNC
, "", 0));
480 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
481 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
484 // The result should be the same if the socket returns
485 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established
486 // connection; a Read of size 0 is the expected behaviour. The key point of this
487 // test is to confirm that ReadFrames() behaviour is identical in both cases.
488 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncCloseWithErr
) {
489 CreateRead(MockRead(SYNCHRONOUS
, ERR_CONNECTION_CLOSED
));
491 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
492 stream_
->ReadFrames(&frames_
, cb_
.callback()));
495 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncCloseWithErr
) {
496 CreateRead(MockRead(ASYNC
, ERR_CONNECTION_CLOSED
));
498 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
499 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
502 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncErrorsPassedThrough
) {
503 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that
504 // WebSocketBasicStream gives no special handling to.
505 CreateRead(MockRead(SYNCHRONOUS
, ERR_INSUFFICIENT_RESOURCES
));
507 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES
,
508 stream_
->ReadFrames(&frames_
, cb_
.callback()));
511 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncErrorsPassedThrough
) {
512 CreateRead(MockRead(ASYNC
, ERR_INSUFFICIENT_RESOURCES
));
514 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
515 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES
, cb_
.WaitForResult());
518 // If we get a frame followed by a close, we should receive them separately.
519 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, CloseAfterFrame
) {
520 // The chunk size equals the data size, so the second chunk is 0 size, closing
522 CreateChunkedRead(SYNCHRONOUS
,
529 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
530 EXPECT_EQ(1U, frames_
.size());
532 EXPECT_EQ(ERR_CONNECTION_CLOSED
,
533 stream_
->ReadFrames(&frames_
, cb_
.callback()));
536 // Synchronous close after an async frame header is handled by a different code
538 TEST_F(WebSocketBasicStreamSocketTest
, AsyncCloseAfterIncompleteHeader
) {
539 MockRead reads
[] = {MockRead(ASYNC
, kSampleFrame
, 1U),
540 MockRead(SYNCHRONOUS
, "", 0)};
541 CreateReadOnly(reads
);
543 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
544 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
547 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a
548 // slightly different code path.
549 TEST_F(WebSocketBasicStreamSocketTest
, AsyncErrCloseAfterIncompleteHeader
) {
550 MockRead reads
[] = {MockRead(ASYNC
, kSampleFrame
, 1U),
551 MockRead(SYNCHRONOUS
, ERR_CONNECTION_CLOSED
)};
552 CreateReadOnly(reads
);
554 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
555 EXPECT_EQ(ERR_CONNECTION_CLOSED
, cb_
.WaitForResult());
558 // An empty first frame is not ignored.
559 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, EmptyFirstFrame
) {
560 CreateRead(MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
));
562 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
563 ASSERT_EQ(1U, frames_
.size());
564 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
565 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
568 // An empty frame in the middle of a message is ignored.
569 TEST_F(WebSocketBasicStreamSocketTest
, EmptyMiddleFrame
) {
571 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
572 MockRead(SYNCHRONOUS
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
573 MockRead(SYNCHRONOUS
, ERR_IO_PENDING
)};
574 CreateReadOnly(reads
);
576 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
577 EXPECT_EQ(1U, frames_
.size());
579 EXPECT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
582 // An empty frame in the middle of a message that arrives separately is still
584 TEST_F(WebSocketBasicStreamSocketTest
, EmptyMiddleFrameAsync
) {
586 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
587 MockRead(ASYNC
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
588 // We include a pong message to verify the middle frame was actually
590 MockRead(ASYNC
, kValidPong
, kValidPongSize
)};
591 CreateReadOnly(reads
);
593 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
594 EXPECT_EQ(1U, frames_
.size());
596 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
597 EXPECT_EQ(OK
, cb_
.WaitForResult());
598 ASSERT_EQ(1U, frames_
.size());
599 EXPECT_EQ(WebSocketFrameHeader::kOpCodePong
, frames_
[0]->header
.opcode
);
602 // An empty final frame is not ignored.
603 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, EmptyFinalFrame
) {
605 MockRead(SYNCHRONOUS
, kEmptyFinalTextFrame
, kEmptyFinalTextFrameSize
));
607 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
608 ASSERT_EQ(1U, frames_
.size());
609 EXPECT_EQ(NULL
, frames_
[0]->data
.get());
610 EXPECT_EQ(0U, frames_
[0]->header
.payload_length
);
613 // An empty middle frame is ignored with a final frame present.
614 TEST_F(WebSocketBasicStreamSocketTest
, ThreeFrameEmptyMessage
) {
616 MockRead(SYNCHRONOUS
, kEmptyFirstFrame
, kEmptyFirstFrameSize
),
617 MockRead(SYNCHRONOUS
, kEmptyMiddleFrame
, kEmptyMiddleFrameSize
),
618 MockRead(SYNCHRONOUS
,
619 kEmptyFinalContinuationFrame
,
620 kEmptyFinalContinuationFrameSize
)};
621 CreateReadOnly(reads
);
623 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
624 ASSERT_EQ(1U, frames_
.size());
625 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
627 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
628 ASSERT_EQ(1U, frames_
.size());
629 EXPECT_TRUE(frames_
[0]->header
.final
);
632 // If there was a frame read at the same time as the response headers (and the
633 // handshake succeeded), then we should parse it.
634 TEST_F(WebSocketBasicStreamSocketTest
, HttpReadBufferIsUsed
) {
635 SetHttpReadBuffer(kSampleFrame
, kSampleFrameSize
);
638 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
639 ASSERT_EQ(1U, frames_
.size());
640 ASSERT_TRUE(frames_
[0]->data
.get());
641 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
644 // Check that a frame whose header partially arrived at the end of the response
645 // headers works correctly.
646 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
647 PartialFrameHeaderInHttpResponse
) {
648 SetHttpReadBuffer(kSampleFrame
, 1);
649 CreateRead(MockRead(ASYNC
, kSampleFrame
+ 1, kSampleFrameSize
- 1));
651 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
652 EXPECT_EQ(OK
, cb_
.WaitForResult());
653 ASSERT_EQ(1U, frames_
.size());
654 ASSERT_TRUE(frames_
[0]->data
.get());
655 EXPECT_EQ(GG_UINT64_C(6), frames_
[0]->header
.payload_length
);
656 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText
, frames_
[0]->header
.opcode
);
659 // Check that a control frame which partially arrives at the end of the response
660 // headers works correctly.
661 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
662 PartialControlFrameInHttpResponse
) {
663 const size_t kPartialFrameBytes
= 3;
664 SetHttpReadBuffer(kCloseFrame
, kPartialFrameBytes
);
665 CreateRead(MockRead(ASYNC
,
666 kCloseFrame
+ kPartialFrameBytes
,
667 kCloseFrameSize
- kPartialFrameBytes
));
669 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
670 EXPECT_EQ(OK
, cb_
.WaitForResult());
671 ASSERT_EQ(1U, frames_
.size());
672 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
673 EXPECT_EQ(kCloseFrameSize
- 2, frames_
[0]->header
.payload_length
);
676 memcmp(frames_
[0]->data
->data(), kCloseFrame
+ 2, kCloseFrameSize
- 2));
679 // Check that a control frame which partially arrives at the end of the response
680 // headers works correctly. Synchronous version (unlikely in practice).
681 TEST_F(WebSocketBasicStreamSocketSingleReadTest
,
682 PartialControlFrameInHttpResponseSync
) {
683 const size_t kPartialFrameBytes
= 3;
684 SetHttpReadBuffer(kCloseFrame
, kPartialFrameBytes
);
685 CreateRead(MockRead(SYNCHRONOUS
,
686 kCloseFrame
+ kPartialFrameBytes
,
687 kCloseFrameSize
- kPartialFrameBytes
));
689 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
690 ASSERT_EQ(1U, frames_
.size());
691 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
694 // Check that an invalid frame results in an error.
695 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, SyncInvalidFrame
) {
696 CreateRead(MockRead(SYNCHRONOUS
, kInvalidFrame
, kInvalidFrameSize
));
698 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
699 stream_
->ReadFrames(&frames_
, cb_
.callback()));
702 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, AsyncInvalidFrame
) {
703 CreateRead(MockRead(ASYNC
, kInvalidFrame
, kInvalidFrameSize
));
705 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
706 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
, cb_
.WaitForResult());
709 // A control frame without a FIN flag is invalid and should not be passed
710 // through to higher layers. RFC6455 5.5 "All control frames ... MUST NOT be
712 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, ControlFrameWithoutFin
) {
714 MockRead(SYNCHRONOUS
, kPingFrameWithoutFin
, kPingFrameWithoutFinSize
));
716 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
717 stream_
->ReadFrames(&frames_
, cb_
.callback()));
718 EXPECT_TRUE(frames_
.empty());
721 // A control frame over 125 characters is invalid. RFC6455 5.5 "All control
722 // frames MUST have a payload length of 125 bytes or less". Since we use a
723 // 125-byte buffer to assemble fragmented control frames, we need to detect this
724 // error before attempting to assemble the fragments.
725 TEST_F(WebSocketBasicStreamSocketSingleReadTest
, OverlongControlFrame
) {
726 CreateRead(MockRead(SYNCHRONOUS
, k126BytePong
, k126BytePongSize
));
728 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
729 stream_
->ReadFrames(&frames_
, cb_
.callback()));
730 EXPECT_TRUE(frames_
.empty());
733 // A control frame over 125 characters should still be rejected if it is split
734 // into multiple chunks.
735 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, SplitOverlongControlFrame
) {
736 const size_t kFirstChunkSize
= 16;
737 expect_all_io_to_complete_
= false;
738 CreateChunkedRead(SYNCHRONOUS
,
745 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
,
746 stream_
->ReadFrames(&frames_
, cb_
.callback()));
747 EXPECT_TRUE(frames_
.empty());
750 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
,
751 AsyncSplitOverlongControlFrame
) {
752 const size_t kFirstChunkSize
= 16;
753 expect_all_io_to_complete_
= false;
754 CreateChunkedRead(ASYNC
,
761 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
762 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR
, cb_
.WaitForResult());
763 // The caller should not call ReadFrames() again after receiving an error
764 // other than ERR_IO_PENDING.
765 EXPECT_TRUE(frames_
.empty());
768 // In the synchronous case, ReadFrames assembles the whole control frame before
770 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, SyncControlFrameAssembly
) {
771 const size_t kChunkSize
= 3;
773 SYNCHRONOUS
, kCloseFrame
, kCloseFrameSize
, kChunkSize
, 3, LAST_FRAME_BIG
);
775 EXPECT_EQ(OK
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
776 ASSERT_EQ(1U, frames_
.size());
777 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
780 // In the asynchronous case, the callback is not called until the control frame
781 // has been completely assembled.
782 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, AsyncControlFrameAssembly
) {
783 const size_t kChunkSize
= 3;
785 ASYNC
, kCloseFrame
, kCloseFrameSize
, kChunkSize
, 3, LAST_FRAME_BIG
);
787 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
788 EXPECT_EQ(OK
, cb_
.WaitForResult());
789 ASSERT_EQ(1U, frames_
.size());
790 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose
, frames_
[0]->header
.opcode
);
793 // A frame with a 1MB payload that has to be read in chunks.
794 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, OneMegFrame
) {
795 // This should be equal to the definition of kReadBufferSize in
796 // websocket_basic_stream.cc.
797 const int kReadBufferSize
= 32 * 1024;
798 const uint64 kPayloadSize
= 1 << 20;
799 const size_t kWireSize
= kPayloadSize
+ kLargeFrameHeaderSize
;
800 const size_t kExpectedFrameCount
=
801 (kWireSize
+ kReadBufferSize
- 1) / kReadBufferSize
;
802 scoped_ptr
<char[]> big_frame(new char[kWireSize
]);
803 memcpy(big_frame
.get(), "\x81\x7F", 2);
804 base::WriteBigEndian(big_frame
.get() + 2, kPayloadSize
);
805 memset(big_frame
.get() + kLargeFrameHeaderSize
, 'A', kPayloadSize
);
807 CreateChunkedRead(ASYNC
,
814 for (size_t frame
= 0; frame
< kExpectedFrameCount
; ++frame
) {
816 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb_
.callback()));
817 EXPECT_EQ(OK
, cb_
.WaitForResult());
818 ASSERT_EQ(1U, frames_
.size());
819 size_t expected_payload_size
= kReadBufferSize
;
821 expected_payload_size
= kReadBufferSize
- kLargeFrameHeaderSize
;
822 } else if (frame
== kExpectedFrameCount
- 1) {
823 expected_payload_size
= kLargeFrameHeaderSize
;
825 EXPECT_EQ(expected_payload_size
, frames_
[0]->header
.payload_length
);
829 // A frame with reserved flag(s) set that arrives in chunks should only have the
830 // reserved flag(s) set on the first chunk when split.
831 TEST_F(WebSocketBasicStreamSocketChunkedReadTest
, ReservedFlagCleared
) {
832 static const char kReservedFlagFrame
[] = "\x41\x05Hello";
833 const size_t kReservedFlagFrameSize
= arraysize(kReservedFlagFrame
) - 1;
834 const size_t kChunkSize
= 5;
836 CreateChunkedRead(ASYNC
,
838 kReservedFlagFrameSize
,
843 TestCompletionCallback cb
[2];
844 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[0].callback()));
845 EXPECT_EQ(OK
, cb
[0].WaitForResult());
846 ASSERT_EQ(1U, frames_
.size());
847 EXPECT_TRUE(frames_
[0]->header
.reserved1
);
850 ASSERT_EQ(ERR_IO_PENDING
, stream_
->ReadFrames(&frames_
, cb
[1].callback()));
851 EXPECT_EQ(OK
, cb
[1].WaitForResult());
852 ASSERT_EQ(1U, frames_
.size());
853 EXPECT_FALSE(frames_
[0]->header
.reserved1
);
856 // Check that writing a frame all at once works.
857 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteAtOnce
) {
858 MockWrite writes
[] = {MockWrite(SYNCHRONOUS
, kWriteFrame
, kWriteFrameSize
)};
859 CreateWriteOnly(writes
);
861 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
864 // Check that completely async writing works.
865 TEST_F(WebSocketBasicStreamSocketWriteTest
, AsyncWriteAtOnce
) {
866 MockWrite writes
[] = {MockWrite(ASYNC
, kWriteFrame
, kWriteFrameSize
)};
867 CreateWriteOnly(writes
);
869 ASSERT_EQ(ERR_IO_PENDING
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
870 EXPECT_EQ(OK
, cb_
.WaitForResult());
873 // Check that writing a frame to an extremely full kernel buffer (so that it
874 // ends up being sent in bits) works. The WriteFrames() callback should not be
875 // called until all parts have been written.
876 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteInBits
) {
877 MockWrite writes
[] = {MockWrite(SYNCHRONOUS
, kWriteFrame
, 4),
878 MockWrite(ASYNC
, kWriteFrame
+ 4, 4),
879 MockWrite(ASYNC
, kWriteFrame
+ 8, kWriteFrameSize
- 8)};
880 CreateWriteOnly(writes
);
882 ASSERT_EQ(ERR_IO_PENDING
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
883 EXPECT_EQ(OK
, cb_
.WaitForResult());
886 // Check that writing a Pong frame with a NULL body works.
887 TEST_F(WebSocketBasicStreamSocketWriteTest
, WriteNullPong
) {
888 MockWrite writes
[] = {
889 MockWrite(SYNCHRONOUS
, kMaskedEmptyPong
, kMaskedEmptyPongSize
)};
890 CreateWriteOnly(writes
);
892 scoped_ptr
<WebSocketFrame
> frame(
893 new WebSocketFrame(WebSocketFrameHeader::kOpCodePong
));
894 WebSocketFrameHeader
& header
= frame
->header
;
896 header
.masked
= true;
897 header
.payload_length
= 0;
898 ScopedVector
<WebSocketFrame
> frames
;
899 frames
.push_back(frame
.release());
900 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames
, cb_
.callback()));
903 // Check that writing with a non-NULL mask works correctly.
904 TEST_F(WebSocketBasicStreamSocketTest
, WriteNonNulMask
) {
905 std::string masked_frame
= std::string("\x81\x88");
906 masked_frame
+= std::string(kNonNulMaskingKey
.key
, 4);
907 masked_frame
+= "jiggered";
908 MockWrite writes
[] = {
909 MockWrite(SYNCHRONOUS
, masked_frame
.data(), masked_frame
.size())};
910 generator_
= &GenerateNonNulMaskingKey
;
911 CreateStream(NULL
, 0, writes
, arraysize(writes
));
913 scoped_ptr
<WebSocketFrame
> frame(
914 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText
));
915 const std::string unmasked_payload
= "graphics";
916 const size_t payload_size
= unmasked_payload
.size();
917 frame
->data
= new IOBuffer(payload_size
);
918 memcpy(frame
->data
->data(), unmasked_payload
.data(), payload_size
);
919 WebSocketFrameHeader
& header
= frame
->header
;
921 header
.masked
= true;
922 header
.payload_length
= payload_size
;
923 frames_
.push_back(frame
.release());
925 EXPECT_EQ(OK
, stream_
->WriteFrames(&frames_
, cb_
.callback()));
928 TEST_F(WebSocketBasicStreamSocketTest
, GetExtensionsWorks
) {
929 extensions_
= "inflate-uuencode";
932 EXPECT_EQ("inflate-uuencode", stream_
->GetExtensions());
935 TEST_F(WebSocketBasicStreamSocketTest
, GetSubProtocolWorks
) {
936 sub_protocol_
= "cyberchat";
939 EXPECT_EQ("cyberchat", stream_
->GetSubProtocol());