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.
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 <string.h>  // for memcpy() and memset().
12
13#include <string>
14
15#include "base/basictypes.h"
16#include "base/port.h"
17#include "net/base/big_endian.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"
22
23namespace net {
24namespace {
25
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;
29
30WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(SampleFrame, "\x81\x06Sample");
31WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
32    PartialLargeFrame,
33    "\x81\x7F\x00\x00\x00\x00\x7F\xFF\xFF\xFF"
34    "chromiunum ad pasco per loca insanis pullum manducat frumenti");
35const size_t kLargeFrameHeaderSize = 10;
36WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(MultipleFrames,
37                                            "\x81\x01X\x81\x01Y\x81\x01Z");
38WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFirstFrame, "\x01\x00");
39WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyMiddleFrame, "\x00\x00");
40WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalTextFrame, "\x81\x00");
41WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(EmptyFinalContinuationFrame,
42                                            "\x80\x00");
43WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(ValidPong, "\x8A\x00");
44// This frame encodes a payload length of 7 in two bytes, which is always
45// invalid.
46WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(InvalidFrame,
47                                            "\x81\x7E\x00\x07Invalid");
48// Control frames must have the FIN bit set. This one does not.
49WEBSOCKET_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.
52WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(
53    126BytePong,
54    "\x8a\x7e\x00\x7eZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
55    "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
56WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(CloseFrame,
57                                            "\x88\x09\x03\xe8occludo");
58WEBSOCKET_BASIC_STREAM_TEST_DEFINE_CONSTANT(WriteFrame,
59                                            "\x81\x85\x00\x00\x00\x00Write");
60const WebSocketMaskingKey kNulMaskingKey = {{'\0', '\0', '\0', '\0'}};
61const WebSocketMaskingKey kNonNulMaskingKey = {
62    {'\x0d', '\x1b', '\x06', '\x17'}};
63
64// A masking key generator function which generates the identity mask,
65// ie. "\0\0\0\0".
66WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; }
67
68// A masking key generation function which generates a fixed masking key with no
69// nul characters.
70WebSocketMaskingKey GenerateNonNulMaskingKey() { return kNonNulMaskingKey; }
71
72// Base class for WebSocketBasicStream test fixtures.
73class WebSocketBasicStreamTest : public ::testing::Test {
74 protected:
75  scoped_ptr<WebSocketBasicStream> stream_;
76  CapturingNetLog net_log_;
77};
78
79// A subclass of StaticSocketDataProvider modified to require that all data
80// expected to be read or written actually is.
81class StrictStaticSocketDataProvider : public StaticSocketDataProvider {
82 public:
83  StrictStaticSocketDataProvider(MockRead* reads,
84                                 size_t reads_count,
85                                 MockWrite* writes,
86                                 size_t writes_count,
87                                 bool strict_mode)
88      : StaticSocketDataProvider(reads, reads_count, writes, writes_count),
89        strict_mode_(strict_mode) {}
90
91  virtual ~StrictStaticSocketDataProvider() {
92    if (strict_mode_) {
93      EXPECT_EQ(read_count(), read_index());
94      EXPECT_EQ(write_count(), write_index());
95    }
96  }
97
98 private:
99  const bool strict_mode_;
100};
101
102// A fixture for tests which only perform normal socket operations.
103class WebSocketBasicStreamSocketTest : public WebSocketBasicStreamTest {
104 protected:
105  WebSocketBasicStreamSocketTest()
106      : histograms_("a"),
107        pool_(1, 1, &histograms_, &factory_),
108        generator_(&GenerateNulMaskingKey),
109        expect_all_io_to_complete_(true) {}
110
111  virtual ~WebSocketBasicStreamSocketTest() {
112    // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so
113    // should be destroyed first.
114    stream_.reset();
115  }
116
117  scoped_ptr<ClientSocketHandle> MakeTransportSocket(MockRead reads[],
118                                                     size_t reads_count,
119                                                     MockWrite writes[],
120                                                     size_t writes_count) {
121    socket_data_.reset(new StrictStaticSocketDataProvider(
122        reads, reads_count, writes, writes_count, expect_all_io_to_complete_));
123    socket_data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
124    factory_.AddSocketDataProvider(socket_data_.get());
125
126    scoped_ptr<ClientSocketHandle> transport_socket(new ClientSocketHandle);
127    scoped_refptr<MockTransportSocketParams> params;
128    transport_socket->Init("a",
129                           params,
130                           MEDIUM,
131                           CompletionCallback(),
132                           &pool_,
133                           bound_net_log_.bound());
134    return transport_socket.Pass();
135  }
136
137  void SetHttpReadBuffer(const char* data, size_t size) {
138    http_read_buffer_ = new GrowableIOBuffer;
139    http_read_buffer_->SetCapacity(size);
140    memcpy(http_read_buffer_->data(), data, size);
141    http_read_buffer_->set_offset(size);
142  }
143
144  void CreateStream(MockRead reads[],
145                    size_t reads_count,
146                    MockWrite writes[],
147                    size_t writes_count) {
148    stream_ = WebSocketBasicStream::CreateWebSocketBasicStreamForTesting(
149        MakeTransportSocket(reads, reads_count, writes, writes_count),
150        http_read_buffer_,
151        sub_protocol_,
152        extensions_,
153        generator_);
154  }
155
156  template <size_t N>
157  void CreateReadOnly(MockRead (&reads)[N]) {
158    CreateStream(reads, N, NULL, 0);
159  }
160
161  void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); }
162
163  scoped_ptr<SocketDataProvider> socket_data_;
164  MockClientSocketFactory factory_;
165  ClientSocketPoolHistograms histograms_;
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_;
175};
176
177// A test fixture for the common case of tests that only perform a single read.
178class WebSocketBasicStreamSocketSingleReadTest
179    : public WebSocketBasicStreamSocketTest {
180 protected:
181  void CreateRead(const MockRead& read) {
182    reads_[0] = read;
183    CreateStream(reads_, 1U, NULL, 0);
184  }
185
186  MockRead reads_[1];
187};
188
189// A test fixture for tests that perform chunked reads.
190class WebSocketBasicStreamSocketChunkedReadTest
191    : public WebSocketBasicStreamSocketTest {
192 protected:
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 {
199    LAST_FRAME_BIG,
200    LAST_FRAME_NOT_BIG
201  };
202
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,
209                         const char data[],
210                         size_t data_size,
211                         int chunk_size,
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);
222      }
223      reads_[i] = MockRead(mode, start, len);
224      start += len;
225    }
226    CreateStream(reads_.get(), number_of_chunks, NULL, 0);
227  }
228
229  scoped_ptr<MockRead[]> reads_;
230};
231
232// Test fixture for write tests.
233class WebSocketBasicStreamSocketWriteTest
234    : public WebSocketBasicStreamSocketTest {
235 protected:
236  // All write tests use the same frame, so it is easiest to create it during
237  // test creation.
238  virtual void SetUp() OVERRIDE { PrepareWriteFrame(); }
239
240  // Creates a WebSocketFrame with a wire format matching kWriteFrame and adds
241  // it to |frames_|.
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,
251           payload_size);
252    WebSocketFrameHeader& header = frame->header;
253    header.final = true;
254    header.masked = true;
255    header.payload_length = payload_size;
256    frames_.push_back(frame.release());
257  }
258
259  // Creates a stream that expects the listed writes.
260  template <size_t N>
261  void CreateWriteOnly(MockWrite (&writes)[N]) {
262    CreateStream(NULL, 0, writes, N);
263  }
264};
265
266TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) {
267  CreateNullStream();
268}
269
270TEST_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);
277}
278
279TEST_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.
288}
289
290// ReadFrames will not return a frame whose header has not been wholly received.
291TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedSync) {
292  CreateChunkedRead(
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);
298}
299
300// The same behaviour applies to asynchronous reads.
301TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedAsync) {
302  CreateChunkedRead(
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);
309}
310
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.
313TEST_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);
322}
323
324// An extended header should also return ERR_IO_PENDING if it is not completely
325// received.
326TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) {
327  MockRead reads[] = {
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()));
332}
333
334// A frame that does not arrive in a single read should be broken into separate
335// frames.
336TEST_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));
343}
344
345// If only the header of a data frame arrives, we should receive a frame with a
346// zero-size payload.
347TEST_F(WebSocketBasicStreamSocketSingleReadTest, HeaderOnlyChunk) {
348  CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize));
349
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);
355}
356
357// If the header and the body of a data frame arrive seperately, we should see
358// them as separate frames.
359TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparated) {
360  MockRead reads[] = {
361      MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize),
362      MockRead(ASYNC,
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);
370  frames_.clear();
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);
378}
379
380// Every frame has a header with a correct payload_length field.
381TEST_F(WebSocketBasicStreamSocketChunkedReadTest, LargeFrameTwoChunks) {
382  const size_t kChunkSize = 16;
383  CreateChunkedRead(ASYNC,
384                    kPartialLargeFrame,
385                    kPartialLargeFrameSize,
386                    kChunkSize,
387                    2,
388                    LAST_FRAME_NOT_BIG);
389  TestCompletionCallback cb[2];
390
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);
396
397  frames_.clear();
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);
402}
403
404// Only the final frame of a fragmented message has |final| bit set.
405TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OnlyFinalChunkIsFinal) {
406  static const size_t kFirstChunkSize = 4;
407  CreateChunkedRead(ASYNC,
408                    kSampleFrame,
409                    kSampleFrameSize,
410                    kFirstChunkSize,
411                    2,
412                    LAST_FRAME_BIG);
413  TestCompletionCallback cb[2];
414
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);
419
420  frames_.clear();
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);
425}
426
427// All frames after the first have their opcode changed to Continuation.
428TEST_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
432  // separate chunks.
433  CreateChunkedRead(ASYNC,
434                    kSampleFrame,
435                    kSampleFrameSize,
436                    kFirstChunkSize,
437                    kChunkCount,
438                    LAST_FRAME_BIG);
439  TestCompletionCallback cb[kChunkCount];
440
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);
445
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) {
449    frames_.clear();
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);
455  }
456}
457
458// Multiple frames that arrive together should be parsed correctly.
459TEST_F(WebSocketBasicStreamSocketSingleReadTest, ThreeFramesTogether) {
460  CreateRead(MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize));
461
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);
467}
468
469// ERR_CONNECTION_CLOSED must be returned on close.
470TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncClose) {
471  CreateRead(MockRead(SYNCHRONOUS, "", 0));
472
473  EXPECT_EQ(ERR_CONNECTION_CLOSED,
474            stream_->ReadFrames(&frames_, cb_.callback()));
475}
476
477TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncClose) {
478  CreateRead(MockRead(ASYNC, "", 0));
479
480  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
481  EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
482}
483
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.
488TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncCloseWithErr) {
489  CreateRead(MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED));
490
491  EXPECT_EQ(ERR_CONNECTION_CLOSED,
492            stream_->ReadFrames(&frames_, cb_.callback()));
493}
494
495TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncCloseWithErr) {
496  CreateRead(MockRead(ASYNC, ERR_CONNECTION_CLOSED));
497
498  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
499  EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
500}
501
502TEST_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));
506
507  EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES,
508            stream_->ReadFrames(&frames_, cb_.callback()));
509}
510
511TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncErrorsPassedThrough) {
512  CreateRead(MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES));
513
514  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
515  EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, cb_.WaitForResult());
516}
517
518// If we get a frame followed by a close, we should receive them separately.
519TEST_F(WebSocketBasicStreamSocketChunkedReadTest, CloseAfterFrame) {
520  // The chunk size equals the data size, so the second chunk is 0 size, closing
521  // the connection.
522  CreateChunkedRead(SYNCHRONOUS,
523                    kSampleFrame,
524                    kSampleFrameSize,
525                    kSampleFrameSize,
526                    2,
527                    LAST_FRAME_NOT_BIG);
528
529  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
530  EXPECT_EQ(1U, frames_.size());
531  frames_.clear();
532  EXPECT_EQ(ERR_CONNECTION_CLOSED,
533            stream_->ReadFrames(&frames_, cb_.callback()));
534}
535
536// Synchronous close after an async frame header is handled by a different code
537// path.
538TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) {
539  MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U),
540                      MockRead(SYNCHRONOUS, "", 0)};
541  CreateReadOnly(reads);
542
543  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
544  EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
545}
546
547// When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a
548// slightly different code path.
549TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) {
550  MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U),
551                      MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)};
552  CreateReadOnly(reads);
553
554  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
555  EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult());
556}
557
558// An empty first frame is not ignored.
559TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFirstFrame) {
560  CreateRead(MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize));
561
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);
566}
567
568// An empty frame in the middle of a message is ignored.
569TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrame) {
570  MockRead reads[] = {
571      MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
572      MockRead(SYNCHRONOUS, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
573      MockRead(SYNCHRONOUS, ERR_IO_PENDING)};
574  CreateReadOnly(reads);
575
576  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
577  EXPECT_EQ(1U, frames_.size());
578  frames_.clear();
579  EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
580}
581
582// An empty frame in the middle of a message that arrives separately is still
583// ignored.
584TEST_F(WebSocketBasicStreamSocketTest, EmptyMiddleFrameAsync) {
585  MockRead reads[] = {
586      MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
587      MockRead(ASYNC, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
588      // We include a pong message to verify the middle frame was actually
589      // processed.
590      MockRead(ASYNC, kValidPong, kValidPongSize)};
591  CreateReadOnly(reads);
592
593  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
594  EXPECT_EQ(1U, frames_.size());
595  frames_.clear();
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);
600}
601
602// An empty final frame is not ignored.
603TEST_F(WebSocketBasicStreamSocketSingleReadTest, EmptyFinalFrame) {
604  CreateRead(
605      MockRead(SYNCHRONOUS, kEmptyFinalTextFrame, kEmptyFinalTextFrameSize));
606
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);
611}
612
613// An empty middle frame is ignored with a final frame present.
614TEST_F(WebSocketBasicStreamSocketTest, ThreeFrameEmptyMessage) {
615  MockRead reads[] = {
616      MockRead(SYNCHRONOUS, kEmptyFirstFrame, kEmptyFirstFrameSize),
617      MockRead(SYNCHRONOUS, kEmptyMiddleFrame, kEmptyMiddleFrameSize),
618      MockRead(SYNCHRONOUS,
619               kEmptyFinalContinuationFrame,
620               kEmptyFinalContinuationFrameSize)};
621  CreateReadOnly(reads);
622
623  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
624  ASSERT_EQ(1U, frames_.size());
625  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
626  frames_.clear();
627  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
628  ASSERT_EQ(1U, frames_.size());
629  EXPECT_TRUE(frames_[0]->header.final);
630}
631
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.
634TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) {
635  SetHttpReadBuffer(kSampleFrame, kSampleFrameSize);
636  CreateNullStream();
637
638  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
639  ASSERT_EQ(1U, frames_.size());
640  ASSERT_TRUE(frames_[0]->data);
641  EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length);
642}
643
644// Check that a frame whose header partially arrived at the end of the response
645// headers works correctly.
646TEST_F(WebSocketBasicStreamSocketSingleReadTest,
647       PartialFrameHeaderInHttpResponse) {
648  SetHttpReadBuffer(kSampleFrame, 1);
649  CreateRead(MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1));
650
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);
655  EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length);
656  EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode);
657}
658
659// Check that a control frame which partially arrives at the end of the response
660// headers works correctly.
661TEST_F(WebSocketBasicStreamSocketSingleReadTest,
662       PartialControlFrameInHttpResponse) {
663  const size_t kPartialFrameBytes = 3;
664  SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes);
665  CreateRead(MockRead(ASYNC,
666                      kCloseFrame + kPartialFrameBytes,
667                      kCloseFrameSize - kPartialFrameBytes));
668
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);
674  EXPECT_EQ(
675      0,
676      memcmp(frames_[0]->data->data(), kCloseFrame + 2, kCloseFrameSize - 2));
677}
678
679// Check that a control frame which partially arrives at the end of the response
680// headers works correctly. Synchronous version (unlikely in practice).
681TEST_F(WebSocketBasicStreamSocketSingleReadTest,
682       PartialControlFrameInHttpResponseSync) {
683  const size_t kPartialFrameBytes = 3;
684  SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes);
685  CreateRead(MockRead(SYNCHRONOUS,
686                      kCloseFrame + kPartialFrameBytes,
687                      kCloseFrameSize - kPartialFrameBytes));
688
689  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
690  ASSERT_EQ(1U, frames_.size());
691  EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
692}
693
694// Check that an invalid frame results in an error.
695TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncInvalidFrame) {
696  CreateRead(MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize));
697
698  EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
699            stream_->ReadFrames(&frames_, cb_.callback()));
700}
701
702TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncInvalidFrame) {
703  CreateRead(MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize));
704
705  ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback()));
706  EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult());
707}
708
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
711// fragmented."
712TEST_F(WebSocketBasicStreamSocketSingleReadTest, ControlFrameWithoutFin) {
713  CreateRead(
714      MockRead(SYNCHRONOUS, kPingFrameWithoutFin, kPingFrameWithoutFinSize));
715
716  EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
717            stream_->ReadFrames(&frames_, cb_.callback()));
718  EXPECT_TRUE(frames_.empty());
719}
720
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.
725TEST_F(WebSocketBasicStreamSocketSingleReadTest, OverlongControlFrame) {
726  CreateRead(MockRead(SYNCHRONOUS, k126BytePong, k126BytePongSize));
727
728  EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
729            stream_->ReadFrames(&frames_, cb_.callback()));
730  EXPECT_TRUE(frames_.empty());
731}
732
733// A control frame over 125 characters should still be rejected if it is split
734// into multiple chunks.
735TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SplitOverlongControlFrame) {
736  const size_t kFirstChunkSize = 16;
737  expect_all_io_to_complete_ = false;
738  CreateChunkedRead(SYNCHRONOUS,
739                    k126BytePong,
740                    k126BytePongSize,
741                    kFirstChunkSize,
742                    2,
743                    LAST_FRAME_BIG);
744
745  EXPECT_EQ(ERR_WS_PROTOCOL_ERROR,
746            stream_->ReadFrames(&frames_, cb_.callback()));
747  EXPECT_TRUE(frames_.empty());
748}
749
750TEST_F(WebSocketBasicStreamSocketChunkedReadTest,
751       AsyncSplitOverlongControlFrame) {
752  const size_t kFirstChunkSize = 16;
753  expect_all_io_to_complete_ = false;
754  CreateChunkedRead(ASYNC,
755                    k126BytePong,
756                    k126BytePongSize,
757                    kFirstChunkSize,
758                    2,
759                    LAST_FRAME_BIG);
760
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());
766}
767
768// In the synchronous case, ReadFrames assembles the whole control frame before
769// returning.
770TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SyncControlFrameAssembly) {
771  const size_t kChunkSize = 3;
772  CreateChunkedRead(
773      SYNCHRONOUS, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG);
774
775  EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback()));
776  ASSERT_EQ(1U, frames_.size());
777  EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode);
778}
779
780// In the asynchronous case, the callback is not called until the control frame
781// has been completely assembled.
782TEST_F(WebSocketBasicStreamSocketChunkedReadTest, AsyncControlFrameAssembly) {
783  const size_t kChunkSize = 3;
784  CreateChunkedRead(
785      ASYNC, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG);
786
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);
791}
792
793// A frame with a 1MB payload that has to be read in chunks.
794TEST_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  WriteBigEndian(big_frame.get() + 2, kPayloadSize);
805  memset(big_frame.get() + kLargeFrameHeaderSize, 'A', kPayloadSize);
806
807  CreateChunkedRead(ASYNC,
808                    big_frame.get(),
809                    kWireSize,
810                    kReadBufferSize,
811                    kExpectedFrameCount,
812                    LAST_FRAME_BIG);
813
814  for (size_t frame = 0; frame < kExpectedFrameCount; ++frame) {
815    frames_.clear();
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;
820    if (frame == 0) {
821      expected_payload_size = kReadBufferSize - kLargeFrameHeaderSize;
822    } else if (frame == kExpectedFrameCount - 1) {
823      expected_payload_size = kLargeFrameHeaderSize;
824    }
825    EXPECT_EQ(expected_payload_size, frames_[0]->header.payload_length);
826  }
827}
828
829// Check that writing a frame all at once works.
830TEST_F(WebSocketBasicStreamSocketWriteTest, WriteAtOnce) {
831  MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)};
832  CreateWriteOnly(writes);
833
834  EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback()));
835}
836
837// Check that completely async writing works.
838TEST_F(WebSocketBasicStreamSocketWriteTest, AsyncWriteAtOnce) {
839  MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)};
840  CreateWriteOnly(writes);
841
842  ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback()));
843  EXPECT_EQ(OK, cb_.WaitForResult());
844}
845
846// Check that writing a frame to an extremely full kernel buffer (so that it
847// ends up being sent in bits) works. The WriteFrames() callback should not be
848// called until all parts have been written.
849TEST_F(WebSocketBasicStreamSocketWriteTest, WriteInBits) {
850  MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4),
851                        MockWrite(ASYNC, kWriteFrame + 4, 4),
852                        MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)};
853  CreateWriteOnly(writes);
854
855  ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback()));
856  EXPECT_EQ(OK, cb_.WaitForResult());
857}
858
859// Check that writing with a non-NULL mask works correctly.
860TEST_F(WebSocketBasicStreamSocketTest, WriteNonNulMask) {
861  std::string masked_frame = std::string("\x81\x88");
862  masked_frame += std::string(kNonNulMaskingKey.key, 4);
863  masked_frame += "jiggered";
864  MockWrite writes[] = {
865      MockWrite(SYNCHRONOUS, masked_frame.data(), masked_frame.size())};
866  generator_ = &GenerateNonNulMaskingKey;
867  CreateStream(NULL, 0, writes, arraysize(writes));
868
869  scoped_ptr<WebSocketFrame> frame(
870      new WebSocketFrame(WebSocketFrameHeader::kOpCodeText));
871  const std::string unmasked_payload = "graphics";
872  const size_t payload_size = unmasked_payload.size();
873  frame->data = new IOBuffer(payload_size);
874  memcpy(frame->data->data(), unmasked_payload.data(), payload_size);
875  WebSocketFrameHeader& header = frame->header;
876  header.final = true;
877  header.masked = true;
878  header.payload_length = payload_size;
879  frames_.push_back(frame.release());
880
881  EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback()));
882}
883
884TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) {
885  extensions_ = "inflate-uuencode";
886  CreateNullStream();
887
888  EXPECT_EQ("inflate-uuencode", stream_->GetExtensions());
889}
890
891TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) {
892  sub_protocol_ = "cyberchat";
893  CreateNullStream();
894
895  EXPECT_EQ("cyberchat", stream_->GetSubProtocol());
896}
897
898}  // namespace
899}  // namespace net
900