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.
5 #include "net/websockets/websocket_job.h"
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"
42 class MockSocketStream
: public SocketStream
{
44 MockSocketStream(const GURL
& url
, SocketStream::Delegate
* delegate
,
45 URLRequestContext
* context
, CookieStore
* cookie_store
)
46 : SocketStream(url
, delegate
, context
, cookie_store
) {}
48 virtual void Connect() OVERRIDE
{}
49 virtual bool SendData(const char* data
, int len
) OVERRIDE
{
50 sent_data_
+= std::string(data
, len
);
54 virtual void Close() OVERRIDE
{}
55 virtual void RestartWithAuth(
56 const AuthCredentials
& credentials
) OVERRIDE
{
59 virtual void DetachDelegate() OVERRIDE
{
63 const std::string
& sent_data() const {
68 virtual ~MockSocketStream() {}
71 std::string sent_data_
;
74 class MockSocketStreamDelegate
: public SocketStream::Delegate
{
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
;
81 virtual ~MockSocketStreamDelegate() {}
83 void SetOnStartOpenConnection(const base::Closure
& callback
) {
84 on_start_open_connection_
= callback
;
86 void SetOnConnected(const base::Closure
& callback
) {
87 on_connected_
= callback
;
89 void SetOnSentData(const base::Closure
& callback
) {
90 on_sent_data_
= callback
;
92 void SetOnReceivedData(const base::Closure
& callback
) {
93 on_received_data_
= callback
;
95 void SetOnClose(const base::Closure
& callback
) {
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();
106 virtual void OnConnected(SocketStream
* socket
,
107 int max_pending_send_allowed
) OVERRIDE
{
108 if (!on_connected_
.is_null())
111 virtual void OnSentData(SocketStream
* socket
,
112 int amount_sent
) OVERRIDE
{
113 amount_sent_
+= amount_sent
;
114 if (!on_sent_data_
.is_null())
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();
123 virtual void OnClose(SocketStream
* socket
) OVERRIDE
{
124 if (!on_close_
.is_null())
127 virtual bool CanGetCookies(SocketStream
* socket
,
128 const GURL
& url
) OVERRIDE
{
129 return allow_all_cookies_
;
131 virtual bool CanSetCookie(SocketStream
* request
,
133 const std::string
& cookie_line
,
134 CookieOptions
* options
) OVERRIDE
{
135 return allow_all_cookies_
;
138 size_t amount_sent() const { return amount_sent_
; }
139 const std::string
& received_data() const { return received_data_
; }
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_
;
152 class MockCookieStore
: public CookieStore
{
156 std::string cookie_line
;
157 CookieOptions options
;
162 bool SetCookieWithOptions(const GURL
& url
,
163 const std::string
& cookie_line
,
164 const CookieOptions
& options
) {
167 entry
.cookie_line
= cookie_line
;
168 entry
.options
= options
;
169 entries_
.push_back(entry
);
173 std::string
GetCookiesWithOptions(const GURL
& url
,
174 const CookieOptions
& options
) {
176 for (size_t i
= 0; i
< entries_
.size(); i
++) {
177 Entry
& entry
= entries_
[i
];
178 if (url
== entry
.url
) {
179 if (!result
.empty()) {
182 result
+= entry
.cookie_line
;
189 virtual void SetCookieWithOptionsAsync(
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
);
199 virtual void GetCookiesWithOptionsAsync(
201 const CookieOptions
& options
,
202 const GetCookiesCallback
& callback
) OVERRIDE
{
203 if (!callback
.is_null())
204 callback
.Run(GetCookiesWithOptions(url
, options
));
207 virtual void GetAllCookiesForURLAsync(
209 const GetCookieListCallback
& callback
) OVERRIDE
{
213 virtual void DeleteCookieAsync(const GURL
& url
,
214 const std::string
& cookie_name
,
215 const base::Closure
& callback
) OVERRIDE
{
219 virtual void DeleteAllCreatedBetweenAsync(
220 const base::Time
& delete_begin
,
221 const base::Time
& delete_end
,
222 const DeleteCallback
& callback
) OVERRIDE
{
226 virtual void DeleteAllCreatedBetweenForHostAsync(
227 const base::Time delete_begin
,
228 const base::Time delete_end
,
230 const DeleteCallback
& callback
) OVERRIDE
{
234 virtual void DeleteSessionCookiesAsync(const DeleteCallback
&) OVERRIDE
{
238 virtual CookieMonster
* GetCookieMonster() OVERRIDE
{ return NULL
; }
240 const std::vector
<Entry
>& entries() const { return entries_
; }
243 friend class base::RefCountedThreadSafe
<MockCookieStore
>;
244 virtual ~MockCookieStore() {}
246 std::vector
<Entry
> entries_
;
249 class MockSSLConfigService
: public SSLConfigService
{
251 virtual void GetSSLConfig(SSLConfig
* config
) OVERRIDE
{}
254 virtual ~MockSSLConfigService() {}
257 class MockURLRequestContext
: public URLRequestContext
{
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
,
269 virtual ~MockURLRequestContext() {}
272 TransportSecurityState transport_security_state_
;
275 class MockHttpTransactionFactory
: public HttpTransactionFactory
{
277 MockHttpTransactionFactory(NextProto next_proto
, OrderedSocketData
* data
) {
279 MockConnect
connect_data(SYNCHRONOUS
, OK
);
280 data_
->set_connect_data(connect_data
);
281 session_deps_
.reset(new SpdySessionDependencies(next_proto
));
282 session_deps_
->socket_factory
->AddSocketDataProvider(data_
);
284 SpdySessionDependencies::SpdyCreateSession(session_deps_
.get());
285 host_port_pair_
.set_host("example.com");
286 host_port_pair_
.set_port(80);
287 spdy_session_key_
= SpdySessionKey(host_port_pair_
,
288 ProxyServer::Direct(),
289 PRIVACY_MODE_DISABLED
);
290 session_
= CreateInsecureSpdySession(
291 http_session_
, spdy_session_key_
, BoundNetLog());
294 virtual int CreateTransaction(
295 RequestPriority priority
,
296 scoped_ptr
<HttpTransaction
>* trans
) OVERRIDE
{
298 return ERR_UNEXPECTED
;
301 virtual HttpCache
* GetCache() OVERRIDE
{
306 virtual HttpNetworkSession
* GetSession() OVERRIDE
{
307 return http_session_
.get();
311 OrderedSocketData
* data_
;
312 scoped_ptr
<SpdySessionDependencies
> session_deps_
;
313 scoped_refptr
<HttpNetworkSession
> http_session_
;
314 base::WeakPtr
<SpdySession
> session_
;
315 HostPortPair host_port_pair_
;
316 SpdySessionKey spdy_session_key_
;
319 class DeletingSocketStreamDelegate
: public SocketStream::Delegate
{
321 DeletingSocketStreamDelegate()
322 : delete_next_(false) {}
324 // Since this class needs to be able to delete |job_|, it must be the only
325 // reference holder (except for temporary references). Provide access to the
326 // pointer for tests to use.
327 WebSocketJob
* job() { return job_
.get(); }
329 void set_job(WebSocketJob
* job
) { job_
= job
; }
331 // After calling this, the next call to a method on this delegate will delete
332 // the WebSocketJob object.
333 void set_delete_next(bool delete_next
) { delete_next_
= delete_next
; }
335 void DeleteJobMaybe() {
337 job_
->DetachContext();
338 job_
->DetachDelegate();
343 // SocketStream::Delegate implementation
345 // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
347 virtual void OnConnected(SocketStream
* socket
,
348 int max_pending_send_allowed
) OVERRIDE
{
352 virtual void OnSentData(SocketStream
* socket
, int amount_sent
) OVERRIDE
{
356 virtual void OnReceivedData(SocketStream
* socket
,
362 virtual void OnClose(SocketStream
* socket
) OVERRIDE
{ DeleteJobMaybe(); }
364 virtual void OnAuthRequired(SocketStream
* socket
,
365 AuthChallengeInfo
* auth_info
) OVERRIDE
{
369 virtual void OnSSLCertificateError(SocketStream
* socket
,
370 const SSLInfo
& ssl_info
,
371 bool fatal
) OVERRIDE
{
375 virtual void OnError(const SocketStream
* socket
, int error
) OVERRIDE
{
379 // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
380 // WebSocketJob object.
383 scoped_refptr
<WebSocketJob
> job_
;
389 class WebSocketJobTest
: public PlatformTest
,
390 public ::testing::WithParamInterface
<NextProto
> {
392 WebSocketJobTest() : spdy_util_(GetParam()) {}
394 virtual void SetUp() OVERRIDE
{
395 stream_type_
= STREAM_INVALID
;
396 cookie_store_
= new MockCookieStore
;
397 context_
.reset(new MockURLRequestContext(cookie_store_
.get()));
399 virtual void TearDown() OVERRIDE
{
400 cookie_store_
= NULL
;
405 void DoSendRequest() {
406 EXPECT_TRUE(websocket_
->SendData(kHandshakeRequestWithoutCookie
,
407 kHandshakeRequestWithoutCookieLength
));
410 if (received_data().size() == kHandshakeResponseWithoutCookieLength
)
411 websocket_
->SendData(kDataHello
, kDataHelloLength
);
414 sync_test_callback_
.callback().Run(OK
);
416 int WaitForResult() {
417 return sync_test_callback_
.WaitForResult();
424 STREAM_SPDY_WEBSOCKET
,
426 enum ThrottlingOption
{
434 void InitWebSocketJob(const GURL
& url
,
435 MockSocketStreamDelegate
* delegate
,
436 StreamType stream_type
) {
437 DCHECK_NE(STREAM_INVALID
, stream_type
);
438 stream_type_
= stream_type
;
439 websocket_
= new WebSocketJob(delegate
);
441 if (stream_type
== STREAM_MOCK_SOCKET
)
442 socket_
= new MockSocketStream(url
, websocket_
.get(), context_
.get(),
445 if (stream_type
== STREAM_SOCKET
|| stream_type
== STREAM_SPDY_WEBSOCKET
) {
446 if (stream_type
== STREAM_SPDY_WEBSOCKET
) {
448 new MockHttpTransactionFactory(GetParam(), data_
.get()));
449 context_
->set_http_transaction_factory(http_factory_
.get());
452 ssl_config_service_
= new MockSSLConfigService();
453 context_
->set_ssl_config_service(ssl_config_service_
.get());
454 proxy_service_
.reset(ProxyService::CreateDirect());
455 context_
->set_proxy_service(proxy_service_
.get());
456 host_resolver_
.reset(new MockHostResolver
);
457 context_
->set_host_resolver(host_resolver_
.get());
459 socket_
= new SocketStream(url
, websocket_
.get(), context_
.get(), NULL
);
460 socket_factory_
.reset(new MockClientSocketFactory
);
462 socket_factory_
->AddSocketDataProvider(data_
.get());
463 socket_
->SetClientSocketFactory(socket_factory_
.get());
466 websocket_
->InitSocketStream(socket_
.get());
467 // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create
468 // a WebSocketJob purely to block another one in a throttling test, we don't
469 // perform a real connect. In that case, the following address is used
472 ParseIPLiteralToNumber("127.0.0.1", &ip
);
473 websocket_
->addresses_
= AddressList::CreateFromIPAddress(ip
, 80);
475 void SkipToConnecting() {
476 websocket_
->state_
= WebSocketJob::CONNECTING
;
477 ASSERT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(websocket_
.get()));
479 WebSocketJob::State
GetWebSocketJobState() {
480 return websocket_
->state_
;
482 void CloseWebSocketJob() {
483 if (websocket_
->socket_
.get()) {
484 websocket_
->socket_
->DetachDelegate();
485 WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_
.get());
487 websocket_
->state_
= WebSocketJob::CLOSED
;
488 websocket_
->delegate_
= NULL
;
489 websocket_
->socket_
= NULL
;
491 SocketStream
* GetSocket(SocketStreamJob
* job
) {
492 return job
->socket_
.get();
494 const std::string
& sent_data() const {
495 DCHECK_EQ(STREAM_MOCK_SOCKET
, stream_type_
);
496 MockSocketStream
* socket
=
497 static_cast<MockSocketStream
*>(socket_
.get());
499 return socket
->sent_data();
501 const std::string
& received_data() const {
502 DCHECK_NE(STREAM_INVALID
, stream_type_
);
503 MockSocketStreamDelegate
* delegate
=
504 static_cast<MockSocketStreamDelegate
*>(websocket_
->delegate_
);
506 return delegate
->received_data();
509 void TestSimpleHandshake();
510 void TestSlowHandshake();
511 void TestHandshakeWithCookie();
512 void TestHandshakeWithCookieButNotAllowed();
513 void TestHSTSUpgrade();
514 void TestInvalidSendData();
515 void TestConnectByWebSocket(ThrottlingOption throttling
);
516 void TestConnectBySpdy(SpdyOption spdy
, ThrottlingOption throttling
);
517 void TestThrottlingLimit();
519 SpdyWebSocketTestUtil spdy_util_
;
520 StreamType stream_type_
;
521 scoped_refptr
<MockCookieStore
> cookie_store_
;
522 scoped_ptr
<MockURLRequestContext
> context_
;
523 scoped_refptr
<WebSocketJob
> websocket_
;
524 scoped_refptr
<SocketStream
> socket_
;
525 scoped_ptr
<MockClientSocketFactory
> socket_factory_
;
526 scoped_ptr
<OrderedSocketData
> data_
;
527 TestCompletionCallback sync_test_callback_
;
528 scoped_refptr
<MockSSLConfigService
> ssl_config_service_
;
529 scoped_ptr
<ProxyService
> proxy_service_
;
530 scoped_ptr
<MockHostResolver
> host_resolver_
;
531 scoped_ptr
<MockHttpTransactionFactory
> http_factory_
;
533 static const char kHandshakeRequestWithoutCookie
[];
534 static const char kHandshakeRequestWithCookie
[];
535 static const char kHandshakeRequestWithFilteredCookie
[];
536 static const char kHandshakeResponseWithoutCookie
[];
537 static const char kHandshakeResponseWithCookie
[];
538 static const char kDataHello
[];
539 static const char kDataWorld
[];
540 static const char* const kHandshakeRequestForSpdy
[];
541 static const char* const kHandshakeResponseForSpdy
[];
542 static const size_t kHandshakeRequestWithoutCookieLength
;
543 static const size_t kHandshakeRequestWithCookieLength
;
544 static const size_t kHandshakeRequestWithFilteredCookieLength
;
545 static const size_t kHandshakeResponseWithoutCookieLength
;
546 static const size_t kHandshakeResponseWithCookieLength
;
547 static const size_t kDataHelloLength
;
548 static const size_t kDataWorldLength
;
551 // Tests using this fixture verify that the WebSocketJob can handle being
552 // deleted while calling back to the delegate correctly. These tests need to be
553 // run under AddressSanitizer or other systems for detecting use-after-free
554 // errors in order to find problems.
555 class WebSocketJobDeleteTest
: public ::testing::Test
{
557 WebSocketJobDeleteTest()
558 : delegate_(new DeletingSocketStreamDelegate
),
559 cookie_store_(new MockCookieStore
),
560 context_(new MockURLRequestContext(cookie_store_
.get())) {
561 WebSocketJob
* websocket
= new WebSocketJob(delegate_
.get());
562 delegate_
->set_job(websocket
);
564 socket_
= new MockSocketStream(
565 GURL("ws://127.0.0.1/"), websocket
, context_
.get(), NULL
);
567 websocket
->InitSocketStream(socket_
.get());
570 void SetDeleteNext() { return delegate_
->set_delete_next(true); }
571 WebSocketJob
* job() { return delegate_
->job(); }
573 scoped_ptr
<DeletingSocketStreamDelegate
> delegate_
;
574 scoped_refptr
<MockCookieStore
> cookie_store_
;
575 scoped_ptr
<MockURLRequestContext
> context_
;
576 scoped_refptr
<SocketStream
> socket_
;
579 const char WebSocketJobTest::kHandshakeRequestWithoutCookie
[] =
580 "GET /demo HTTP/1.1\r\n"
581 "Host: example.com\r\n"
582 "Upgrade: WebSocket\r\n"
583 "Connection: Upgrade\r\n"
584 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
585 "Origin: http://example.com\r\n"
586 "Sec-WebSocket-Protocol: sample\r\n"
587 "Sec-WebSocket-Version: 13\r\n"
590 const char WebSocketJobTest::kHandshakeRequestWithCookie
[] =
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 "Cookie: WK-test=1\r\n"
602 const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie
[] =
603 "GET /demo HTTP/1.1\r\n"
604 "Host: example.com\r\n"
605 "Upgrade: WebSocket\r\n"
606 "Connection: Upgrade\r\n"
607 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
608 "Origin: http://example.com\r\n"
609 "Sec-WebSocket-Protocol: sample\r\n"
610 "Sec-WebSocket-Version: 13\r\n"
611 "Cookie: CR-test=1; CR-test-httponly=1\r\n"
614 const char WebSocketJobTest::kHandshakeResponseWithoutCookie
[] =
615 "HTTP/1.1 101 Switching Protocols\r\n"
616 "Upgrade: websocket\r\n"
617 "Connection: Upgrade\r\n"
618 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
619 "Sec-WebSocket-Protocol: sample\r\n"
622 const char WebSocketJobTest::kHandshakeResponseWithCookie
[] =
623 "HTTP/1.1 101 Switching Protocols\r\n"
624 "Upgrade: websocket\r\n"
625 "Connection: Upgrade\r\n"
626 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
627 "Sec-WebSocket-Protocol: sample\r\n"
628 "Set-Cookie: CR-set-test=1\r\n"
631 const char WebSocketJobTest::kDataHello
[] = "Hello, ";
633 const char WebSocketJobTest::kDataWorld
[] = "World!\n";
635 const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength
=
636 arraysize(kHandshakeRequestWithoutCookie
) - 1;
637 const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength
=
638 arraysize(kHandshakeRequestWithCookie
) - 1;
639 const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength
=
640 arraysize(kHandshakeRequestWithFilteredCookie
) - 1;
641 const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength
=
642 arraysize(kHandshakeResponseWithoutCookie
) - 1;
643 const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength
=
644 arraysize(kHandshakeResponseWithCookie
) - 1;
645 const size_t WebSocketJobTest::kDataHelloLength
=
646 arraysize(kDataHello
) - 1;
647 const size_t WebSocketJobTest::kDataWorldLength
=
648 arraysize(kDataWorld
) - 1;
650 void WebSocketJobTest::TestSimpleHandshake() {
651 GURL
url("ws://example.com/demo");
652 MockSocketStreamDelegate delegate
;
653 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
657 base::MessageLoop::current()->RunUntilIdle();
658 EXPECT_EQ(kHandshakeRequestWithoutCookie
, sent_data());
659 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
660 websocket_
->OnSentData(socket_
.get(),
661 kHandshakeRequestWithoutCookieLength
);
662 EXPECT_EQ(kHandshakeRequestWithoutCookieLength
, delegate
.amount_sent());
664 websocket_
->OnReceivedData(socket_
.get(),
665 kHandshakeResponseWithoutCookie
,
666 kHandshakeResponseWithoutCookieLength
);
667 base::MessageLoop::current()->RunUntilIdle();
668 EXPECT_EQ(kHandshakeResponseWithoutCookie
, delegate
.received_data());
669 EXPECT_EQ(WebSocketJob::OPEN
, GetWebSocketJobState());
673 void WebSocketJobTest::TestSlowHandshake() {
674 GURL
url("ws://example.com/demo");
675 MockSocketStreamDelegate delegate
;
676 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
680 // We assume request is sent in one data chunk (from WebKit)
681 // We don't support streaming request.
682 base::MessageLoop::current()->RunUntilIdle();
683 EXPECT_EQ(kHandshakeRequestWithoutCookie
, sent_data());
684 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
685 websocket_
->OnSentData(socket_
.get(),
686 kHandshakeRequestWithoutCookieLength
);
687 EXPECT_EQ(kHandshakeRequestWithoutCookieLength
, delegate
.amount_sent());
689 std::vector
<std::string
> lines
;
690 base::SplitString(kHandshakeResponseWithoutCookie
, '\n', &lines
);
691 for (size_t i
= 0; i
< lines
.size() - 2; i
++) {
692 std::string line
= lines
[i
] + "\r\n";
693 SCOPED_TRACE("Line: " + line
);
694 websocket_
->OnReceivedData(socket_
.get(), line
.c_str(), line
.size());
695 base::MessageLoop::current()->RunUntilIdle();
696 EXPECT_TRUE(delegate
.received_data().empty());
697 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
699 websocket_
->OnReceivedData(socket_
.get(), "\r\n", 2);
700 base::MessageLoop::current()->RunUntilIdle();
701 EXPECT_FALSE(delegate
.received_data().empty());
702 EXPECT_EQ(kHandshakeResponseWithoutCookie
, delegate
.received_data());
703 EXPECT_EQ(WebSocketJob::OPEN
, GetWebSocketJobState());
707 INSTANTIATE_TEST_CASE_P(
710 testing::Values(kProtoDeprecatedSPDY2
,
711 kProtoSPDY3
, kProtoSPDY31
, kProtoSPDY4
));
713 TEST_P(WebSocketJobTest
, DelayedCookies
) {
714 WebSocketJob::set_websocket_over_spdy_enabled(true);
715 GURL
url("ws://example.com/demo");
716 GURL
cookieUrl("http://example.com/demo");
717 CookieOptions cookie_options
;
718 scoped_refptr
<DelayedCookieMonster
> cookie_store
= new DelayedCookieMonster();
719 context_
->set_cookie_store(cookie_store
.get());
720 cookie_store
->SetCookieWithOptionsAsync(cookieUrl
,
723 CookieMonster::SetCookiesCallback());
724 cookie_options
.set_include_httponly();
725 cookie_store
->SetCookieWithOptionsAsync(
726 cookieUrl
, "CR-test-httponly=1", cookie_options
,
727 CookieMonster::SetCookiesCallback());
729 MockSocketStreamDelegate delegate
;
730 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
733 bool sent
= websocket_
->SendData(kHandshakeRequestWithCookie
,
734 kHandshakeRequestWithCookieLength
);
736 base::MessageLoop::current()->RunUntilIdle();
737 EXPECT_EQ(kHandshakeRequestWithFilteredCookie
, sent_data());
738 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
739 websocket_
->OnSentData(socket_
.get(),
740 kHandshakeRequestWithFilteredCookieLength
);
741 EXPECT_EQ(kHandshakeRequestWithCookieLength
,
742 delegate
.amount_sent());
744 websocket_
->OnReceivedData(socket_
.get(),
745 kHandshakeResponseWithCookie
,
746 kHandshakeResponseWithCookieLength
);
747 base::MessageLoop::current()->RunUntilIdle();
748 EXPECT_EQ(kHandshakeResponseWithoutCookie
, delegate
.received_data());
749 EXPECT_EQ(WebSocketJob::OPEN
, GetWebSocketJobState());
754 void WebSocketJobTest::TestHandshakeWithCookie() {
755 GURL
url("ws://example.com/demo");
756 GURL
cookieUrl("http://example.com/demo");
757 CookieOptions cookie_options
;
758 cookie_store_
->SetCookieWithOptions(
759 cookieUrl
, "CR-test=1", cookie_options
);
760 cookie_options
.set_include_httponly();
761 cookie_store_
->SetCookieWithOptions(
762 cookieUrl
, "CR-test-httponly=1", cookie_options
);
764 MockSocketStreamDelegate delegate
;
765 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
768 bool sent
= websocket_
->SendData(kHandshakeRequestWithCookie
,
769 kHandshakeRequestWithCookieLength
);
771 base::MessageLoop::current()->RunUntilIdle();
772 EXPECT_EQ(kHandshakeRequestWithFilteredCookie
, sent_data());
773 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
774 websocket_
->OnSentData(socket_
.get(),
775 kHandshakeRequestWithFilteredCookieLength
);
776 EXPECT_EQ(kHandshakeRequestWithCookieLength
,
777 delegate
.amount_sent());
779 websocket_
->OnReceivedData(socket_
.get(),
780 kHandshakeResponseWithCookie
,
781 kHandshakeResponseWithCookieLength
);
782 base::MessageLoop::current()->RunUntilIdle();
783 EXPECT_EQ(kHandshakeResponseWithoutCookie
, delegate
.received_data());
784 EXPECT_EQ(WebSocketJob::OPEN
, GetWebSocketJobState());
786 EXPECT_EQ(3U, cookie_store_
->entries().size());
787 EXPECT_EQ(cookieUrl
, cookie_store_
->entries()[0].url
);
788 EXPECT_EQ("CR-test=1", cookie_store_
->entries()[0].cookie_line
);
789 EXPECT_EQ(cookieUrl
, cookie_store_
->entries()[1].url
);
790 EXPECT_EQ("CR-test-httponly=1", cookie_store_
->entries()[1].cookie_line
);
791 EXPECT_EQ(cookieUrl
, cookie_store_
->entries()[2].url
);
792 EXPECT_EQ("CR-set-test=1", cookie_store_
->entries()[2].cookie_line
);
797 void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() {
798 GURL
url("ws://example.com/demo");
799 GURL
cookieUrl("http://example.com/demo");
800 CookieOptions cookie_options
;
801 cookie_store_
->SetCookieWithOptions(
802 cookieUrl
, "CR-test=1", cookie_options
);
803 cookie_options
.set_include_httponly();
804 cookie_store_
->SetCookieWithOptions(
805 cookieUrl
, "CR-test-httponly=1", cookie_options
);
807 MockSocketStreamDelegate delegate
;
808 delegate
.set_allow_all_cookies(false);
809 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
812 bool sent
= websocket_
->SendData(kHandshakeRequestWithCookie
,
813 kHandshakeRequestWithCookieLength
);
815 base::MessageLoop::current()->RunUntilIdle();
816 EXPECT_EQ(kHandshakeRequestWithoutCookie
, sent_data());
817 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
818 websocket_
->OnSentData(socket_
.get(), kHandshakeRequestWithoutCookieLength
);
819 EXPECT_EQ(kHandshakeRequestWithCookieLength
, delegate
.amount_sent());
821 websocket_
->OnReceivedData(socket_
.get(),
822 kHandshakeResponseWithCookie
,
823 kHandshakeResponseWithCookieLength
);
824 base::MessageLoop::current()->RunUntilIdle();
825 EXPECT_EQ(kHandshakeResponseWithoutCookie
, delegate
.received_data());
826 EXPECT_EQ(WebSocketJob::OPEN
, GetWebSocketJobState());
828 EXPECT_EQ(2U, cookie_store_
->entries().size());
829 EXPECT_EQ(cookieUrl
, cookie_store_
->entries()[0].url
);
830 EXPECT_EQ("CR-test=1", cookie_store_
->entries()[0].cookie_line
);
831 EXPECT_EQ(cookieUrl
, cookie_store_
->entries()[1].url
);
832 EXPECT_EQ("CR-test-httponly=1", cookie_store_
->entries()[1].cookie_line
);
837 void WebSocketJobTest::TestHSTSUpgrade() {
838 GURL
url("ws://upgrademe.com/");
839 MockSocketStreamDelegate delegate
;
840 scoped_refptr
<SocketStreamJob
> job
=
841 SocketStreamJob::CreateSocketStreamJob(
842 url
, &delegate
, context_
->transport_security_state(),
843 context_
->ssl_config_service(), NULL
, NULL
);
844 EXPECT_TRUE(GetSocket(job
.get())->is_secure());
845 job
->DetachDelegate();
847 url
= GURL("ws://donotupgrademe.com/");
848 job
= SocketStreamJob::CreateSocketStreamJob(
849 url
, &delegate
, context_
->transport_security_state(),
850 context_
->ssl_config_service(), NULL
, NULL
);
851 EXPECT_FALSE(GetSocket(job
.get())->is_secure());
852 job
->DetachDelegate();
855 void WebSocketJobTest::TestInvalidSendData() {
856 GURL
url("ws://example.com/demo");
857 MockSocketStreamDelegate delegate
;
858 InitWebSocketJob(url
, &delegate
, STREAM_MOCK_SOCKET
);
862 // We assume request is sent in one data chunk (from WebKit)
863 // We don't support streaming request.
864 base::MessageLoop::current()->RunUntilIdle();
865 EXPECT_EQ(kHandshakeRequestWithoutCookie
, sent_data());
866 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
867 websocket_
->OnSentData(socket_
.get(),
868 kHandshakeRequestWithoutCookieLength
);
869 EXPECT_EQ(kHandshakeRequestWithoutCookieLength
, delegate
.amount_sent());
871 // We could not send any data until connection is established.
872 bool sent
= websocket_
->SendData(kHandshakeRequestWithoutCookie
,
873 kHandshakeRequestWithoutCookieLength
);
875 EXPECT_EQ(WebSocketJob::CONNECTING
, GetWebSocketJobState());
879 // Following tests verify cooperation between WebSocketJob and SocketStream.
880 // Other former tests use MockSocketStream as SocketStream, so we could not
881 // check SocketStream behavior.
882 // OrderedSocketData provide socket level verifiation by checking out-going
883 // packets in comparison with the MockWrite array and emulating in-coming
884 // packets with MockRead array.
886 void WebSocketJobTest::TestConnectByWebSocket(
887 ThrottlingOption throttling
) {
888 // This is a test for verifying cooperation between WebSocketJob and
889 // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic
890 // situation. If |throttling| was |THROTTLING_ON|, throttling limits the
891 // latter connection.
892 MockWrite writes
[] = {
894 kHandshakeRequestWithoutCookie
,
895 kHandshakeRequestWithoutCookieLength
,
904 kHandshakeResponseWithoutCookie
,
905 kHandshakeResponseWithoutCookieLength
,
911 MockRead(SYNCHRONOUS
, 0, 5) // EOF
913 data_
.reset(new OrderedSocketData(
914 reads
, arraysize(reads
), writes
, arraysize(writes
)));
916 GURL
url("ws://example.com/demo");
917 MockSocketStreamDelegate delegate
;
918 WebSocketJobTest
* test
= this;
919 if (throttling
== THROTTLING_ON
)
920 delegate
.SetOnStartOpenConnection(
921 base::Bind(&WebSocketJobTest::DoSync
, base::Unretained(test
)));
922 delegate
.SetOnConnected(
923 base::Bind(&WebSocketJobTest::DoSendRequest
,
924 base::Unretained(test
)));
925 delegate
.SetOnReceivedData(
926 base::Bind(&WebSocketJobTest::DoSendData
, base::Unretained(test
)));
928 base::Bind(&WebSocketJobTest::DoSync
, base::Unretained(test
)));
929 InitWebSocketJob(url
, &delegate
, STREAM_SOCKET
);
931 scoped_refptr
<WebSocketJob
> block_websocket
;
932 if (throttling
== THROTTLING_ON
) {
933 // Create former WebSocket object which obstructs the latter one.
934 block_websocket
= new WebSocketJob(NULL
);
935 block_websocket
->addresses_
= AddressList(websocket_
->address_list());
937 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket
.get()));
940 websocket_
->Connect();
942 if (throttling
== THROTTLING_ON
) {
943 EXPECT_EQ(OK
, WaitForResult());
944 EXPECT_TRUE(websocket_
->IsWaiting());
946 // Remove the former WebSocket object from throttling queue to unblock the
948 block_websocket
->state_
= WebSocketJob::CLOSED
;
949 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket
.get());
950 block_websocket
= NULL
;
953 EXPECT_EQ(OK
, WaitForResult());
954 EXPECT_TRUE(data_
->at_read_eof());
955 EXPECT_TRUE(data_
->at_write_eof());
956 EXPECT_EQ(WebSocketJob::CLOSED
, GetWebSocketJobState());
959 void WebSocketJobTest::TestConnectBySpdy(
960 SpdyOption spdy
, ThrottlingOption throttling
) {
961 // This is a test for verifying cooperation between WebSocketJob and
962 // SocketStream in the situation we have SPDY session to the server. If
963 // |throttling| was |THROTTLING_ON|, throttling limits the latter connection.
964 // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected
965 // results depend on its configuration.
966 MockWrite writes_websocket
[] = {
968 kHandshakeRequestWithoutCookie
,
969 kHandshakeRequestWithoutCookieLength
,
976 MockRead reads_websocket
[] = {
978 kHandshakeResponseWithoutCookie
,
979 kHandshakeResponseWithoutCookieLength
,
985 MockRead(SYNCHRONOUS
, 0, 5) // EOF
988 scoped_ptr
<SpdyHeaderBlock
> request_headers(new SpdyHeaderBlock());
989 spdy_util_
.SetHeader("path", "/demo", request_headers
.get());
990 spdy_util_
.SetHeader("version", "WebSocket/13", request_headers
.get());
991 spdy_util_
.SetHeader("scheme", "ws", request_headers
.get());
992 spdy_util_
.SetHeader("host", "example.com", request_headers
.get());
993 spdy_util_
.SetHeader("origin", "http://example.com", request_headers
.get());
994 spdy_util_
.SetHeader("sec-websocket-protocol", "sample",
995 request_headers
.get());
997 scoped_ptr
<SpdyHeaderBlock
> response_headers(new SpdyHeaderBlock());
998 spdy_util_
.SetHeader("status", "101 Switching Protocols",
999 response_headers
.get());
1000 spdy_util_
.SetHeader("sec-websocket-protocol", "sample",
1001 response_headers
.get());
1003 const SpdyStreamId kStreamId
= 1;
1004 scoped_ptr
<SpdyFrame
> request_frame(
1005 spdy_util_
.ConstructSpdyWebSocketHandshakeRequestFrame(
1006 request_headers
.Pass(),
1009 scoped_ptr
<SpdyFrame
> response_frame(
1010 spdy_util_
.ConstructSpdyWebSocketHandshakeResponseFrame(
1011 response_headers
.Pass(),
1014 scoped_ptr
<SpdyFrame
> data_hello_frame(
1015 spdy_util_
.ConstructSpdyWebSocketDataFrame(
1020 scoped_ptr
<SpdyFrame
> data_world_frame(
1021 spdy_util_
.ConstructSpdyWebSocketDataFrame(
1026 MockWrite writes_spdy
[] = {
1027 CreateMockWrite(*request_frame
.get(), 1),
1028 CreateMockWrite(*data_hello_frame
.get(), 3),
1030 MockRead reads_spdy
[] = {
1031 CreateMockRead(*response_frame
.get(), 2),
1032 CreateMockRead(*data_world_frame
.get(), 4),
1033 MockRead(SYNCHRONOUS
, 0, 5) // EOF
1036 if (spdy
== SPDY_ON
)
1037 data_
.reset(new OrderedSocketData(
1038 reads_spdy
, arraysize(reads_spdy
),
1039 writes_spdy
, arraysize(writes_spdy
)));
1041 data_
.reset(new OrderedSocketData(
1042 reads_websocket
, arraysize(reads_websocket
),
1043 writes_websocket
, arraysize(writes_websocket
)));
1045 GURL
url("ws://example.com/demo");
1046 MockSocketStreamDelegate delegate
;
1047 WebSocketJobTest
* test
= this;
1048 if (throttling
== THROTTLING_ON
)
1049 delegate
.SetOnStartOpenConnection(
1050 base::Bind(&WebSocketJobTest::DoSync
, base::Unretained(test
)));
1051 delegate
.SetOnConnected(
1052 base::Bind(&WebSocketJobTest::DoSendRequest
,
1053 base::Unretained(test
)));
1054 delegate
.SetOnReceivedData(
1055 base::Bind(&WebSocketJobTest::DoSendData
, base::Unretained(test
)));
1056 delegate
.SetOnClose(
1057 base::Bind(&WebSocketJobTest::DoSync
, base::Unretained(test
)));
1058 InitWebSocketJob(url
, &delegate
, STREAM_SPDY_WEBSOCKET
);
1060 scoped_refptr
<WebSocketJob
> block_websocket
;
1061 if (throttling
== THROTTLING_ON
) {
1062 // Create former WebSocket object which obstructs the latter one.
1063 block_websocket
= new WebSocketJob(NULL
);
1064 block_websocket
->addresses_
= AddressList(websocket_
->address_list());
1066 WebSocketThrottle::GetInstance()->PutInQueue(block_websocket
.get()));
1069 websocket_
->Connect();
1071 if (throttling
== THROTTLING_ON
) {
1072 EXPECT_EQ(OK
, WaitForResult());
1073 EXPECT_TRUE(websocket_
->IsWaiting());
1075 // Remove the former WebSocket object from throttling queue to unblock the
1077 block_websocket
->state_
= WebSocketJob::CLOSED
;
1078 WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket
.get());
1079 block_websocket
= NULL
;
1082 EXPECT_EQ(OK
, WaitForResult());
1083 EXPECT_TRUE(data_
->at_read_eof());
1084 EXPECT_TRUE(data_
->at_write_eof());
1085 EXPECT_EQ(WebSocketJob::CLOSED
, GetWebSocketJobState());
1088 void WebSocketJobTest::TestThrottlingLimit() {
1089 std::vector
<scoped_refptr
<WebSocketJob
> > jobs
;
1090 const int kMaxWebSocketJobsThrottled
= 1024;
1092 ParseIPLiteralToNumber("127.0.0.1", &ip
);
1093 for (int i
= 0; i
< kMaxWebSocketJobsThrottled
+ 1; ++i
) {
1094 scoped_refptr
<WebSocketJob
> job
= new WebSocketJob(NULL
);
1095 job
->addresses_
= AddressList(AddressList::CreateFromIPAddress(ip
, 80));
1096 if (i
>= kMaxWebSocketJobsThrottled
)
1097 EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job
));
1099 EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job
));
1100 jobs
.push_back(job
);
1103 // Close the jobs in reverse order. Otherwise, We need to make them prepared
1105 for (std::vector
<scoped_refptr
<WebSocketJob
> >::reverse_iterator iter
=
1107 iter
!= jobs
.rend();
1109 WebSocketJob
* job
= (*iter
).get();
1110 job
->state_
= WebSocketJob::CLOSED
;
1111 WebSocketThrottle::GetInstance()->RemoveFromQueue(job
);
1115 // Execute tests in both spdy-disabled mode and spdy-enabled mode.
1116 TEST_P(WebSocketJobTest
, SimpleHandshake
) {
1117 WebSocketJob::set_websocket_over_spdy_enabled(false);
1118 TestSimpleHandshake();
1121 TEST_P(WebSocketJobTest
, SlowHandshake
) {
1122 WebSocketJob::set_websocket_over_spdy_enabled(false);
1123 TestSlowHandshake();
1126 TEST_P(WebSocketJobTest
, HandshakeWithCookie
) {
1127 WebSocketJob::set_websocket_over_spdy_enabled(false);
1128 TestHandshakeWithCookie();
1131 TEST_P(WebSocketJobTest
, HandshakeWithCookieButNotAllowed
) {
1132 WebSocketJob::set_websocket_over_spdy_enabled(false);
1133 TestHandshakeWithCookieButNotAllowed();
1136 TEST_P(WebSocketJobTest
, HSTSUpgrade
) {
1137 WebSocketJob::set_websocket_over_spdy_enabled(false);
1141 TEST_P(WebSocketJobTest
, InvalidSendData
) {
1142 WebSocketJob::set_websocket_over_spdy_enabled(false);
1143 TestInvalidSendData();
1146 TEST_P(WebSocketJobTest
, SimpleHandshakeSpdyEnabled
) {
1147 WebSocketJob::set_websocket_over_spdy_enabled(true);
1148 TestSimpleHandshake();
1151 TEST_P(WebSocketJobTest
, SlowHandshakeSpdyEnabled
) {
1152 WebSocketJob::set_websocket_over_spdy_enabled(true);
1153 TestSlowHandshake();
1156 TEST_P(WebSocketJobTest
, HandshakeWithCookieSpdyEnabled
) {
1157 WebSocketJob::set_websocket_over_spdy_enabled(true);
1158 TestHandshakeWithCookie();
1161 TEST_P(WebSocketJobTest
, HandshakeWithCookieButNotAllowedSpdyEnabled
) {
1162 WebSocketJob::set_websocket_over_spdy_enabled(true);
1163 TestHandshakeWithCookieButNotAllowed();
1166 TEST_P(WebSocketJobTest
, HSTSUpgradeSpdyEnabled
) {
1167 WebSocketJob::set_websocket_over_spdy_enabled(true);
1171 TEST_P(WebSocketJobTest
, InvalidSendDataSpdyEnabled
) {
1172 WebSocketJob::set_websocket_over_spdy_enabled(true);
1173 TestInvalidSendData();
1176 TEST_P(WebSocketJobTest
, ConnectByWebSocket
) {
1177 WebSocketJob::set_websocket_over_spdy_enabled(false);
1178 TestConnectByWebSocket(THROTTLING_OFF
);
1181 TEST_P(WebSocketJobTest
, ConnectByWebSocketSpdyEnabled
) {
1182 WebSocketJob::set_websocket_over_spdy_enabled(true);
1183 TestConnectByWebSocket(THROTTLING_OFF
);
1186 TEST_P(WebSocketJobTest
, ConnectBySpdy
) {
1187 WebSocketJob::set_websocket_over_spdy_enabled(false);
1188 TestConnectBySpdy(SPDY_OFF
, THROTTLING_OFF
);
1191 TEST_P(WebSocketJobTest
, ConnectBySpdySpdyEnabled
) {
1192 WebSocketJob::set_websocket_over_spdy_enabled(true);
1193 TestConnectBySpdy(SPDY_ON
, THROTTLING_OFF
);
1196 TEST_P(WebSocketJobTest
, ThrottlingWebSocket
) {
1197 WebSocketJob::set_websocket_over_spdy_enabled(false);
1198 TestConnectByWebSocket(THROTTLING_ON
);
1201 TEST_P(WebSocketJobTest
, ThrottlingMaxNumberOfThrottledJobLimit
) {
1202 TestThrottlingLimit();
1205 TEST_P(WebSocketJobTest
, ThrottlingWebSocketSpdyEnabled
) {
1206 WebSocketJob::set_websocket_over_spdy_enabled(true);
1207 TestConnectByWebSocket(THROTTLING_ON
);
1210 TEST_P(WebSocketJobTest
, ThrottlingSpdy
) {
1211 WebSocketJob::set_websocket_over_spdy_enabled(false);
1212 TestConnectBySpdy(SPDY_OFF
, THROTTLING_ON
);
1215 TEST_P(WebSocketJobTest
, ThrottlingSpdySpdyEnabled
) {
1216 WebSocketJob::set_websocket_over_spdy_enabled(true);
1217 TestConnectBySpdy(SPDY_ON
, THROTTLING_ON
);
1220 TEST_F(WebSocketJobDeleteTest
, OnClose
) {
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_
1228 socket_
->DetachDelegate();
1229 EXPECT_FALSE(job());
1232 TEST_F(WebSocketJobDeleteTest
, OnAuthRequired
) {
1234 job()->OnAuthRequired(socket_
.get(), NULL
);
1235 EXPECT_FALSE(job());
1238 TEST_F(WebSocketJobDeleteTest
, OnSSLCertificateError
) {
1241 job()->OnSSLCertificateError(socket_
.get(), ssl_info
, true);
1242 EXPECT_FALSE(job());
1245 TEST_F(WebSocketJobDeleteTest
, OnError
) {
1247 job()->OnError(socket_
.get(), ERR_CONNECTION_RESET
);
1248 EXPECT_FALSE(job());
1251 TEST_F(WebSocketJobDeleteTest
, OnSentSpdyHeaders
) {
1254 job()->OnSentSpdyHeaders();
1255 EXPECT_FALSE(job());
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"
1268 const size_t kMinimalRequestSize
= arraysize(kMinimalRequest
) - 1;
1270 job()->SendData(kMinimalRequest
, kMinimalRequestSize
);
1272 job()->OnSentData(socket_
.get(), kMinimalRequestSize
);
1273 EXPECT_FALSE(job());
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"
1285 job()->OnReceivedData(
1286 socket_
.get(), kMinimalResponse
, arraysize(kMinimalResponse
) - 1);
1287 EXPECT_FALSE(job());
1290 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
1291 // TODO(toyoshim,yutak): Add tests to verify closing handshake.