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 |