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 #include "net/websockets/websocket_stream.h" | 5 #include "net/websockets/websocket_stream.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/memory/scoped_vector.h" | 12 #include "base/memory/scoped_vector.h" |
13 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
16 #include "net/http/http_request_headers.h" | 16 #include "net/http/http_request_headers.h" |
17 #include "net/http/http_response_headers.h" | 17 #include "net/http/http_response_headers.h" |
18 #include "net/socket/client_socket_handle.h" | 18 #include "net/socket/client_socket_handle.h" |
19 #include "net/socket/socket_test_util.h" | 19 #include "net/socket/socket_test_util.h" |
20 #include "net/url_request/url_request_test_util.h" | 20 #include "net/url_request/url_request_test_util.h" |
21 #include "net/websockets/websocket_basic_handshake_stream.h" | 21 #include "net/websockets/websocket_basic_handshake_stream.h" |
22 #include "net/websockets/websocket_frame.h" | 22 #include "net/websockets/websocket_frame.h" |
23 #include "net/websockets/websocket_handshake_request_info.h" | 23 #include "net/websockets/websocket_handshake_request_info.h" |
24 #include "net/websockets/websocket_handshake_response_info.h" | 24 #include "net/websockets/websocket_handshake_response_info.h" |
25 #include "net/websockets/websocket_handshake_stream_create_helper.h" | 25 #include "net/websockets/websocket_handshake_stream_create_helper.h" |
26 #include "net/websockets/websocket_test_util.h" | 26 #include "net/websockets/websocket_test_util.h" |
27 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
28 #include "url/gurl.h" | 28 #include "url/gurl.h" |
| 29 #include "url/origin.h" |
29 | 30 |
30 namespace net { | 31 namespace net { |
31 namespace { | 32 namespace { |
32 | 33 |
33 typedef std::pair<std::string, std::string> HeaderKeyValuePair; | 34 typedef std::pair<std::string, std::string> HeaderKeyValuePair; |
34 | 35 |
35 std::vector<HeaderKeyValuePair> ToVector(const HttpRequestHeaders& headers) { | 36 std::vector<HeaderKeyValuePair> ToVector(const HttpRequestHeaders& headers) { |
36 HttpRequestHeaders::Iterator it(headers); | 37 HttpRequestHeaders::Iterator it(headers); |
37 std::vector<HeaderKeyValuePair> result; | 38 std::vector<HeaderKeyValuePair> result; |
38 while (it.GetNext()) | 39 while (it.GetNext()) |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 const std::vector<std::string>& sub_protocols, | 123 const std::vector<std::string>& sub_protocols, |
123 const std::string& origin) { | 124 const std::string& origin) { |
124 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( | 125 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( |
125 new TestConnectDelegate(this)); | 126 new TestConnectDelegate(this)); |
126 WebSocketStream::ConnectDelegate* delegate = connect_delegate.get(); | 127 WebSocketStream::ConnectDelegate* delegate = connect_delegate.get(); |
127 stream_request_ = ::net::CreateAndConnectStreamForTesting( | 128 stream_request_ = ::net::CreateAndConnectStreamForTesting( |
128 GURL(socket_url), | 129 GURL(socket_url), |
129 scoped_ptr<WebSocketHandshakeStreamCreateHelper>( | 130 scoped_ptr<WebSocketHandshakeStreamCreateHelper>( |
130 new DeterministicKeyWebSocketHandshakeStreamCreateHelper( | 131 new DeterministicKeyWebSocketHandshakeStreamCreateHelper( |
131 delegate, sub_protocols)), | 132 delegate, sub_protocols)), |
132 GURL(origin), | 133 url::Origin(origin), |
133 url_request_context_host_.GetURLRequestContext(), | 134 url_request_context_host_.GetURLRequestContext(), |
134 BoundNetLog(), | 135 BoundNetLog(), |
135 connect_delegate.Pass()); | 136 connect_delegate.Pass()); |
136 } | 137 } |
137 | 138 |
138 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } | 139 static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } |
139 | 140 |
140 // A simple function to make the tests more readable. Creates an empty vector. | 141 // A simple function to make the tests more readable. Creates an empty vector. |
141 static std::vector<std::string> NoSubProtocols() { | 142 static std::vector<std::string> NoSubProtocols() { |
142 return std::vector<std::string>(); | 143 return std::vector<std::string>(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 public: | 194 public: |
194 // Performs a standard connect, with the value of the Sec-WebSocket-Extensions | 195 // Performs a standard connect, with the value of the Sec-WebSocket-Extensions |
195 // header in the response set to |extensions_header_value|. Runs the event | 196 // header in the response set to |extensions_header_value|. Runs the event |
196 // loop to allow the connect to complete. | 197 // loop to allow the connect to complete. |
197 void CreateAndConnectWithExtensions( | 198 void CreateAndConnectWithExtensions( |
198 const std::string& extensions_header_value) { | 199 const std::string& extensions_header_value) { |
199 CreateAndConnectStandard( | 200 CreateAndConnectStandard( |
200 "ws://localhost/testing_path", | 201 "ws://localhost/testing_path", |
201 "/testing_path", | 202 "/testing_path", |
202 NoSubProtocols(), | 203 NoSubProtocols(), |
203 "http://localhost/", | 204 "http://localhost", |
204 "", | 205 "", |
205 "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); | 206 "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); |
206 RunUntilIdle(); | 207 RunUntilIdle(); |
207 } | 208 } |
208 }; | 209 }; |
209 | 210 |
210 // Confirm that the basic case works as expected. | 211 // Confirm that the basic case works as expected. |
211 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { | 212 TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { |
212 CreateAndConnectStandard( | 213 CreateAndConnectStandard( |
213 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); | 214 "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); |
214 EXPECT_FALSE(request_info_); | 215 EXPECT_FALSE(request_info_); |
215 EXPECT_FALSE(response_info_); | 216 EXPECT_FALSE(response_info_); |
216 RunUntilIdle(); | 217 RunUntilIdle(); |
217 EXPECT_FALSE(has_failed()); | 218 EXPECT_FALSE(has_failed()); |
218 EXPECT_TRUE(stream_); | 219 EXPECT_TRUE(stream_); |
219 EXPECT_TRUE(request_info_); | 220 EXPECT_TRUE(request_info_); |
220 EXPECT_TRUE(response_info_); | 221 EXPECT_TRUE(response_info_); |
221 } | 222 } |
222 | 223 |
223 TEST_F(WebSocketStreamCreateTest, HandshakeInfo) { | 224 TEST_F(WebSocketStreamCreateTest, HandshakeInfo) { |
224 static const char kResponse[] = | 225 static const char kResponse[] = |
225 "HTTP/1.1 101 Switching Protocols\r\n" | 226 "HTTP/1.1 101 Switching Protocols\r\n" |
226 "Upgrade: websocket\r\n" | 227 "Upgrade: websocket\r\n" |
227 "Connection: Upgrade\r\n" | 228 "Connection: Upgrade\r\n" |
228 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 229 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
229 "foo: bar, baz\r\n" | 230 "foo: bar, baz\r\n" |
230 "hoge: fuga\r\n" | 231 "hoge: fuga\r\n" |
231 "hoge: piyo\r\n" | 232 "hoge: piyo\r\n" |
232 "\r\n"; | 233 "\r\n"; |
233 | 234 |
234 CreateAndConnectCustomResponse( | 235 CreateAndConnectCustomResponse( |
235 "ws://localhost/", | 236 "ws://localhost/", |
236 "/", | 237 "/", |
237 NoSubProtocols(), | 238 NoSubProtocols(), |
238 "http://localhost/", | 239 "http://localhost", |
239 "", | 240 "", |
240 kResponse); | 241 kResponse); |
241 EXPECT_FALSE(request_info_); | 242 EXPECT_FALSE(request_info_); |
242 EXPECT_FALSE(response_info_); | 243 EXPECT_FALSE(response_info_); |
243 RunUntilIdle(); | 244 RunUntilIdle(); |
244 EXPECT_TRUE(stream_); | 245 EXPECT_TRUE(stream_); |
245 ASSERT_TRUE(request_info_); | 246 ASSERT_TRUE(request_info_); |
246 ASSERT_TRUE(response_info_); | 247 ASSERT_TRUE(response_info_); |
247 std::vector<HeaderKeyValuePair> request_headers = | 248 std::vector<HeaderKeyValuePair> request_headers = |
248 ToVector(request_info_->headers); | 249 ToVector(request_info_->headers); |
249 // We examine the contents of request_info_ and response_info_ | 250 // We examine the contents of request_info_ and response_info_ |
250 // mainly only in this test case. | 251 // mainly only in this test case. |
251 EXPECT_EQ(GURL("ws://localhost/"), request_info_->url); | 252 EXPECT_EQ(GURL("ws://localhost/"), request_info_->url); |
252 EXPECT_EQ(GURL("ws://localhost/"), response_info_->url); | 253 EXPECT_EQ(GURL("ws://localhost/"), response_info_->url); |
253 EXPECT_EQ(101, response_info_->status_code); | 254 EXPECT_EQ(101, response_info_->status_code); |
254 EXPECT_EQ("Switching Protocols", response_info_->status_text); | 255 EXPECT_EQ("Switching Protocols", response_info_->status_text); |
255 ASSERT_EQ(12u, request_headers.size()); | 256 ASSERT_EQ(12u, request_headers.size()); |
256 EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); | 257 EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); |
257 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | 258 EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); |
258 EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | 259 EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); |
259 EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | 260 EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), |
260 request_headers[3]); | 261 request_headers[3]); |
261 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | 262 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); |
262 EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost/"), | 263 EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), |
263 request_headers[5]); | 264 request_headers[5]); |
264 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | 265 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), |
265 request_headers[6]); | 266 request_headers[6]); |
266 EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]); | 267 EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]); |
267 EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"), | 268 EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"), |
268 request_headers[8]); | 269 request_headers[8]); |
269 EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"), | 270 EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"), |
270 request_headers[9]); | 271 request_headers[9]); |
271 EXPECT_EQ("Sec-WebSocket-Key", request_headers[10].first); | 272 EXPECT_EQ("Sec-WebSocket-Key", request_headers[10].first); |
272 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", | 273 EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", |
(...skipping 10 matching lines...) Expand all Loading... |
283 EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first); | 284 EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first); |
284 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]); | 285 EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]); |
285 EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]); | 286 EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]); |
286 EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]); | 287 EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]); |
287 EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]); | 288 EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]); |
288 } | 289 } |
289 | 290 |
290 // Confirm that the stream isn't established until the message loop runs. | 291 // Confirm that the stream isn't established until the message loop runs. |
291 TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { | 292 TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { |
292 CreateAndConnectStandard( | 293 CreateAndConnectStandard( |
293 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); | 294 "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); |
294 EXPECT_FALSE(has_failed()); | 295 EXPECT_FALSE(has_failed()); |
295 EXPECT_FALSE(stream_); | 296 EXPECT_FALSE(stream_); |
296 } | 297 } |
297 | 298 |
298 // Check the path is used. | 299 // Check the path is used. |
299 TEST_F(WebSocketStreamCreateTest, PathIsUsed) { | 300 TEST_F(WebSocketStreamCreateTest, PathIsUsed) { |
300 CreateAndConnectStandard("ws://localhost/testing_path", | 301 CreateAndConnectStandard("ws://localhost/testing_path", |
301 "/testing_path", | 302 "/testing_path", |
302 NoSubProtocols(), | 303 NoSubProtocols(), |
303 "http://localhost/", | 304 "http://localhost", |
304 "", | 305 "", |
305 ""); | 306 ""); |
306 RunUntilIdle(); | 307 RunUntilIdle(); |
307 EXPECT_FALSE(has_failed()); | 308 EXPECT_FALSE(has_failed()); |
308 EXPECT_TRUE(stream_); | 309 EXPECT_TRUE(stream_); |
309 } | 310 } |
310 | 311 |
311 // Check that the origin is used. | 312 // Check that the origin is used. |
312 TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { | 313 TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { |
313 CreateAndConnectStandard("ws://localhost/testing_path", | 314 CreateAndConnectStandard("ws://localhost/testing_path", |
314 "/testing_path", | 315 "/testing_path", |
315 NoSubProtocols(), | 316 NoSubProtocols(), |
316 "http://google.com/", | 317 "http://google.com", |
317 "", | 318 "", |
318 ""); | 319 ""); |
319 RunUntilIdle(); | 320 RunUntilIdle(); |
320 EXPECT_FALSE(has_failed()); | 321 EXPECT_FALSE(has_failed()); |
321 EXPECT_TRUE(stream_); | 322 EXPECT_TRUE(stream_); |
322 } | 323 } |
323 | 324 |
324 // Check that sub-protocols are sent and parsed. | 325 // Check that sub-protocols are sent and parsed. |
325 TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { | 326 TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { |
326 std::vector<std::string> sub_protocols; | 327 std::vector<std::string> sub_protocols; |
327 sub_protocols.push_back("chatv11.chromium.org"); | 328 sub_protocols.push_back("chatv11.chromium.org"); |
328 sub_protocols.push_back("chatv20.chromium.org"); | 329 sub_protocols.push_back("chatv20.chromium.org"); |
329 CreateAndConnectStandard("ws://localhost/testing_path", | 330 CreateAndConnectStandard("ws://localhost/testing_path", |
330 "/testing_path", | 331 "/testing_path", |
331 sub_protocols, | 332 sub_protocols, |
332 "http://google.com/", | 333 "http://google.com", |
333 "Sec-WebSocket-Protocol: chatv11.chromium.org, " | 334 "Sec-WebSocket-Protocol: chatv11.chromium.org, " |
334 "chatv20.chromium.org\r\n", | 335 "chatv20.chromium.org\r\n", |
335 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); | 336 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); |
336 RunUntilIdle(); | 337 RunUntilIdle(); |
337 EXPECT_TRUE(stream_); | 338 EXPECT_TRUE(stream_); |
338 EXPECT_FALSE(has_failed()); | 339 EXPECT_FALSE(has_failed()); |
339 EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); | 340 EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); |
340 } | 341 } |
341 | 342 |
342 // Unsolicited sub-protocols are rejected. | 343 // Unsolicited sub-protocols are rejected. |
343 TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { | 344 TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { |
344 CreateAndConnectStandard("ws://localhost/testing_path", | 345 CreateAndConnectStandard("ws://localhost/testing_path", |
345 "/testing_path", | 346 "/testing_path", |
346 NoSubProtocols(), | 347 NoSubProtocols(), |
347 "http://google.com/", | 348 "http://google.com", |
348 "", | 349 "", |
349 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); | 350 "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); |
350 RunUntilIdle(); | 351 RunUntilIdle(); |
351 EXPECT_FALSE(stream_); | 352 EXPECT_FALSE(stream_); |
352 EXPECT_TRUE(has_failed()); | 353 EXPECT_TRUE(has_failed()); |
353 EXPECT_EQ("Error during WebSocket handshake: " | 354 EXPECT_EQ("Error during WebSocket handshake: " |
354 "Response must not include 'Sec-WebSocket-Protocol' header " | 355 "Response must not include 'Sec-WebSocket-Protocol' header " |
355 "if not present in request: chatv20.chromium.org", | 356 "if not present in request: chatv20.chromium.org", |
356 failure_message()); | 357 failure_message()); |
357 } | 358 } |
358 | 359 |
359 // Missing sub-protocol response is rejected. | 360 // Missing sub-protocol response is rejected. |
360 TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { | 361 TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { |
361 std::vector<std::string> sub_protocols; | 362 std::vector<std::string> sub_protocols; |
362 sub_protocols.push_back("chat.example.com"); | 363 sub_protocols.push_back("chat.example.com"); |
363 CreateAndConnectStandard("ws://localhost/testing_path", | 364 CreateAndConnectStandard("ws://localhost/testing_path", |
364 "/testing_path", | 365 "/testing_path", |
365 sub_protocols, | 366 sub_protocols, |
366 "http://localhost/", | 367 "http://localhost", |
367 "Sec-WebSocket-Protocol: chat.example.com\r\n", | 368 "Sec-WebSocket-Protocol: chat.example.com\r\n", |
368 ""); | 369 ""); |
369 RunUntilIdle(); | 370 RunUntilIdle(); |
370 EXPECT_FALSE(stream_); | 371 EXPECT_FALSE(stream_); |
371 EXPECT_TRUE(has_failed()); | 372 EXPECT_TRUE(has_failed()); |
372 EXPECT_EQ("Error during WebSocket handshake: " | 373 EXPECT_EQ("Error during WebSocket handshake: " |
373 "Sent non-empty 'Sec-WebSocket-Protocol' header " | 374 "Sent non-empty 'Sec-WebSocket-Protocol' header " |
374 "but no response was received", | 375 "but no response was received", |
375 failure_message()); | 376 failure_message()); |
376 } | 377 } |
377 | 378 |
378 // Only one sub-protocol can be accepted. | 379 // Only one sub-protocol can be accepted. |
379 TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { | 380 TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { |
380 std::vector<std::string> sub_protocols; | 381 std::vector<std::string> sub_protocols; |
381 sub_protocols.push_back("chatv11.chromium.org"); | 382 sub_protocols.push_back("chatv11.chromium.org"); |
382 sub_protocols.push_back("chatv20.chromium.org"); | 383 sub_protocols.push_back("chatv20.chromium.org"); |
383 CreateAndConnectStandard("ws://localhost/testing_path", | 384 CreateAndConnectStandard("ws://localhost/testing_path", |
384 "/testing_path", | 385 "/testing_path", |
385 sub_protocols, | 386 sub_protocols, |
386 "http://google.com/", | 387 "http://google.com", |
387 "Sec-WebSocket-Protocol: chatv11.chromium.org, " | 388 "Sec-WebSocket-Protocol: chatv11.chromium.org, " |
388 "chatv20.chromium.org\r\n", | 389 "chatv20.chromium.org\r\n", |
389 "Sec-WebSocket-Protocol: chatv11.chromium.org, " | 390 "Sec-WebSocket-Protocol: chatv11.chromium.org, " |
390 "chatv20.chromium.org\r\n"); | 391 "chatv20.chromium.org\r\n"); |
391 RunUntilIdle(); | 392 RunUntilIdle(); |
392 EXPECT_FALSE(stream_); | 393 EXPECT_FALSE(stream_); |
393 EXPECT_TRUE(has_failed()); | 394 EXPECT_TRUE(has_failed()); |
394 EXPECT_EQ("Error during WebSocket handshake: " | 395 EXPECT_EQ("Error during WebSocket handshake: " |
395 "'Sec-WebSocket-Protocol' header must not appear " | 396 "'Sec-WebSocket-Protocol' header must not appear " |
396 "more than once in a response", | 397 "more than once in a response", |
397 failure_message()); | 398 failure_message()); |
398 } | 399 } |
399 | 400 |
400 // Unmatched sub-protocol should be rejected. | 401 // Unmatched sub-protocol should be rejected. |
401 TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) { | 402 TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) { |
402 std::vector<std::string> sub_protocols; | 403 std::vector<std::string> sub_protocols; |
403 sub_protocols.push_back("chatv11.chromium.org"); | 404 sub_protocols.push_back("chatv11.chromium.org"); |
404 sub_protocols.push_back("chatv20.chromium.org"); | 405 sub_protocols.push_back("chatv20.chromium.org"); |
405 CreateAndConnectStandard("ws://localhost/testing_path", | 406 CreateAndConnectStandard("ws://localhost/testing_path", |
406 "/testing_path", | 407 "/testing_path", |
407 sub_protocols, | 408 sub_protocols, |
408 "http://google.com/", | 409 "http://google.com", |
409 "Sec-WebSocket-Protocol: chatv11.chromium.org, " | 410 "Sec-WebSocket-Protocol: chatv11.chromium.org, " |
410 "chatv20.chromium.org\r\n", | 411 "chatv20.chromium.org\r\n", |
411 "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); | 412 "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); |
412 RunUntilIdle(); | 413 RunUntilIdle(); |
413 EXPECT_FALSE(stream_); | 414 EXPECT_FALSE(stream_); |
414 EXPECT_TRUE(has_failed()); | 415 EXPECT_TRUE(has_failed()); |
415 EXPECT_EQ("Error during WebSocket handshake: " | 416 EXPECT_EQ("Error during WebSocket handshake: " |
416 "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " | 417 "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " |
417 "in response does not match any of sent values", | 418 "in response does not match any of sent values", |
418 failure_message()); | 419 failure_message()); |
(...skipping 16 matching lines...) Expand all Loading... |
435 EXPECT_FALSE(has_failed()); | 436 EXPECT_FALSE(has_failed()); |
436 } | 437 } |
437 | 438 |
438 // Verify that incoming messages are actually decompressed with | 439 // Verify that incoming messages are actually decompressed with |
439 // permessage-deflate enabled. | 440 // permessage-deflate enabled. |
440 TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) { | 441 TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) { |
441 CreateAndConnectCustomResponse( | 442 CreateAndConnectCustomResponse( |
442 "ws://localhost/testing_path", | 443 "ws://localhost/testing_path", |
443 "/testing_path", | 444 "/testing_path", |
444 NoSubProtocols(), | 445 NoSubProtocols(), |
445 "http://localhost/", | 446 "http://localhost", |
446 "", | 447 "", |
447 WebSocketStandardResponse( | 448 WebSocketStandardResponse( |
448 "Sec-WebSocket-Extensions: permessage-deflate\r\n") + | 449 "Sec-WebSocket-Extensions: permessage-deflate\r\n") + |
449 std::string( | 450 std::string( |
450 "\xc1\x07" // WebSocket header (FIN + RSV1, Text payload 7 bytes) | 451 "\xc1\x07" // WebSocket header (FIN + RSV1, Text payload 7 bytes) |
451 "\xf2\x48\xcd\xc9\xc9\x07\x00", // "Hello" DEFLATE compressed | 452 "\xf2\x48\xcd\xc9\xc9\x07\x00", // "Hello" DEFLATE compressed |
452 9)); | 453 9)); |
453 RunUntilIdle(); | 454 RunUntilIdle(); |
454 | 455 |
455 ASSERT_TRUE(stream_); | 456 ASSERT_TRUE(stream_); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 // TODO(ricea): Check that WebSocketDeflateStream is initialised with the | 622 // TODO(ricea): Check that WebSocketDeflateStream is initialised with the |
622 // arguments from the server. This is difficult because the data written to the | 623 // arguments from the server. This is difficult because the data written to the |
623 // socket is randomly masked. | 624 // socket is randomly masked. |
624 | 625 |
625 // Additional Sec-WebSocket-Accept headers should be rejected. | 626 // Additional Sec-WebSocket-Accept headers should be rejected. |
626 TEST_F(WebSocketStreamCreateTest, DoubleAccept) { | 627 TEST_F(WebSocketStreamCreateTest, DoubleAccept) { |
627 CreateAndConnectStandard( | 628 CreateAndConnectStandard( |
628 "ws://localhost/", | 629 "ws://localhost/", |
629 "/", | 630 "/", |
630 NoSubProtocols(), | 631 NoSubProtocols(), |
631 "http://localhost/", | 632 "http://localhost", |
632 "", | 633 "", |
633 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); | 634 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); |
634 RunUntilIdle(); | 635 RunUntilIdle(); |
635 EXPECT_FALSE(stream_); | 636 EXPECT_FALSE(stream_); |
636 EXPECT_TRUE(has_failed()); | 637 EXPECT_TRUE(has_failed()); |
637 EXPECT_EQ("Error during WebSocket handshake: " | 638 EXPECT_EQ("Error during WebSocket handshake: " |
638 "'Sec-WebSocket-Accept' header must not appear " | 639 "'Sec-WebSocket-Accept' header must not appear " |
639 "more than once in a response", | 640 "more than once in a response", |
640 failure_message()); | 641 failure_message()); |
641 } | 642 } |
642 | 643 |
643 // Response code 200 must be rejected. | 644 // Response code 200 must be rejected. |
644 TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { | 645 TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { |
645 static const char kInvalidStatusCodeResponse[] = | 646 static const char kInvalidStatusCodeResponse[] = |
646 "HTTP/1.1 200 OK\r\n" | 647 "HTTP/1.1 200 OK\r\n" |
647 "Upgrade: websocket\r\n" | 648 "Upgrade: websocket\r\n" |
648 "Connection: Upgrade\r\n" | 649 "Connection: Upgrade\r\n" |
649 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 650 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
650 "\r\n"; | 651 "\r\n"; |
651 CreateAndConnectCustomResponse("ws://localhost/", | 652 CreateAndConnectCustomResponse("ws://localhost/", |
652 "/", | 653 "/", |
653 NoSubProtocols(), | 654 NoSubProtocols(), |
654 "http://localhost/", | 655 "http://localhost", |
655 "", | 656 "", |
656 kInvalidStatusCodeResponse); | 657 kInvalidStatusCodeResponse); |
657 RunUntilIdle(); | 658 RunUntilIdle(); |
658 EXPECT_TRUE(has_failed()); | 659 EXPECT_TRUE(has_failed()); |
659 EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200", | 660 EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200", |
660 failure_message()); | 661 failure_message()); |
661 } | 662 } |
662 | 663 |
663 // Redirects are not followed (according to the WHATWG WebSocket API, which | 664 // Redirects are not followed (according to the WHATWG WebSocket API, which |
664 // overrides RFC6455 for browser applications). | 665 // overrides RFC6455 for browser applications). |
665 TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { | 666 TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { |
666 static const char kRedirectResponse[] = | 667 static const char kRedirectResponse[] = |
667 "HTTP/1.1 302 Moved Temporarily\r\n" | 668 "HTTP/1.1 302 Moved Temporarily\r\n" |
668 "Content-Type: text/html\r\n" | 669 "Content-Type: text/html\r\n" |
669 "Content-Length: 34\r\n" | 670 "Content-Length: 34\r\n" |
670 "Connection: keep-alive\r\n" | 671 "Connection: keep-alive\r\n" |
671 "Location: ws://localhost/other\r\n" | 672 "Location: ws://localhost/other\r\n" |
672 "\r\n" | 673 "\r\n" |
673 "<title>Moved</title><h1>Moved</h1>"; | 674 "<title>Moved</title><h1>Moved</h1>"; |
674 CreateAndConnectCustomResponse("ws://localhost/", | 675 CreateAndConnectCustomResponse("ws://localhost/", |
675 "/", | 676 "/", |
676 NoSubProtocols(), | 677 NoSubProtocols(), |
677 "http://localhost/", | 678 "http://localhost", |
678 "", | 679 "", |
679 kRedirectResponse); | 680 kRedirectResponse); |
680 RunUntilIdle(); | 681 RunUntilIdle(); |
681 EXPECT_TRUE(has_failed()); | 682 EXPECT_TRUE(has_failed()); |
682 EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302", | 683 EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302", |
683 failure_message()); | 684 failure_message()); |
684 } | 685 } |
685 | 686 |
686 // Malformed responses should be rejected. HttpStreamParser will accept just | 687 // Malformed responses should be rejected. HttpStreamParser will accept just |
687 // about any garbage in the middle of the headers. To make it give up, the junk | 688 // about any garbage in the middle of the headers. To make it give up, the junk |
688 // has to be at the start of the response. Even then, it just gets treated as an | 689 // has to be at the start of the response. Even then, it just gets treated as an |
689 // HTTP/0.9 response. | 690 // HTTP/0.9 response. |
690 TEST_F(WebSocketStreamCreateTest, MalformedResponse) { | 691 TEST_F(WebSocketStreamCreateTest, MalformedResponse) { |
691 static const char kMalformedResponse[] = | 692 static const char kMalformedResponse[] = |
692 "220 mx.google.com ESMTP\r\n" | 693 "220 mx.google.com ESMTP\r\n" |
693 "HTTP/1.1 101 OK\r\n" | 694 "HTTP/1.1 101 OK\r\n" |
694 "Upgrade: websocket\r\n" | 695 "Upgrade: websocket\r\n" |
695 "Connection: Upgrade\r\n" | 696 "Connection: Upgrade\r\n" |
696 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 697 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
697 "\r\n"; | 698 "\r\n"; |
698 CreateAndConnectCustomResponse("ws://localhost/", | 699 CreateAndConnectCustomResponse("ws://localhost/", |
699 "/", | 700 "/", |
700 NoSubProtocols(), | 701 NoSubProtocols(), |
701 "http://localhost/", | 702 "http://localhost", |
702 "", | 703 "", |
703 kMalformedResponse); | 704 kMalformedResponse); |
704 RunUntilIdle(); | 705 RunUntilIdle(); |
705 EXPECT_TRUE(has_failed()); | 706 EXPECT_TRUE(has_failed()); |
706 EXPECT_EQ("Error during WebSocket handshake: Invalid status line", | 707 EXPECT_EQ("Error during WebSocket handshake: Invalid status line", |
707 failure_message()); | 708 failure_message()); |
708 } | 709 } |
709 | 710 |
710 // Upgrade header must be present. | 711 // Upgrade header must be present. |
711 TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { | 712 TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { |
712 static const char kMissingUpgradeResponse[] = | 713 static const char kMissingUpgradeResponse[] = |
713 "HTTP/1.1 101 Switching Protocols\r\n" | 714 "HTTP/1.1 101 Switching Protocols\r\n" |
714 "Connection: Upgrade\r\n" | 715 "Connection: Upgrade\r\n" |
715 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 716 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
716 "\r\n"; | 717 "\r\n"; |
717 CreateAndConnectCustomResponse("ws://localhost/", | 718 CreateAndConnectCustomResponse("ws://localhost/", |
718 "/", | 719 "/", |
719 NoSubProtocols(), | 720 NoSubProtocols(), |
720 "http://localhost/", | 721 "http://localhost", |
721 "", | 722 "", |
722 kMissingUpgradeResponse); | 723 kMissingUpgradeResponse); |
723 RunUntilIdle(); | 724 RunUntilIdle(); |
724 EXPECT_TRUE(has_failed()); | 725 EXPECT_TRUE(has_failed()); |
725 EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing", | 726 EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing", |
726 failure_message()); | 727 failure_message()); |
727 } | 728 } |
728 | 729 |
729 // There must only be one upgrade header. | 730 // There must only be one upgrade header. |
730 TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { | 731 TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { |
731 CreateAndConnectStandard( | 732 CreateAndConnectStandard( |
732 "ws://localhost/", | 733 "ws://localhost/", |
733 "/", | 734 "/", |
734 NoSubProtocols(), | 735 NoSubProtocols(), |
735 "http://localhost/", | 736 "http://localhost", |
736 "", "Upgrade: HTTP/2.0\r\n"); | 737 "", "Upgrade: HTTP/2.0\r\n"); |
737 RunUntilIdle(); | 738 RunUntilIdle(); |
738 EXPECT_TRUE(has_failed()); | 739 EXPECT_TRUE(has_failed()); |
739 EXPECT_EQ("Error during WebSocket handshake: " | 740 EXPECT_EQ("Error during WebSocket handshake: " |
740 "'Upgrade' header must not appear more than once in a response", | 741 "'Upgrade' header must not appear more than once in a response", |
741 failure_message()); | 742 failure_message()); |
742 } | 743 } |
743 | 744 |
744 // There must only be one correct upgrade header. | 745 // There must only be one correct upgrade header. |
745 TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) { | 746 TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) { |
746 static const char kMissingUpgradeResponse[] = | 747 static const char kMissingUpgradeResponse[] = |
747 "HTTP/1.1 101 Switching Protocols\r\n" | 748 "HTTP/1.1 101 Switching Protocols\r\n" |
748 "Connection: Upgrade\r\n" | 749 "Connection: Upgrade\r\n" |
749 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 750 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
750 "Upgrade: hogefuga\r\n" | 751 "Upgrade: hogefuga\r\n" |
751 "\r\n"; | 752 "\r\n"; |
752 CreateAndConnectCustomResponse("ws://localhost/", | 753 CreateAndConnectCustomResponse("ws://localhost/", |
753 "/", | 754 "/", |
754 NoSubProtocols(), | 755 NoSubProtocols(), |
755 "http://localhost/", | 756 "http://localhost", |
756 "", | 757 "", |
757 kMissingUpgradeResponse); | 758 kMissingUpgradeResponse); |
758 RunUntilIdle(); | 759 RunUntilIdle(); |
759 EXPECT_TRUE(has_failed()); | 760 EXPECT_TRUE(has_failed()); |
760 EXPECT_EQ("Error during WebSocket handshake: " | 761 EXPECT_EQ("Error during WebSocket handshake: " |
761 "'Upgrade' header value is not 'WebSocket': hogefuga", | 762 "'Upgrade' header value is not 'WebSocket': hogefuga", |
762 failure_message()); | 763 failure_message()); |
763 } | 764 } |
764 | 765 |
765 // Connection header must be present. | 766 // Connection header must be present. |
766 TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { | 767 TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { |
767 static const char kMissingConnectionResponse[] = | 768 static const char kMissingConnectionResponse[] = |
768 "HTTP/1.1 101 Switching Protocols\r\n" | 769 "HTTP/1.1 101 Switching Protocols\r\n" |
769 "Upgrade: websocket\r\n" | 770 "Upgrade: websocket\r\n" |
770 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 771 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
771 "\r\n"; | 772 "\r\n"; |
772 CreateAndConnectCustomResponse("ws://localhost/", | 773 CreateAndConnectCustomResponse("ws://localhost/", |
773 "/", | 774 "/", |
774 NoSubProtocols(), | 775 NoSubProtocols(), |
775 "http://localhost/", | 776 "http://localhost", |
776 "", | 777 "", |
777 kMissingConnectionResponse); | 778 kMissingConnectionResponse); |
778 RunUntilIdle(); | 779 RunUntilIdle(); |
779 EXPECT_TRUE(has_failed()); | 780 EXPECT_TRUE(has_failed()); |
780 EXPECT_EQ("Error during WebSocket handshake: " | 781 EXPECT_EQ("Error during WebSocket handshake: " |
781 "'Connection' header is missing", | 782 "'Connection' header is missing", |
782 failure_message()); | 783 failure_message()); |
783 } | 784 } |
784 | 785 |
785 // Connection header must contain "Upgrade". | 786 // Connection header must contain "Upgrade". |
786 TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) { | 787 TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) { |
787 static const char kMissingConnectionResponse[] = | 788 static const char kMissingConnectionResponse[] = |
788 "HTTP/1.1 101 Switching Protocols\r\n" | 789 "HTTP/1.1 101 Switching Protocols\r\n" |
789 "Upgrade: websocket\r\n" | 790 "Upgrade: websocket\r\n" |
790 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 791 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
791 "Connection: hogefuga\r\n" | 792 "Connection: hogefuga\r\n" |
792 "\r\n"; | 793 "\r\n"; |
793 CreateAndConnectCustomResponse("ws://localhost/", | 794 CreateAndConnectCustomResponse("ws://localhost/", |
794 "/", | 795 "/", |
795 NoSubProtocols(), | 796 NoSubProtocols(), |
796 "http://localhost/", | 797 "http://localhost", |
797 "", | 798 "", |
798 kMissingConnectionResponse); | 799 kMissingConnectionResponse); |
799 RunUntilIdle(); | 800 RunUntilIdle(); |
800 EXPECT_TRUE(has_failed()); | 801 EXPECT_TRUE(has_failed()); |
801 EXPECT_EQ("Error during WebSocket handshake: " | 802 EXPECT_EQ("Error during WebSocket handshake: " |
802 "'Connection' header value must contain 'Upgrade'", | 803 "'Connection' header value must contain 'Upgrade'", |
803 failure_message()); | 804 failure_message()); |
804 } | 805 } |
805 | 806 |
806 // Connection header is permitted to contain other tokens. | 807 // Connection header is permitted to contain other tokens. |
807 TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { | 808 TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { |
808 static const char kAdditionalConnectionTokenResponse[] = | 809 static const char kAdditionalConnectionTokenResponse[] = |
809 "HTTP/1.1 101 Switching Protocols\r\n" | 810 "HTTP/1.1 101 Switching Protocols\r\n" |
810 "Upgrade: websocket\r\n" | 811 "Upgrade: websocket\r\n" |
811 "Connection: Upgrade, Keep-Alive\r\n" | 812 "Connection: Upgrade, Keep-Alive\r\n" |
812 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" | 813 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" |
813 "\r\n"; | 814 "\r\n"; |
814 CreateAndConnectCustomResponse("ws://localhost/", | 815 CreateAndConnectCustomResponse("ws://localhost/", |
815 "/", | 816 "/", |
816 NoSubProtocols(), | 817 NoSubProtocols(), |
817 "http://localhost/", | 818 "http://localhost", |
818 "", | 819 "", |
819 kAdditionalConnectionTokenResponse); | 820 kAdditionalConnectionTokenResponse); |
820 RunUntilIdle(); | 821 RunUntilIdle(); |
821 EXPECT_FALSE(has_failed()); | 822 EXPECT_FALSE(has_failed()); |
822 EXPECT_TRUE(stream_); | 823 EXPECT_TRUE(stream_); |
823 } | 824 } |
824 | 825 |
825 // Sec-WebSocket-Accept header must be present. | 826 // Sec-WebSocket-Accept header must be present. |
826 TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { | 827 TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { |
827 static const char kMissingAcceptResponse[] = | 828 static const char kMissingAcceptResponse[] = |
828 "HTTP/1.1 101 Switching Protocols\r\n" | 829 "HTTP/1.1 101 Switching Protocols\r\n" |
829 "Upgrade: websocket\r\n" | 830 "Upgrade: websocket\r\n" |
830 "Connection: Upgrade\r\n" | 831 "Connection: Upgrade\r\n" |
831 "\r\n"; | 832 "\r\n"; |
832 CreateAndConnectCustomResponse("ws://localhost/", | 833 CreateAndConnectCustomResponse("ws://localhost/", |
833 "/", | 834 "/", |
834 NoSubProtocols(), | 835 NoSubProtocols(), |
835 "http://localhost/", | 836 "http://localhost", |
836 "", | 837 "", |
837 kMissingAcceptResponse); | 838 kMissingAcceptResponse); |
838 RunUntilIdle(); | 839 RunUntilIdle(); |
839 EXPECT_TRUE(has_failed()); | 840 EXPECT_TRUE(has_failed()); |
840 EXPECT_EQ("Error during WebSocket handshake: " | 841 EXPECT_EQ("Error during WebSocket handshake: " |
841 "'Sec-WebSocket-Accept' header is missing", | 842 "'Sec-WebSocket-Accept' header is missing", |
842 failure_message()); | 843 failure_message()); |
843 } | 844 } |
844 | 845 |
845 // Sec-WebSocket-Accept header must match the key that was sent. | 846 // Sec-WebSocket-Accept header must match the key that was sent. |
846 TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { | 847 TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { |
847 static const char kIncorrectAcceptResponse[] = | 848 static const char kIncorrectAcceptResponse[] = |
848 "HTTP/1.1 101 Switching Protocols\r\n" | 849 "HTTP/1.1 101 Switching Protocols\r\n" |
849 "Upgrade: websocket\r\n" | 850 "Upgrade: websocket\r\n" |
850 "Connection: Upgrade\r\n" | 851 "Connection: Upgrade\r\n" |
851 "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n" | 852 "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n" |
852 "\r\n"; | 853 "\r\n"; |
853 CreateAndConnectCustomResponse("ws://localhost/", | 854 CreateAndConnectCustomResponse("ws://localhost/", |
854 "/", | 855 "/", |
855 NoSubProtocols(), | 856 NoSubProtocols(), |
856 "http://localhost/", | 857 "http://localhost", |
857 "", | 858 "", |
858 kIncorrectAcceptResponse); | 859 kIncorrectAcceptResponse); |
859 RunUntilIdle(); | 860 RunUntilIdle(); |
860 EXPECT_TRUE(has_failed()); | 861 EXPECT_TRUE(has_failed()); |
861 EXPECT_EQ("Error during WebSocket handshake: " | 862 EXPECT_EQ("Error during WebSocket handshake: " |
862 "Incorrect 'Sec-WebSocket-Accept' header value", | 863 "Incorrect 'Sec-WebSocket-Accept' header value", |
863 failure_message()); | 864 failure_message()); |
864 } | 865 } |
865 | 866 |
866 // Cancellation works. | 867 // Cancellation works. |
867 TEST_F(WebSocketStreamCreateTest, Cancellation) { | 868 TEST_F(WebSocketStreamCreateTest, Cancellation) { |
868 CreateAndConnectStandard( | 869 CreateAndConnectStandard( |
869 "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); | 870 "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", ""); |
870 stream_request_.reset(); | 871 stream_request_.reset(); |
871 RunUntilIdle(); | 872 RunUntilIdle(); |
872 EXPECT_FALSE(has_failed()); | 873 EXPECT_FALSE(has_failed()); |
873 EXPECT_FALSE(stream_); | 874 EXPECT_FALSE(stream_); |
874 EXPECT_FALSE(request_info_); | 875 EXPECT_FALSE(request_info_); |
875 EXPECT_FALSE(response_info_); | 876 EXPECT_FALSE(response_info_); |
876 } | 877 } |
877 | 878 |
878 // Connect failure must look just like negotiation failure. | 879 // Connect failure must look just like negotiation failure. |
879 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { | 880 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { |
880 scoped_ptr<DeterministicSocketData> socket_data( | 881 scoped_ptr<DeterministicSocketData> socket_data( |
881 new DeterministicSocketData(NULL, 0, NULL, 0)); | 882 new DeterministicSocketData(NULL, 0, NULL, 0)); |
882 socket_data->set_connect_data( | 883 socket_data->set_connect_data( |
883 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); | 884 MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); |
884 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), | 885 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
885 "http://localhost/", socket_data.Pass()); | 886 "http://localhost", socket_data.Pass()); |
886 RunUntilIdle(); | 887 RunUntilIdle(); |
887 EXPECT_TRUE(has_failed()); | 888 EXPECT_TRUE(has_failed()); |
888 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", | 889 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", |
889 failure_message()); | 890 failure_message()); |
890 EXPECT_FALSE(request_info_); | 891 EXPECT_FALSE(request_info_); |
891 EXPECT_FALSE(response_info_); | 892 EXPECT_FALSE(response_info_); |
892 } | 893 } |
893 | 894 |
894 // Connect timeout must look just like any other failure. | 895 // Connect timeout must look just like any other failure. |
895 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { | 896 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { |
896 scoped_ptr<DeterministicSocketData> socket_data( | 897 scoped_ptr<DeterministicSocketData> socket_data( |
897 new DeterministicSocketData(NULL, 0, NULL, 0)); | 898 new DeterministicSocketData(NULL, 0, NULL, 0)); |
898 socket_data->set_connect_data( | 899 socket_data->set_connect_data( |
899 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); | 900 MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); |
900 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), | 901 CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), |
901 "http://localhost/", socket_data.Pass()); | 902 "http://localhost", socket_data.Pass()); |
902 RunUntilIdle(); | 903 RunUntilIdle(); |
903 EXPECT_TRUE(has_failed()); | 904 EXPECT_TRUE(has_failed()); |
904 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", | 905 EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", |
905 failure_message()); | 906 failure_message()); |
906 } | 907 } |
907 | 908 |
908 // Cancellation during connect works. | 909 // Cancellation during connect works. |
909 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { | 910 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { |
910 scoped_ptr<DeterministicSocketData> socket_data( | 911 scoped_ptr<DeterministicSocketData> socket_data( |
911 new DeterministicSocketData(NULL, 0, NULL, 0)); | 912 new DeterministicSocketData(NULL, 0, NULL, 0)); |
912 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); | 913 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); |
913 CreateAndConnectRawExpectations("ws://localhost/", | 914 CreateAndConnectRawExpectations("ws://localhost/", |
914 NoSubProtocols(), | 915 NoSubProtocols(), |
915 "http://localhost/", | 916 "http://localhost", |
916 socket_data.Pass()); | 917 socket_data.Pass()); |
917 stream_request_.reset(); | 918 stream_request_.reset(); |
918 RunUntilIdle(); | 919 RunUntilIdle(); |
919 EXPECT_FALSE(has_failed()); | 920 EXPECT_FALSE(has_failed()); |
920 EXPECT_FALSE(stream_); | 921 EXPECT_FALSE(stream_); |
921 } | 922 } |
922 | 923 |
923 // Cancellation during write of the request headers works. | 924 // Cancellation during write of the request headers works. |
924 TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { | 925 TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { |
925 // We seem to need at least two operations in order to use SetStop(). | 926 // We seem to need at least two operations in order to use SetStop(). |
926 MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"), | 927 MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"), |
927 MockWrite(ASYNC, 1, "1.1\r\n")}; | 928 MockWrite(ASYNC, 1, "1.1\r\n")}; |
928 // We keep a copy of the pointer so that we can call RunFor() on it later. | 929 // We keep a copy of the pointer so that we can call RunFor() on it later. |
929 DeterministicSocketData* socket_data( | 930 DeterministicSocketData* socket_data( |
930 new DeterministicSocketData(NULL, 0, writes, arraysize(writes))); | 931 new DeterministicSocketData(NULL, 0, writes, arraysize(writes))); |
931 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | 932 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
932 socket_data->SetStop(1); | 933 socket_data->SetStop(1); |
933 CreateAndConnectRawExpectations("ws://localhost/", | 934 CreateAndConnectRawExpectations("ws://localhost/", |
934 NoSubProtocols(), | 935 NoSubProtocols(), |
935 "http://localhost/", | 936 "http://localhost", |
936 make_scoped_ptr(socket_data)); | 937 make_scoped_ptr(socket_data)); |
937 socket_data->Run(); | 938 socket_data->Run(); |
938 stream_request_.reset(); | 939 stream_request_.reset(); |
939 RunUntilIdle(); | 940 RunUntilIdle(); |
940 EXPECT_FALSE(has_failed()); | 941 EXPECT_FALSE(has_failed()); |
941 EXPECT_FALSE(stream_); | 942 EXPECT_FALSE(stream_); |
942 EXPECT_TRUE(request_info_); | 943 EXPECT_TRUE(request_info_); |
943 EXPECT_FALSE(response_info_); | 944 EXPECT_FALSE(response_info_); |
944 } | 945 } |
945 | 946 |
946 // Cancellation during read of the response headers works. | 947 // Cancellation during read of the response headers works. |
947 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { | 948 TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { |
948 std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); | 949 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); |
949 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; | 950 MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; |
950 MockRead reads[] = { | 951 MockRead reads[] = { |
951 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), | 952 MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), |
952 }; | 953 }; |
953 DeterministicSocketData* socket_data(new DeterministicSocketData( | 954 DeterministicSocketData* socket_data(new DeterministicSocketData( |
954 reads, arraysize(reads), writes, arraysize(writes))); | 955 reads, arraysize(reads), writes, arraysize(writes))); |
955 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | 956 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
956 socket_data->SetStop(1); | 957 socket_data->SetStop(1); |
957 CreateAndConnectRawExpectations("ws://localhost/", | 958 CreateAndConnectRawExpectations("ws://localhost/", |
958 NoSubProtocols(), | 959 NoSubProtocols(), |
959 "http://localhost/", | 960 "http://localhost", |
960 make_scoped_ptr(socket_data)); | 961 make_scoped_ptr(socket_data)); |
961 socket_data->Run(); | 962 socket_data->Run(); |
962 stream_request_.reset(); | 963 stream_request_.reset(); |
963 RunUntilIdle(); | 964 RunUntilIdle(); |
964 EXPECT_FALSE(has_failed()); | 965 EXPECT_FALSE(has_failed()); |
965 EXPECT_FALSE(stream_); | 966 EXPECT_FALSE(stream_); |
966 EXPECT_TRUE(request_info_); | 967 EXPECT_TRUE(request_info_); |
967 EXPECT_FALSE(response_info_); | 968 EXPECT_FALSE(response_info_); |
968 } | 969 } |
969 | 970 |
970 // Over-size response headers (> 256KB) should not cause a crash. This is a | 971 // Over-size response headers (> 256KB) should not cause a crash. This is a |
971 // regression test for crbug.com/339456. It is based on the layout test | 972 // regression test for crbug.com/339456. It is based on the layout test |
972 // "cookie-flood.html". | 973 // "cookie-flood.html". |
973 TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) { | 974 TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) { |
974 std::string set_cookie_headers; | 975 std::string set_cookie_headers; |
975 set_cookie_headers.reserve(45 * 10000); | 976 set_cookie_headers.reserve(45 * 10000); |
976 for (int i = 0; i < 10000; ++i) { | 977 for (int i = 0; i < 10000; ++i) { |
977 set_cookie_headers += | 978 set_cookie_headers += |
978 base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i); | 979 base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i); |
979 } | 980 } |
980 CreateAndConnectStandard("ws://localhost/", "/", NoSubProtocols(), | 981 CreateAndConnectStandard("ws://localhost/", "/", NoSubProtocols(), |
981 "http://localhost/", "", set_cookie_headers); | 982 "http://localhost", "", set_cookie_headers); |
982 RunUntilIdle(); | 983 RunUntilIdle(); |
983 EXPECT_TRUE(has_failed()); | 984 EXPECT_TRUE(has_failed()); |
984 EXPECT_FALSE(response_info_); | 985 EXPECT_FALSE(response_info_); |
985 } | 986 } |
986 | 987 |
987 // If the remote host closes the connection without sending headers, we should | 988 // If the remote host closes the connection without sending headers, we should |
988 // log the console message "Connection closed before receiving a handshake | 989 // log the console message "Connection closed before receiving a handshake |
989 // response". | 990 // response". |
990 TEST_F(WebSocketStreamCreateTest, NoResponse) { | 991 TEST_F(WebSocketStreamCreateTest, NoResponse) { |
991 std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); | 992 std::string request = WebSocketStandardRequest("/", "http://localhost", ""); |
992 MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; | 993 MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; |
993 MockRead reads[] = {MockRead(ASYNC, 0, 1)}; | 994 MockRead reads[] = {MockRead(ASYNC, 0, 1)}; |
994 DeterministicSocketData* socket_data(new DeterministicSocketData( | 995 DeterministicSocketData* socket_data(new DeterministicSocketData( |
995 reads, arraysize(reads), writes, arraysize(writes))); | 996 reads, arraysize(reads), writes, arraysize(writes))); |
996 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | 997 socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
997 CreateAndConnectRawExpectations("ws://localhost/", | 998 CreateAndConnectRawExpectations("ws://localhost/", |
998 NoSubProtocols(), | 999 NoSubProtocols(), |
999 "http://localhost/", | 1000 "http://localhost", |
1000 make_scoped_ptr(socket_data)); | 1001 make_scoped_ptr(socket_data)); |
1001 socket_data->RunFor(2); | 1002 socket_data->RunFor(2); |
1002 EXPECT_TRUE(has_failed()); | 1003 EXPECT_TRUE(has_failed()); |
1003 EXPECT_FALSE(stream_); | 1004 EXPECT_FALSE(stream_); |
1004 EXPECT_FALSE(response_info_); | 1005 EXPECT_FALSE(response_info_); |
1005 EXPECT_EQ("Connection closed before receiving a handshake response", | 1006 EXPECT_EQ("Connection closed before receiving a handshake response", |
1006 failure_message()); | 1007 failure_message()); |
1007 } | 1008 } |
1008 | 1009 |
1009 } // namespace | 1010 } // namespace |
1010 } // namespace net | 1011 } // namespace net |
OLD | NEW |