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