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