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 3 // found in the LICENSE file. 4 5 #include "net/websockets/websocket_job.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/callback.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/strings/string_split.h" 15 #include "base/strings/string_util.h" 16 #include "net/base/completion_callback.h" 17 #include "net/base/net_errors.h" 18 #include "net/base/test_completion_callback.h" 19 #include "net/cookies/cookie_store.h" 20 #include "net/cookies/cookie_store_test_helpers.h" 21 #include "net/dns/mock_host_resolver.h" 22 #include "net/http/http_transaction_factory.h" 23 #include "net/http/transport_security_state.h" 24 #include "net/proxy/proxy_service.h" 25 #include "net/socket/next_proto.h" 26 #include "net/socket/socket_test_util.h" 27 #include "net/socket_stream/socket_stream.h" 28 #include "net/spdy/spdy_session.h" 29 #include "net/spdy/spdy_websocket_test_util.h" 30 #include "net/ssl/ssl_config_service.h" 31 #include "net/url_request/url_request_context.h" 32 #include "net/websockets/websocket_throttle.h" 33 #include "testing/gmock/include/gmock/gmock.h" 34 #include "testing/gtest/include/gtest/gtest.h" 35 #include "testing/platform_test.h" 36 #include "url/gurl.h" 37 38 namespace net { 39 40 namespace { 41 42 class MockSocketStream : public SocketStream { 43 public: 44 MockSocketStream(const GURL& url, SocketStream::Delegate* delegate, 45 URLRequestContext* context, CookieStore* cookie_store) 46 : SocketStream(url, delegate, context, cookie_store) {} 47 48 virtual void Connect() OVERRIDE {} 49 virtual bool SendData(const char* data, int len) OVERRIDE { 50 sent_data_ += std::string(data, len); 51 return true; 52 } 53 54 virtual void Close() OVERRIDE {} 55 virtual void RestartWithAuth( 56 const AuthCredentials& credentials) OVERRIDE { 57 } 58 59 virtual void DetachDelegate() OVERRIDE { 60 delegate_ = NULL; 61 } 62 63 const std::string& sent_data() const { 64 return sent_data_; 65 } 66 67 protected: 68 virtual ~MockSocketStream() {} 69 70 private: 71 std::string sent_data_; 72 }; 73 74 class MockSocketStreamDelegate : public SocketStream::Delegate { 75 public: 76 MockSocketStreamDelegate() 77 : amount_sent_(0), allow_all_cookies_(true) {} 78 void set_allow_all_cookies(bool allow_all_cookies) { 79 allow_all_cookies_ = allow_all_cookies; 80 } 81 virtual ~MockSocketStreamDelegate() {} 82 83 void SetOnStartOpenConnection(const base::Closure& callback) { 84 on_start_open_connection_ = callback; 85 } 86 void SetOnConnected(const base::Closure& callback) { 87 on_connected_ = callback; 88 } 89 void SetOnSentData(const base::Closure& callback) { 90 on_sent_data_ = callback; 91 } 92 void SetOnReceivedData(const base::Closure& callback) { 93 on_received_data_ = callback; 94 } 95 void SetOnClose(const base::Closure& callback) { 96 on_close_ = callback; 97 } 98 99 virtual int OnStartOpenConnection( 100 SocketStream* socket, 101 const CompletionCallback& callback) OVERRIDE { 102 if (!on_start_open_connection_.is_null()) 103 on_start_open_connection_.Run(); 104 return OK; 105 } 106 virtual void OnConnected(SocketStream* socket, 107 int max_pending_send_allowed) OVERRIDE { 108 if (!on_connected_.is_null()) 109 on_connected_.Run(); 110 } 111 virtual void OnSentData(SocketStream* socket, 112 int amount_sent) OVERRIDE { 113 amount_sent_ += amount_sent; 114 if (!on_sent_data_.is_null()) 115 on_sent_data_.Run(); 116 } 117 virtual void OnReceivedData(SocketStream* socket, 118 const char* data, int len) OVERRIDE { 119 received_data_ += std::string(data, len); 120 if (!on_received_data_.is_null()) 121 on_received_data_.Run(); 122 } 123 virtual void OnClose(SocketStream* socket) OVERRIDE { 124 if (!on_close_.is_null()) 125 on_close_.Run(); 126 } 127 virtual bool CanGetCookies(SocketStream* socket, 128 const GURL& url) OVERRIDE { 129 return allow_all_cookies_; 130 } 131 virtual bool CanSetCookie(SocketStream* request, 132 const GURL& url, 133 const std::string& cookie_line, 134 CookieOptions* options) OVERRIDE { 135 return allow_all_cookies_; 136 } 137 138 size_t amount_sent() const { return amount_sent_; } 139 const std::string& received_data() const { return received_data_; } 140 141 private: 142 int amount_sent_; 143 bool allow_all_cookies_; 144 std::string received_data_; 145 base::Closure on_start_open_connection_; 146 base::Closure on_connected_; 147 base::Closure on_sent_data_; 148 base::Closure on_received_data_; 149 base::Closure on_close_; 150 }; 151 152 class MockCookieStore : public CookieStore { 153 public: 154 struct Entry { 155 GURL url; 156 std::string cookie_line; 157 CookieOptions options; 158 }; 159 160 MockCookieStore() {} 161 162 bool SetCookieWithOptions(const GURL& url, 163 const std::string& cookie_line, 164 const CookieOptions& options) { 165 Entry entry; 166 entry.url = url; 167 entry.cookie_line = cookie_line; 168 entry.options = options; 169 entries_.push_back(entry); 170 return true; 171 } 172 173 std::string GetCookiesWithOptions(const GURL& url, 174 const CookieOptions& options) { 175 std::string result; 176 for (size_t i = 0; i < entries_.size(); i++) { 177 Entry& entry = entries_[i]; 178 if (url == entry.url) { 179 if (!result.empty()) { 180 result += "; "; 181 } 182 result += entry.cookie_line; 183 } 184 } 185 return result; 186 } 187 188 // CookieStore: 189 virtual void SetCookieWithOptionsAsync( 190 const GURL& url, 191 const std::string& cookie_line, 192 const CookieOptions& options, 193 const SetCookiesCallback& callback) OVERRIDE { 194 bool result = SetCookieWithOptions(url, cookie_line, options); 195 if (!callback.is_null()) 196 callback.Run(result); 197 } 198 199 virtual void GetCookiesWithOptionsAsync( 200 const GURL& url, 201 const CookieOptions& options, 202 const GetCookiesCallback& callback) OVERRIDE { 203 if (!callback.is_null()) 204 callback.Run(GetCookiesWithOptions(url, options)); 205 } 206 207 virtual void GetAllCookiesForURLAsync( 208 const GURL& url, 209 const GetCookieListCallback& callback) OVERRIDE { 210 ADD_FAILURE(); 211 } 212 213 virtual void DeleteCookieAsync(const GURL& url, 214 const std::string& cookie_name, 215 const base::Closure& callback) OVERRIDE { 216 ADD_FAILURE(); 217 } 218 219 virtual void DeleteAllCreatedBetweenAsync( 220 const base::Time& delete_begin, 221 const base::Time& delete_end, 222 const DeleteCallback& callback) OVERRIDE { 223 ADD_FAILURE(); 224 } 225 226 virtual void DeleteAllCreatedBetweenForHostAsync( 227 const base::Time delete_begin, 228 const base::Time delete_end, 229 const GURL& url, 230 const DeleteCallback& callback) OVERRIDE { 231 ADD_FAILURE(); 232 } 233 234 virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE { 235 ADD_FAILURE(); 236 } 237 238 virtual CookieMonster* GetCookieMonster() OVERRIDE { return NULL; } 239 240 const std::vector<Entry>& entries() const { return entries_; } 241 242 private: 243 friend class base::RefCountedThreadSafe<MockCookieStore>; 244 virtual ~MockCookieStore() {} 245 246 std::vector<Entry> entries_; 247 }; 248 249 class MockSSLConfigService : public SSLConfigService { 250 public: 251 virtual void GetSSLConfig(SSLConfig* config) OVERRIDE {} 252 253 protected: 254 virtual ~MockSSLConfigService() {} 255 }; 256 257 class MockURLRequestContext : public URLRequestContext { 258 public: 259 explicit MockURLRequestContext(CookieStore* cookie_store) 260 : transport_security_state_() { 261 set_cookie_store(cookie_store); 262 set_transport_security_state(&transport_security_state_); 263 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000); 264 bool include_subdomains = false; 265 transport_security_state_.AddHSTS("upgrademe.com", expiry, 266 include_subdomains); 267 } 268 269 virtual ~MockURLRequestContext() { 270 AssertNoURLRequests(); 271 } 272 273 private: 274 TransportSecurityState transport_security_state_; 275 }; 276 277 class MockHttpTransactionFactory : public HttpTransactionFactory { 278 public: 279 MockHttpTransactionFactory(NextProto next_proto, 280 OrderedSocketData* data, 281 bool enable_websocket_over_spdy) { 282 data_ = data; 283 MockConnect connect_data(SYNCHRONOUS, OK); 284 data_->set_connect_data(connect_data); 285 session_deps_.reset(new SpdySessionDependencies(next_proto)); 286 session_deps_->enable_websocket_over_spdy = enable_websocket_over_spdy; 287 session_deps_->socket_factory->AddSocketDataProvider(data_); 288 http_session_ = 289 SpdySessionDependencies::SpdyCreateSession(session_deps_.get()); 290 host_port_pair_.set_host("example.com"); 291 host_port_pair_.set_port(80); 292 spdy_session_key_ = SpdySessionKey(host_port_pair_, 293 ProxyServer::Direct(), 294 PRIVACY_MODE_DISABLED); 295 session_ = CreateInsecureSpdySession( 296 http_session_, spdy_session_key_, BoundNetLog()); 297 } 298 299 virtual int CreateTransaction( 300 RequestPriority priority, 301 scoped_ptr<HttpTransaction>* trans) OVERRIDE { 302 NOTREACHED(); 303 return ERR_UNEXPECTED; 304 } 305 306 virtual HttpCache* GetCache() OVERRIDE { 307 NOTREACHED(); 308 return NULL; 309 } 310 311 virtual HttpNetworkSession* GetSession() OVERRIDE { 312 return http_session_.get(); 313 } 314 315 private: 316 OrderedSocketData* data_; 317 scoped_ptr<SpdySessionDependencies> session_deps_; 318 scoped_refptr<HttpNetworkSession> http_session_; 319 base::WeakPtr<SpdySession> session_; 320 HostPortPair host_port_pair_; 321 SpdySessionKey spdy_session_key_; 322 }; 323 324 class DeletingSocketStreamDelegate : public SocketStream::Delegate { 325 public: 326 DeletingSocketStreamDelegate() 327 : delete_next_(false) {} 328 329 // Since this class needs to be able to delete |job_|, it must be the only 330 // reference holder (except for temporary references). Provide access to the 331 // pointer for tests to use. 332 WebSocketJob* job() { return job_.get(); } 333 334 void set_job(WebSocketJob* job) { job_ = job; } 335 336 // After calling this, the next call to a method on this delegate will delete 337 // the WebSocketJob object. 338 void set_delete_next(bool delete_next) { delete_next_ = delete_next; } 339 340 void DeleteJobMaybe() { 341 if (delete_next_) { 342 job_->DetachContext(); 343 job_->DetachDelegate(); 344 job_ = NULL; 345 } 346 } 347 348 // SocketStream::Delegate implementation 349 350 // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost 351 352 virtual void OnConnected(SocketStream* socket, 353 int max_pending_send_allowed) OVERRIDE { 354 DeleteJobMaybe(); 355 } 356 357 virtual void OnSentData(SocketStream* socket, int amount_sent) OVERRIDE { 358 DeleteJobMaybe(); 359 } 360 361 virtual void OnReceivedData(SocketStream* socket, 362 const char* data, 363 int len) OVERRIDE { 364 DeleteJobMaybe(); 365 } 366 367 virtual void OnClose(SocketStream* socket) OVERRIDE { DeleteJobMaybe(); } 368 369 virtual void OnAuthRequired(SocketStream* socket, 370 AuthChallengeInfo* auth_info) OVERRIDE { 371 DeleteJobMaybe(); 372 } 373 374 virtual void OnSSLCertificateError(SocketStream* socket, 375 const SSLInfo& ssl_info, 376 bool fatal) OVERRIDE { 377 DeleteJobMaybe(); 378 } 379 380 virtual void OnError(const SocketStream* socket, int error) OVERRIDE { 381 DeleteJobMaybe(); 382 } 383 384 // CanGetCookies() and CanSetCookies() do not appear to be able to delete the 385 // WebSocketJob object. 386 387 private: 388 scoped_refptr<WebSocketJob> job_; 389 bool delete_next_; 390 }; 391 392 } // namespace 393 394 class WebSocketJobTest : public PlatformTest, 395 public ::testing::WithParamInterface<NextProto> { 396 public: 397 WebSocketJobTest() 398 : spdy_util_(GetParam()), 399 enable_websocket_over_spdy_(false) {} 400 401 virtual void SetUp() OVERRIDE { 402 stream_type_ = STREAM_INVALID; 403 cookie_store_ = new MockCookieStore; 404 context_.reset(new MockURLRequestContext(cookie_store_.get())); 405 } 406 virtual void TearDown() OVERRIDE { 407 cookie_store_ = NULL; 408 context_.reset(); 409 websocket_ = NULL; 410 socket_ = NULL; 411 } 412 void DoSendRequest() { 413 EXPECT_TRUE(websocket_->SendData(kHandshakeRequestWithoutCookie, 414 kHandshakeRequestWithoutCookieLength)); 415 } 416 void DoSendData() { 417 if (received_data().size() == kHandshakeResponseWithoutCookieLength) 418 websocket_->SendData(kDataHello, kDataHelloLength); 419 } 420 void DoSync() { 421 sync_test_callback_.callback().Run(OK); 422 } 423 int WaitForResult() { 424 return sync_test_callback_.WaitForResult(); 425 } 426 427 protected: 428 enum StreamType { 429 STREAM_INVALID, 430 STREAM_MOCK_SOCKET, 431 STREAM_SOCKET, 432 STREAM_SPDY_WEBSOCKET, 433 }; 434 enum ThrottlingOption { 435 THROTTLING_OFF, 436 THROTTLING_ON, 437 }; 438 enum SpdyOption { 439 SPDY_OFF, 440 SPDY_ON, 441 }; 442 void InitWebSocketJob(const GURL& url, 443 MockSocketStreamDelegate* delegate, 444 StreamType stream_type) { 445 DCHECK_NE(STREAM_INVALID, stream_type); 446 stream_type_ = stream_type; 447 websocket_ = new WebSocketJob(delegate); 448 449 if (stream_type == STREAM_MOCK_SOCKET) 450 socket_ = new MockSocketStream(url, websocket_.get(), context_.get(), 451 NULL); 452 453 if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) { 454 if (stream_type == STREAM_SPDY_WEBSOCKET) { 455 http_factory_.reset(new MockHttpTransactionFactory( 456 GetParam(), data_.get(), enable_websocket_over_spdy_)); 457 context_->set_http_transaction_factory(http_factory_.get()); 458 } 459 460 ssl_config_service_ = new MockSSLConfigService(); 461 context_->set_ssl_config_service(ssl_config_service_.get()); 462 proxy_service_.reset(ProxyService::CreateDirect()); 463 context_->set_proxy_service(proxy_service_.get()); 464 host_resolver_.reset(new MockHostResolver); 465 context_->set_host_resolver(host_resolver_.get()); 466 467 socket_ = new SocketStream(url, websocket_.get(), context_.get(), NULL); 468 socket_factory_.reset(new MockClientSocketFactory); 469 DCHECK(data_.get()); 470 socket_factory_->AddSocketDataProvider(data_.get()); 471 socket_->SetClientSocketFactory(socket_factory_.get()); 472 } 473 474 websocket_->InitSocketStream(socket_.get()); 475 // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create 476 // a WebSocketJob purely to block another one in a throttling test, we don't 477 // perform a real connect. In that case, the following address is used 478 // instead. 479 IPAddressNumber ip; 480 ParseIPLiteralToNumber("127.0.0.1", &ip); 481 websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80); 482 } 483 void SkipToConnecting() { 484 websocket_->state_ = WebSocketJob::CONNECTING; 485 ASSERT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(websocket_.get())); 486 } 487 WebSocketJob::State GetWebSocketJobState() { 488 return websocket_->state_; 489 } 490 void CloseWebSocketJob() { 491 if (websocket_->socket_.get()) { 492 websocket_->socket_->DetachDelegate(); 493 WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_.get()); 494 } 495 websocket_->state_ = WebSocketJob::CLOSED; 496 websocket_->delegate_ = NULL; 497 websocket_->socket_ = NULL; 498 } 499 SocketStream* GetSocket(SocketStreamJob* job) { 500 return job->socket_.get(); 501 } 502 const std::string& sent_data() const { 503 DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_); 504 MockSocketStream* socket = 505 static_cast<MockSocketStream*>(socket_.get()); 506 DCHECK(socket); 507 return socket->sent_data(); 508 } 509 const std::string& received_data() const { 510 DCHECK_NE(STREAM_INVALID, stream_type_); 511 MockSocketStreamDelegate* delegate = 512 static_cast<MockSocketStreamDelegate*>(websocket_->delegate_); 513 DCHECK(delegate); 514 return delegate->received_data(); 515 } 516 517 void TestSimpleHandshake(); 518 void TestSlowHandshake(); 519 void TestHandshakeWithCookie(); 520 void TestHandshakeWithCookieButNotAllowed(); 521 void TestHSTSUpgrade(); 522 void TestInvalidSendData(); 523 void TestConnectByWebSocket(ThrottlingOption throttling); 524 void TestConnectBySpdy(SpdyOption spdy, ThrottlingOption throttling); 525 void TestThrottlingLimit(); 526 527 SpdyWebSocketTestUtil spdy_util_; 528 StreamType stream_type_; 529 scoped_refptr<MockCookieStore> cookie_store_; 530 scoped_ptr<MockURLRequestContext> context_; 531 scoped_refptr<WebSocketJob> websocket_; 532 scoped_refptr<SocketStream> socket_; 533 scoped_ptr<MockClientSocketFactory> socket_factory_; 534 scoped_ptr<OrderedSocketData> data_; 535 TestCompletionCallback sync_test_callback_; 536 scoped_refptr<MockSSLConfigService> ssl_config_service_; 537 scoped_ptr<ProxyService> proxy_service_; 538 scoped_ptr<MockHostResolver> host_resolver_; 539 scoped_ptr<MockHttpTransactionFactory> http_factory_; 540 541 // Must be set before call to enable_websocket_over_spdy, defaults to false. 542 bool enable_websocket_over_spdy_; 543 544 static const char kHandshakeRequestWithoutCookie[]; 545 static const char kHandshakeRequestWithCookie[]; 546 static const char kHandshakeRequestWithFilteredCookie[]; 547 static const char kHandshakeResponseWithoutCookie[]; 548 static const char kHandshakeResponseWithCookie[]; 549 static const char kDataHello[]; 550 static const char kDataWorld[]; 551 static const char* const kHandshakeRequestForSpdy[]; 552 static const char* const kHandshakeResponseForSpdy[]; 553 static const size_t kHandshakeRequestWithoutCookieLength; 554 static const size_t kHandshakeRequestWithCookieLength; 555 static const size_t kHandshakeRequestWithFilteredCookieLength; 556 static const size_t kHandshakeResponseWithoutCookieLength; 557 static const size_t kHandshakeResponseWithCookieLength; 558 static const size_t kDataHelloLength; 559 static const size_t kDataWorldLength; 560 }; 561 562 // Tests using this fixture verify that the WebSocketJob can handle being 563 // deleted while calling back to the delegate correctly. These tests need to be 564 // run under AddressSanitizer or other systems for detecting use-after-free 565 // errors in order to find problems. 566 class WebSocketJobDeleteTest : public ::testing::Test { 567 protected: 568 WebSocketJobDeleteTest() 569 : delegate_(new DeletingSocketStreamDelegate), 570 cookie_store_(new MockCookieStore), 571 context_(new MockURLRequestContext(cookie_store_.get())) { 572 WebSocketJob* websocket = new WebSocketJob(delegate_.get()); 573 delegate_->set_job(websocket); 574 575 socket_ = new MockSocketStream( 576 GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL); 577 578 websocket->InitSocketStream(socket_.get()); 579 } 580 581 void SetDeleteNext() { return delegate_->set_delete_next(true); } 582 WebSocketJob* job() { return delegate_->job(); } 583 584 scoped_ptr<DeletingSocketStreamDelegate> delegate_; 585 scoped_refptr<MockCookieStore> cookie_store_; 586 scoped_ptr<MockURLRequestContext> context_; 587 scoped_refptr<SocketStream> socket_; 588 }; 589 590 const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] = 591 "GET /demo HTTP/1.1\r\n" 592 "Host: example.com\r\n" 593 "Upgrade: WebSocket\r\n" 594 "Connection: Upgrade\r\n" 595 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" 596 "Origin: http://example.com\r\n" 597 "Sec-WebSocket-Protocol: sample\r\n" 598 "Sec-WebSocket-Version: 13\r\n" 599 "\r\n"; 600 601 const char WebSocketJobTest::kHandshakeRequestWithCookie[] = 602 "GET /demo HTTP/1.1\r\n" 603 "Host: example.com\r\n" 604 "Upgrade: WebSocket\r\n" 605 "Connection: Upgrade\r\n" 606 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" 607 "Origin: http://example.com\r\n" 608 "Sec-WebSocket-Protocol: sample\r\n" 609 "Sec-WebSocket-Version: 13\r\n" 610 "Cookie: WK-test=1\r\n" 611 "\r\n"; 612 613 const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie[] = 614 "GET /demo HTTP/1.1\r\n" 615 "Host: example.com\r\n" 616 "Upgrade: WebSocket\r\n" 617 "Connection: Upgrade\r\n" 618 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" 619 "Origin: http://example.com\r\n" 620 "Sec-WebSocket-Protocol: sample\r\n" 621 "Sec-WebSocket-Version: 13\r\n" 622 "Cookie: CR-test=1; CR-test-httponly=1\r\n" 623 "\r\n"; 624 625 const char WebSocketJobTest::kHandshakeResponseWithoutCookie[] = 626 "HTTP/1.1 101 Switching Protocols\r\n" 627 "Upgrade: websocket\r\n" 628 "Connection: Upgrade\r\n" 629 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 630 "Sec-WebSocket-Protocol: sample\r\n" 631 "\r\n"; 632 633 const char WebSocketJobTest::kHandshakeResponseWithCookie[] = 634 "HTTP/1.1 101 Switching Protocols\r\n" 635 "Upgrade: websocket\r\n" 636 "Connection: Upgrade\r\n" 637 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 638 "Sec-WebSocket-Protocol: sample\r\n" 639 "Set-Cookie: CR-set-test=1\r\n" 640 "\r\n"; 641 642 const char WebSocketJobTest::kDataHello[] = "Hello, "; 643 644 const char WebSocketJobTest::kDataWorld[] = "World!\n"; 645 646 const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength = 647 arraysize(kHandshakeRequestWithoutCookie) - 1; 648 const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength = 649 arraysize(kHandshakeRequestWithCookie) - 1; 650 const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength = 651 arraysize(kHandshakeRequestWithFilteredCookie) - 1; 652 const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength = 653 arraysize(kHandshakeResponseWithoutCookie) - 1; 654 const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength = 655 arraysize(kHandshakeResponseWithCookie) - 1; 656 const size_t WebSocketJobTest::kDataHelloLength = 657 arraysize(kDataHello) - 1; 658 const size_t WebSocketJobTest::kDataWorldLength = 659 arraysize(kDataWorld) - 1; 660 661 void WebSocketJobTest::TestSimpleHandshake() { 662 GURL url("ws://example.com/demo"); 663 MockSocketStreamDelegate delegate; 664 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 665 SkipToConnecting(); 666 667 DoSendRequest(); 668 base::MessageLoop::current()->RunUntilIdle(); 669 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); 670 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 671 websocket_->OnSentData(socket_.get(), 672 kHandshakeRequestWithoutCookieLength); 673 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent()); 674 675 websocket_->OnReceivedData(socket_.get(), 676 kHandshakeResponseWithoutCookie, 677 kHandshakeResponseWithoutCookieLength); 678 base::MessageLoop::current()->RunUntilIdle(); 679 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); 680 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); 681 CloseWebSocketJob(); 682 } 683 684 void WebSocketJobTest::TestSlowHandshake() { 685 GURL url("ws://example.com/demo"); 686 MockSocketStreamDelegate delegate; 687 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 688 SkipToConnecting(); 689 690 DoSendRequest(); 691 // We assume request is sent in one data chunk (from WebKit) 692 // We don't support streaming request. 693 base::MessageLoop::current()->RunUntilIdle(); 694 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); 695 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 696 websocket_->OnSentData(socket_.get(), 697 kHandshakeRequestWithoutCookieLength); 698 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent()); 699 700 std::vector<std::string> lines; 701 base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines); 702 for (size_t i = 0; i < lines.size() - 2; i++) { 703 std::string line = lines[i] + "\r\n"; 704 SCOPED_TRACE("Line: " + line); 705 websocket_->OnReceivedData(socket_.get(), line.c_str(), line.size()); 706 base::MessageLoop::current()->RunUntilIdle(); 707 EXPECT_TRUE(delegate.received_data().empty()); 708 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 709 } 710 websocket_->OnReceivedData(socket_.get(), "\r\n", 2); 711 base::MessageLoop::current()->RunUntilIdle(); 712 EXPECT_FALSE(delegate.received_data().empty()); 713 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); 714 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); 715 CloseWebSocketJob(); 716 } 717 718 INSTANTIATE_TEST_CASE_P( 719 NextProto, 720 WebSocketJobTest, 721 testing::Values(kProtoDeprecatedSPDY2, 722 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); 723 724 TEST_P(WebSocketJobTest, DelayedCookies) { 725 enable_websocket_over_spdy_ = true; 726 GURL url("ws://example.com/demo"); 727 GURL cookieUrl("http://example.com/demo"); 728 CookieOptions cookie_options; 729 scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster(); 730 context_->set_cookie_store(cookie_store.get()); 731 cookie_store->SetCookieWithOptionsAsync(cookieUrl, 732 "CR-test=1", 733 cookie_options, 734 CookieMonster::SetCookiesCallback()); 735 cookie_options.set_include_httponly(); 736 cookie_store->SetCookieWithOptionsAsync( 737 cookieUrl, "CR-test-httponly=1", cookie_options, 738 CookieMonster::SetCookiesCallback()); 739 740 MockSocketStreamDelegate delegate; 741 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 742 SkipToConnecting(); 743 744 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, 745 kHandshakeRequestWithCookieLength); 746 EXPECT_TRUE(sent); 747 base::MessageLoop::current()->RunUntilIdle(); 748 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); 749 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 750 websocket_->OnSentData(socket_.get(), 751 kHandshakeRequestWithFilteredCookieLength); 752 EXPECT_EQ(kHandshakeRequestWithCookieLength, 753 delegate.amount_sent()); 754 755 websocket_->OnReceivedData(socket_.get(), 756 kHandshakeResponseWithCookie, 757 kHandshakeResponseWithCookieLength); 758 base::MessageLoop::current()->RunUntilIdle(); 759 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); 760 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); 761 762 CloseWebSocketJob(); 763 } 764 765 void WebSocketJobTest::TestHandshakeWithCookie() { 766 GURL url("ws://example.com/demo"); 767 GURL cookieUrl("http://example.com/demo"); 768 CookieOptions cookie_options; 769 cookie_store_->SetCookieWithOptions( 770 cookieUrl, "CR-test=1", cookie_options); 771 cookie_options.set_include_httponly(); 772 cookie_store_->SetCookieWithOptions( 773 cookieUrl, "CR-test-httponly=1", cookie_options); 774 775 MockSocketStreamDelegate delegate; 776 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 777 SkipToConnecting(); 778 779 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, 780 kHandshakeRequestWithCookieLength); 781 EXPECT_TRUE(sent); 782 base::MessageLoop::current()->RunUntilIdle(); 783 EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data()); 784 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 785 websocket_->OnSentData(socket_.get(), 786 kHandshakeRequestWithFilteredCookieLength); 787 EXPECT_EQ(kHandshakeRequestWithCookieLength, 788 delegate.amount_sent()); 789 790 websocket_->OnReceivedData(socket_.get(), 791 kHandshakeResponseWithCookie, 792 kHandshakeResponseWithCookieLength); 793 base::MessageLoop::current()->RunUntilIdle(); 794 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); 795 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); 796 797 EXPECT_EQ(3U, cookie_store_->entries().size()); 798 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url); 799 EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line); 800 EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url); 801 EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line); 802 EXPECT_EQ(cookieUrl, cookie_store_->entries()[2].url); 803 EXPECT_EQ("CR-set-test=1", cookie_store_->entries()[2].cookie_line); 804 805 CloseWebSocketJob(); 806 } 807 808 void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() { 809 GURL url("ws://example.com/demo"); 810 GURL cookieUrl("http://example.com/demo"); 811 CookieOptions cookie_options; 812 cookie_store_->SetCookieWithOptions( 813 cookieUrl, "CR-test=1", cookie_options); 814 cookie_options.set_include_httponly(); 815 cookie_store_->SetCookieWithOptions( 816 cookieUrl, "CR-test-httponly=1", cookie_options); 817 818 MockSocketStreamDelegate delegate; 819 delegate.set_allow_all_cookies(false); 820 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 821 SkipToConnecting(); 822 823 bool sent = websocket_->SendData(kHandshakeRequestWithCookie, 824 kHandshakeRequestWithCookieLength); 825 EXPECT_TRUE(sent); 826 base::MessageLoop::current()->RunUntilIdle(); 827 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); 828 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 829 websocket_->OnSentData(socket_.get(), kHandshakeRequestWithoutCookieLength); 830 EXPECT_EQ(kHandshakeRequestWithCookieLength, delegate.amount_sent()); 831 832 websocket_->OnReceivedData(socket_.get(), 833 kHandshakeResponseWithCookie, 834 kHandshakeResponseWithCookieLength); 835 base::MessageLoop::current()->RunUntilIdle(); 836 EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data()); 837 EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState()); 838 839 EXPECT_EQ(2U, cookie_store_->entries().size()); 840 EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url); 841 EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line); 842 EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url); 843 EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line); 844 845 CloseWebSocketJob(); 846 } 847 848 void WebSocketJobTest::TestHSTSUpgrade() { 849 GURL url("ws://upgrademe.com/"); 850 MockSocketStreamDelegate delegate; 851 scoped_refptr<SocketStreamJob> job = 852 SocketStreamJob::CreateSocketStreamJob( 853 url, &delegate, context_->transport_security_state(), 854 context_->ssl_config_service(), NULL, NULL); 855 EXPECT_TRUE(GetSocket(job.get())->is_secure()); 856 job->DetachDelegate(); 857 858 url = GURL("ws://donotupgrademe.com/"); 859 job = SocketStreamJob::CreateSocketStreamJob( 860 url, &delegate, context_->transport_security_state(), 861 context_->ssl_config_service(), NULL, NULL); 862 EXPECT_FALSE(GetSocket(job.get())->is_secure()); 863 job->DetachDelegate(); 864 } 865 866 void WebSocketJobTest::TestInvalidSendData() { 867 GURL url("ws://example.com/demo"); 868 MockSocketStreamDelegate delegate; 869 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET); 870 SkipToConnecting(); 871 872 DoSendRequest(); 873 // We assume request is sent in one data chunk (from WebKit) 874 // We don't support streaming request. 875 base::MessageLoop::current()->RunUntilIdle(); 876 EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data()); 877 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 878 websocket_->OnSentData(socket_.get(), 879 kHandshakeRequestWithoutCookieLength); 880 EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent()); 881 882 // We could not send any data until connection is established. 883 bool sent = websocket_->SendData(kHandshakeRequestWithoutCookie, 884 kHandshakeRequestWithoutCookieLength); 885 EXPECT_FALSE(sent); 886 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState()); 887 CloseWebSocketJob(); 888 } 889 890 // Following tests verify cooperation between WebSocketJob and SocketStream. 891 // Other former tests use MockSocketStream as SocketStream, so we could not 892 // check SocketStream behavior. 893 // OrderedSocketData provide socket level verifiation by checking out-going 894 // packets in comparison with the MockWrite array and emulating in-coming 895 // packets with MockRead array. 896 897 void WebSocketJobTest::TestConnectByWebSocket( 898 ThrottlingOption throttling) { 899 // This is a test for verifying cooperation between WebSocketJob and 900 // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic 901 // situation. If |throttling| was |THROTTLING_ON|, throttling limits the 902 // latter connection. 903 MockWrite writes[] = { 904 MockWrite(ASYNC, 905 kHandshakeRequestWithoutCookie, 906 kHandshakeRequestWithoutCookieLength, 907 1), 908 MockWrite(ASYNC, 909 kDataHello, 910 kDataHelloLength, 911 3) 912 }; 913 MockRead reads[] = { 914 MockRead(ASYNC, 915 kHandshakeResponseWithoutCookie, 916 kHandshakeResponseWithoutCookieLength, 917 2), 918 MockRead(ASYNC, 919 kDataWorld, 920 kDataWorldLength, 921 4), 922 MockRead(SYNCHRONOUS, 0, 5) // EOF 923 }; 924 data_.reset(new OrderedSocketData( 925 reads, arraysize(reads), writes, arraysize(writes))); 926 927 GURL url("ws://example.com/demo"); 928 MockSocketStreamDelegate delegate; 929 WebSocketJobTest* test = this; 930 if (throttling == THROTTLING_ON) 931 delegate.SetOnStartOpenConnection( 932 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test))); 933 delegate.SetOnConnected( 934 base::Bind(&WebSocketJobTest::DoSendRequest, 935 base::Unretained(test))); 936 delegate.SetOnReceivedData( 937 base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test))); 938 delegate.SetOnClose( 939 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test))); 940 InitWebSocketJob(url, &delegate, STREAM_SOCKET); 941 942 scoped_refptr<WebSocketJob> block_websocket; 943 if (throttling == THROTTLING_ON) { 944 // Create former WebSocket object which obstructs the latter one. 945 block_websocket = new WebSocketJob(NULL); 946 block_websocket->addresses_ = AddressList(websocket_->address_list()); 947 ASSERT_TRUE( 948 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get())); 949 } 950 951 websocket_->Connect(); 952 953 if (throttling == THROTTLING_ON) { 954 EXPECT_EQ(OK, WaitForResult()); 955 EXPECT_TRUE(websocket_->IsWaiting()); 956 957 // Remove the former WebSocket object from throttling queue to unblock the 958 // latter. 959 block_websocket->state_ = WebSocketJob::CLOSED; 960 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get()); 961 block_websocket = NULL; 962 } 963 964 EXPECT_EQ(OK, WaitForResult()); 965 EXPECT_TRUE(data_->at_read_eof()); 966 EXPECT_TRUE(data_->at_write_eof()); 967 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); 968 } 969 970 void WebSocketJobTest::TestConnectBySpdy( 971 SpdyOption spdy, ThrottlingOption throttling) { 972 // This is a test for verifying cooperation between WebSocketJob and 973 // SocketStream in the situation we have SPDY session to the server. If 974 // |throttling| was |THROTTLING_ON|, throttling limits the latter connection. 975 // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected 976 // results depend on its configuration. 977 MockWrite writes_websocket[] = { 978 MockWrite(ASYNC, 979 kHandshakeRequestWithoutCookie, 980 kHandshakeRequestWithoutCookieLength, 981 1), 982 MockWrite(ASYNC, 983 kDataHello, 984 kDataHelloLength, 985 3) 986 }; 987 MockRead reads_websocket[] = { 988 MockRead(ASYNC, 989 kHandshakeResponseWithoutCookie, 990 kHandshakeResponseWithoutCookieLength, 991 2), 992 MockRead(ASYNC, 993 kDataWorld, 994 kDataWorldLength, 995 4), 996 MockRead(SYNCHRONOUS, 0, 5) // EOF 997 }; 998 999 scoped_ptr<SpdyHeaderBlock> request_headers(new SpdyHeaderBlock()); 1000 spdy_util_.SetHeader("path", "/demo", request_headers.get()); 1001 spdy_util_.SetHeader("version", "WebSocket/13", request_headers.get()); 1002 spdy_util_.SetHeader("scheme", "ws", request_headers.get()); 1003 spdy_util_.SetHeader("host", "example.com", request_headers.get()); 1004 spdy_util_.SetHeader("origin", "http://example.com", request_headers.get()); 1005 spdy_util_.SetHeader("sec-websocket-protocol", "sample", 1006 request_headers.get()); 1007 1008 scoped_ptr<SpdyHeaderBlock> response_headers(new SpdyHeaderBlock()); 1009 spdy_util_.SetHeader("status", "101 Switching Protocols", 1010 response_headers.get()); 1011 spdy_util_.SetHeader("sec-websocket-protocol", "sample", 1012 response_headers.get()); 1013 1014 const SpdyStreamId kStreamId = 1; 1015 scoped_ptr<SpdyFrame> request_frame( 1016 spdy_util_.ConstructSpdyWebSocketHandshakeRequestFrame( 1017 request_headers.Pass(), 1018 kStreamId, 1019 MEDIUM)); 1020 scoped_ptr<SpdyFrame> response_frame( 1021 spdy_util_.ConstructSpdyWebSocketHandshakeResponseFrame( 1022 response_headers.Pass(), 1023 kStreamId, 1024 MEDIUM)); 1025 scoped_ptr<SpdyFrame> data_hello_frame( 1026 spdy_util_.ConstructSpdyWebSocketDataFrame( 1027 kDataHello, 1028 kDataHelloLength, 1029 kStreamId, 1030 false)); 1031 scoped_ptr<SpdyFrame> data_world_frame( 1032 spdy_util_.ConstructSpdyWebSocketDataFrame( 1033 kDataWorld, 1034 kDataWorldLength, 1035 kStreamId, 1036 false)); 1037 MockWrite writes_spdy[] = { 1038 CreateMockWrite(*request_frame.get(), 1), 1039 CreateMockWrite(*data_hello_frame.get(), 3), 1040 }; 1041 MockRead reads_spdy[] = { 1042 CreateMockRead(*response_frame.get(), 2), 1043 CreateMockRead(*data_world_frame.get(), 4), 1044 MockRead(SYNCHRONOUS, 0, 5) // EOF 1045 }; 1046 1047 if (spdy == SPDY_ON) 1048 data_.reset(new OrderedSocketData( 1049 reads_spdy, arraysize(reads_spdy), 1050 writes_spdy, arraysize(writes_spdy))); 1051 else 1052 data_.reset(new OrderedSocketData( 1053 reads_websocket, arraysize(reads_websocket), 1054 writes_websocket, arraysize(writes_websocket))); 1055 1056 GURL url("ws://example.com/demo"); 1057 MockSocketStreamDelegate delegate; 1058 WebSocketJobTest* test = this; 1059 if (throttling == THROTTLING_ON) 1060 delegate.SetOnStartOpenConnection( 1061 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test))); 1062 delegate.SetOnConnected( 1063 base::Bind(&WebSocketJobTest::DoSendRequest, 1064 base::Unretained(test))); 1065 delegate.SetOnReceivedData( 1066 base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test))); 1067 delegate.SetOnClose( 1068 base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test))); 1069 InitWebSocketJob(url, &delegate, STREAM_SPDY_WEBSOCKET); 1070 1071 scoped_refptr<WebSocketJob> block_websocket; 1072 if (throttling == THROTTLING_ON) { 1073 // Create former WebSocket object which obstructs the latter one. 1074 block_websocket = new WebSocketJob(NULL); 1075 block_websocket->addresses_ = AddressList(websocket_->address_list()); 1076 ASSERT_TRUE( 1077 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get())); 1078 } 1079 1080 websocket_->Connect(); 1081 1082 if (throttling == THROTTLING_ON) { 1083 EXPECT_EQ(OK, WaitForResult()); 1084 EXPECT_TRUE(websocket_->IsWaiting()); 1085 1086 // Remove the former WebSocket object from throttling queue to unblock the 1087 // latter. 1088 block_websocket->state_ = WebSocketJob::CLOSED; 1089 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get()); 1090 block_websocket = NULL; 1091 } 1092 1093 EXPECT_EQ(OK, WaitForResult()); 1094 EXPECT_TRUE(data_->at_read_eof()); 1095 EXPECT_TRUE(data_->at_write_eof()); 1096 EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState()); 1097 } 1098 1099 void WebSocketJobTest::TestThrottlingLimit() { 1100 std::vector<scoped_refptr<WebSocketJob> > jobs; 1101 const int kMaxWebSocketJobsThrottled = 1024; 1102 IPAddressNumber ip; 1103 ParseIPLiteralToNumber("127.0.0.1", &ip); 1104 for (int i = 0; i < kMaxWebSocketJobsThrottled + 1; ++i) { 1105 scoped_refptr<WebSocketJob> job = new WebSocketJob(NULL); 1106 job->addresses_ = AddressList(AddressList::CreateFromIPAddress(ip, 80)); 1107 if (i >= kMaxWebSocketJobsThrottled) 1108 EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job.get())); 1109 else 1110 EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job.get())); 1111 jobs.push_back(job); 1112 } 1113 1114 // Close the jobs in reverse order. Otherwise, We need to make them prepared 1115 // for Wakeup call. 1116 for (std::vector<scoped_refptr<WebSocketJob> >::reverse_iterator iter = 1117 jobs.rbegin(); 1118 iter != jobs.rend(); 1119 ++iter) { 1120 WebSocketJob* job = (*iter).get(); 1121 job->state_ = WebSocketJob::CLOSED; 1122 WebSocketThrottle::GetInstance()->RemoveFromQueue(job); 1123 } 1124 } 1125 1126 // Execute tests in both spdy-disabled mode and spdy-enabled mode. 1127 TEST_P(WebSocketJobTest, SimpleHandshake) { 1128 TestSimpleHandshake(); 1129 } 1130 1131 TEST_P(WebSocketJobTest, SlowHandshake) { 1132 TestSlowHandshake(); 1133 } 1134 1135 TEST_P(WebSocketJobTest, HandshakeWithCookie) { 1136 TestHandshakeWithCookie(); 1137 } 1138 1139 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) { 1140 TestHandshakeWithCookieButNotAllowed(); 1141 } 1142 1143 TEST_P(WebSocketJobTest, HSTSUpgrade) { 1144 TestHSTSUpgrade(); 1145 } 1146 1147 TEST_P(WebSocketJobTest, InvalidSendData) { 1148 TestInvalidSendData(); 1149 } 1150 1151 TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) { 1152 enable_websocket_over_spdy_ = true; 1153 TestSimpleHandshake(); 1154 } 1155 1156 TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) { 1157 enable_websocket_over_spdy_ = true; 1158 TestSlowHandshake(); 1159 } 1160 1161 TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) { 1162 enable_websocket_over_spdy_ = true; 1163 TestHandshakeWithCookie(); 1164 } 1165 1166 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) { 1167 enable_websocket_over_spdy_ = true; 1168 TestHandshakeWithCookieButNotAllowed(); 1169 } 1170 1171 TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) { 1172 enable_websocket_over_spdy_ = true; 1173 TestHSTSUpgrade(); 1174 } 1175 1176 TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) { 1177 enable_websocket_over_spdy_ = true; 1178 TestInvalidSendData(); 1179 } 1180 1181 TEST_P(WebSocketJobTest, ConnectByWebSocket) { 1182 enable_websocket_over_spdy_ = true; 1183 TestConnectByWebSocket(THROTTLING_OFF); 1184 } 1185 1186 TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) { 1187 enable_websocket_over_spdy_ = true; 1188 TestConnectByWebSocket(THROTTLING_OFF); 1189 } 1190 1191 TEST_P(WebSocketJobTest, ConnectBySpdy) { 1192 TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF); 1193 } 1194 1195 TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) { 1196 enable_websocket_over_spdy_ = true; 1197 TestConnectBySpdy(SPDY_ON, THROTTLING_OFF); 1198 } 1199 1200 TEST_P(WebSocketJobTest, ThrottlingWebSocket) { 1201 TestConnectByWebSocket(THROTTLING_ON); 1202 } 1203 1204 TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) { 1205 TestThrottlingLimit(); 1206 } 1207 1208 TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) { 1209 enable_websocket_over_spdy_ = true; 1210 TestConnectByWebSocket(THROTTLING_ON); 1211 } 1212 1213 TEST_P(WebSocketJobTest, ThrottlingSpdy) { 1214 TestConnectBySpdy(SPDY_OFF, THROTTLING_ON); 1215 } 1216 1217 TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) { 1218 enable_websocket_over_spdy_ = true; 1219 TestConnectBySpdy(SPDY_ON, THROTTLING_ON); 1220 } 1221 1222 TEST_F(WebSocketJobDeleteTest, OnClose) { 1223 SetDeleteNext(); 1224 job()->OnClose(socket_.get()); 1225 // OnClose() sets WebSocketJob::_socket to NULL before we can detach it, so 1226 // socket_->delegate is still set at this point. Clear it to avoid hitting 1227 // DCHECK(!delegate_) in the SocketStream destructor. SocketStream::Finish() 1228 // is the only caller of this method in real code, and it also sets delegate_ 1229 // to NULL. 1230 socket_->DetachDelegate(); 1231 EXPECT_FALSE(job()); 1232 } 1233 1234 TEST_F(WebSocketJobDeleteTest, OnAuthRequired) { 1235 SetDeleteNext(); 1236 job()->OnAuthRequired(socket_.get(), NULL); 1237 EXPECT_FALSE(job()); 1238 } 1239 1240 TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) { 1241 SSLInfo ssl_info; 1242 SetDeleteNext(); 1243 job()->OnSSLCertificateError(socket_.get(), ssl_info, true); 1244 EXPECT_FALSE(job()); 1245 } 1246 1247 TEST_F(WebSocketJobDeleteTest, OnError) { 1248 SetDeleteNext(); 1249 job()->OnError(socket_.get(), ERR_CONNECTION_RESET); 1250 EXPECT_FALSE(job()); 1251 } 1252 1253 TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) { 1254 job()->Connect(); 1255 SetDeleteNext(); 1256 job()->OnSentSpdyHeaders(); 1257 EXPECT_FALSE(job()); 1258 } 1259 1260 TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) { 1261 static const char kMinimalRequest[] = 1262 "GET /demo HTTP/1.1\r\n" 1263 "Host: example.com\r\n" 1264 "Upgrade: WebSocket\r\n" 1265 "Connection: Upgrade\r\n" 1266 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" 1267 "Origin: http://example.com\r\n" 1268 "Sec-WebSocket-Version: 13\r\n" 1269 "\r\n"; 1270 const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1; 1271 job()->Connect(); 1272 job()->SendData(kMinimalRequest, kMinimalRequestSize); 1273 SetDeleteNext(); 1274 job()->OnSentData(socket_.get(), kMinimalRequestSize); 1275 EXPECT_FALSE(job()); 1276 } 1277 1278 TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) { 1279 static const char kMinimalResponse[] = 1280 "HTTP/1.1 101 Switching Protocols\r\n" 1281 "Upgrade: websocket\r\n" 1282 "Connection: Upgrade\r\n" 1283 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 1284 "\r\n"; 1285 job()->Connect(); 1286 SetDeleteNext(); 1287 job()->OnReceivedData( 1288 socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1); 1289 EXPECT_FALSE(job()); 1290 } 1291 1292 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation. 1293 // TODO(toyoshim,yutak): Add tests to verify closing handshake. 1294 } // namespace net 1295