Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Tests for WebSocketBasicStream. Note that we do not attempt to verify that | 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 | 6 // frame parsing itself functions correctly, as that is covered by the |
| 7 // WebSocketFrameParser tests. | 7 // WebSocketFrameParser tests. |
| 8 | 8 |
| 9 #include "net/websockets/websocket_basic_stream.h" | 9 #include "net/websockets/websocket_basic_stream.h" |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 "chromiunum ad pasco per loca insanis pullum manducat frumenti"; | 30 "chromiunum ad pasco per loca insanis pullum manducat frumenti"; |
| 31 const size_t kPartialLargeFrameSize = arraysize(kPartialLargeFrame) - 1; | 31 const size_t kPartialLargeFrameSize = arraysize(kPartialLargeFrame) - 1; |
| 32 const size_t kLargeFrameHeaderSize = 10; | 32 const size_t kLargeFrameHeaderSize = 10; |
| 33 const size_t kLargeFrameDeclaredPayloadSize = 0x7FFFFFFF; | 33 const size_t kLargeFrameDeclaredPayloadSize = 0x7FFFFFFF; |
| 34 const char kMultipleFrames[] = "\x81\x01X\x81\x01Y\x81\x01Z"; | 34 const char kMultipleFrames[] = "\x81\x01X\x81\x01Y\x81\x01Z"; |
| 35 const size_t kMultipleFramesSize = arraysize(kMultipleFrames) - 1; | 35 const size_t kMultipleFramesSize = arraysize(kMultipleFrames) - 1; |
| 36 // This frame encodes a payload length of 7 in two bytes, which is always | 36 // This frame encodes a payload length of 7 in two bytes, which is always |
| 37 // invalid. | 37 // invalid. |
| 38 const char kInvalidFrame[] = "\x81\x7E\x00\x07Invalid"; | 38 const char kInvalidFrame[] = "\x81\x7E\x00\x07Invalid"; |
| 39 const size_t kInvalidFrameSize = arraysize(kInvalidFrame) - 1; | 39 const size_t kInvalidFrameSize = arraysize(kInvalidFrame) - 1; |
| 40 // Control frames must have the FIN bit set. This one does not. | |
| 41 const char kPingFrameWithoutFin[] = "\x0A\x00"; | |
| 42 const size_t kPingFrameWithoutFinSize = arraysize(kPingFrameWithoutFin) - 1; | |
| 43 // Control frames must have a payload of 125 bytes or less. This one has | |
| 44 // a payload of 126 bytes. | |
| 45 const char k126BytePong[] = | |
| 46 "\x89\x7e\x00\x7eZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" | |
| 47 "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; | |
| 48 const size_t k126BytePongSize = arraysize(k126BytePong) - 1; | |
| 49 const char kCloseFrame[] = "\x88\x09\x03\xe8occludo"; | |
| 50 const size_t kCloseFrameSize = arraysize(kCloseFrame) - 1; | |
| 40 const char kWriteFrame[] = "\x81\x85\x00\x00\x00\x00Write"; | 51 const char kWriteFrame[] = "\x81\x85\x00\x00\x00\x00Write"; |
| 41 const size_t kWriteFrameSize = arraysize(kWriteFrame) - 1; | 52 const size_t kWriteFrameSize = arraysize(kWriteFrame) - 1; |
| 42 const WebSocketMaskingKey kNulMaskingKey = {{'\0', '\0', '\0', '\0'}}; | 53 const WebSocketMaskingKey kNulMaskingKey = {{'\0', '\0', '\0', '\0'}}; |
| 43 | 54 |
| 44 // Generates a ScopedVector<WebSocketFrameChunk> which will have a wire format | 55 // Generates a ScopedVector<WebSocketFrame> which will have a wire format |
| 45 // matching kWriteFrame. | 56 // matching kWriteFrame. |
| 46 ScopedVector<WebSocketFrameChunk> GenerateWriteFrame() { | 57 ScopedVector<WebSocketFrame> GenerateWriteFrame() { |
|
yhirano
2013/09/13 10:03:17
Why do you use ScopedVector instead of scoptr_ptr?
Adam Rice
2013/09/13 14:09:53
I realised I was always calling it in the same way
| |
| 47 scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk); | 58 scoped_ptr<WebSocketFrame> frame( |
| 59 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText)); | |
| 48 const size_t payload_size = | 60 const size_t payload_size = |
| 49 kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize + | 61 kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize + |
| 50 WebSocketFrameHeader::kMaskingKeyLength); | 62 WebSocketFrameHeader::kMaskingKeyLength); |
| 51 chunk->data = new IOBufferWithSize(payload_size); | 63 frame->data = new IOBufferWithSize(payload_size); |
| 52 memcpy(chunk->data->data(), | 64 memcpy(frame->data->data(), |
| 53 kWriteFrame + kWriteFrameSize - payload_size, | 65 kWriteFrame + kWriteFrameSize - payload_size, |
| 54 payload_size); | 66 payload_size); |
| 55 chunk->final_chunk = true; | 67 WebSocketFrameHeader& header = frame->header; |
| 56 scoped_ptr<WebSocketFrameHeader> header( | 68 header.final = true; |
| 57 new WebSocketFrameHeader(WebSocketFrameHeader::kOpCodeText)); | 69 header.masked = true; |
| 58 header->final = true; | 70 header.payload_length = payload_size; |
| 59 header->masked = true; | 71 ScopedVector<WebSocketFrame> frames; |
| 60 header->payload_length = payload_size; | 72 frames.push_back(frame.release()); |
| 61 chunk->header = header.Pass(); | 73 return frames.Pass(); |
| 62 ScopedVector<WebSocketFrameChunk> chunks; | |
| 63 chunks.push_back(chunk.release()); | |
| 64 return chunks.Pass(); | |
| 65 } | 74 } |
| 66 | 75 |
| 67 // A masking key generator function which generates the identity mask, | 76 // A masking key generator function which generates the identity mask, |
| 68 // ie. "\0\0\0\0". | 77 // ie. "\0\0\0\0". |
| 69 WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; } | 78 WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; } |
| 70 | 79 |
| 71 // Base class for WebSocketBasicStream test fixtures. | 80 // Base class for WebSocketBasicStream test fixtures. |
| 72 class WebSocketBasicStreamTest : public ::testing::Test { | 81 class WebSocketBasicStreamTest : public ::testing::Test { |
| 73 protected: | 82 protected: |
| 74 scoped_ptr<WebSocketBasicStream> stream_; | 83 scoped_ptr<WebSocketBasicStream> stream_; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 CreateStream(NULL, 0, writes, N); | 145 CreateStream(NULL, 0, writes, N); |
| 137 } | 146 } |
| 138 | 147 |
| 139 void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); } | 148 void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); } |
| 140 | 149 |
| 141 scoped_ptr<SocketDataProvider> socket_data_; | 150 scoped_ptr<SocketDataProvider> socket_data_; |
| 142 MockClientSocketFactory factory_; | 151 MockClientSocketFactory factory_; |
| 143 ClientSocketPoolHistograms histograms_; | 152 ClientSocketPoolHistograms histograms_; |
| 144 MockTransportClientSocketPool pool_; | 153 MockTransportClientSocketPool pool_; |
| 145 CapturingBoundNetLog(bound_net_log_); | 154 CapturingBoundNetLog(bound_net_log_); |
| 146 ScopedVector<WebSocketFrameChunk> frame_chunks_; | 155 ScopedVector<WebSocketFrame> frames_; |
| 147 TestCompletionCallback cb_; | 156 TestCompletionCallback cb_; |
| 148 scoped_refptr<GrowableIOBuffer> http_read_buffer_; | 157 scoped_refptr<GrowableIOBuffer> http_read_buffer_; |
| 149 std::string sub_protocol_; | 158 std::string sub_protocol_; |
| 150 std::string extensions_; | 159 std::string extensions_; |
| 151 }; | 160 }; |
| 152 | 161 |
| 162 // A test fixture for the common case of tests that only perform a single read. | |
| 163 class WebSocketBasicStreamSocketSingleReadTest | |
| 164 : public WebSocketBasicStreamSocketTest { | |
| 165 protected: | |
| 166 void CreateRead(const MockRead& read) { | |
| 167 reads_[0] = read; | |
| 168 CreateStream(reads_, 1U, NULL, 0); | |
| 169 } | |
| 170 | |
| 171 MockRead reads_[1]; | |
| 172 }; | |
| 173 | |
| 174 // A test fixture for tests that perform chunked reads. | |
| 175 class WebSocketBasicStreamSocketChunkedReadTest | |
| 176 : public WebSocketBasicStreamSocketTest { | |
| 177 protected: | |
| 178 // Specify the behaviour if there aren't enough chunks to use all the data. If | |
| 179 // LAST_FRAME_BIG is specified, the the rest of the data will be | |
| 180 // put in the last chunk. If LAST_FRAME_NOT_BIG is specified, then the last | |
| 181 // frame will be no bigger than the rest of the frames (but it can be smaller, | |
| 182 // if not enough data remains). | |
| 183 enum LastFrameBehaviour { | |
| 184 LAST_FRAME_BIG, | |
| 185 LAST_FRAME_NOT_BIG | |
| 186 }; | |
| 187 | |
| 188 // Prepares a read from |data| of |data_size|, split into |number_of_chunks|, | |
| 189 // each of |chunk_size| (except that the last chunk may be larger or | |
| 190 // smaller). All reads must be either SYNCHRONOUS or ASYNC (not a mixture), | |
| 191 // and errors cannot be simulated. Once data is exhausted, further reads will | |
| 192 // return 0 (ie. connection closed). | |
| 193 void CreateChunkedRead(IoMode mode, | |
| 194 const char data[], | |
| 195 size_t data_size, | |
| 196 int chunk_size, | |
| 197 int number_of_chunks, | |
| 198 LastFrameBehaviour last_frame_behaviour) { | |
| 199 reads_.reset(new MockRead[number_of_chunks]); | |
| 200 const char* start = data; | |
| 201 for (int i = 0; i < number_of_chunks; ++i) { | |
| 202 int len = chunk_size; | |
| 203 if (last_frame_behaviour == LAST_FRAME_BIG && i == number_of_chunks - 1 && | |
| 204 data + data_size - start > static_cast<size_t>(len)) { | |
|
yhirano
2013/09/13 10:03:17
Is the last condition necessary?
Adam Rice
2013/09/13 14:09:53
No. I have cleaned up this condition a bit.
| |
| 205 len = static_cast<int>(data + data_size - start); | |
| 206 } else if (data + data_size - start < static_cast<size_t>(len)) { | |
| 207 len = static_cast<int>(data + data_size - start); | |
| 208 } | |
| 209 reads_[i] = MockRead(mode, start, len); | |
| 210 start += len; | |
| 211 } | |
| 212 CreateStream(reads_.get(), number_of_chunks, NULL, 0); | |
| 213 } | |
| 214 | |
| 215 scoped_ptr<MockRead[]> reads_; | |
| 216 }; | |
| 217 | |
| 153 TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) { | 218 TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) { |
| 154 CreateNullStream(); | 219 CreateNullStream(); |
| 155 } | 220 } |
| 156 | 221 |
| 157 TEST_F(WebSocketBasicStreamSocketTest, SyncReadWorks) { | 222 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncReadWorks) { |
| 158 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize)}; | 223 CreateRead(MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize)); |
| 159 CreateReadOnly(reads); | 224 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
| 160 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
| 161 EXPECT_EQ(OK, result); | 225 EXPECT_EQ(OK, result); |
| 162 ASSERT_EQ(1U, frame_chunks_.size()); | 226 ASSERT_EQ(1U, frames_.size()); |
| 163 ASSERT_TRUE(frame_chunks_[0]->header); | 227 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 164 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | 228 EXPECT_TRUE(frames_[0]->header.final); |
| 165 EXPECT_TRUE(frame_chunks_[0]->header->final); | |
| 166 EXPECT_TRUE(frame_chunks_[0]->final_chunk); | |
| 167 } | 229 } |
| 168 | 230 |
| 169 TEST_F(WebSocketBasicStreamSocketTest, AsyncReadWorks) { | 231 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncReadWorks) { |
| 170 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kSampleFrameSize)}; | 232 CreateRead(MockRead(ASYNC, kSampleFrame, kSampleFrameSize)); |
| 171 CreateReadOnly(reads); | 233 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
| 172 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
| 173 ASSERT_EQ(ERR_IO_PENDING, result); | 234 ASSERT_EQ(ERR_IO_PENDING, result); |
| 174 EXPECT_EQ(OK, cb_.WaitForResult()); | 235 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 175 ASSERT_EQ(1U, frame_chunks_.size()); | 236 ASSERT_EQ(1U, frames_.size()); |
| 176 ASSERT_TRUE(frame_chunks_[0]->header); | 237 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 177 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | |
| 178 // Don't repeat all the tests from SyncReadWorks; just enough to be sure the | 238 // Don't repeat all the tests from SyncReadWorks; just enough to be sure the |
| 179 // frame was really read. | 239 // frame was really read. |
| 180 } | 240 } |
| 181 | 241 |
| 182 // ReadFrames will not return a frame whose header has not been wholly received. | 242 // ReadFrames will not return a frame whose header has not been wholly received. |
| 183 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSync) { | 243 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedSync) { |
| 184 MockRead reads[] = { | 244 CreateChunkedRead( |
| 185 MockRead(SYNCHRONOUS, kSampleFrame, 1), | 245 SYNCHRONOUS, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG); |
| 186 MockRead(SYNCHRONOUS, kSampleFrame + 1, kSampleFrameSize - 1)}; | 246 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
| 187 CreateReadOnly(reads); | |
| 188 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
| 189 ASSERT_EQ(OK, result); | 247 ASSERT_EQ(OK, result); |
| 190 ASSERT_EQ(1U, frame_chunks_.size()); | 248 ASSERT_EQ(1U, frames_.size()); |
| 191 ASSERT_TRUE(frame_chunks_[0]->header); | 249 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 192 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | |
| 193 } | 250 } |
| 194 | 251 |
| 195 // The same behaviour applies to asynchronous reads. | 252 // The same behaviour applies to asynchronous reads. |
| 196 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedAsync) { | 253 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedAsync) { |
| 197 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1), | 254 CreateChunkedRead( |
| 198 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 255 ASYNC, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG); |
| 199 CreateReadOnly(reads); | 256 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
| 200 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
| 201 ASSERT_EQ(ERR_IO_PENDING, result); | 257 ASSERT_EQ(ERR_IO_PENDING, result); |
| 202 EXPECT_EQ(OK, cb_.WaitForResult()); | 258 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 203 ASSERT_EQ(1U, frame_chunks_.size()); | 259 ASSERT_EQ(1U, frames_.size()); |
| 204 ASSERT_TRUE(frame_chunks_[0]->header); | 260 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 205 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | |
| 206 } | 261 } |
| 207 | 262 |
| 208 // If it receives an incomplete header in a synchronous call, then has to wait | 263 // If it receives an incomplete header in a synchronous call, then has to wait |
| 209 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING. | 264 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING. |
| 210 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) { | 265 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) { |
| 211 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1), | 266 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1), |
| 212 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 267 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; |
| 213 CreateReadOnly(reads); | 268 CreateReadOnly(reads); |
| 214 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | 269 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
| 215 ASSERT_EQ(ERR_IO_PENDING, result); | 270 ASSERT_EQ(ERR_IO_PENDING, result); |
| 216 EXPECT_EQ(OK, cb_.WaitForResult()); | 271 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 217 ASSERT_EQ(1U, frame_chunks_.size()); | 272 ASSERT_EQ(1U, frames_.size()); |
| 218 ASSERT_TRUE(frame_chunks_[0]->header); | 273 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 219 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | |
| 220 } | 274 } |
| 221 | 275 |
| 222 // An extended header should also return ERR_IO_PENDING if it is not completely | 276 // An extended header should also return ERR_IO_PENDING if it is not completely |
| 223 // received. | 277 // received. |
| 224 TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) { | 278 TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) { |
| 225 MockRead reads[] = { | 279 MockRead reads[] = { |
| 226 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1), | 280 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1), |
| 227 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; | 281 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; |
| 228 CreateReadOnly(reads); | 282 CreateReadOnly(reads); |
| 229 EXPECT_EQ(ERR_IO_PENDING, | 283 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 230 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 231 } | 284 } |
| 232 | 285 |
| 233 // A frame that does not arrive in a single read should arrive in chunks. | 286 // A frame that does not arrive in a single read should be broken into separate |
| 234 TEST_F(WebSocketBasicStreamSocketTest, LargeFrameFirstChunk) { | 287 // frames. |
| 235 MockRead reads[] = { | 288 TEST_F(WebSocketBasicStreamSocketSingleReadTest, LargeFrameFirstChunk) { |
| 236 MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize)}; | 289 CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize)); |
| 237 CreateReadOnly(reads); | 290 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 238 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 291 ASSERT_EQ(1U, frames_.size()); |
| 239 ASSERT_EQ(1U, frame_chunks_.size()); | 292 EXPECT_FALSE(frames_[0]->header.final); |
| 240 ASSERT_TRUE(frame_chunks_[0]->header); | |
| 241 EXPECT_EQ(kLargeFrameDeclaredPayloadSize, | |
| 242 frame_chunks_[0]->header->payload_length); | |
| 243 EXPECT_TRUE(frame_chunks_[0]->header->final); | |
| 244 EXPECT_FALSE(frame_chunks_[0]->final_chunk); | |
| 245 EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, | 293 EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, |
| 246 static_cast<size_t>(frame_chunks_[0]->data->size())); | 294 static_cast<size_t>(frames_[0]->header.payload_length)); |
| 247 } | 295 } |
| 248 | 296 |
| 249 // If only the header arrives, we should get a zero-byte chunk. | 297 // If only the header of a data frame arrives, we should not receive a frame and |
| 298 // be told to wait. WebSocketBasicStream does two reads in this case, as after | |
| 299 // the first read it has no frames to return. | |
| 250 TEST_F(WebSocketBasicStreamSocketTest, HeaderOnlyChunk) { | 300 TEST_F(WebSocketBasicStreamSocketTest, HeaderOnlyChunk) { |
| 251 MockRead reads[] = { | 301 MockRead reads[] = { |
| 252 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize)}; | 302 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize), |
| 303 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; | |
| 253 CreateReadOnly(reads); | 304 CreateReadOnly(reads); |
| 254 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 305 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 255 ASSERT_EQ(1U, frame_chunks_.size()); | 306 ASSERT_EQ(0U, frames_.size()); |
| 256 EXPECT_FALSE(frame_chunks_[0]->final_chunk); | |
| 257 EXPECT_TRUE(frame_chunks_[0]->data.get() == NULL); | |
| 258 } | 307 } |
| 259 | 308 |
| 260 // The second and subsequent chunks of a frame have no header. | 309 // If the header and the body of a data frame arrive seperately, we should only |
| 261 TEST_F(WebSocketBasicStreamSocketTest, LargeFrameTwoChunks) { | 310 // see one frame. |
| 262 static const size_t kChunkSize = 16; | 311 TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparated) { |
| 263 MockRead reads[] = { | 312 MockRead reads[] = { |
| 264 MockRead(ASYNC, kPartialLargeFrame, kChunkSize), | 313 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize), |
| 265 MockRead(ASYNC, kPartialLargeFrame + kChunkSize, kChunkSize)}; | 314 MockRead(ASYNC, |
| 315 kPartialLargeFrame + kLargeFrameHeaderSize, | |
| 316 kPartialLargeFrameSize - kLargeFrameHeaderSize)}; | |
| 266 CreateReadOnly(reads); | 317 CreateReadOnly(reads); |
| 318 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); | |
| 319 EXPECT_EQ(OK, cb_.WaitForResult()); | |
| 320 ASSERT_EQ(1U, frames_.size()); | |
| 321 EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, | |
| 322 frames_[0]->header.payload_length); | |
| 323 } | |
| 324 | |
| 325 // Every frame has a header with a correct payload_length field. | |
| 326 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, LargeFrameTwoChunks) { | |
| 327 const size_t kChunkSize = 16; | |
| 328 CreateChunkedRead(ASYNC, | |
| 329 kPartialLargeFrame, | |
| 330 kPartialLargeFrameSize, | |
| 331 kChunkSize, | |
| 332 2, | |
| 333 LAST_FRAME_NOT_BIG); | |
| 267 TestCompletionCallback cb[2]; | 334 TestCompletionCallback cb[2]; |
| 268 | 335 |
| 269 ASSERT_EQ(ERR_IO_PENDING, | 336 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback())); |
| 270 stream_->ReadFrames(&frame_chunks_, cb[0].callback())); | |
| 271 EXPECT_EQ(OK, cb[0].WaitForResult()); | 337 EXPECT_EQ(OK, cb[0].WaitForResult()); |
| 272 ASSERT_EQ(1U, frame_chunks_.size()); | 338 ASSERT_EQ(1U, frames_.size()); |
| 273 ASSERT_TRUE(frame_chunks_[0]->header); | 339 EXPECT_EQ(kChunkSize - kLargeFrameHeaderSize, |
| 340 frames_[0]->header.payload_length); | |
| 274 | 341 |
| 275 frame_chunks_.clear(); | 342 frames_.clear(); |
| 276 ASSERT_EQ(ERR_IO_PENDING, | 343 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[1].callback())); |
| 277 stream_->ReadFrames(&frame_chunks_, cb[1].callback())); | |
| 278 EXPECT_EQ(OK, cb[1].WaitForResult()); | 344 EXPECT_EQ(OK, cb[1].WaitForResult()); |
| 279 ASSERT_EQ(1U, frame_chunks_.size()); | 345 ASSERT_EQ(1U, frames_.size()); |
| 280 ASSERT_FALSE(frame_chunks_[0]->header); | 346 EXPECT_EQ(kChunkSize, frames_[0]->header.payload_length); |
| 281 } | 347 } |
| 282 | 348 |
| 283 // Only the final chunk of a frame has final_chunk set. | 349 // Only the final frame of a fragmented message has |final| bit set. |
| 284 TEST_F(WebSocketBasicStreamSocketTest, OnlyFinalChunkIsFinal) { | 350 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OnlyFinalChunkIsFinal) { |
| 285 static const size_t kFirstChunkSize = 4; | 351 static const size_t kFirstChunkSize = 4; |
| 286 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kFirstChunkSize), | 352 CreateChunkedRead(ASYNC, |
| 287 MockRead(ASYNC, | 353 kSampleFrame, |
| 288 kSampleFrame + kFirstChunkSize, | 354 kSampleFrameSize, |
| 289 kSampleFrameSize - kFirstChunkSize)}; | 355 kFirstChunkSize, |
| 290 CreateReadOnly(reads); | 356 2, |
| 357 LAST_FRAME_BIG); | |
| 291 TestCompletionCallback cb[2]; | 358 TestCompletionCallback cb[2]; |
| 292 | 359 |
| 293 ASSERT_EQ(ERR_IO_PENDING, | 360 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback())); |
| 294 stream_->ReadFrames(&frame_chunks_, cb[0].callback())); | |
| 295 EXPECT_EQ(OK, cb[0].WaitForResult()); | 361 EXPECT_EQ(OK, cb[0].WaitForResult()); |
| 296 ASSERT_EQ(1U, frame_chunks_.size()); | 362 ASSERT_EQ(1U, frames_.size()); |
| 297 ASSERT_FALSE(frame_chunks_[0]->final_chunk); | 363 ASSERT_FALSE(frames_[0]->header.final); |
| 298 | 364 |
| 299 frame_chunks_.clear(); | 365 frames_.clear(); |
| 300 ASSERT_EQ(ERR_IO_PENDING, | 366 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[1].callback())); |
| 301 stream_->ReadFrames(&frame_chunks_, cb[1].callback())); | |
| 302 EXPECT_EQ(OK, cb[1].WaitForResult()); | 367 EXPECT_EQ(OK, cb[1].WaitForResult()); |
| 303 ASSERT_EQ(1U, frame_chunks_.size()); | 368 ASSERT_EQ(1U, frames_.size()); |
| 304 ASSERT_TRUE(frame_chunks_[0]->final_chunk); | 369 ASSERT_TRUE(frames_[0]->header.final); |
| 305 } | 370 } |
| 306 | 371 |
| 307 // Multiple frames that arrive together should be parsed correctly. | 372 // Multiple frames that arrive together should be parsed correctly. |
| 308 TEST_F(WebSocketBasicStreamSocketTest, ThreeFramesTogether) { | 373 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ThreeFramesTogether) { |
| 309 MockRead reads[] = { | 374 CreateRead(MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize)); |
| 310 MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize)}; | |
| 311 CreateReadOnly(reads); | |
| 312 | 375 |
| 313 ASSERT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 376 ASSERT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 314 ASSERT_EQ(3U, frame_chunks_.size()); | 377 ASSERT_EQ(3U, frames_.size()); |
| 315 EXPECT_TRUE(frame_chunks_[0]->final_chunk); | 378 EXPECT_TRUE(frames_[0]->header.final); |
| 316 EXPECT_TRUE(frame_chunks_[1]->final_chunk); | 379 EXPECT_TRUE(frames_[1]->header.final); |
| 317 EXPECT_TRUE(frame_chunks_[2]->final_chunk); | 380 EXPECT_TRUE(frames_[2]->header.final); |
| 318 } | 381 } |
| 319 | 382 |
| 320 // ERR_CONNECTION_CLOSED must be returned on close. | 383 // ERR_CONNECTION_CLOSED must be returned on close. |
| 321 TEST_F(WebSocketBasicStreamSocketTest, SyncClose) { | 384 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncClose) { |
| 322 MockRead reads[] = {MockRead(SYNCHRONOUS, "", 0)}; | 385 CreateRead(MockRead(SYNCHRONOUS, "", 0)); |
| 323 CreateReadOnly(reads); | |
| 324 | 386 |
| 325 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 387 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| 326 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 388 stream_->ReadFrames(&frames_, cb_.callback())); |
| 327 } | 389 } |
| 328 | 390 |
| 329 TEST_F(WebSocketBasicStreamSocketTest, AsyncClose) { | 391 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncClose) { |
| 330 MockRead reads[] = {MockRead(ASYNC, "", 0)}; | 392 CreateRead(MockRead(ASYNC, "", 0)); |
| 331 CreateReadOnly(reads); | |
| 332 | 393 |
| 333 ASSERT_EQ(ERR_IO_PENDING, | 394 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 334 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 335 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); | 395 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| 336 } | 396 } |
| 337 | 397 |
| 338 // The result should be the same if the socket returns | 398 // The result should be the same if the socket returns |
| 339 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established | 399 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established |
| 340 // connection; a Read of size 0 is the expected behaviour. The key point of this | 400 // connection; a Read of size 0 is the expected behaviour. The key point of this |
| 341 // test is to confirm that ReadFrames() behaviour is identical in both cases. | 401 // test is to confirm that ReadFrames() behaviour is identical in both cases. |
| 342 TEST_F(WebSocketBasicStreamSocketTest, SyncCloseWithErr) { | 402 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncCloseWithErr) { |
| 343 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; | 403 CreateRead(MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)); |
| 344 CreateReadOnly(reads); | |
| 345 | 404 |
| 346 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 405 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| 347 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 406 stream_->ReadFrames(&frames_, cb_.callback())); |
| 348 } | 407 } |
| 349 | 408 |
| 350 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseWithErr) { | 409 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncCloseWithErr) { |
| 351 MockRead reads[] = {MockRead(ASYNC, ERR_CONNECTION_CLOSED)}; | 410 CreateRead(MockRead(ASYNC, ERR_CONNECTION_CLOSED)); |
| 352 CreateReadOnly(reads); | |
| 353 | 411 |
| 354 ASSERT_EQ(ERR_IO_PENDING, | 412 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 355 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 356 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); | 413 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| 357 } | 414 } |
| 358 | 415 |
| 359 TEST_F(WebSocketBasicStreamSocketTest, SyncErrorsPassedThrough) { | 416 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncErrorsPassedThrough) { |
| 360 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that | 417 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that |
| 361 // WebSocketBasicStream gives no special handling to. | 418 // WebSocketBasicStream gives no special handling to. |
| 362 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES)}; | 419 CreateRead(MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES)); |
| 363 CreateReadOnly(reads); | |
| 364 | 420 |
| 365 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, | 421 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, |
| 366 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 422 stream_->ReadFrames(&frames_, cb_.callback())); |
| 367 } | 423 } |
| 368 | 424 |
| 369 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrorsPassedThrough) { | 425 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncErrorsPassedThrough) { |
| 370 MockRead reads[] = {MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES)}; | 426 CreateRead(MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES)); |
| 371 CreateReadOnly(reads); | |
| 372 | 427 |
| 373 ASSERT_EQ(ERR_IO_PENDING, | 428 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 374 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 375 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, cb_.WaitForResult()); | 429 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, cb_.WaitForResult()); |
| 376 } | 430 } |
| 377 | 431 |
| 378 // If we get a frame followed by a close, we should receive them separately. | 432 // If we get a frame followed by a close, we should receive them separately. |
| 379 TEST_F(WebSocketBasicStreamSocketTest, CloseAfterFrame) { | 433 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, CloseAfterFrame) { |
| 380 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize), | 434 // The chunk size equals the data size, so the second chunk is 0 size, closing |
| 381 MockRead(SYNCHRONOUS, "", 0)}; | 435 // the connection. |
| 382 CreateReadOnly(reads); | 436 CreateChunkedRead(SYNCHRONOUS, |
| 437 kSampleFrame, | |
| 438 kSampleFrameSize, | |
| 439 kSampleFrameSize, | |
| 440 2, | |
| 441 LAST_FRAME_NOT_BIG); | |
| 383 | 442 |
| 384 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 443 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 385 EXPECT_EQ(1U, frame_chunks_.size()); | 444 EXPECT_EQ(1U, frames_.size()); |
| 386 frame_chunks_.clear(); | 445 frames_.clear(); |
| 387 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 446 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| 388 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 447 stream_->ReadFrames(&frames_, cb_.callback())); |
| 389 } | 448 } |
| 390 | 449 |
| 391 // Synchronous close after an async frame header is handled by a different code | 450 // Synchronous close after an async frame header is handled by a different code |
| 392 // path. | 451 // path. |
| 393 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) { | 452 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) { |
| 394 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), | 453 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
| 395 MockRead(SYNCHRONOUS, "", 0)}; | 454 MockRead(SYNCHRONOUS, "", 0)}; |
| 396 CreateReadOnly(reads); | 455 CreateReadOnly(reads); |
| 397 | 456 |
| 398 ASSERT_EQ(ERR_IO_PENDING, | 457 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 399 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 400 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); | 458 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| 401 } | 459 } |
| 402 | 460 |
| 403 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a | 461 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a |
| 404 // slightly different code path. | 462 // slightly different code path. |
| 405 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) { | 463 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) { |
| 406 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), | 464 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
| 407 MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; | 465 MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; |
| 408 CreateReadOnly(reads); | 466 CreateReadOnly(reads); |
| 409 | 467 |
| 410 ASSERT_EQ(ERR_IO_PENDING, | 468 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 411 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 412 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); | 469 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| 413 } | 470 } |
| 414 | 471 |
| 415 // If there was a frame read at the same time as the response headers (and the | 472 // If there was a frame read at the same time as the response headers (and the |
| 416 // handshake succeeded), then we should parse it. | 473 // handshake succeeded), then we should parse it. |
| 417 TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) { | 474 TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) { |
| 418 SetHttpReadBuffer(kSampleFrame, kSampleFrameSize); | 475 SetHttpReadBuffer(kSampleFrame, kSampleFrameSize); |
| 419 CreateNullStream(); | 476 CreateNullStream(); |
| 420 | 477 |
| 421 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 478 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 422 ASSERT_EQ(1U, frame_chunks_.size()); | 479 ASSERT_EQ(1U, frames_.size()); |
| 423 ASSERT_TRUE(frame_chunks_[0]->data); | 480 ASSERT_TRUE(frames_[0]->data); |
| 424 EXPECT_EQ(6, frame_chunks_[0]->data->size()); | 481 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 425 } | 482 } |
| 426 | 483 |
| 427 // Check that a frame whose header partially arrived at the end of the response | 484 // Check that a frame whose header partially arrived at the end of the response |
| 428 // headers works correctly. | 485 // headers works correctly. |
| 429 TEST_F(WebSocketBasicStreamSocketTest, PartialFrameHeaderInHttpResponse) { | 486 TEST_F(WebSocketBasicStreamSocketSingleReadTest, |
| 487 PartialFrameHeaderInHttpResponse) { | |
| 430 SetHttpReadBuffer(kSampleFrame, 1); | 488 SetHttpReadBuffer(kSampleFrame, 1); |
| 431 MockRead reads[] = {MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 489 CreateRead(MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)); |
| 432 CreateReadOnly(reads); | |
| 433 | 490 |
| 434 ASSERT_EQ(ERR_IO_PENDING, | 491 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 435 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 436 EXPECT_EQ(OK, cb_.WaitForResult()); | 492 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 437 ASSERT_EQ(1U, frame_chunks_.size()); | 493 ASSERT_EQ(1U, frames_.size()); |
| 438 ASSERT_TRUE(frame_chunks_[0]->data); | 494 ASSERT_TRUE(frames_[0]->data); |
| 439 EXPECT_EQ(6, frame_chunks_[0]->data->size()); | 495 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
| 440 ASSERT_TRUE(frame_chunks_[0]->header); | 496 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode); |
| 441 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, | |
| 442 frame_chunks_[0]->header->opcode); | |
| 443 } | 497 } |
| 444 | 498 |
| 445 // Check that an invalid frame results in an error. | 499 // Check that an invalid frame results in an error. |
| 446 TEST_F(WebSocketBasicStreamSocketTest, SyncInvalidFrame) { | 500 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncInvalidFrame) { |
| 447 MockRead reads[] = {MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize)}; | 501 CreateRead(MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize)); |
| 448 CreateReadOnly(reads); | |
| 449 | 502 |
| 450 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, | 503 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, |
| 451 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 504 stream_->ReadFrames(&frames_, cb_.callback())); |
| 452 } | 505 } |
| 453 | 506 |
| 454 TEST_F(WebSocketBasicStreamSocketTest, AsyncInvalidFrame) { | 507 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncInvalidFrame) { |
| 455 MockRead reads[] = {MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize)}; | 508 CreateRead(MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize)); |
| 456 CreateReadOnly(reads); | |
| 457 | 509 |
| 458 ASSERT_EQ(ERR_IO_PENDING, | 510 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 459 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
| 460 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); | 511 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); |
| 461 } | 512 } |
| 462 | 513 |
| 514 // A control frame without a FIN flag is invalid and should not be passed | |
| 515 // through to higher layers. RFC6455 5.5 "All control frames ... MUST NOT be | |
| 516 // fragmented." | |
| 517 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ControlFrameWithoutFin) { | |
| 518 CreateRead( | |
| 519 MockRead(SYNCHRONOUS, kPingFrameWithoutFin, kPingFrameWithoutFinSize)); | |
| 520 | |
| 521 ASSERT_EQ(ERR_WS_PROTOCOL_ERROR, | |
| 522 stream_->ReadFrames(&frames_, cb_.callback())); | |
| 523 EXPECT_TRUE(frames_.empty()); | |
| 524 } | |
| 525 | |
| 526 // A control frame over 125 characters is invalid. RFC6455 5.5 "All control | |
| 527 // frames MUST have a payload length of 125 bytes or less". Since we use a | |
| 528 // 125-byte buffer to assemble fragmented control frames, we need to detect this | |
| 529 // error before attempting to assemble the fragments. | |
| 530 TEST_F(WebSocketBasicStreamSocketSingleReadTest, OverlongControlFrame) { | |
| 531 CreateRead(MockRead(SYNCHRONOUS, k126BytePong, k126BytePongSize)); | |
| 532 | |
| 533 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, | |
| 534 stream_->ReadFrames(&frames_, cb_.callback())); | |
| 535 EXPECT_TRUE(frames_.empty()); | |
| 536 } | |
| 537 | |
| 538 // A control frame over 125 characters should still be rejected if it is split | |
| 539 // into multiple chunks. | |
| 540 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SplitOverlongControlFrame) { | |
| 541 const size_t kFirstChunkSize = 16; | |
| 542 CreateChunkedRead(SYNCHRONOUS, | |
| 543 k126BytePong, | |
| 544 k126BytePongSize, | |
| 545 kFirstChunkSize, | |
| 546 2, | |
| 547 LAST_FRAME_BIG); | |
| 548 | |
| 549 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, | |
| 550 stream_->ReadFrames(&frames_, cb_.callback())); | |
| 551 EXPECT_TRUE(frames_.empty()); | |
| 552 } | |
| 553 | |
| 554 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, | |
| 555 AsyncSplitOverlongControlFrame) { | |
| 556 const size_t kFirstChunkSize = 16; | |
| 557 CreateChunkedRead(ASYNC, | |
| 558 k126BytePong, | |
| 559 k126BytePongSize, | |
| 560 kFirstChunkSize, | |
| 561 2, | |
| 562 LAST_FRAME_BIG); | |
| 563 | |
| 564 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); | |
| 565 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); | |
| 566 // The caller should not call ReadFrames() again after receiving an error | |
| 567 // other than ERR_IO_PENDING. | |
| 568 EXPECT_TRUE(frames_.empty()); | |
| 569 } | |
| 570 | |
| 571 // In the synchronous case, ReadFrames assembles the whole control frame before | |
| 572 // returning. | |
| 573 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SyncControlFrameAssembly) { | |
| 574 const size_t kChunkSize = 3; | |
| 575 CreateChunkedRead( | |
| 576 SYNCHRONOUS, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG); | |
| 577 | |
| 578 ASSERT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); | |
| 579 ASSERT_EQ(1U, frames_.size()); | |
| 580 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); | |
| 581 } | |
| 582 | |
| 583 // In the asynchronous case, the callback is not called until the control frame | |
| 584 // has been completely assembled. | |
| 585 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, AsyncControlFrameAssembly) { | |
| 586 const size_t kChunkSize = 3; | |
| 587 CreateChunkedRead( | |
| 588 ASYNC, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG); | |
| 589 | |
| 590 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); | |
| 591 ASSERT_EQ(OK, cb_.WaitForResult()); | |
| 592 ASSERT_EQ(1U, frames_.size()); | |
| 593 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); | |
| 594 } | |
| 595 | |
| 463 // Check that writing a frame all at once works. | 596 // Check that writing a frame all at once works. |
| 464 TEST_F(WebSocketBasicStreamSocketTest, WriteAtOnce) { | 597 TEST_F(WebSocketBasicStreamSocketTest, WriteAtOnce) { |
| 465 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)}; | 598 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)}; |
| 466 CreateWriteOnly(writes); | 599 CreateWriteOnly(writes); |
| 467 frame_chunks_ = GenerateWriteFrame(); | 600 frames_ = GenerateWriteFrame(); |
| 468 | 601 |
| 469 EXPECT_EQ(OK, stream_->WriteFrames(&frame_chunks_, cb_.callback())); | 602 EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback())); |
| 470 } | 603 } |
| 471 | 604 |
| 472 // Check that completely async writing works. | 605 // Check that completely async writing works. |
| 473 TEST_F(WebSocketBasicStreamSocketTest, AsyncWriteAtOnce) { | 606 TEST_F(WebSocketBasicStreamSocketTest, AsyncWriteAtOnce) { |
| 474 MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)}; | 607 MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)}; |
| 475 CreateWriteOnly(writes); | 608 CreateWriteOnly(writes); |
| 476 frame_chunks_ = GenerateWriteFrame(); | 609 frames_ = GenerateWriteFrame(); |
| 477 | 610 |
| 478 ASSERT_EQ(ERR_IO_PENDING, | 611 ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback())); |
| 479 stream_->WriteFrames(&frame_chunks_, cb_.callback())); | |
| 480 EXPECT_EQ(OK, cb_.WaitForResult()); | 612 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 481 } | 613 } |
| 482 | 614 |
| 483 // Check that writing a frame to an extremely full kernel buffer (so that it | 615 // Check that writing a frame to an extremely full kernel buffer (so that it |
| 484 // ends up being sent in bits) works. The WriteFrames() callback should not be | 616 // ends up being sent in bits) works. The WriteFrames() callback should not be |
| 485 // called until all parts have been written. | 617 // called until all parts have been written. |
| 486 TEST_F(WebSocketBasicStreamSocketTest, WriteInBits) { | 618 TEST_F(WebSocketBasicStreamSocketTest, WriteInBits) { |
| 487 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4), | 619 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4), |
| 488 MockWrite(ASYNC, kWriteFrame + 4, 4), | 620 MockWrite(ASYNC, kWriteFrame + 4, 4), |
| 489 MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)}; | 621 MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)}; |
| 490 CreateWriteOnly(writes); | 622 CreateWriteOnly(writes); |
| 491 frame_chunks_ = GenerateWriteFrame(); | 623 frames_ = GenerateWriteFrame(); |
| 492 | 624 |
| 493 ASSERT_EQ(ERR_IO_PENDING, | 625 ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback())); |
| 494 stream_->WriteFrames(&frame_chunks_, cb_.callback())); | |
| 495 EXPECT_EQ(OK, cb_.WaitForResult()); | 626 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 496 } | 627 } |
| 497 | 628 |
| 498 TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) { | 629 TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) { |
| 499 extensions_ = "inflate-uuencode"; | 630 extensions_ = "inflate-uuencode"; |
| 500 CreateNullStream(); | 631 CreateNullStream(); |
| 501 | 632 |
| 502 EXPECT_EQ("inflate-uuencode", stream_->GetExtensions()); | 633 EXPECT_EQ("inflate-uuencode", stream_->GetExtensions()); |
| 503 } | 634 } |
| 504 | 635 |
| 505 TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) { | 636 TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) { |
| 506 sub_protocol_ = "cyberchat"; | 637 sub_protocol_ = "cyberchat"; |
| 507 CreateNullStream(); | 638 CreateNullStream(); |
| 508 | 639 |
| 509 EXPECT_EQ("cyberchat", stream_->GetSubProtocol()); | 640 EXPECT_EQ("cyberchat", stream_->GetSubProtocol()); |
| 510 } | 641 } |
| 511 | 642 |
| 512 } // namespace | 643 } // namespace |
| 513 } // namespace net | 644 } // namespace net |
|
yhirano
2013/09/13 10:03:17
It's good to have a test that checks if the opcode
Adam Rice
2013/09/13 14:09:53
Added test "ContinuationOpCodeUsed".
| |
| OLD | NEW |