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     AssertNoURLRequests();
    271   }
    272 
    273  private:
    274   TransportSecurityState transport_security_state_;
    275 };
    276 
    277 class 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 
    324 class 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 
    394 class 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.
    566 class 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 
    590 const 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 
    601 const 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 
    613 const 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 
    625 const 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 
    633 const 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 
    642 const char WebSocketJobTest::kDataHello[] = "Hello, ";
    643 
    644 const char WebSocketJobTest::kDataWorld[] = "World!\n";
    645 
    646 const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength =
    647     arraysize(kHandshakeRequestWithoutCookie) - 1;
    648 const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength =
    649     arraysize(kHandshakeRequestWithCookie) - 1;
    650 const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength =
    651     arraysize(kHandshakeRequestWithFilteredCookie) - 1;
    652 const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength =
    653     arraysize(kHandshakeResponseWithoutCookie) - 1;
    654 const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength =
    655     arraysize(kHandshakeResponseWithCookie) - 1;
    656 const size_t WebSocketJobTest::kDataHelloLength =
    657     arraysize(kDataHello) - 1;
    658 const size_t WebSocketJobTest::kDataWorldLength =
    659     arraysize(kDataWorld) - 1;
    660 
    661 void 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 
    684 void 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 
    718 INSTANTIATE_TEST_CASE_P(
    719     NextProto,
    720     WebSocketJobTest,
    721     testing::Values(kProtoDeprecatedSPDY2,
    722                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
    723 
    724 TEST_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 
    765 void 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 
    808 void 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 
    848 void 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 
    866 void 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 
    897 void 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 
    970 void 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 
   1099 void 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.
   1127 TEST_P(WebSocketJobTest, SimpleHandshake) {
   1128   TestSimpleHandshake();
   1129 }
   1130 
   1131 TEST_P(WebSocketJobTest, SlowHandshake) {
   1132   TestSlowHandshake();
   1133 }
   1134 
   1135 TEST_P(WebSocketJobTest, HandshakeWithCookie) {
   1136   TestHandshakeWithCookie();
   1137 }
   1138 
   1139 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
   1140   TestHandshakeWithCookieButNotAllowed();
   1141 }
   1142 
   1143 TEST_P(WebSocketJobTest, HSTSUpgrade) {
   1144   TestHSTSUpgrade();
   1145 }
   1146 
   1147 TEST_P(WebSocketJobTest, InvalidSendData) {
   1148   TestInvalidSendData();
   1149 }
   1150 
   1151 TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
   1152   enable_websocket_over_spdy_ = true;
   1153   TestSimpleHandshake();
   1154 }
   1155 
   1156 TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
   1157   enable_websocket_over_spdy_ = true;
   1158   TestSlowHandshake();
   1159 }
   1160 
   1161 TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
   1162   enable_websocket_over_spdy_ = true;
   1163   TestHandshakeWithCookie();
   1164 }
   1165 
   1166 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
   1167   enable_websocket_over_spdy_ = true;
   1168   TestHandshakeWithCookieButNotAllowed();
   1169 }
   1170 
   1171 TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
   1172   enable_websocket_over_spdy_ = true;
   1173   TestHSTSUpgrade();
   1174 }
   1175 
   1176 TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
   1177   enable_websocket_over_spdy_ = true;
   1178   TestInvalidSendData();
   1179 }
   1180 
   1181 TEST_P(WebSocketJobTest, ConnectByWebSocket) {
   1182   enable_websocket_over_spdy_ = true;
   1183   TestConnectByWebSocket(THROTTLING_OFF);
   1184 }
   1185 
   1186 TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
   1187   enable_websocket_over_spdy_ = true;
   1188   TestConnectByWebSocket(THROTTLING_OFF);
   1189 }
   1190 
   1191 TEST_P(WebSocketJobTest, ConnectBySpdy) {
   1192   TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
   1193 }
   1194 
   1195 TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
   1196   enable_websocket_over_spdy_ = true;
   1197   TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
   1198 }
   1199 
   1200 TEST_P(WebSocketJobTest, ThrottlingWebSocket) {
   1201   TestConnectByWebSocket(THROTTLING_ON);
   1202 }
   1203 
   1204 TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) {
   1205   TestThrottlingLimit();
   1206 }
   1207 
   1208 TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
   1209   enable_websocket_over_spdy_ = true;
   1210   TestConnectByWebSocket(THROTTLING_ON);
   1211 }
   1212 
   1213 TEST_P(WebSocketJobTest, ThrottlingSpdy) {
   1214   TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
   1215 }
   1216 
   1217 TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
   1218   enable_websocket_over_spdy_ = true;
   1219   TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
   1220 }
   1221 
   1222 TEST_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 
   1234 TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
   1235   SetDeleteNext();
   1236   job()->OnAuthRequired(socket_.get(), NULL);
   1237   EXPECT_FALSE(job());
   1238 }
   1239 
   1240 TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
   1241   SSLInfo ssl_info;
   1242   SetDeleteNext();
   1243   job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
   1244   EXPECT_FALSE(job());
   1245 }
   1246 
   1247 TEST_F(WebSocketJobDeleteTest, OnError) {
   1248   SetDeleteNext();
   1249   job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
   1250   EXPECT_FALSE(job());
   1251 }
   1252 
   1253 TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
   1254   job()->Connect();
   1255   SetDeleteNext();
   1256   job()->OnSentSpdyHeaders();
   1257   EXPECT_FALSE(job());
   1258 }
   1259 
   1260 TEST_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 
   1278 TEST_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