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