| Index: net/websockets/websocket_job_test.cc
|
| diff --git a/net/websockets/websocket_job_test.cc b/net/websockets/websocket_job_test.cc
|
| deleted file mode 100644
|
| index c84af8f27cdde452bb4318f70ea411ea987b4ba9..0000000000000000000000000000000000000000
|
| --- a/net/websockets/websocket_job_test.cc
|
| +++ /dev/null
|
| @@ -1,1287 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/websockets/websocket_job.h"
|
| -
|
| -#include <string>
|
| -#include <vector>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/callback.h"
|
| -#include "base/memory/ref_counted.h"
|
| -#include "base/strings/string_split.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "net/base/completion_callback.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/test_completion_callback.h"
|
| -#include "net/cookies/cookie_store.h"
|
| -#include "net/cookies/cookie_store_test_helpers.h"
|
| -#include "net/dns/mock_host_resolver.h"
|
| -#include "net/http/http_transaction_factory.h"
|
| -#include "net/http/transport_security_state.h"
|
| -#include "net/proxy/proxy_service.h"
|
| -#include "net/socket/next_proto.h"
|
| -#include "net/socket/socket_test_util.h"
|
| -#include "net/socket_stream/socket_stream.h"
|
| -#include "net/spdy/spdy_session.h"
|
| -#include "net/spdy/spdy_websocket_test_util.h"
|
| -#include "net/ssl/ssl_config_service.h"
|
| -#include "net/url_request/url_request_context.h"
|
| -#include "net/websockets/websocket_throttle.h"
|
| -#include "testing/gmock/include/gmock/gmock.h"
|
| -#include "testing/gtest/include/gtest/gtest.h"
|
| -#include "testing/platform_test.h"
|
| -#include "url/gurl.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -class MockSocketStream : public SocketStream {
|
| - public:
|
| - MockSocketStream(const GURL& url, SocketStream::Delegate* delegate,
|
| - URLRequestContext* context, CookieStore* cookie_store)
|
| - : SocketStream(url, delegate, context, cookie_store) {}
|
| -
|
| - void Connect() override {}
|
| - bool SendData(const char* data, int len) override {
|
| - sent_data_ += std::string(data, len);
|
| - return true;
|
| - }
|
| -
|
| - void Close() override {}
|
| - void RestartWithAuth(const AuthCredentials& credentials) override {}
|
| -
|
| - void DetachDelegate() override { delegate_ = NULL; }
|
| -
|
| - const std::string& sent_data() const {
|
| - return sent_data_;
|
| - }
|
| -
|
| - protected:
|
| - ~MockSocketStream() override {}
|
| -
|
| - private:
|
| - std::string sent_data_;
|
| -};
|
| -
|
| -class MockSocketStreamDelegate : public SocketStream::Delegate {
|
| - public:
|
| - MockSocketStreamDelegate()
|
| - : amount_sent_(0), allow_all_cookies_(true) {}
|
| - void set_allow_all_cookies(bool allow_all_cookies) {
|
| - allow_all_cookies_ = allow_all_cookies;
|
| - }
|
| - ~MockSocketStreamDelegate() override {}
|
| -
|
| - void SetOnStartOpenConnection(const base::Closure& callback) {
|
| - on_start_open_connection_ = callback;
|
| - }
|
| - void SetOnConnected(const base::Closure& callback) {
|
| - on_connected_ = callback;
|
| - }
|
| - void SetOnSentData(const base::Closure& callback) {
|
| - on_sent_data_ = callback;
|
| - }
|
| - void SetOnReceivedData(const base::Closure& callback) {
|
| - on_received_data_ = callback;
|
| - }
|
| - void SetOnClose(const base::Closure& callback) {
|
| - on_close_ = callback;
|
| - }
|
| -
|
| - int OnStartOpenConnection(SocketStream* socket,
|
| - const CompletionCallback& callback) override {
|
| - if (!on_start_open_connection_.is_null())
|
| - on_start_open_connection_.Run();
|
| - return OK;
|
| - }
|
| - void OnConnected(SocketStream* socket,
|
| - int max_pending_send_allowed) override {
|
| - if (!on_connected_.is_null())
|
| - on_connected_.Run();
|
| - }
|
| - void OnSentData(SocketStream* socket, int amount_sent) override {
|
| - amount_sent_ += amount_sent;
|
| - if (!on_sent_data_.is_null())
|
| - on_sent_data_.Run();
|
| - }
|
| - void OnReceivedData(SocketStream* socket,
|
| - const char* data,
|
| - int len) override {
|
| - received_data_ += std::string(data, len);
|
| - if (!on_received_data_.is_null())
|
| - on_received_data_.Run();
|
| - }
|
| - void OnClose(SocketStream* socket) override {
|
| - if (!on_close_.is_null())
|
| - on_close_.Run();
|
| - }
|
| - bool CanGetCookies(SocketStream* socket, const GURL& url) override {
|
| - return allow_all_cookies_;
|
| - }
|
| - bool CanSetCookie(SocketStream* request,
|
| - const GURL& url,
|
| - const std::string& cookie_line,
|
| - CookieOptions* options) override {
|
| - return allow_all_cookies_;
|
| - }
|
| -
|
| - size_t amount_sent() const { return amount_sent_; }
|
| - const std::string& received_data() const { return received_data_; }
|
| -
|
| - private:
|
| - int amount_sent_;
|
| - bool allow_all_cookies_;
|
| - std::string received_data_;
|
| - base::Closure on_start_open_connection_;
|
| - base::Closure on_connected_;
|
| - base::Closure on_sent_data_;
|
| - base::Closure on_received_data_;
|
| - base::Closure on_close_;
|
| -};
|
| -
|
| -class MockCookieStore : public CookieStore {
|
| - public:
|
| - struct Entry {
|
| - GURL url;
|
| - std::string cookie_line;
|
| - CookieOptions options;
|
| - };
|
| -
|
| - MockCookieStore() {}
|
| -
|
| - bool SetCookieWithOptions(const GURL& url,
|
| - const std::string& cookie_line,
|
| - const CookieOptions& options) {
|
| - Entry entry;
|
| - entry.url = url;
|
| - entry.cookie_line = cookie_line;
|
| - entry.options = options;
|
| - entries_.push_back(entry);
|
| - return true;
|
| - }
|
| -
|
| - std::string GetCookiesWithOptions(const GURL& url,
|
| - const CookieOptions& options) {
|
| - std::string result;
|
| - for (size_t i = 0; i < entries_.size(); i++) {
|
| - Entry& entry = entries_[i];
|
| - if (url == entry.url) {
|
| - if (!result.empty()) {
|
| - result += "; ";
|
| - }
|
| - result += entry.cookie_line;
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - // CookieStore:
|
| - void SetCookieWithOptionsAsync(const GURL& url,
|
| - const std::string& cookie_line,
|
| - const CookieOptions& options,
|
| - const SetCookiesCallback& callback) override {
|
| - bool result = SetCookieWithOptions(url, cookie_line, options);
|
| - if (!callback.is_null())
|
| - callback.Run(result);
|
| - }
|
| -
|
| - void GetCookiesWithOptionsAsync(const GURL& url,
|
| - const CookieOptions& options,
|
| - const GetCookiesCallback& callback) override {
|
| - if (!callback.is_null())
|
| - callback.Run(GetCookiesWithOptions(url, options));
|
| - }
|
| -
|
| - void GetAllCookiesForURLAsync(
|
| - const GURL& url,
|
| - const GetCookieListCallback& callback) override {
|
| - ADD_FAILURE();
|
| - }
|
| -
|
| - void DeleteCookieAsync(const GURL& url,
|
| - const std::string& cookie_name,
|
| - const base::Closure& callback) override {
|
| - ADD_FAILURE();
|
| - }
|
| -
|
| - void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
|
| - const base::Time& delete_end,
|
| - const DeleteCallback& callback) override {
|
| - ADD_FAILURE();
|
| - }
|
| -
|
| - void DeleteAllCreatedBetweenForHostAsync(
|
| - const base::Time delete_begin,
|
| - const base::Time delete_end,
|
| - const GURL& url,
|
| - const DeleteCallback& callback) override {
|
| - ADD_FAILURE();
|
| - }
|
| -
|
| - void DeleteSessionCookiesAsync(const DeleteCallback&) override {
|
| - ADD_FAILURE();
|
| - }
|
| -
|
| - CookieMonster* GetCookieMonster() override { return NULL; }
|
| -
|
| - scoped_ptr<CookieStore::CookieChangedSubscription>
|
| - AddCallbackForCookie(const GURL& url, const std::string& name,
|
| - const CookieChangedCallback& callback) override {
|
| - ADD_FAILURE();
|
| - return scoped_ptr<CookieChangedSubscription>();
|
| - }
|
| -
|
| - const std::vector<Entry>& entries() const { return entries_; }
|
| -
|
| - private:
|
| - friend class base::RefCountedThreadSafe<MockCookieStore>;
|
| - ~MockCookieStore() override {}
|
| -
|
| - std::vector<Entry> entries_;
|
| -};
|
| -
|
| -class MockSSLConfigService : public SSLConfigService {
|
| - public:
|
| - void GetSSLConfig(SSLConfig* config) override {}
|
| -
|
| - protected:
|
| - ~MockSSLConfigService() override {}
|
| -};
|
| -
|
| -class MockURLRequestContext : public URLRequestContext {
|
| - public:
|
| - explicit MockURLRequestContext(CookieStore* cookie_store)
|
| - : transport_security_state_() {
|
| - set_cookie_store(cookie_store);
|
| - set_transport_security_state(&transport_security_state_);
|
| - base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
|
| - bool include_subdomains = false;
|
| - transport_security_state_.AddHSTS("upgrademe.com", expiry,
|
| - include_subdomains);
|
| - }
|
| -
|
| - ~MockURLRequestContext() override { AssertNoURLRequests(); }
|
| -
|
| - private:
|
| - TransportSecurityState transport_security_state_;
|
| -};
|
| -
|
| -class MockHttpTransactionFactory : public HttpTransactionFactory {
|
| - public:
|
| - MockHttpTransactionFactory(NextProto next_proto,
|
| - OrderedSocketData* data,
|
| - bool enable_websocket_over_spdy) {
|
| - data_ = data;
|
| - MockConnect connect_data(SYNCHRONOUS, OK);
|
| - data_->set_connect_data(connect_data);
|
| - session_deps_.reset(new SpdySessionDependencies(next_proto));
|
| - session_deps_->enable_websocket_over_spdy = enable_websocket_over_spdy;
|
| - session_deps_->socket_factory->AddSocketDataProvider(data_);
|
| - http_session_ =
|
| - SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
|
| - host_port_pair_.set_host("example.com");
|
| - host_port_pair_.set_port(80);
|
| - spdy_session_key_ = SpdySessionKey(host_port_pair_,
|
| - ProxyServer::Direct(),
|
| - PRIVACY_MODE_DISABLED);
|
| - session_ = CreateInsecureSpdySession(
|
| - http_session_, spdy_session_key_, BoundNetLog());
|
| - }
|
| -
|
| - int CreateTransaction(RequestPriority priority,
|
| - scoped_ptr<HttpTransaction>* trans) override {
|
| - NOTREACHED();
|
| - return ERR_UNEXPECTED;
|
| - }
|
| -
|
| - HttpCache* GetCache() override {
|
| - NOTREACHED();
|
| - return NULL;
|
| - }
|
| -
|
| - HttpNetworkSession* GetSession() override { return http_session_.get(); }
|
| -
|
| - private:
|
| - OrderedSocketData* data_;
|
| - scoped_ptr<SpdySessionDependencies> session_deps_;
|
| - scoped_refptr<HttpNetworkSession> http_session_;
|
| - base::WeakPtr<SpdySession> session_;
|
| - HostPortPair host_port_pair_;
|
| - SpdySessionKey spdy_session_key_;
|
| -};
|
| -
|
| -class DeletingSocketStreamDelegate : public SocketStream::Delegate {
|
| - public:
|
| - DeletingSocketStreamDelegate()
|
| - : delete_next_(false) {}
|
| -
|
| - // Since this class needs to be able to delete |job_|, it must be the only
|
| - // reference holder (except for temporary references). Provide access to the
|
| - // pointer for tests to use.
|
| - WebSocketJob* job() { return job_.get(); }
|
| -
|
| - void set_job(WebSocketJob* job) { job_ = job; }
|
| -
|
| - // After calling this, the next call to a method on this delegate will delete
|
| - // the WebSocketJob object.
|
| - void set_delete_next(bool delete_next) { delete_next_ = delete_next; }
|
| -
|
| - void DeleteJobMaybe() {
|
| - if (delete_next_) {
|
| - job_->DetachContext();
|
| - job_->DetachDelegate();
|
| - job_ = NULL;
|
| - }
|
| - }
|
| -
|
| - // SocketStream::Delegate implementation
|
| -
|
| - // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
|
| -
|
| - void OnConnected(SocketStream* socket,
|
| - int max_pending_send_allowed) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - void OnSentData(SocketStream* socket, int amount_sent) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - void OnReceivedData(SocketStream* socket,
|
| - const char* data,
|
| - int len) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - void OnClose(SocketStream* socket) override { DeleteJobMaybe(); }
|
| -
|
| - void OnAuthRequired(SocketStream* socket,
|
| - AuthChallengeInfo* auth_info) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - void OnSSLCertificateError(SocketStream* socket,
|
| - const SSLInfo& ssl_info,
|
| - bool fatal) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - void OnError(const SocketStream* socket, int error) override {
|
| - DeleteJobMaybe();
|
| - }
|
| -
|
| - // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
|
| - // WebSocketJob object.
|
| -
|
| - private:
|
| - scoped_refptr<WebSocketJob> job_;
|
| - bool delete_next_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -class WebSocketJobTest : public PlatformTest,
|
| - public ::testing::WithParamInterface<NextProto> {
|
| - public:
|
| - WebSocketJobTest()
|
| - : spdy_util_(GetParam()),
|
| - enable_websocket_over_spdy_(false) {}
|
| -
|
| - void SetUp() override {
|
| - stream_type_ = STREAM_INVALID;
|
| - cookie_store_ = new MockCookieStore;
|
| - context_.reset(new MockURLRequestContext(cookie_store_.get()));
|
| - }
|
| - void TearDown() override {
|
| - cookie_store_ = NULL;
|
| - context_.reset();
|
| - websocket_ = NULL;
|
| - socket_ = NULL;
|
| - }
|
| - void DoSendRequest() {
|
| - EXPECT_TRUE(websocket_->SendData(kHandshakeRequestWithoutCookie,
|
| - kHandshakeRequestWithoutCookieLength));
|
| - }
|
| - void DoSendData() {
|
| - if (received_data().size() == kHandshakeResponseWithoutCookieLength)
|
| - websocket_->SendData(kDataHello, kDataHelloLength);
|
| - }
|
| - void DoSync() {
|
| - sync_test_callback_.callback().Run(OK);
|
| - }
|
| - int WaitForResult() {
|
| - return sync_test_callback_.WaitForResult();
|
| - }
|
| -
|
| - protected:
|
| - enum StreamType {
|
| - STREAM_INVALID,
|
| - STREAM_MOCK_SOCKET,
|
| - STREAM_SOCKET,
|
| - STREAM_SPDY_WEBSOCKET,
|
| - };
|
| - enum ThrottlingOption {
|
| - THROTTLING_OFF,
|
| - THROTTLING_ON,
|
| - };
|
| - enum SpdyOption {
|
| - SPDY_OFF,
|
| - SPDY_ON,
|
| - };
|
| - void InitWebSocketJob(const GURL& url,
|
| - MockSocketStreamDelegate* delegate,
|
| - StreamType stream_type) {
|
| - DCHECK_NE(STREAM_INVALID, stream_type);
|
| - stream_type_ = stream_type;
|
| - websocket_ = new WebSocketJob(delegate);
|
| -
|
| - if (stream_type == STREAM_MOCK_SOCKET)
|
| - socket_ = new MockSocketStream(url, websocket_.get(), context_.get(),
|
| - NULL);
|
| -
|
| - if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
|
| - if (stream_type == STREAM_SPDY_WEBSOCKET) {
|
| - http_factory_.reset(new MockHttpTransactionFactory(
|
| - GetParam(), data_.get(), enable_websocket_over_spdy_));
|
| - context_->set_http_transaction_factory(http_factory_.get());
|
| - }
|
| -
|
| - ssl_config_service_ = new MockSSLConfigService();
|
| - context_->set_ssl_config_service(ssl_config_service_.get());
|
| - proxy_service_.reset(ProxyService::CreateDirect());
|
| - context_->set_proxy_service(proxy_service_.get());
|
| - host_resolver_.reset(new MockHostResolver);
|
| - context_->set_host_resolver(host_resolver_.get());
|
| -
|
| - socket_ = new SocketStream(url, websocket_.get(), context_.get(), NULL);
|
| - socket_factory_.reset(new MockClientSocketFactory);
|
| - DCHECK(data_.get());
|
| - socket_factory_->AddSocketDataProvider(data_.get());
|
| - socket_->SetClientSocketFactory(socket_factory_.get());
|
| - }
|
| -
|
| - websocket_->InitSocketStream(socket_.get());
|
| - // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create
|
| - // a WebSocketJob purely to block another one in a throttling test, we don't
|
| - // perform a real connect. In that case, the following address is used
|
| - // instead.
|
| - IPAddressNumber ip;
|
| - ParseIPLiteralToNumber("127.0.0.1", &ip);
|
| - websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80);
|
| - }
|
| - void SkipToConnecting() {
|
| - websocket_->state_ = WebSocketJob::CONNECTING;
|
| - ASSERT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(websocket_.get()));
|
| - }
|
| - WebSocketJob::State GetWebSocketJobState() {
|
| - return websocket_->state_;
|
| - }
|
| - void CloseWebSocketJob() {
|
| - if (websocket_->socket_.get()) {
|
| - websocket_->socket_->DetachDelegate();
|
| - WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_.get());
|
| - }
|
| - websocket_->state_ = WebSocketJob::CLOSED;
|
| - websocket_->delegate_ = NULL;
|
| - websocket_->socket_ = NULL;
|
| - }
|
| - SocketStream* GetSocket(SocketStreamJob* job) {
|
| - return job->socket_.get();
|
| - }
|
| - const std::string& sent_data() const {
|
| - DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_);
|
| - MockSocketStream* socket =
|
| - static_cast<MockSocketStream*>(socket_.get());
|
| - DCHECK(socket);
|
| - return socket->sent_data();
|
| - }
|
| - const std::string& received_data() const {
|
| - DCHECK_NE(STREAM_INVALID, stream_type_);
|
| - MockSocketStreamDelegate* delegate =
|
| - static_cast<MockSocketStreamDelegate*>(websocket_->delegate_);
|
| - DCHECK(delegate);
|
| - return delegate->received_data();
|
| - }
|
| -
|
| - void TestSimpleHandshake();
|
| - void TestSlowHandshake();
|
| - void TestHandshakeWithCookie();
|
| - void TestHandshakeWithCookieButNotAllowed();
|
| - void TestHSTSUpgrade();
|
| - void TestInvalidSendData();
|
| - void TestConnectByWebSocket(ThrottlingOption throttling);
|
| - void TestConnectBySpdy(SpdyOption spdy, ThrottlingOption throttling);
|
| - void TestThrottlingLimit();
|
| -
|
| - SpdyWebSocketTestUtil spdy_util_;
|
| - StreamType stream_type_;
|
| - scoped_refptr<MockCookieStore> cookie_store_;
|
| - scoped_ptr<MockURLRequestContext> context_;
|
| - scoped_refptr<WebSocketJob> websocket_;
|
| - scoped_refptr<SocketStream> socket_;
|
| - scoped_ptr<MockClientSocketFactory> socket_factory_;
|
| - scoped_ptr<OrderedSocketData> data_;
|
| - TestCompletionCallback sync_test_callback_;
|
| - scoped_refptr<MockSSLConfigService> ssl_config_service_;
|
| - scoped_ptr<ProxyService> proxy_service_;
|
| - scoped_ptr<MockHostResolver> host_resolver_;
|
| - scoped_ptr<MockHttpTransactionFactory> http_factory_;
|
| -
|
| - // Must be set before call to enable_websocket_over_spdy, defaults to false.
|
| - bool enable_websocket_over_spdy_;
|
| -
|
| - static const char kHandshakeRequestWithoutCookie[];
|
| - static const char kHandshakeRequestWithCookie[];
|
| - static const char kHandshakeRequestWithFilteredCookie[];
|
| - static const char kHandshakeResponseWithoutCookie[];
|
| - static const char kHandshakeResponseWithCookie[];
|
| - static const char kDataHello[];
|
| - static const char kDataWorld[];
|
| - static const char* const kHandshakeRequestForSpdy[];
|
| - static const char* const kHandshakeResponseForSpdy[];
|
| - static const size_t kHandshakeRequestWithoutCookieLength;
|
| - static const size_t kHandshakeRequestWithCookieLength;
|
| - static const size_t kHandshakeRequestWithFilteredCookieLength;
|
| - static const size_t kHandshakeResponseWithoutCookieLength;
|
| - static const size_t kHandshakeResponseWithCookieLength;
|
| - static const size_t kDataHelloLength;
|
| - static const size_t kDataWorldLength;
|
| -};
|
| -
|
| -// Tests using this fixture verify that the WebSocketJob can handle being
|
| -// deleted while calling back to the delegate correctly. These tests need to be
|
| -// run under AddressSanitizer or other systems for detecting use-after-free
|
| -// errors in order to find problems.
|
| -class WebSocketJobDeleteTest : public ::testing::Test {
|
| - protected:
|
| - WebSocketJobDeleteTest()
|
| - : delegate_(new DeletingSocketStreamDelegate),
|
| - cookie_store_(new MockCookieStore),
|
| - context_(new MockURLRequestContext(cookie_store_.get())) {
|
| - WebSocketJob* websocket = new WebSocketJob(delegate_.get());
|
| - delegate_->set_job(websocket);
|
| -
|
| - socket_ = new MockSocketStream(
|
| - GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL);
|
| -
|
| - websocket->InitSocketStream(socket_.get());
|
| - }
|
| -
|
| - void SetDeleteNext() { return delegate_->set_delete_next(true); }
|
| - WebSocketJob* job() { return delegate_->job(); }
|
| -
|
| - scoped_ptr<DeletingSocketStreamDelegate> delegate_;
|
| - scoped_refptr<MockCookieStore> cookie_store_;
|
| - scoped_ptr<MockURLRequestContext> context_;
|
| - scoped_refptr<SocketStream> socket_;
|
| -};
|
| -
|
| -const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
|
| - "GET /demo HTTP/1.1\r\n"
|
| - "Host: example.com\r\n"
|
| - "Upgrade: WebSocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
| - "Origin: http://example.com\r\n"
|
| - "Sec-WebSocket-Protocol: sample\r\n"
|
| - "Sec-WebSocket-Version: 13\r\n"
|
| - "\r\n";
|
| -
|
| -const char WebSocketJobTest::kHandshakeRequestWithCookie[] =
|
| - "GET /demo HTTP/1.1\r\n"
|
| - "Host: example.com\r\n"
|
| - "Upgrade: WebSocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
| - "Origin: http://example.com\r\n"
|
| - "Sec-WebSocket-Protocol: sample\r\n"
|
| - "Sec-WebSocket-Version: 13\r\n"
|
| - "Cookie: WK-test=1\r\n"
|
| - "\r\n";
|
| -
|
| -const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie[] =
|
| - "GET /demo HTTP/1.1\r\n"
|
| - "Host: example.com\r\n"
|
| - "Upgrade: WebSocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
| - "Origin: http://example.com\r\n"
|
| - "Sec-WebSocket-Protocol: sample\r\n"
|
| - "Sec-WebSocket-Version: 13\r\n"
|
| - "Cookie: CR-test=1; CR-test-httponly=1\r\n"
|
| - "\r\n";
|
| -
|
| -const char WebSocketJobTest::kHandshakeResponseWithoutCookie[] =
|
| - "HTTP/1.1 101 Switching Protocols\r\n"
|
| - "Upgrade: websocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
| - "Sec-WebSocket-Protocol: sample\r\n"
|
| - "\r\n";
|
| -
|
| -const char WebSocketJobTest::kHandshakeResponseWithCookie[] =
|
| - "HTTP/1.1 101 Switching Protocols\r\n"
|
| - "Upgrade: websocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
| - "Sec-WebSocket-Protocol: sample\r\n"
|
| - "Set-Cookie: CR-set-test=1\r\n"
|
| - "\r\n";
|
| -
|
| -const char WebSocketJobTest::kDataHello[] = "Hello, ";
|
| -
|
| -const char WebSocketJobTest::kDataWorld[] = "World!\n";
|
| -
|
| -const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength =
|
| - arraysize(kHandshakeRequestWithoutCookie) - 1;
|
| -const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength =
|
| - arraysize(kHandshakeRequestWithCookie) - 1;
|
| -const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength =
|
| - arraysize(kHandshakeRequestWithFilteredCookie) - 1;
|
| -const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength =
|
| - arraysize(kHandshakeResponseWithoutCookie) - 1;
|
| -const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength =
|
| - arraysize(kHandshakeResponseWithCookie) - 1;
|
| -const size_t WebSocketJobTest::kDataHelloLength =
|
| - arraysize(kDataHello) - 1;
|
| -const size_t WebSocketJobTest::kDataWorldLength =
|
| - arraysize(kDataWorld) - 1;
|
| -
|
| -void WebSocketJobTest::TestSimpleHandshake() {
|
| - GURL url("ws://example.com/demo");
|
| - MockSocketStreamDelegate delegate;
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - DoSendRequest();
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(),
|
| - kHandshakeRequestWithoutCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
|
| -
|
| - websocket_->OnReceivedData(socket_.get(),
|
| - kHandshakeResponseWithoutCookie,
|
| - kHandshakeResponseWithoutCookieLength);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
|
| - EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -void WebSocketJobTest::TestSlowHandshake() {
|
| - GURL url("ws://example.com/demo");
|
| - MockSocketStreamDelegate delegate;
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - DoSendRequest();
|
| - // We assume request is sent in one data chunk (from WebKit)
|
| - // We don't support streaming request.
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(),
|
| - kHandshakeRequestWithoutCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
|
| -
|
| - std::vector<std::string> lines;
|
| - base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines);
|
| - for (size_t i = 0; i < lines.size() - 2; i++) {
|
| - std::string line = lines[i] + "\r\n";
|
| - SCOPED_TRACE("Line: " + line);
|
| - websocket_->OnReceivedData(socket_.get(), line.c_str(), line.size());
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_TRUE(delegate.received_data().empty());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - }
|
| - websocket_->OnReceivedData(socket_.get(), "\r\n", 2);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_FALSE(delegate.received_data().empty());
|
| - EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
|
| - EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -INSTANTIATE_TEST_CASE_P(
|
| - NextProto,
|
| - WebSocketJobTest,
|
| - testing::Values(kProtoDeprecatedSPDY2,
|
| - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
|
| -
|
| -TEST_P(WebSocketJobTest, DelayedCookies) {
|
| - enable_websocket_over_spdy_ = true;
|
| - GURL url("ws://example.com/demo");
|
| - GURL cookieUrl("http://example.com/demo");
|
| - CookieOptions cookie_options;
|
| - scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster();
|
| - context_->set_cookie_store(cookie_store.get());
|
| - cookie_store->SetCookieWithOptionsAsync(cookieUrl,
|
| - "CR-test=1",
|
| - cookie_options,
|
| - CookieMonster::SetCookiesCallback());
|
| - cookie_options.set_include_httponly();
|
| - cookie_store->SetCookieWithOptionsAsync(
|
| - cookieUrl, "CR-test-httponly=1", cookie_options,
|
| - CookieMonster::SetCookiesCallback());
|
| -
|
| - MockSocketStreamDelegate delegate;
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
|
| - kHandshakeRequestWithCookieLength);
|
| - EXPECT_TRUE(sent);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(),
|
| - kHandshakeRequestWithFilteredCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithCookieLength,
|
| - delegate.amount_sent());
|
| -
|
| - websocket_->OnReceivedData(socket_.get(),
|
| - kHandshakeResponseWithCookie,
|
| - kHandshakeResponseWithCookieLength);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
|
| - EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
|
| -
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -void WebSocketJobTest::TestHandshakeWithCookie() {
|
| - GURL url("ws://example.com/demo");
|
| - GURL cookieUrl("http://example.com/demo");
|
| - CookieOptions cookie_options;
|
| - cookie_store_->SetCookieWithOptions(
|
| - cookieUrl, "CR-test=1", cookie_options);
|
| - cookie_options.set_include_httponly();
|
| - cookie_store_->SetCookieWithOptions(
|
| - cookieUrl, "CR-test-httponly=1", cookie_options);
|
| -
|
| - MockSocketStreamDelegate delegate;
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
|
| - kHandshakeRequestWithCookieLength);
|
| - EXPECT_TRUE(sent);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(),
|
| - kHandshakeRequestWithFilteredCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithCookieLength,
|
| - delegate.amount_sent());
|
| -
|
| - websocket_->OnReceivedData(socket_.get(),
|
| - kHandshakeResponseWithCookie,
|
| - kHandshakeResponseWithCookieLength);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
|
| - EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
|
| -
|
| - EXPECT_EQ(3U, cookie_store_->entries().size());
|
| - EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
|
| - EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
|
| - EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
|
| - EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
|
| - EXPECT_EQ(cookieUrl, cookie_store_->entries()[2].url);
|
| - EXPECT_EQ("CR-set-test=1", cookie_store_->entries()[2].cookie_line);
|
| -
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() {
|
| - GURL url("ws://example.com/demo");
|
| - GURL cookieUrl("http://example.com/demo");
|
| - CookieOptions cookie_options;
|
| - cookie_store_->SetCookieWithOptions(
|
| - cookieUrl, "CR-test=1", cookie_options);
|
| - cookie_options.set_include_httponly();
|
| - cookie_store_->SetCookieWithOptions(
|
| - cookieUrl, "CR-test-httponly=1", cookie_options);
|
| -
|
| - MockSocketStreamDelegate delegate;
|
| - delegate.set_allow_all_cookies(false);
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
|
| - kHandshakeRequestWithCookieLength);
|
| - EXPECT_TRUE(sent);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(), kHandshakeRequestWithoutCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithCookieLength, delegate.amount_sent());
|
| -
|
| - websocket_->OnReceivedData(socket_.get(),
|
| - kHandshakeResponseWithCookie,
|
| - kHandshakeResponseWithCookieLength);
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
|
| - EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
|
| -
|
| - EXPECT_EQ(2U, cookie_store_->entries().size());
|
| - EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
|
| - EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
|
| - EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
|
| - EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
|
| -
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -void WebSocketJobTest::TestHSTSUpgrade() {
|
| - GURL url("ws://upgrademe.com/");
|
| - MockSocketStreamDelegate delegate;
|
| - scoped_refptr<SocketStreamJob> job =
|
| - SocketStreamJob::CreateSocketStreamJob(
|
| - url, &delegate, context_->transport_security_state(),
|
| - context_->ssl_config_service(), NULL, NULL);
|
| - EXPECT_TRUE(GetSocket(job.get())->is_secure());
|
| - job->DetachDelegate();
|
| -
|
| - url = GURL("ws://donotupgrademe.com/");
|
| - job = SocketStreamJob::CreateSocketStreamJob(
|
| - url, &delegate, context_->transport_security_state(),
|
| - context_->ssl_config_service(), NULL, NULL);
|
| - EXPECT_FALSE(GetSocket(job.get())->is_secure());
|
| - job->DetachDelegate();
|
| -}
|
| -
|
| -void WebSocketJobTest::TestInvalidSendData() {
|
| - GURL url("ws://example.com/demo");
|
| - MockSocketStreamDelegate delegate;
|
| - InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
|
| - SkipToConnecting();
|
| -
|
| - DoSendRequest();
|
| - // We assume request is sent in one data chunk (from WebKit)
|
| - // We don't support streaming request.
|
| - base::MessageLoop::current()->RunUntilIdle();
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - websocket_->OnSentData(socket_.get(),
|
| - kHandshakeRequestWithoutCookieLength);
|
| - EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
|
| -
|
| - // We could not send any data until connection is established.
|
| - bool sent = websocket_->SendData(kHandshakeRequestWithoutCookie,
|
| - kHandshakeRequestWithoutCookieLength);
|
| - EXPECT_FALSE(sent);
|
| - EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
|
| - CloseWebSocketJob();
|
| -}
|
| -
|
| -// Following tests verify cooperation between WebSocketJob and SocketStream.
|
| -// Other former tests use MockSocketStream as SocketStream, so we could not
|
| -// check SocketStream behavior.
|
| -// OrderedSocketData provide socket level verifiation by checking out-going
|
| -// packets in comparison with the MockWrite array and emulating in-coming
|
| -// packets with MockRead array.
|
| -
|
| -void WebSocketJobTest::TestConnectByWebSocket(
|
| - ThrottlingOption throttling) {
|
| - // This is a test for verifying cooperation between WebSocketJob and
|
| - // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic
|
| - // situation. If |throttling| was |THROTTLING_ON|, throttling limits the
|
| - // latter connection.
|
| - MockWrite writes[] = {
|
| - MockWrite(ASYNC,
|
| - kHandshakeRequestWithoutCookie,
|
| - kHandshakeRequestWithoutCookieLength,
|
| - 1),
|
| - MockWrite(ASYNC,
|
| - kDataHello,
|
| - kDataHelloLength,
|
| - 3)
|
| - };
|
| - MockRead reads[] = {
|
| - MockRead(ASYNC,
|
| - kHandshakeResponseWithoutCookie,
|
| - kHandshakeResponseWithoutCookieLength,
|
| - 2),
|
| - MockRead(ASYNC,
|
| - kDataWorld,
|
| - kDataWorldLength,
|
| - 4),
|
| - MockRead(SYNCHRONOUS, 0, 5) // EOF
|
| - };
|
| - data_.reset(new OrderedSocketData(
|
| - reads, arraysize(reads), writes, arraysize(writes)));
|
| -
|
| - GURL url("ws://example.com/demo");
|
| - MockSocketStreamDelegate delegate;
|
| - WebSocketJobTest* test = this;
|
| - if (throttling == THROTTLING_ON)
|
| - delegate.SetOnStartOpenConnection(
|
| - base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
|
| - delegate.SetOnConnected(
|
| - base::Bind(&WebSocketJobTest::DoSendRequest,
|
| - base::Unretained(test)));
|
| - delegate.SetOnReceivedData(
|
| - base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
|
| - delegate.SetOnClose(
|
| - base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
|
| - InitWebSocketJob(url, &delegate, STREAM_SOCKET);
|
| -
|
| - scoped_refptr<WebSocketJob> block_websocket;
|
| - if (throttling == THROTTLING_ON) {
|
| - // Create former WebSocket object which obstructs the latter one.
|
| - block_websocket = new WebSocketJob(NULL);
|
| - block_websocket->addresses_ = AddressList(websocket_->address_list());
|
| - ASSERT_TRUE(
|
| - WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
|
| - }
|
| -
|
| - websocket_->Connect();
|
| -
|
| - if (throttling == THROTTLING_ON) {
|
| - EXPECT_EQ(OK, WaitForResult());
|
| - EXPECT_TRUE(websocket_->IsWaiting());
|
| -
|
| - // Remove the former WebSocket object from throttling queue to unblock the
|
| - // latter.
|
| - block_websocket->state_ = WebSocketJob::CLOSED;
|
| - WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
|
| - block_websocket = NULL;
|
| - }
|
| -
|
| - EXPECT_EQ(OK, WaitForResult());
|
| - EXPECT_TRUE(data_->at_read_eof());
|
| - EXPECT_TRUE(data_->at_write_eof());
|
| - EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
|
| -}
|
| -
|
| -void WebSocketJobTest::TestConnectBySpdy(
|
| - SpdyOption spdy, ThrottlingOption throttling) {
|
| - // This is a test for verifying cooperation between WebSocketJob and
|
| - // SocketStream in the situation we have SPDY session to the server. If
|
| - // |throttling| was |THROTTLING_ON|, throttling limits the latter connection.
|
| - // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected
|
| - // results depend on its configuration.
|
| - MockWrite writes_websocket[] = {
|
| - MockWrite(ASYNC,
|
| - kHandshakeRequestWithoutCookie,
|
| - kHandshakeRequestWithoutCookieLength,
|
| - 1),
|
| - MockWrite(ASYNC,
|
| - kDataHello,
|
| - kDataHelloLength,
|
| - 3)
|
| - };
|
| - MockRead reads_websocket[] = {
|
| - MockRead(ASYNC,
|
| - kHandshakeResponseWithoutCookie,
|
| - kHandshakeResponseWithoutCookieLength,
|
| - 2),
|
| - MockRead(ASYNC,
|
| - kDataWorld,
|
| - kDataWorldLength,
|
| - 4),
|
| - MockRead(SYNCHRONOUS, 0, 5) // EOF
|
| - };
|
| -
|
| - scoped_ptr<SpdyHeaderBlock> request_headers(new SpdyHeaderBlock());
|
| - spdy_util_.SetHeader("path", "/demo", request_headers.get());
|
| - spdy_util_.SetHeader("version", "WebSocket/13", request_headers.get());
|
| - spdy_util_.SetHeader("scheme", "ws", request_headers.get());
|
| - spdy_util_.SetHeader("host", "example.com", request_headers.get());
|
| - spdy_util_.SetHeader("origin", "http://example.com", request_headers.get());
|
| - spdy_util_.SetHeader("sec-websocket-protocol", "sample",
|
| - request_headers.get());
|
| -
|
| - scoped_ptr<SpdyHeaderBlock> response_headers(new SpdyHeaderBlock());
|
| - spdy_util_.SetHeader("status", "101 Switching Protocols",
|
| - response_headers.get());
|
| - spdy_util_.SetHeader("sec-websocket-protocol", "sample",
|
| - response_headers.get());
|
| -
|
| - const SpdyStreamId kStreamId = 1;
|
| - scoped_ptr<SpdyFrame> request_frame(
|
| - spdy_util_.ConstructSpdyWebSocketHandshakeRequestFrame(
|
| - request_headers.Pass(),
|
| - kStreamId,
|
| - MEDIUM));
|
| - scoped_ptr<SpdyFrame> response_frame(
|
| - spdy_util_.ConstructSpdyWebSocketHandshakeResponseFrame(
|
| - response_headers.Pass(),
|
| - kStreamId,
|
| - MEDIUM));
|
| - scoped_ptr<SpdyFrame> data_hello_frame(
|
| - spdy_util_.ConstructSpdyWebSocketDataFrame(
|
| - kDataHello,
|
| - kDataHelloLength,
|
| - kStreamId,
|
| - false));
|
| - scoped_ptr<SpdyFrame> data_world_frame(
|
| - spdy_util_.ConstructSpdyWebSocketDataFrame(
|
| - kDataWorld,
|
| - kDataWorldLength,
|
| - kStreamId,
|
| - false));
|
| - MockWrite writes_spdy[] = {
|
| - CreateMockWrite(*request_frame.get(), 1),
|
| - CreateMockWrite(*data_hello_frame.get(), 3),
|
| - };
|
| - MockRead reads_spdy[] = {
|
| - CreateMockRead(*response_frame.get(), 2),
|
| - CreateMockRead(*data_world_frame.get(), 4),
|
| - MockRead(SYNCHRONOUS, 0, 5) // EOF
|
| - };
|
| -
|
| - if (spdy == SPDY_ON)
|
| - data_.reset(new OrderedSocketData(
|
| - reads_spdy, arraysize(reads_spdy),
|
| - writes_spdy, arraysize(writes_spdy)));
|
| - else
|
| - data_.reset(new OrderedSocketData(
|
| - reads_websocket, arraysize(reads_websocket),
|
| - writes_websocket, arraysize(writes_websocket)));
|
| -
|
| - GURL url("ws://example.com/demo");
|
| - MockSocketStreamDelegate delegate;
|
| - WebSocketJobTest* test = this;
|
| - if (throttling == THROTTLING_ON)
|
| - delegate.SetOnStartOpenConnection(
|
| - base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
|
| - delegate.SetOnConnected(
|
| - base::Bind(&WebSocketJobTest::DoSendRequest,
|
| - base::Unretained(test)));
|
| - delegate.SetOnReceivedData(
|
| - base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
|
| - delegate.SetOnClose(
|
| - base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
|
| - InitWebSocketJob(url, &delegate, STREAM_SPDY_WEBSOCKET);
|
| -
|
| - scoped_refptr<WebSocketJob> block_websocket;
|
| - if (throttling == THROTTLING_ON) {
|
| - // Create former WebSocket object which obstructs the latter one.
|
| - block_websocket = new WebSocketJob(NULL);
|
| - block_websocket->addresses_ = AddressList(websocket_->address_list());
|
| - ASSERT_TRUE(
|
| - WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
|
| - }
|
| -
|
| - websocket_->Connect();
|
| -
|
| - if (throttling == THROTTLING_ON) {
|
| - EXPECT_EQ(OK, WaitForResult());
|
| - EXPECT_TRUE(websocket_->IsWaiting());
|
| -
|
| - // Remove the former WebSocket object from throttling queue to unblock the
|
| - // latter.
|
| - block_websocket->state_ = WebSocketJob::CLOSED;
|
| - WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
|
| - block_websocket = NULL;
|
| - }
|
| -
|
| - EXPECT_EQ(OK, WaitForResult());
|
| - EXPECT_TRUE(data_->at_read_eof());
|
| - EXPECT_TRUE(data_->at_write_eof());
|
| - EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
|
| -}
|
| -
|
| -void WebSocketJobTest::TestThrottlingLimit() {
|
| - std::vector<scoped_refptr<WebSocketJob> > jobs;
|
| - const int kMaxWebSocketJobsThrottled = 1024;
|
| - IPAddressNumber ip;
|
| - ParseIPLiteralToNumber("127.0.0.1", &ip);
|
| - for (int i = 0; i < kMaxWebSocketJobsThrottled + 1; ++i) {
|
| - scoped_refptr<WebSocketJob> job = new WebSocketJob(NULL);
|
| - job->addresses_ = AddressList(AddressList::CreateFromIPAddress(ip, 80));
|
| - if (i >= kMaxWebSocketJobsThrottled)
|
| - EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
|
| - else
|
| - EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
|
| - jobs.push_back(job);
|
| - }
|
| -
|
| - // Close the jobs in reverse order. Otherwise, We need to make them prepared
|
| - // for Wakeup call.
|
| - for (std::vector<scoped_refptr<WebSocketJob> >::reverse_iterator iter =
|
| - jobs.rbegin();
|
| - iter != jobs.rend();
|
| - ++iter) {
|
| - WebSocketJob* job = (*iter).get();
|
| - job->state_ = WebSocketJob::CLOSED;
|
| - WebSocketThrottle::GetInstance()->RemoveFromQueue(job);
|
| - }
|
| -}
|
| -
|
| -// Execute tests in both spdy-disabled mode and spdy-enabled mode.
|
| -TEST_P(WebSocketJobTest, SimpleHandshake) {
|
| - TestSimpleHandshake();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, SlowHandshake) {
|
| - TestSlowHandshake();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HandshakeWithCookie) {
|
| - TestHandshakeWithCookie();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
|
| - TestHandshakeWithCookieButNotAllowed();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HSTSUpgrade) {
|
| - TestHSTSUpgrade();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, InvalidSendData) {
|
| - TestInvalidSendData();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestSimpleHandshake();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestSlowHandshake();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestHandshakeWithCookie();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestHandshakeWithCookieButNotAllowed();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestHSTSUpgrade();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestInvalidSendData();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ConnectByWebSocket) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestConnectByWebSocket(THROTTLING_OFF);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestConnectByWebSocket(THROTTLING_OFF);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ConnectBySpdy) {
|
| - TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ThrottlingWebSocket) {
|
| - TestConnectByWebSocket(THROTTLING_ON);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) {
|
| - TestThrottlingLimit();
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestConnectByWebSocket(THROTTLING_ON);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ThrottlingSpdy) {
|
| - TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
|
| -}
|
| -
|
| -TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
|
| - enable_websocket_over_spdy_ = true;
|
| - TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnClose) {
|
| - SetDeleteNext();
|
| - job()->OnClose(socket_.get());
|
| - // OnClose() sets WebSocketJob::_socket to NULL before we can detach it, so
|
| - // socket_->delegate is still set at this point. Clear it to avoid hitting
|
| - // DCHECK(!delegate_) in the SocketStream destructor. SocketStream::Finish()
|
| - // is the only caller of this method in real code, and it also sets delegate_
|
| - // to NULL.
|
| - socket_->DetachDelegate();
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
|
| - SetDeleteNext();
|
| - job()->OnAuthRequired(socket_.get(), NULL);
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
|
| - SSLInfo ssl_info;
|
| - SetDeleteNext();
|
| - job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnError) {
|
| - SetDeleteNext();
|
| - job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
|
| - job()->Connect();
|
| - SetDeleteNext();
|
| - job()->OnSentSpdyHeaders();
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) {
|
| - static const char kMinimalRequest[] =
|
| - "GET /demo HTTP/1.1\r\n"
|
| - "Host: example.com\r\n"
|
| - "Upgrade: WebSocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
| - "Origin: http://example.com\r\n"
|
| - "Sec-WebSocket-Version: 13\r\n"
|
| - "\r\n";
|
| - const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1;
|
| - job()->Connect();
|
| - job()->SendData(kMinimalRequest, kMinimalRequestSize);
|
| - SetDeleteNext();
|
| - job()->OnSentData(socket_.get(), kMinimalRequestSize);
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) {
|
| - static const char kMinimalResponse[] =
|
| - "HTTP/1.1 101 Switching Protocols\r\n"
|
| - "Upgrade: websocket\r\n"
|
| - "Connection: Upgrade\r\n"
|
| - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
|
| - "\r\n";
|
| - job()->Connect();
|
| - SetDeleteNext();
|
| - job()->OnReceivedData(
|
| - socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1);
|
| - EXPECT_FALSE(job());
|
| -}
|
| -
|
| -// TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
|
| -// TODO(toyoshim,yutak): Add tests to verify closing handshake.
|
| -} // namespace net
|
|
|