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