Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / net / websockets / websocket_job_test.cc
blob22fd6e732ada9a9b7833ecd9596c8184f41d9e73
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 virtual void Connect() OVERRIDE {}
49 virtual bool SendData(const char* data, int len) OVERRIDE {
50 sent_data_ += std::string(data, len);
51 return true;
54 virtual void Close() OVERRIDE {}
55 virtual void RestartWithAuth(
56 const AuthCredentials& credentials) OVERRIDE {
59 virtual void DetachDelegate() OVERRIDE {
60 delegate_ = NULL;
63 const std::string& sent_data() const {
64 return sent_data_;
67 protected:
68 virtual ~MockSocketStream() {}
70 private:
71 std::string sent_data_;
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;
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) {
96 on_close_ = 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();
104 return OK;
106 virtual void OnConnected(SocketStream* socket,
107 int max_pending_send_allowed) OVERRIDE {
108 if (!on_connected_.is_null())
109 on_connected_.Run();
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();
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())
125 on_close_.Run();
127 virtual bool CanGetCookies(SocketStream* socket,
128 const GURL& url) OVERRIDE {
129 return allow_all_cookies_;
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_;
138 size_t amount_sent() const { return amount_sent_; }
139 const std::string& received_data() const { return received_data_; }
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_;
152 class MockCookieStore : public CookieStore {
153 public:
154 struct Entry {
155 GURL url;
156 std::string cookie_line;
157 CookieOptions options;
160 MockCookieStore() {}
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;
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 += "; ";
182 result += entry.cookie_line;
185 return result;
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);
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));
207 virtual void GetAllCookiesForURLAsync(
208 const GURL& url,
209 const GetCookieListCallback& callback) OVERRIDE {
210 ADD_FAILURE();
213 virtual void DeleteCookieAsync(const GURL& url,
214 const std::string& cookie_name,
215 const base::Closure& callback) OVERRIDE {
216 ADD_FAILURE();
219 virtual void DeleteAllCreatedBetweenAsync(
220 const base::Time& delete_begin,
221 const base::Time& delete_end,
222 const DeleteCallback& callback) OVERRIDE {
223 ADD_FAILURE();
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();
234 virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE {
235 ADD_FAILURE();
238 virtual CookieMonster* GetCookieMonster() OVERRIDE { return NULL; }
240 const std::vector<Entry>& entries() const { return entries_; }
242 private:
243 friend class base::RefCountedThreadSafe<MockCookieStore>;
244 virtual ~MockCookieStore() {}
246 std::vector<Entry> entries_;
249 class MockSSLConfigService : public SSLConfigService {
250 public:
251 virtual void GetSSLConfig(SSLConfig* config) OVERRIDE {}
253 protected:
254 virtual ~MockSSLConfigService() {}
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);
269 virtual ~MockURLRequestContext() {}
271 private:
272 TransportSecurityState transport_security_state_;
275 class MockHttpTransactionFactory : public HttpTransactionFactory {
276 public:
277 MockHttpTransactionFactory(NextProto next_proto, OrderedSocketData* data) {
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_->socket_factory->AddSocketDataProvider(data_);
283 http_session_ =
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 {
297 NOTREACHED();
298 return ERR_UNEXPECTED;
301 virtual HttpCache* GetCache() OVERRIDE {
302 NOTREACHED();
303 return NULL;
306 virtual HttpNetworkSession* GetSession() OVERRIDE {
307 return http_session_.get();
310 private:
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 {
320 public:
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() {
336 if (delete_next_) {
337 job_->DetachContext();
338 job_->DetachDelegate();
339 job_ = NULL;
343 // SocketStream::Delegate implementation
345 // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
347 virtual void OnConnected(SocketStream* socket,
348 int max_pending_send_allowed) OVERRIDE {
349 DeleteJobMaybe();
352 virtual void OnSentData(SocketStream* socket, int amount_sent) OVERRIDE {
353 DeleteJobMaybe();
356 virtual void OnReceivedData(SocketStream* socket,
357 const char* data,
358 int len) OVERRIDE {
359 DeleteJobMaybe();
362 virtual void OnClose(SocketStream* socket) OVERRIDE { DeleteJobMaybe(); }
364 virtual void OnAuthRequired(SocketStream* socket,
365 AuthChallengeInfo* auth_info) OVERRIDE {
366 DeleteJobMaybe();
369 virtual void OnSSLCertificateError(SocketStream* socket,
370 const SSLInfo& ssl_info,
371 bool fatal) OVERRIDE {
372 DeleteJobMaybe();
375 virtual void OnError(const SocketStream* socket, int error) OVERRIDE {
376 DeleteJobMaybe();
379 // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
380 // WebSocketJob object.
382 private:
383 scoped_refptr<WebSocketJob> job_;
384 bool delete_next_;
387 } // namespace
389 class WebSocketJobTest : public PlatformTest,
390 public ::testing::WithParamInterface<NextProto> {
391 public:
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;
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();
419 protected:
420 enum StreamType {
421 STREAM_INVALID,
422 STREAM_MOCK_SOCKET,
423 STREAM_SOCKET,
424 STREAM_SPDY_WEBSOCKET,
426 enum ThrottlingOption {
427 THROTTLING_OFF,
428 THROTTLING_ON,
430 enum SpdyOption {
431 SPDY_OFF,
432 SPDY_ON,
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(),
443 NULL);
445 if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
446 if (stream_type == STREAM_SPDY_WEBSOCKET) {
447 http_factory_.reset(
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);
461 DCHECK(data_.get());
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
470 // instead.
471 IPAddressNumber ip;
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());
498 DCHECK(socket);
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_);
505 DCHECK(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 {
556 protected:
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"
588 "\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"
600 "\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"
612 "\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"
620 "\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"
629 "\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);
654 SkipToConnecting();
656 DoSendRequest();
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());
670 CloseWebSocketJob();
673 void WebSocketJobTest::TestSlowHandshake() {
674 GURL url("ws://example.com/demo");
675 MockSocketStreamDelegate delegate;
676 InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
677 SkipToConnecting();
679 DoSendRequest();
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());
704 CloseWebSocketJob();
707 INSTANTIATE_TEST_CASE_P(
708 NextProto,
709 WebSocketJobTest,
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,
721 "CR-test=1",
722 cookie_options,
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);
731 SkipToConnecting();
733 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
734 kHandshakeRequestWithCookieLength);
735 EXPECT_TRUE(sent);
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());
751 CloseWebSocketJob();
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);
766 SkipToConnecting();
768 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
769 kHandshakeRequestWithCookieLength);
770 EXPECT_TRUE(sent);
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);
794 CloseWebSocketJob();
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);
810 SkipToConnecting();
812 bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
813 kHandshakeRequestWithCookieLength);
814 EXPECT_TRUE(sent);
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);
834 CloseWebSocketJob();
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);
859 SkipToConnecting();
861 DoSendRequest();
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);
874 EXPECT_FALSE(sent);
875 EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
876 CloseWebSocketJob();
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[] = {
893 MockWrite(ASYNC,
894 kHandshakeRequestWithoutCookie,
895 kHandshakeRequestWithoutCookieLength,
897 MockWrite(ASYNC,
898 kDataHello,
899 kDataHelloLength,
902 MockRead reads[] = {
903 MockRead(ASYNC,
904 kHandshakeResponseWithoutCookie,
905 kHandshakeResponseWithoutCookieLength,
907 MockRead(ASYNC,
908 kDataWorld,
909 kDataWorldLength,
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)));
927 delegate.SetOnClose(
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());
936 ASSERT_TRUE(
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
947 // latter.
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[] = {
967 MockWrite(ASYNC,
968 kHandshakeRequestWithoutCookie,
969 kHandshakeRequestWithoutCookieLength,
971 MockWrite(ASYNC,
972 kDataHello,
973 kDataHelloLength,
976 MockRead reads_websocket[] = {
977 MockRead(ASYNC,
978 kHandshakeResponseWithoutCookie,
979 kHandshakeResponseWithoutCookieLength,
981 MockRead(ASYNC,
982 kDataWorld,
983 kDataWorldLength,
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(),
1007 kStreamId,
1008 MEDIUM));
1009 scoped_ptr<SpdyFrame> response_frame(
1010 spdy_util_.ConstructSpdyWebSocketHandshakeResponseFrame(
1011 response_headers.Pass(),
1012 kStreamId,
1013 MEDIUM));
1014 scoped_ptr<SpdyFrame> data_hello_frame(
1015 spdy_util_.ConstructSpdyWebSocketDataFrame(
1016 kDataHello,
1017 kDataHelloLength,
1018 kStreamId,
1019 false));
1020 scoped_ptr<SpdyFrame> data_world_frame(
1021 spdy_util_.ConstructSpdyWebSocketDataFrame(
1022 kDataWorld,
1023 kDataWorldLength,
1024 kStreamId,
1025 false));
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)));
1040 else
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());
1065 ASSERT_TRUE(
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
1076 // latter.
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;
1091 IPAddressNumber ip;
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));
1098 else
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
1104 // for Wakeup call.
1105 for (std::vector<scoped_refptr<WebSocketJob> >::reverse_iterator iter =
1106 jobs.rbegin();
1107 iter != jobs.rend();
1108 ++iter) {
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);
1138 TestHSTSUpgrade();
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);
1168 TestHSTSUpgrade();
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) {
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());
1232 TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
1233 SetDeleteNext();
1234 job()->OnAuthRequired(socket_.get(), NULL);
1235 EXPECT_FALSE(job());
1238 TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
1239 SSLInfo ssl_info;
1240 SetDeleteNext();
1241 job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
1242 EXPECT_FALSE(job());
1245 TEST_F(WebSocketJobDeleteTest, OnError) {
1246 SetDeleteNext();
1247 job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
1248 EXPECT_FALSE(job());
1251 TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
1252 job()->Connect();
1253 SetDeleteNext();
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"
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());
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());
1290 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
1291 // TODO(toyoshim,yutak): Add tests to verify closing handshake.
1292 } // namespace net