| 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 |