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[] = "\x09\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 "\x8a\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 | |
45 // matching kWriteFrame. | |
46 ScopedVector<WebSocketFrameChunk> GenerateWriteFrame() { | |
47 scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk); | |
48 const size_t payload_size = | |
49 kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize + | |
50 WebSocketFrameHeader::kMaskingKeyLength); | |
51 chunk->data = new IOBufferWithSize(payload_size); | |
52 memcpy(chunk->data->data(), | |
53 kWriteFrame + kWriteFrameSize - payload_size, | |
54 payload_size); | |
55 chunk->final_chunk = true; | |
56 scoped_ptr<WebSocketFrameHeader> header( | |
57 new WebSocketFrameHeader(WebSocketFrameHeader::kOpCodeText)); | |
58 header->final = true; | |
59 header->masked = true; | |
60 header->payload_length = payload_size; | |
61 chunk->header = header.Pass(); | |
62 ScopedVector<WebSocketFrameChunk> chunks; | |
63 chunks.push_back(chunk.release()); | |
64 return chunks.Pass(); | |
65 } | |
66 | |
67 // A masking key generator function which generates the identity mask, | 55 // A masking key generator function which generates the identity mask, |
68 // ie. "\0\0\0\0". | 56 // ie. "\0\0\0\0". |
69 WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; } | 57 WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; } |
70 | 58 |
71 // Base class for WebSocketBasicStream test fixtures. | 59 // Base class for WebSocketBasicStream test fixtures. |
72 class WebSocketBasicStreamTest : public ::testing::Test { | 60 class WebSocketBasicStreamTest : public ::testing::Test { |
73 protected: | 61 protected: |
74 scoped_ptr<WebSocketBasicStream> stream_; | 62 scoped_ptr<WebSocketBasicStream> stream_; |
75 CapturingNetLog net_log_; | 63 CapturingNetLog net_log_; |
76 }; | 64 }; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 sub_protocol_, | 112 sub_protocol_, |
125 extensions_, | 113 extensions_, |
126 &GenerateNulMaskingKey); | 114 &GenerateNulMaskingKey); |
127 } | 115 } |
128 | 116 |
129 template <size_t N> | 117 template <size_t N> |
130 void CreateReadOnly(MockRead (&reads)[N]) { | 118 void CreateReadOnly(MockRead (&reads)[N]) { |
131 CreateStream(reads, N, NULL, 0); | 119 CreateStream(reads, N, NULL, 0); |
132 } | 120 } |
133 | 121 |
134 template <size_t N> | |
135 void CreateWriteOnly(MockWrite (&writes)[N]) { | |
136 CreateStream(NULL, 0, writes, N); | |
137 } | |
138 | |
139 void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); } | 122 void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); } |
140 | 123 |
141 scoped_ptr<SocketDataProvider> socket_data_; | 124 scoped_ptr<SocketDataProvider> socket_data_; |
142 MockClientSocketFactory factory_; | 125 MockClientSocketFactory factory_; |
143 ClientSocketPoolHistograms histograms_; | 126 ClientSocketPoolHistograms histograms_; |
144 MockTransportClientSocketPool pool_; | 127 MockTransportClientSocketPool pool_; |
145 CapturingBoundNetLog(bound_net_log_); | 128 CapturingBoundNetLog(bound_net_log_); |
146 ScopedVector<WebSocketFrameChunk> frame_chunks_; | 129 ScopedVector<WebSocketFrame> frames_; |
147 TestCompletionCallback cb_; | 130 TestCompletionCallback cb_; |
148 scoped_refptr<GrowableIOBuffer> http_read_buffer_; | 131 scoped_refptr<GrowableIOBuffer> http_read_buffer_; |
149 std::string sub_protocol_; | 132 std::string sub_protocol_; |
150 std::string extensions_; | 133 std::string extensions_; |
151 }; | 134 }; |
152 | 135 |
| 136 // A test fixture for the common case of tests that only perform a single read. |
| 137 class WebSocketBasicStreamSocketSingleReadTest |
| 138 : public WebSocketBasicStreamSocketTest { |
| 139 protected: |
| 140 void CreateRead(const MockRead& read) { |
| 141 reads_[0] = read; |
| 142 CreateStream(reads_, 1U, NULL, 0); |
| 143 } |
| 144 |
| 145 MockRead reads_[1]; |
| 146 }; |
| 147 |
| 148 // A test fixture for tests that perform chunked reads. |
| 149 class WebSocketBasicStreamSocketChunkedReadTest |
| 150 : public WebSocketBasicStreamSocketTest { |
| 151 protected: |
| 152 // Specify the behaviour if there aren't enough chunks to use all the data. If |
| 153 // LAST_FRAME_BIG is specified, then the rest of the data will be |
| 154 // put in the last chunk. If LAST_FRAME_NOT_BIG is specified, then the last |
| 155 // frame will be no bigger than the rest of the frames (but it can be smaller, |
| 156 // if not enough data remains). |
| 157 enum LastFrameBehaviour { |
| 158 LAST_FRAME_BIG, |
| 159 LAST_FRAME_NOT_BIG |
| 160 }; |
| 161 |
| 162 // Prepares a read from |data| of |data_size|, split into |number_of_chunks|, |
| 163 // each of |chunk_size| (except that the last chunk may be larger or |
| 164 // smaller). All reads must be either SYNCHRONOUS or ASYNC (not a mixture), |
| 165 // and errors cannot be simulated. Once data is exhausted, further reads will |
| 166 // return 0 (ie. connection closed). |
| 167 void CreateChunkedRead(IoMode mode, |
| 168 const char data[], |
| 169 size_t data_size, |
| 170 int chunk_size, |
| 171 int number_of_chunks, |
| 172 LastFrameBehaviour last_frame_behaviour) { |
| 173 reads_.reset(new MockRead[number_of_chunks]); |
| 174 const char* start = data; |
| 175 for (int i = 0; i < number_of_chunks; ++i) { |
| 176 int len = chunk_size; |
| 177 const bool is_last_chunk = (i == number_of_chunks - 1); |
| 178 if ((last_frame_behaviour == LAST_FRAME_BIG && is_last_chunk) || |
| 179 static_cast<int>(data + data_size - start) < len) { |
| 180 len = static_cast<int>(data + data_size - start); |
| 181 } |
| 182 reads_[i] = MockRead(mode, start, len); |
| 183 start += len; |
| 184 } |
| 185 CreateStream(reads_.get(), number_of_chunks, NULL, 0); |
| 186 } |
| 187 |
| 188 scoped_ptr<MockRead[]> reads_; |
| 189 }; |
| 190 |
| 191 // Test fixture for write tests. |
| 192 class WebSocketBasicStreamSocketWriteTest |
| 193 : public WebSocketBasicStreamSocketTest { |
| 194 protected: |
| 195 // All write tests use the same frame, so it is easiest to create it during |
| 196 // test creation. |
| 197 virtual void SetUp() OVERRIDE { PrepareWriteFrame(); } |
| 198 |
| 199 // Creates a WebSocketFrame with a wire format matching kWriteFrame and adds |
| 200 // it to |frames_|. |
| 201 void PrepareWriteFrame() { |
| 202 scoped_ptr<WebSocketFrame> frame( |
| 203 new WebSocketFrame(WebSocketFrameHeader::kOpCodeText)); |
| 204 const size_t payload_size = |
| 205 kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize + |
| 206 WebSocketFrameHeader::kMaskingKeyLength); |
| 207 frame->data = new IOBuffer(payload_size); |
| 208 memcpy(frame->data->data(), |
| 209 kWriteFrame + kWriteFrameSize - payload_size, |
| 210 payload_size); |
| 211 WebSocketFrameHeader& header = frame->header; |
| 212 header.final = true; |
| 213 header.masked = true; |
| 214 header.payload_length = payload_size; |
| 215 frames_.push_back(frame.release()); |
| 216 } |
| 217 |
| 218 // Creates a stream that expects the listed writes. |
| 219 template <size_t N> |
| 220 void CreateWriteOnly(MockWrite (&writes)[N]) { |
| 221 CreateStream(NULL, 0, writes, N); |
| 222 } |
| 223 }; |
| 224 |
153 TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) { | 225 TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) { |
154 CreateNullStream(); | 226 CreateNullStream(); |
155 } | 227 } |
156 | 228 |
157 TEST_F(WebSocketBasicStreamSocketTest, SyncReadWorks) { | 229 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncReadWorks) { |
158 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize)}; | 230 CreateRead(MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize)); |
159 CreateReadOnly(reads); | 231 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
160 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
161 EXPECT_EQ(OK, result); | 232 EXPECT_EQ(OK, result); |
162 ASSERT_EQ(1U, frame_chunks_.size()); | 233 ASSERT_EQ(1U, frames_.size()); |
163 ASSERT_TRUE(frame_chunks_[0]->header); | 234 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
164 EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); | 235 EXPECT_TRUE(frames_[0]->header.final); |
165 EXPECT_TRUE(frame_chunks_[0]->header->final); | |
166 EXPECT_TRUE(frame_chunks_[0]->final_chunk); | |
167 } | 236 } |
168 | 237 |
169 TEST_F(WebSocketBasicStreamSocketTest, AsyncReadWorks) { | 238 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncReadWorks) { |
170 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kSampleFrameSize)}; | 239 CreateRead(MockRead(ASYNC, kSampleFrame, kSampleFrameSize)); |
171 CreateReadOnly(reads); | 240 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
172 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
173 ASSERT_EQ(ERR_IO_PENDING, result); | 241 ASSERT_EQ(ERR_IO_PENDING, result); |
174 EXPECT_EQ(OK, cb_.WaitForResult()); | 242 EXPECT_EQ(OK, cb_.WaitForResult()); |
175 ASSERT_EQ(1U, frame_chunks_.size()); | 243 ASSERT_EQ(1U, frames_.size()); |
176 ASSERT_TRUE(frame_chunks_[0]->header); | 244 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 | 245 // Don't repeat all the tests from SyncReadWorks; just enough to be sure the |
179 // frame was really read. | 246 // frame was really read. |
180 } | 247 } |
181 | 248 |
182 // ReadFrames will not return a frame whose header has not been wholly received. | 249 // ReadFrames will not return a frame whose header has not been wholly received. |
183 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSync) { | 250 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedSync) { |
184 MockRead reads[] = { | 251 CreateChunkedRead( |
185 MockRead(SYNCHRONOUS, kSampleFrame, 1), | 252 SYNCHRONOUS, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG); |
186 MockRead(SYNCHRONOUS, kSampleFrame + 1, kSampleFrameSize - 1)}; | 253 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
187 CreateReadOnly(reads); | |
188 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
189 ASSERT_EQ(OK, result); | 254 ASSERT_EQ(OK, result); |
190 ASSERT_EQ(1U, frame_chunks_.size()); | 255 ASSERT_EQ(1U, frames_.size()); |
191 ASSERT_TRUE(frame_chunks_[0]->header); | 256 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 } | 257 } |
194 | 258 |
195 // The same behaviour applies to asynchronous reads. | 259 // The same behaviour applies to asynchronous reads. |
196 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedAsync) { | 260 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, HeaderFragmentedAsync) { |
197 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1), | 261 CreateChunkedRead( |
198 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 262 ASYNC, kSampleFrame, kSampleFrameSize, 1, 2, LAST_FRAME_BIG); |
199 CreateReadOnly(reads); | 263 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
200 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | |
201 ASSERT_EQ(ERR_IO_PENDING, result); | 264 ASSERT_EQ(ERR_IO_PENDING, result); |
202 EXPECT_EQ(OK, cb_.WaitForResult()); | 265 EXPECT_EQ(OK, cb_.WaitForResult()); |
203 ASSERT_EQ(1U, frame_chunks_.size()); | 266 ASSERT_EQ(1U, frames_.size()); |
204 ASSERT_TRUE(frame_chunks_[0]->header); | 267 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 } | 268 } |
207 | 269 |
208 // If it receives an incomplete header in a synchronous call, then has to wait | 270 // 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. | 271 // for the rest of the frame, ReadFrames will return ERR_IO_PENDING. |
210 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) { | 272 TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) { |
211 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1), | 273 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1), |
212 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 274 MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; |
213 CreateReadOnly(reads); | 275 CreateReadOnly(reads); |
214 int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); | 276 int result = stream_->ReadFrames(&frames_, cb_.callback()); |
215 ASSERT_EQ(ERR_IO_PENDING, result); | 277 ASSERT_EQ(ERR_IO_PENDING, result); |
216 EXPECT_EQ(OK, cb_.WaitForResult()); | 278 EXPECT_EQ(OK, cb_.WaitForResult()); |
217 ASSERT_EQ(1U, frame_chunks_.size()); | 279 ASSERT_EQ(1U, frames_.size()); |
218 ASSERT_TRUE(frame_chunks_[0]->header); | 280 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 } | 281 } |
221 | 282 |
222 // An extended header should also return ERR_IO_PENDING if it is not completely | 283 // An extended header should also return ERR_IO_PENDING if it is not completely |
223 // received. | 284 // received. |
224 TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) { | 285 TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) { |
225 MockRead reads[] = { | 286 MockRead reads[] = { |
226 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1), | 287 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1), |
227 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; | 288 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; |
228 CreateReadOnly(reads); | 289 CreateReadOnly(reads); |
229 EXPECT_EQ(ERR_IO_PENDING, | 290 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
230 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
231 } | 291 } |
232 | 292 |
233 // A frame that does not arrive in a single read should arrive in chunks. | 293 // A frame that does not arrive in a single read should be broken into separate |
234 TEST_F(WebSocketBasicStreamSocketTest, LargeFrameFirstChunk) { | 294 // frames. |
235 MockRead reads[] = { | 295 TEST_F(WebSocketBasicStreamSocketSingleReadTest, LargeFrameFirstChunk) { |
236 MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize)}; | 296 CreateRead(MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize)); |
237 CreateReadOnly(reads); | 297 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
238 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 298 ASSERT_EQ(1U, frames_.size()); |
239 ASSERT_EQ(1U, frame_chunks_.size()); | 299 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, | 300 EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, |
246 static_cast<size_t>(frame_chunks_[0]->data->size())); | 301 static_cast<size_t>(frames_[0]->header.payload_length)); |
247 } | 302 } |
248 | 303 |
249 // If only the header arrives, we should get a zero-byte chunk. | 304 // If only the header of a data frame arrives, we should not receive a frame and |
| 305 // be told to wait. WebSocketBasicStream does two reads in this case, as after |
| 306 // the first read it has no frames to return. |
250 TEST_F(WebSocketBasicStreamSocketTest, HeaderOnlyChunk) { | 307 TEST_F(WebSocketBasicStreamSocketTest, HeaderOnlyChunk) { |
251 MockRead reads[] = { | 308 MockRead reads[] = { |
252 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize)}; | 309 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize), |
| 310 MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; |
253 CreateReadOnly(reads); | 311 CreateReadOnly(reads); |
254 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 312 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
255 ASSERT_EQ(1U, frame_chunks_.size()); | 313 ASSERT_EQ(0U, frames_.size()); |
256 EXPECT_FALSE(frame_chunks_[0]->final_chunk); | |
257 EXPECT_TRUE(frame_chunks_[0]->data.get() == NULL); | |
258 } | 314 } |
259 | 315 |
260 // The second and subsequent chunks of a frame have no header. | 316 // If the header and the body of a data frame arrive seperately, we should only |
261 TEST_F(WebSocketBasicStreamSocketTest, LargeFrameTwoChunks) { | 317 // see one frame. |
262 static const size_t kChunkSize = 16; | 318 TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparated) { |
263 MockRead reads[] = { | 319 MockRead reads[] = { |
264 MockRead(ASYNC, kPartialLargeFrame, kChunkSize), | 320 MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize), |
265 MockRead(ASYNC, kPartialLargeFrame + kChunkSize, kChunkSize)}; | 321 MockRead(ASYNC, |
| 322 kPartialLargeFrame + kLargeFrameHeaderSize, |
| 323 kPartialLargeFrameSize - kLargeFrameHeaderSize)}; |
266 CreateReadOnly(reads); | 324 CreateReadOnly(reads); |
| 325 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 326 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 327 ASSERT_EQ(1U, frames_.size()); |
| 328 EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, |
| 329 frames_[0]->header.payload_length); |
| 330 } |
| 331 |
| 332 // If the header and body of a data frame arrive separately, the frame we see |
| 333 // should have the opcode from the header (not Continuation). |
| 334 TEST_F(WebSocketBasicStreamSocketTest, HeaderBodySeparatedOpCodeNotLost) { |
| 335 MockRead reads[] = { |
| 336 MockRead(ASYNC, kPartialLargeFrame, kLargeFrameHeaderSize), |
| 337 MockRead(ASYNC, |
| 338 kPartialLargeFrame + kLargeFrameHeaderSize, |
| 339 kPartialLargeFrameSize - kLargeFrameHeaderSize)}; |
| 340 CreateReadOnly(reads); |
| 341 EXPECT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 342 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 343 ASSERT_EQ(1U, frames_.size()); |
| 344 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode); |
| 345 } |
| 346 |
| 347 // Every frame has a header with a correct payload_length field. |
| 348 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, LargeFrameTwoChunks) { |
| 349 const size_t kChunkSize = 16; |
| 350 CreateChunkedRead(ASYNC, |
| 351 kPartialLargeFrame, |
| 352 kPartialLargeFrameSize, |
| 353 kChunkSize, |
| 354 2, |
| 355 LAST_FRAME_NOT_BIG); |
267 TestCompletionCallback cb[2]; | 356 TestCompletionCallback cb[2]; |
268 | 357 |
269 ASSERT_EQ(ERR_IO_PENDING, | 358 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()); | 359 EXPECT_EQ(OK, cb[0].WaitForResult()); |
272 ASSERT_EQ(1U, frame_chunks_.size()); | 360 ASSERT_EQ(1U, frames_.size()); |
273 ASSERT_TRUE(frame_chunks_[0]->header); | 361 EXPECT_EQ(kChunkSize - kLargeFrameHeaderSize, |
| 362 frames_[0]->header.payload_length); |
274 | 363 |
275 frame_chunks_.clear(); | 364 frames_.clear(); |
276 ASSERT_EQ(ERR_IO_PENDING, | 365 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()); | 366 EXPECT_EQ(OK, cb[1].WaitForResult()); |
279 ASSERT_EQ(1U, frame_chunks_.size()); | 367 ASSERT_EQ(1U, frames_.size()); |
280 ASSERT_FALSE(frame_chunks_[0]->header); | 368 EXPECT_EQ(kChunkSize, frames_[0]->header.payload_length); |
281 } | 369 } |
282 | 370 |
283 // Only the final chunk of a frame has final_chunk set. | 371 // Only the final frame of a fragmented message has |final| bit set. |
284 TEST_F(WebSocketBasicStreamSocketTest, OnlyFinalChunkIsFinal) { | 372 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, OnlyFinalChunkIsFinal) { |
285 static const size_t kFirstChunkSize = 4; | 373 static const size_t kFirstChunkSize = 4; |
286 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kFirstChunkSize), | 374 CreateChunkedRead(ASYNC, |
287 MockRead(ASYNC, | 375 kSampleFrame, |
288 kSampleFrame + kFirstChunkSize, | 376 kSampleFrameSize, |
289 kSampleFrameSize - kFirstChunkSize)}; | 377 kFirstChunkSize, |
290 CreateReadOnly(reads); | 378 2, |
| 379 LAST_FRAME_BIG); |
291 TestCompletionCallback cb[2]; | 380 TestCompletionCallback cb[2]; |
292 | 381 |
293 ASSERT_EQ(ERR_IO_PENDING, | 382 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()); | 383 EXPECT_EQ(OK, cb[0].WaitForResult()); |
296 ASSERT_EQ(1U, frame_chunks_.size()); | 384 ASSERT_EQ(1U, frames_.size()); |
297 ASSERT_FALSE(frame_chunks_[0]->final_chunk); | 385 ASSERT_FALSE(frames_[0]->header.final); |
298 | 386 |
299 frame_chunks_.clear(); | 387 frames_.clear(); |
300 ASSERT_EQ(ERR_IO_PENDING, | 388 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()); | 389 EXPECT_EQ(OK, cb[1].WaitForResult()); |
303 ASSERT_EQ(1U, frame_chunks_.size()); | 390 ASSERT_EQ(1U, frames_.size()); |
304 ASSERT_TRUE(frame_chunks_[0]->final_chunk); | 391 ASSERT_TRUE(frames_[0]->header.final); |
| 392 } |
| 393 |
| 394 // All frames after the first have their opcode changed to Continuation. |
| 395 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, ContinuationOpCodeUsed) { |
| 396 const size_t kFirstChunkSize = 3; |
| 397 const int kChunkCount = 3; |
| 398 // The input data is one frame with opcode Text, which arrives in three |
| 399 // separate chunks. |
| 400 CreateChunkedRead(ASYNC, |
| 401 kSampleFrame, |
| 402 kSampleFrameSize, |
| 403 kFirstChunkSize, |
| 404 kChunkCount, |
| 405 LAST_FRAME_BIG); |
| 406 TestCompletionCallback cb[kChunkCount]; |
| 407 |
| 408 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[0].callback())); |
| 409 EXPECT_EQ(OK, cb[0].WaitForResult()); |
| 410 ASSERT_EQ(1U, frames_.size()); |
| 411 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode); |
| 412 |
| 413 // This test uses a loop to verify that the opcode for every frames generated |
| 414 // after the first is converted to Continuation. |
| 415 for (int i = 1; i < kChunkCount; ++i) { |
| 416 frames_.clear(); |
| 417 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb[i].callback())); |
| 418 EXPECT_EQ(OK, cb[i].WaitForResult()); |
| 419 ASSERT_EQ(1U, frames_.size()); |
| 420 EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation, |
| 421 frames_[0]->header.opcode); |
| 422 } |
305 } | 423 } |
306 | 424 |
307 // Multiple frames that arrive together should be parsed correctly. | 425 // Multiple frames that arrive together should be parsed correctly. |
308 TEST_F(WebSocketBasicStreamSocketTest, ThreeFramesTogether) { | 426 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ThreeFramesTogether) { |
309 MockRead reads[] = { | 427 CreateRead(MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize)); |
310 MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize)}; | |
311 CreateReadOnly(reads); | |
312 | 428 |
313 ASSERT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 429 ASSERT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
314 ASSERT_EQ(3U, frame_chunks_.size()); | 430 ASSERT_EQ(3U, frames_.size()); |
315 EXPECT_TRUE(frame_chunks_[0]->final_chunk); | 431 EXPECT_TRUE(frames_[0]->header.final); |
316 EXPECT_TRUE(frame_chunks_[1]->final_chunk); | 432 EXPECT_TRUE(frames_[1]->header.final); |
317 EXPECT_TRUE(frame_chunks_[2]->final_chunk); | 433 EXPECT_TRUE(frames_[2]->header.final); |
318 } | 434 } |
319 | 435 |
320 // ERR_CONNECTION_CLOSED must be returned on close. | 436 // ERR_CONNECTION_CLOSED must be returned on close. |
321 TEST_F(WebSocketBasicStreamSocketTest, SyncClose) { | 437 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncClose) { |
322 MockRead reads[] = {MockRead(SYNCHRONOUS, "", 0)}; | 438 CreateRead(MockRead(SYNCHRONOUS, "", 0)); |
323 CreateReadOnly(reads); | |
324 | 439 |
325 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 440 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
326 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 441 stream_->ReadFrames(&frames_, cb_.callback())); |
327 } | 442 } |
328 | 443 |
329 TEST_F(WebSocketBasicStreamSocketTest, AsyncClose) { | 444 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncClose) { |
330 MockRead reads[] = {MockRead(ASYNC, "", 0)}; | 445 CreateRead(MockRead(ASYNC, "", 0)); |
331 CreateReadOnly(reads); | |
332 | 446 |
333 ASSERT_EQ(ERR_IO_PENDING, | 447 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()); | 448 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
336 } | 449 } |
337 | 450 |
338 // The result should be the same if the socket returns | 451 // The result should be the same if the socket returns |
339 // ERR_CONNECTION_CLOSED. This is not expected to happen on an established | 452 // 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 | 453 // 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. | 454 // test is to confirm that ReadFrames() behaviour is identical in both cases. |
342 TEST_F(WebSocketBasicStreamSocketTest, SyncCloseWithErr) { | 455 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncCloseWithErr) { |
343 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; | 456 CreateRead(MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)); |
344 CreateReadOnly(reads); | |
345 | 457 |
346 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 458 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
347 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 459 stream_->ReadFrames(&frames_, cb_.callback())); |
348 } | 460 } |
349 | 461 |
350 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseWithErr) { | 462 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncCloseWithErr) { |
351 MockRead reads[] = {MockRead(ASYNC, ERR_CONNECTION_CLOSED)}; | 463 CreateRead(MockRead(ASYNC, ERR_CONNECTION_CLOSED)); |
352 CreateReadOnly(reads); | |
353 | 464 |
354 ASSERT_EQ(ERR_IO_PENDING, | 465 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()); | 466 EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
357 } | 467 } |
358 | 468 |
359 TEST_F(WebSocketBasicStreamSocketTest, SyncErrorsPassedThrough) { | 469 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncErrorsPassedThrough) { |
360 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that | 470 // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that |
361 // WebSocketBasicStream gives no special handling to. | 471 // WebSocketBasicStream gives no special handling to. |
362 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES)}; | 472 CreateRead(MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES)); |
363 CreateReadOnly(reads); | |
364 | 473 |
365 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, | 474 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, |
366 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 475 stream_->ReadFrames(&frames_, cb_.callback())); |
367 } | 476 } |
368 | 477 |
369 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrorsPassedThrough) { | 478 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncErrorsPassedThrough) { |
370 MockRead reads[] = {MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES)}; | 479 CreateRead(MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES)); |
371 CreateReadOnly(reads); | |
372 | 480 |
373 ASSERT_EQ(ERR_IO_PENDING, | 481 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()); | 482 EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, cb_.WaitForResult()); |
376 } | 483 } |
377 | 484 |
378 // If we get a frame followed by a close, we should receive them separately. | 485 // If we get a frame followed by a close, we should receive them separately. |
379 TEST_F(WebSocketBasicStreamSocketTest, CloseAfterFrame) { | 486 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, CloseAfterFrame) { |
380 MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize), | 487 // The chunk size equals the data size, so the second chunk is 0 size, closing |
381 MockRead(SYNCHRONOUS, "", 0)}; | 488 // the connection. |
382 CreateReadOnly(reads); | 489 CreateChunkedRead(SYNCHRONOUS, |
| 490 kSampleFrame, |
| 491 kSampleFrameSize, |
| 492 kSampleFrameSize, |
| 493 2, |
| 494 LAST_FRAME_NOT_BIG); |
383 | 495 |
384 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 496 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
385 EXPECT_EQ(1U, frame_chunks_.size()); | 497 EXPECT_EQ(1U, frames_.size()); |
386 frame_chunks_.clear(); | 498 frames_.clear(); |
387 EXPECT_EQ(ERR_CONNECTION_CLOSED, | 499 EXPECT_EQ(ERR_CONNECTION_CLOSED, |
388 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 500 stream_->ReadFrames(&frames_, cb_.callback())); |
389 } | 501 } |
390 | 502 |
391 // Synchronous close after an async frame header is handled by a different code | 503 // Synchronous close after an async frame header is handled by a different code |
392 // path. | 504 // path. |
393 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) { | 505 TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) { |
394 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), | 506 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
395 MockRead(SYNCHRONOUS, "", 0)}; | 507 MockRead(SYNCHRONOUS, "", 0)}; |
396 CreateReadOnly(reads); | 508 CreateReadOnly(reads); |
397 | 509 |
398 ASSERT_EQ(ERR_IO_PENDING, | 510 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()); | 511 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
401 } | 512 } |
402 | 513 |
403 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a | 514 // When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a |
404 // slightly different code path. | 515 // slightly different code path. |
405 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) { | 516 TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) { |
406 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), | 517 MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
407 MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; | 518 MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; |
408 CreateReadOnly(reads); | 519 CreateReadOnly(reads); |
409 | 520 |
410 ASSERT_EQ(ERR_IO_PENDING, | 521 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()); | 522 ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
413 } | 523 } |
414 | 524 |
415 // If there was a frame read at the same time as the response headers (and the | 525 // If there was a frame read at the same time as the response headers (and the |
416 // handshake succeeded), then we should parse it. | 526 // handshake succeeded), then we should parse it. |
417 TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) { | 527 TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) { |
418 SetHttpReadBuffer(kSampleFrame, kSampleFrameSize); | 528 SetHttpReadBuffer(kSampleFrame, kSampleFrameSize); |
419 CreateNullStream(); | 529 CreateNullStream(); |
420 | 530 |
421 EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 531 EXPECT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
422 ASSERT_EQ(1U, frame_chunks_.size()); | 532 ASSERT_EQ(1U, frames_.size()); |
423 ASSERT_TRUE(frame_chunks_[0]->data); | 533 ASSERT_TRUE(frames_[0]->data); |
424 EXPECT_EQ(6, frame_chunks_[0]->data->size()); | 534 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
425 } | 535 } |
426 | 536 |
427 // Check that a frame whose header partially arrived at the end of the response | 537 // Check that a frame whose header partially arrived at the end of the response |
428 // headers works correctly. | 538 // headers works correctly. |
429 TEST_F(WebSocketBasicStreamSocketTest, PartialFrameHeaderInHttpResponse) { | 539 TEST_F(WebSocketBasicStreamSocketSingleReadTest, |
| 540 PartialFrameHeaderInHttpResponse) { |
430 SetHttpReadBuffer(kSampleFrame, 1); | 541 SetHttpReadBuffer(kSampleFrame, 1); |
431 MockRead reads[] = {MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; | 542 CreateRead(MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)); |
432 CreateReadOnly(reads); | |
433 | 543 |
434 ASSERT_EQ(ERR_IO_PENDING, | 544 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
435 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | |
436 EXPECT_EQ(OK, cb_.WaitForResult()); | 545 EXPECT_EQ(OK, cb_.WaitForResult()); |
437 ASSERT_EQ(1U, frame_chunks_.size()); | 546 ASSERT_EQ(1U, frames_.size()); |
438 ASSERT_TRUE(frame_chunks_[0]->data); | 547 ASSERT_TRUE(frames_[0]->data); |
439 EXPECT_EQ(6, frame_chunks_[0]->data->size()); | 548 EXPECT_EQ(GG_UINT64_C(6), frames_[0]->header.payload_length); |
440 ASSERT_TRUE(frame_chunks_[0]->header); | 549 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_[0]->header.opcode); |
441 EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, | 550 } |
442 frame_chunks_[0]->header->opcode); | 551 |
| 552 // Check that a control frame which partially arrives at the end of the response |
| 553 // headers works correctly. |
| 554 TEST_F(WebSocketBasicStreamSocketSingleReadTest, |
| 555 PartialControlFrameInHttpResponse) { |
| 556 const size_t kPartialFrameBytes = 3; |
| 557 SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes); |
| 558 CreateRead(MockRead(ASYNC, |
| 559 kCloseFrame + kPartialFrameBytes, |
| 560 kCloseFrameSize - kPartialFrameBytes)); |
| 561 |
| 562 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 563 EXPECT_EQ(OK, cb_.WaitForResult()); |
| 564 ASSERT_EQ(1U, frames_.size()); |
| 565 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); |
| 566 EXPECT_EQ(kCloseFrameSize - 2, frames_[0]->header.payload_length); |
| 567 EXPECT_EQ( |
| 568 0, |
| 569 memcmp(frames_[0]->data->data(), kCloseFrame + 2, kCloseFrameSize - 2)); |
| 570 } |
| 571 |
| 572 // Check that a control frame which partially arrives at the end of the response |
| 573 // headers works correctly. Synchronous version (unlikely in practice). |
| 574 TEST_F(WebSocketBasicStreamSocketSingleReadTest, |
| 575 PartialControlFrameInHttpResponseSync) { |
| 576 const size_t kPartialFrameBytes = 3; |
| 577 SetHttpReadBuffer(kCloseFrame, kPartialFrameBytes); |
| 578 CreateRead(MockRead(SYNCHRONOUS, |
| 579 kCloseFrame + kPartialFrameBytes, |
| 580 kCloseFrameSize - kPartialFrameBytes)); |
| 581 |
| 582 ASSERT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 583 ASSERT_EQ(1U, frames_.size()); |
| 584 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); |
443 } | 585 } |
444 | 586 |
445 // Check that an invalid frame results in an error. | 587 // Check that an invalid frame results in an error. |
446 TEST_F(WebSocketBasicStreamSocketTest, SyncInvalidFrame) { | 588 TEST_F(WebSocketBasicStreamSocketSingleReadTest, SyncInvalidFrame) { |
447 MockRead reads[] = {MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize)}; | 589 CreateRead(MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize)); |
448 CreateReadOnly(reads); | |
449 | 590 |
450 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, | 591 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, |
451 stream_->ReadFrames(&frame_chunks_, cb_.callback())); | 592 stream_->ReadFrames(&frames_, cb_.callback())); |
452 } | 593 } |
453 | 594 |
454 TEST_F(WebSocketBasicStreamSocketTest, AsyncInvalidFrame) { | 595 TEST_F(WebSocketBasicStreamSocketSingleReadTest, AsyncInvalidFrame) { |
455 MockRead reads[] = {MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize)}; | 596 CreateRead(MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize)); |
456 CreateReadOnly(reads); | |
457 | 597 |
458 ASSERT_EQ(ERR_IO_PENDING, | 598 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()); | 599 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); |
461 } | 600 } |
462 | 601 |
| 602 // A control frame without a FIN flag is invalid and should not be passed |
| 603 // through to higher layers. RFC6455 5.5 "All control frames ... MUST NOT be |
| 604 // fragmented." |
| 605 TEST_F(WebSocketBasicStreamSocketSingleReadTest, ControlFrameWithoutFin) { |
| 606 CreateRead( |
| 607 MockRead(SYNCHRONOUS, kPingFrameWithoutFin, kPingFrameWithoutFinSize)); |
| 608 |
| 609 ASSERT_EQ(ERR_WS_PROTOCOL_ERROR, |
| 610 stream_->ReadFrames(&frames_, cb_.callback())); |
| 611 EXPECT_TRUE(frames_.empty()); |
| 612 } |
| 613 |
| 614 // A control frame over 125 characters is invalid. RFC6455 5.5 "All control |
| 615 // frames MUST have a payload length of 125 bytes or less". Since we use a |
| 616 // 125-byte buffer to assemble fragmented control frames, we need to detect this |
| 617 // error before attempting to assemble the fragments. |
| 618 TEST_F(WebSocketBasicStreamSocketSingleReadTest, OverlongControlFrame) { |
| 619 CreateRead(MockRead(SYNCHRONOUS, k126BytePong, k126BytePongSize)); |
| 620 |
| 621 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, |
| 622 stream_->ReadFrames(&frames_, cb_.callback())); |
| 623 EXPECT_TRUE(frames_.empty()); |
| 624 } |
| 625 |
| 626 // A control frame over 125 characters should still be rejected if it is split |
| 627 // into multiple chunks. |
| 628 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SplitOverlongControlFrame) { |
| 629 const size_t kFirstChunkSize = 16; |
| 630 CreateChunkedRead(SYNCHRONOUS, |
| 631 k126BytePong, |
| 632 k126BytePongSize, |
| 633 kFirstChunkSize, |
| 634 2, |
| 635 LAST_FRAME_BIG); |
| 636 |
| 637 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, |
| 638 stream_->ReadFrames(&frames_, cb_.callback())); |
| 639 EXPECT_TRUE(frames_.empty()); |
| 640 } |
| 641 |
| 642 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, |
| 643 AsyncSplitOverlongControlFrame) { |
| 644 const size_t kFirstChunkSize = 16; |
| 645 CreateChunkedRead(ASYNC, |
| 646 k126BytePong, |
| 647 k126BytePongSize, |
| 648 kFirstChunkSize, |
| 649 2, |
| 650 LAST_FRAME_BIG); |
| 651 |
| 652 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 653 EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); |
| 654 // The caller should not call ReadFrames() again after receiving an error |
| 655 // other than ERR_IO_PENDING. |
| 656 EXPECT_TRUE(frames_.empty()); |
| 657 } |
| 658 |
| 659 // In the synchronous case, ReadFrames assembles the whole control frame before |
| 660 // returning. |
| 661 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, SyncControlFrameAssembly) { |
| 662 const size_t kChunkSize = 3; |
| 663 CreateChunkedRead( |
| 664 SYNCHRONOUS, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG); |
| 665 |
| 666 ASSERT_EQ(OK, stream_->ReadFrames(&frames_, cb_.callback())); |
| 667 ASSERT_EQ(1U, frames_.size()); |
| 668 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); |
| 669 } |
| 670 |
| 671 // In the asynchronous case, the callback is not called until the control frame |
| 672 // has been completely assembled. |
| 673 TEST_F(WebSocketBasicStreamSocketChunkedReadTest, AsyncControlFrameAssembly) { |
| 674 const size_t kChunkSize = 3; |
| 675 CreateChunkedRead( |
| 676 ASYNC, kCloseFrame, kCloseFrameSize, kChunkSize, 3, LAST_FRAME_BIG); |
| 677 |
| 678 ASSERT_EQ(ERR_IO_PENDING, stream_->ReadFrames(&frames_, cb_.callback())); |
| 679 ASSERT_EQ(OK, cb_.WaitForResult()); |
| 680 ASSERT_EQ(1U, frames_.size()); |
| 681 EXPECT_EQ(WebSocketFrameHeader::kOpCodeClose, frames_[0]->header.opcode); |
| 682 } |
| 683 |
463 // Check that writing a frame all at once works. | 684 // Check that writing a frame all at once works. |
464 TEST_F(WebSocketBasicStreamSocketTest, WriteAtOnce) { | 685 TEST_F(WebSocketBasicStreamSocketWriteTest, WriteAtOnce) { |
465 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)}; | 686 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)}; |
466 CreateWriteOnly(writes); | 687 CreateWriteOnly(writes); |
467 frame_chunks_ = GenerateWriteFrame(); | |
468 | 688 |
469 EXPECT_EQ(OK, stream_->WriteFrames(&frame_chunks_, cb_.callback())); | 689 EXPECT_EQ(OK, stream_->WriteFrames(&frames_, cb_.callback())); |
470 } | 690 } |
471 | 691 |
472 // Check that completely async writing works. | 692 // Check that completely async writing works. |
473 TEST_F(WebSocketBasicStreamSocketTest, AsyncWriteAtOnce) { | 693 TEST_F(WebSocketBasicStreamSocketWriteTest, AsyncWriteAtOnce) { |
474 MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)}; | 694 MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)}; |
475 CreateWriteOnly(writes); | 695 CreateWriteOnly(writes); |
476 frame_chunks_ = GenerateWriteFrame(); | |
477 | 696 |
478 ASSERT_EQ(ERR_IO_PENDING, | 697 ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback())); |
479 stream_->WriteFrames(&frame_chunks_, cb_.callback())); | |
480 EXPECT_EQ(OK, cb_.WaitForResult()); | 698 EXPECT_EQ(OK, cb_.WaitForResult()); |
481 } | 699 } |
482 | 700 |
483 // Check that writing a frame to an extremely full kernel buffer (so that it | 701 // 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 | 702 // ends up being sent in bits) works. The WriteFrames() callback should not be |
485 // called until all parts have been written. | 703 // called until all parts have been written. |
486 TEST_F(WebSocketBasicStreamSocketTest, WriteInBits) { | 704 TEST_F(WebSocketBasicStreamSocketWriteTest, WriteInBits) { |
487 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4), | 705 MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4), |
488 MockWrite(ASYNC, kWriteFrame + 4, 4), | 706 MockWrite(ASYNC, kWriteFrame + 4, 4), |
489 MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)}; | 707 MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)}; |
490 CreateWriteOnly(writes); | 708 CreateWriteOnly(writes); |
491 frame_chunks_ = GenerateWriteFrame(); | |
492 | 709 |
493 ASSERT_EQ(ERR_IO_PENDING, | 710 ASSERT_EQ(ERR_IO_PENDING, stream_->WriteFrames(&frames_, cb_.callback())); |
494 stream_->WriteFrames(&frame_chunks_, cb_.callback())); | |
495 EXPECT_EQ(OK, cb_.WaitForResult()); | 711 EXPECT_EQ(OK, cb_.WaitForResult()); |
496 } | 712 } |
497 | 713 |
498 TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) { | 714 TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) { |
499 extensions_ = "inflate-uuencode"; | 715 extensions_ = "inflate-uuencode"; |
500 CreateNullStream(); | 716 CreateNullStream(); |
501 | 717 |
502 EXPECT_EQ("inflate-uuencode", stream_->GetExtensions()); | 718 EXPECT_EQ("inflate-uuencode", stream_->GetExtensions()); |
503 } | 719 } |
504 | 720 |
505 TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) { | 721 TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) { |
506 sub_protocol_ = "cyberchat"; | 722 sub_protocol_ = "cyberchat"; |
507 CreateNullStream(); | 723 CreateNullStream(); |
508 | 724 |
509 EXPECT_EQ("cyberchat", stream_->GetSubProtocol()); | 725 EXPECT_EQ("cyberchat", stream_->GetSubProtocol()); |
510 } | 726 } |
511 | 727 |
512 } // namespace | 728 } // namespace |
513 } // namespace net | 729 } // namespace net |
OLD | NEW |