diff options
author | ricea <ricea@chromium.org> | 2014-11-08 06:21:56 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-08 14:22:14 +0000 |
commit | 5563c9df40ff8738c49cb1b86633c0ca91ac07c2 (patch) | |
tree | ef37780813f290e1904c70a4e689a06782b8a6c3 | |
parent | 626256ab20378c1aba947414a84ab3868d2efad9 (diff) | |
download | chromium_src-5563c9df40ff8738c49cb1b86633c0ca91ac07c2.zip chromium_src-5563c9df40ff8738c49cb1b86633c0ca91ac07c2.tar.gz chromium_src-5563c9df40ff8738c49cb1b86633c0ca91ac07c2.tar.bz2 |
Delete the old WebSocket implementation from net/
The removal of NetworkDelegate::OnBeforeSocketStreamConnect() is in http://crrev.com/652363005 so not too many reviewers will need to review this more-complex CL.
BUG=423201
TEST=net_unittests, browser_tests
Review URL: https://codereview.chromium.org/679273005
Cr-Commit-Position: refs/heads/master@{#303387}
50 files changed, 14 insertions, 8696 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 24064c6..e5c9e03 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -803,18 +803,11 @@ void IOThread::InitializeNetworkOptions(const CommandLine& command_line) { } else if (command_line.HasSwitch(switches::kEnableNpnHttpOnly)) { globals_->next_protos = net::NextProtosHttpOnly(); globals_->use_alternate_protocols.set(false); - } else if (command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) { - // Use the current SPDY default (SPDY/3.1). - globals_->next_protos = net::NextProtosSpdy31(); - globals_->use_alternate_protocols.set(true); } else { // No SPDY command-line flags have been specified. Examine trial groups. ConfigureSpdyFromTrial( base::FieldTrialList::FindFullName(kSpdyFieldTrialName), globals_); } - - if (command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) - globals_->enable_websocket_over_spdy.set(true); } ConfigureTCPFastOpen(command_line); @@ -1028,8 +1021,6 @@ void IOThread::InitializeNetworkSessionParamsFromGlobals( ¶ms->use_alternate_protocols); globals.alternate_protocol_probability_threshold.CopyToIfSet( ¶ms->alternate_protocol_probability_threshold); - globals.enable_websocket_over_spdy.CopyToIfSet( - ¶ms->enable_websocket_over_spdy); globals.enable_quic.CopyToIfSet(¶ms->enable_quic); globals.quic_always_require_handshake_confirmation.CopyToIfSet( diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h index 6df3171..4fa68e0 100644 --- a/chrome/browser/io_thread.h +++ b/chrome/browser/io_thread.h @@ -184,7 +184,6 @@ class IOThread : public content::BrowserThreadDelegate { std::set<net::HostPortPair> forced_spdy_exclusions; Optional<bool> use_alternate_protocols; Optional<double> alternate_protocol_probability_threshold; - Optional<bool> enable_websocket_over_spdy; Optional<bool> enable_quic; Optional<bool> enable_quic_port_selection; diff --git a/chrome/browser/resources/net_internals/source_entry.js b/chrome/browser/resources/net_internals/source_entry.js index fafd4e3..974adc9 100644 --- a/chrome/browser/resources/net_internals/source_entry.js +++ b/chrome/browser/resources/net_internals/source_entry.js @@ -79,6 +79,7 @@ var SourceEntry = (function() { switch (e.source.type) { case EventSourceType.URL_REQUEST: + // TODO(ricea): Remove SOCKET_STREAM after M41 is released. case EventSourceType.SOCKET_STREAM: case EventSourceType.HTTP_STREAM_JOB: case EventSourceType.ASYNC_REVALIDATION: @@ -181,8 +182,8 @@ var SourceEntry = (function() { /** * Returns the starting entry for this source. Conceptually this is the * first entry that was logged to this source. However, we skip over the - * TYPE_REQUEST_ALIVE entries which wrap TYPE_URL_REQUEST_START_JOB / - * TYPE_SOCKET_STREAM_CONNECT. + * TYPE_REQUEST_ALIVE entries which wrap TYPE_URL_REQUEST_START_JO + * entries. */ getStartEntry_: function() { if (this.entries_.length < 1) diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 8c5ef48..577f648 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -631,9 +631,6 @@ const char kEnableTranslateNewUX[] = "enable-translate-new-ux"; const char kEnableUserAlternateProtocolPorts[] = "enable-user-controlled-alternate-protocol-ports"; -// Uses WebSocket over SPDY. -const char kEnableWebSocketOverSpdy[] = "enable-websocket-over-spdy"; - // Enables the Website Settings page on the Settings page. const char kEnableWebsiteSettingsManager[] = "enable-website-settings-manager"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index b3b00fa..9cca880 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -182,7 +182,6 @@ extern const char kEnableTabAudioMuting[]; extern const char kEnableThumbnailRetargeting[]; extern const char kEnableTranslateNewUX[]; extern const char kEnableUserAlternateProtocolPorts[]; -extern const char kEnableWebSocketOverSpdy[]; extern const char kEnableWebsiteSettingsManager[]; extern const char kEnhancedBookmarksExperiment[]; extern const char kExplicitlyAllowedPorts[]; diff --git a/net/BUILD.gn b/net/BUILD.gn index 04d976d..acaf231 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -381,16 +381,6 @@ component("net") { if (!enable_websockets) { sources -= [ - "socket_stream/socket_stream.cc", - "socket_stream/socket_stream.h", - "socket_stream/socket_stream_job.cc", - "socket_stream/socket_stream_job.h", - "socket_stream/socket_stream_job_manager.cc", - "socket_stream/socket_stream_job_manager.h", - "socket_stream/socket_stream_metrics.cc", - "socket_stream/socket_stream_metrics.h", - "spdy/spdy_websocket_stream.cc", - "spdy/spdy_websocket_stream.h", "websockets/websocket_basic_handshake_stream.cc", "websockets/websocket_basic_handshake_stream.h", "websockets/websocket_basic_stream.cc", @@ -427,15 +417,9 @@ component("net") { "websockets/websocket_handshake_stream_create_helper.h", "websockets/websocket_inflater.cc", "websockets/websocket_inflater.h", - "websockets/websocket_job.cc", - "websockets/websocket_job.h", "websockets/websocket_mux.h", - "websockets/websocket_net_log_params.cc", - "websockets/websocket_net_log_params.h", "websockets/websocket_stream.cc", "websockets/websocket_stream.h", - "websockets/websocket_throttle.cc", - "websockets/websocket_throttle.h", ] } @@ -1226,9 +1210,6 @@ test("net_unittests") { if (!enable_websockets) { sources -= [ - "socket_stream/socket_stream_metrics_unittest.cc", - "socket_stream/socket_stream_unittest.cc", - "spdy/spdy_websocket_stream_unittest.cc", "websockets/websocket_basic_stream_test.cc", "websockets/websocket_channel_test.cc", "websockets/websocket_deflate_predictor_impl_test.cc", @@ -1242,12 +1223,9 @@ test("net_unittests") { "websockets/websocket_handshake_handler_test.cc", "websockets/websocket_handshake_stream_create_helper_test.cc", "websockets/websocket_inflater_test.cc", - "websockets/websocket_job_test.cc", - "websockets/websocket_net_log_params_test.cc", "websockets/websocket_stream_test.cc", "websockets/websocket_test_util.cc", "websockets/websocket_test_util.h", - "websockets/websocket_throttle_test.cc", ] } diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 4b61e0e..7cee212 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -271,9 +271,7 @@ NET_ERROR(SPDY_SESSION_ALREADY_EXISTS, -143) // due to a malformed frame or other protocol violation. NET_ERROR(WS_PROTOCOL_ERROR, -145) -// Connection was aborted for switching to another ptotocol. -// WebSocket abort SocketStream connection when alternate protocol is found. -NET_ERROR(PROTOCOL_SWITCHED, -146) +// Error -146 was removed (PROTOCOL_SWITCHED) // Returned when attempting to bind an address that is already in use. NET_ERROR(ADDRESS_IN_USE, -147) @@ -305,9 +303,7 @@ NET_ERROR(SSL_DECRYPT_ERROR_ALERT, -153) // pushed to the queue. NET_ERROR(WS_THROTTLE_QUEUE_TOO_LARGE, -154) -// There are too many active SocketStream instances, so the new connect request -// was rejected. -NET_ERROR(TOO_MANY_SOCKET_STREAMS, -155) +// Error -155 was removed (TOO_MANY_SOCKET_STREAMS) // The SSL server certificate changed in a renegotiation. NET_ERROR(SSL_SERVER_CERT_CHANGED, -156) diff --git a/net/base/net_log.h b/net/base/net_log.h index 1b598ed..5fb2791 100644 --- a/net/base/net_log.h +++ b/net/base/net_log.h @@ -27,7 +27,7 @@ namespace net { // NetLog is the destination for log messages generated by the network stack. // Each log message has a "source" field which identifies the specific entity // that generated the message (for example, which URLRequest or which -// SocketStream). +// SpdySession). // // To avoid needing to pass in the "source ID" to the logging functions, NetLog // is usually accessed through a BoundNetLog, which will always pass in a diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 823cde1..814cf33 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h @@ -26,8 +26,7 @@ EVENT_TYPE(CANCELLED) // } EVENT_TYPE(FAILED) -// Marks the creation/destruction of a request (net::URLRequest or -// SocketStream). +// Marks the creation/destruction of a request (net::URLRequest). EVENT_TYPE(REQUEST_ALIVE) // ------------------------------------------------------------------------ @@ -1694,49 +1693,6 @@ EVENT_TYPE(QUIC_HTTP_STREAM_READ_RESPONSE_HEADERS) EVENT_TYPE(HTTP_STREAM_PARSER_READ_HEADERS) // ------------------------------------------------------------------------ -// SocketStream -// ------------------------------------------------------------------------ - -// Measures the time between SocketStream::Connect() and -// SocketStream::DidEstablishConnection() -// -// For the BEGIN phase, the following parameters are attached: -// { -// "url": <String of URL being loaded>, -// } -// -// For the END phase, if there was an error, the following parameters are -// attached: -// { -// "net_error": <Net error code of the failure>, -// } -EVENT_TYPE(SOCKET_STREAM_CONNECT) - -// A message sent on the SocketStream. -EVENT_TYPE(SOCKET_STREAM_SENT) - -// A message received on the SocketStream. -EVENT_TYPE(SOCKET_STREAM_RECEIVED) - -// ------------------------------------------------------------------------ -// WebSocketJob -// ------------------------------------------------------------------------ - -// This event is sent for a WebSocket handshake request. -// The following parameters are attached: -// { -// "headers": <handshake request message>, -// } -EVENT_TYPE(WEB_SOCKET_SEND_REQUEST_HEADERS) - -// This event is sent on receipt of the WebSocket handshake response headers. -// The following parameters are attached: -// { -// "headers": <handshake response message>, -// } -EVENT_TYPE(WEB_SOCKET_READ_RESPONSE_HEADERS) - -// ------------------------------------------------------------------------ // SOCKS5ClientSocket // ------------------------------------------------------------------------ diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h index 9d66c17..1a12cd4 100644 --- a/net/base/net_log_source_type_list.h +++ b/net/base/net_log_source_type_list.h @@ -9,7 +9,6 @@ SOURCE_TYPE(NONE) SOURCE_TYPE(URL_REQUEST) -SOURCE_TYPE(SOCKET_STREAM) SOURCE_TYPE(PROXY_SCRIPT_DECIDER) SOURCE_TYPE(CONNECT_JOB) SOURCE_TYPE(SOCKET) diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc index 9cad50a..5b69cfb 100644 --- a/net/base/network_delegate.cc +++ b/net/base/network_delegate.cc @@ -176,19 +176,6 @@ NetworkDelegate::AuthRequiredResponse NetworkDelegate::NotifyAuthRequired( return OnAuthRequired(request, auth_info, callback, credentials); } -int NetworkDelegate::NotifyBeforeSocketStreamConnect( - SocketStream* socket, - const CompletionCallback& callback) { - DCHECK(CalledOnValidThread()); - DCHECK(socket); - DCHECK(!callback.is_null()); - // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "423948 NetworkDelegate::OnBeforeSocketStreamConnect")); - return OnBeforeSocketStreamConnect(socket, callback); -} - bool NetworkDelegate::CanGetCookies(const URLRequest& request, const CookieList& cookie_list) { DCHECK(CalledOnValidThread()); diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h index 299989c..03dee0b 100644 --- a/net/base/network_delegate.h +++ b/net/base/network_delegate.h @@ -105,9 +105,6 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe { bool CanEnablePrivacyMode(const GURL& url, const GURL& first_party_for_cookies) const; - int NotifyBeforeSocketStreamConnect(SocketStream* socket, - const CompletionCallback& callback); - bool CancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url, diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 3ec607e..28b3b22 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -89,7 +89,6 @@ HttpNetworkSession::Params::Params() force_spdy_always(false), use_alternate_protocols(false), alternate_protocol_probability_threshold(1), - enable_websocket_over_spdy(false), enable_quic(false), enable_quic_port_selection(true), quic_always_require_handshake_confirmation(false), diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index a3f70aa..557b84e 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -109,7 +109,6 @@ class NET_EXPORT HttpNetworkSession // trying SSL and then falling back to http. bool use_alternate_protocols; double alternate_protocol_probability_threshold; - bool enable_websocket_over_spdy; bool enable_quic; bool enable_quic_port_selection; diff --git a/net/net.gyp b/net/net.gyp index 7b4b5d6..6f264fb 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -376,13 +376,8 @@ }], [ 'enable_websockets != 1', { 'sources/': [ - ['exclude', '^socket_stream/'], ['exclude', '^websockets/'], ], - 'sources!': [ - 'spdy/spdy_websocket_stream.cc', - 'spdy/spdy_websocket_stream.h', - ], }], [ 'enable_mdns != 1', { 'sources!' : [ @@ -654,9 +649,7 @@ }], [ 'enable_websockets != 1', { 'sources/': [ - ['exclude', '^socket_stream/'], ['exclude', '^websockets/'], - ['exclude', '^spdy/spdy_websocket_stream_unittest\\.cc$'], ], }], ['disable_file_support==1', { diff --git a/net/net.gypi b/net/net.gypi index f43c67f..fef6136 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -1016,14 +1016,6 @@ 'socket/websocket_transport_client_socket_pool.h', 'socket/websocket_transport_connect_sub_job.cc', 'socket/websocket_transport_connect_sub_job.h', - 'socket_stream/socket_stream.cc', - 'socket_stream/socket_stream.h', - 'socket_stream/socket_stream_job.cc', - 'socket_stream/socket_stream_job.h', - 'socket_stream/socket_stream_job_manager.cc', - 'socket_stream/socket_stream_job_manager.h', - 'socket_stream/socket_stream_metrics.cc', - 'socket_stream/socket_stream_metrics.h', 'spdy/buffered_spdy_framer.cc', 'spdy/buffered_spdy_framer.h', 'spdy/fuzzing/hpack_fuzz_util.cc', @@ -1089,8 +1081,6 @@ 'spdy/spdy_session_pool.h', 'spdy/spdy_stream.cc', 'spdy/spdy_stream.h', - 'spdy/spdy_websocket_stream.cc', - 'spdy/spdy_websocket_stream.h', 'spdy/spdy_write_queue.cc', 'spdy/spdy_write_queue.h', 'spdy/write_blocked_list.h', @@ -1249,15 +1239,9 @@ 'websockets/websocket_handshake_stream_create_helper.h', 'websockets/websocket_inflater.cc', 'websockets/websocket_inflater.h', - 'websockets/websocket_job.cc', - 'websockets/websocket_job.h', 'websockets/websocket_mux.h', - 'websockets/websocket_net_log_params.cc', - 'websockets/websocket_net_log_params.h', 'websockets/websocket_stream.cc', 'websockets/websocket_stream.h', - 'websockets/websocket_throttle.cc', - 'websockets/websocket_throttle.h', ], 'net_extras_sources': [ 'extras/sqlite/sqlite_channel_id_store.cc', @@ -1613,8 +1597,6 @@ 'socket/unix_domain_server_socket_posix_unittest.cc', 'socket/websocket_endpoint_lock_manager_unittest.cc', 'socket/websocket_transport_client_socket_pool_unittest.cc', - 'socket_stream/socket_stream_metrics_unittest.cc', - 'socket_stream/socket_stream_unittest.cc', 'spdy/buffered_spdy_framer_unittest.cc', 'spdy/fuzzing/hpack_fuzz_util_test.cc', 'spdy/hpack_decoder_test.cc', @@ -1657,9 +1639,6 @@ 'spdy/spdy_test_util_common.h', 'spdy/spdy_test_utils.cc', 'spdy/spdy_test_utils.h', - 'spdy/spdy_websocket_stream_unittest.cc', - 'spdy/spdy_websocket_test_util.cc', - 'spdy/spdy_websocket_test_util.h', 'spdy/spdy_write_queue_unittest.cc', 'spdy/write_blocked_list_test.cc', 'ssl/channel_id_service_unittest.cc', @@ -1722,16 +1701,12 @@ 'websockets/websocket_extension_parser_test.cc', 'websockets/websocket_frame_parser_test.cc', 'websockets/websocket_frame_test.cc', - 'websockets/websocket_handshake_handler_spdy_test.cc', 'websockets/websocket_handshake_handler_test.cc', 'websockets/websocket_handshake_stream_create_helper_test.cc', 'websockets/websocket_inflater_test.cc', - 'websockets/websocket_job_test.cc', - 'websockets/websocket_net_log_params_test.cc', 'websockets/websocket_stream_test.cc', 'websockets/websocket_test_util.cc', 'websockets/websocket_test_util.h', - 'websockets/websocket_throttle_test.cc', ], 'net_linux_test_sources': [ 'quic/quic_end_to_end_unittest.cc', diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc deleted file mode 100644 index 422d61d..0000000 --- a/net/socket_stream/socket_stream.cc +++ /dev/null @@ -1,1353 +0,0 @@ -// Copyright (c) 2012 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. -// -// TODO(ukai): code is similar with http_network_transaction.cc. We should -// think about ways to share code, if possible. - -#include "net/socket_stream/socket_stream.h" - -#include <set> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "net/base/auth.h" -#include "net/base/io_buffer.h" -#include "net/base/load_flags.h" -#include "net/base/net_errors.h" -#include "net/base/net_util.h" -#include "net/dns/host_resolver.h" -#include "net/http/http_auth_controller.h" -#include "net/http/http_network_session.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_request_info.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_stream_factory.h" -#include "net/http/http_transaction_factory.h" -#include "net/http/http_util.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/socks5_client_socket.h" -#include "net/socket/socks_client_socket.h" -#include "net/socket/ssl_client_socket.h" -#include "net/socket/tcp_client_socket.h" -#include "net/socket_stream/socket_stream_metrics.h" -#include "net/ssl/ssl_cert_request_info.h" -#include "net/ssl/ssl_info.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_context.h" - -static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes. -static const int kReadBufferSize = 4096; - -namespace net { - -int SocketStream::Delegate::OnStartOpenConnection( - SocketStream* socket, const CompletionCallback& callback) { - return OK; -} - -void SocketStream::Delegate::OnAuthRequired(SocketStream* socket, - AuthChallengeInfo* auth_info) { - // By default, no credential is available and close the connection. - socket->Close(); -} - -void SocketStream::Delegate::OnSSLCertificateError( - SocketStream* socket, - const SSLInfo& ssl_info, - bool fatal) { - socket->CancelWithSSLError(ssl_info); -} - -bool SocketStream::Delegate::CanGetCookies(SocketStream* socket, - const GURL& url) { - return true; -} - -bool SocketStream::Delegate::CanSetCookie(SocketStream* request, - const GURL& url, - const std::string& cookie_line, - CookieOptions* options) { - return true; -} - -SocketStream::ResponseHeaders::ResponseHeaders() : IOBuffer() {} - -void SocketStream::ResponseHeaders::Realloc(size_t new_size) { - headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size))); -} - -SocketStream::ResponseHeaders::~ResponseHeaders() { data_ = NULL; } - -SocketStream::SocketStream(const GURL& url, Delegate* delegate, - URLRequestContext* context, - CookieStore* cookie_store) - : delegate_(delegate), - url_(url), - max_pending_send_allowed_(kMaxPendingSendAllowed), - context_(context), - next_state_(STATE_NONE), - factory_(ClientSocketFactory::GetDefaultFactory()), - proxy_mode_(kDirectConnection), - proxy_url_(url), - pac_request_(NULL), - connection_(new ClientSocketHandle), - privacy_mode_(PRIVACY_MODE_DISABLED), - // Unretained() is required; without it, Bind() creates a circular - // dependency and the SocketStream object will not be freed. - io_callback_(base::Bind(&SocketStream::OnIOCompleted, - base::Unretained(this))), - read_buf_(NULL), - current_write_buf_(NULL), - waiting_for_write_completion_(false), - closing_(false), - server_closed_(false), - metrics_(new SocketStreamMetrics(url)), - cookie_store_(cookie_store) { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - DCHECK(delegate_); - - if (context_) { - if (!cookie_store_.get()) - cookie_store_ = context_->cookie_store(); - - net_log_ = BoundNetLog::Make( - context->net_log(), - NetLog::SOURCE_SOCKET_STREAM); - - net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE); - } -} - -SocketStream::UserData* SocketStream::GetUserData( - const void* key) const { - UserDataMap::const_iterator found = user_data_.find(key); - if (found != user_data_.end()) - return found->second.get(); - return NULL; -} - -void SocketStream::SetUserData(const void* key, UserData* data) { - user_data_[key] = linked_ptr<UserData>(data); -} - -bool SocketStream::is_secure() const { - return url_.SchemeIs("wss"); -} - -void SocketStream::DetachContext() { - if (!context_) - return; - - if (pac_request_) { - context_->proxy_service()->CancelPacRequest(pac_request_); - pac_request_ = NULL; - } - - net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE); - net_log_ = BoundNetLog(); - - context_ = NULL; - cookie_store_ = NULL; -} - -void SocketStream::CheckPrivacyMode() { - if (context_ && context_->network_delegate()) { - bool enable = context_->network_delegate()->CanEnablePrivacyMode(url_, - url_); - privacy_mode_ = enable ? PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED; - // Disable Channel ID if privacy mode is enabled. - if (enable) - server_ssl_config_.channel_id_enabled = false; - } -} - -void SocketStream::Connect() { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - if (context_) { - context_->ssl_config_service()->GetSSLConfig(&server_ssl_config_); - proxy_ssl_config_ = server_ssl_config_; - } - CheckPrivacyMode(); - - DCHECK_EQ(next_state_, STATE_NONE); - - AddRef(); // Released in Finish() - // Open a connection asynchronously, so that delegate won't be called - // back before returning Connect(). - next_state_ = STATE_BEFORE_CONNECT; - net_log_.BeginEvent( - NetLog::TYPE_SOCKET_STREAM_CONNECT, - NetLog::StringCallback("url", &url_.possibly_invalid_spec())); - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); -} - -size_t SocketStream::GetTotalSizeOfPendingWriteBufs() const { - size_t total_size = 0; - for (PendingDataQueue::const_iterator iter = pending_write_bufs_.begin(); - iter != pending_write_bufs_.end(); - ++iter) - total_size += (*iter)->size(); - return total_size; -} - -bool SocketStream::SendData(const char* data, int len) { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - DCHECK_GT(len, 0); - - if (!connection_->socket() || - !connection_->socket()->IsConnected() || next_state_ == STATE_NONE) { - return false; - } - - int total_buffered_bytes = len; - if (current_write_buf_.get()) { - // Since - // - the purpose of this check is to limit the amount of buffer used by - // this instance. - // - the DrainableIOBuffer doesn't release consumed memory. - // we need to use not BytesRemaining() but size() here. - total_buffered_bytes += current_write_buf_->size(); - } - total_buffered_bytes += GetTotalSizeOfPendingWriteBufs(); - if (total_buffered_bytes > max_pending_send_allowed_) - return false; - - // TODO(tyoshino): Split data into smaller chunks e.g. 8KiB to free consumed - // buffer progressively - pending_write_bufs_.push_back(make_scoped_refptr( - new IOBufferWithSize(len))); - memcpy(pending_write_bufs_.back()->data(), data, len); - - // If current_write_buf_ is not NULL, it means that a) there's ongoing write - // operation or b) the connection is being closed. If a), the buffer we just - // pushed will be automatically handled when the completion callback runs - // the loop, and therefore we don't need to enqueue DoLoop(). If b), it's ok - // to do nothing. If current_write_buf_ is NULL, to make sure DoLoop() is - // ran soon, enequeue it. - if (!current_write_buf_.get()) { - // Send pending data asynchronously, so that delegate won't be called - // back before returning from SendData(). - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); - } - - return true; -} - -void SocketStream::Close() { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - // If next_state_ is STATE_NONE, the socket was not opened, or already - // closed. So, return immediately. - // Otherwise, it might call Finish() more than once, so breaks balance - // of AddRef() and Release() in Connect() and Finish(), respectively. - if (next_state_ == STATE_NONE) - return; - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoClose, this)); -} - -void SocketStream::RestartWithAuth(const AuthCredentials& credentials) { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - DCHECK(proxy_auth_controller_.get()); - if (!connection_->socket()) { - DVLOG(1) << "Socket is closed before restarting with auth."; - return; - } - - proxy_auth_controller_->ResetAuth(credentials); - - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this)); -} - -void SocketStream::DetachDelegate() { - if (!delegate_) - return; - delegate_ = NULL; - // Prevent the rest of the function from executing if we are being called from - // within Finish(). - if (next_state_ == STATE_NONE) - return; - net_log_.AddEvent(NetLog::TYPE_CANCELLED); - // We don't need to send pending data when client detach the delegate. - pending_write_bufs_.clear(); - Close(); -} - -const ProxyServer& SocketStream::proxy_server() const { - return proxy_info_.proxy_server(); -} - -void SocketStream::SetClientSocketFactory( - ClientSocketFactory* factory) { - DCHECK(factory); - factory_ = factory; -} - -void SocketStream::CancelWithError(int error) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoLoop, this, error)); -} - -void SocketStream::CancelWithSSLError(const SSLInfo& ssl_info) { - CancelWithError(MapCertStatusToNetError(ssl_info.cert_status)); -} - -void SocketStream::ContinueDespiteError() { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK)); -} - -SocketStream::~SocketStream() { - DetachContext(); - DCHECK(!delegate_); - DCHECK(!pac_request_); -} - -SocketStream::RequestHeaders::~RequestHeaders() { data_ = NULL; } - -void SocketStream::set_addresses(const AddressList& addresses) { - addresses_ = addresses; -} - -void SocketStream::DoClose() { - closing_ = true; - // If next_state_ is: - // - STATE_TCP_CONNECT_COMPLETE, it's waiting other socket establishing - // connection. - // - STATE_AUTH_REQUIRED, it's waiting for restarting. - // - STATE_RESOLVE_PROTOCOL_COMPLETE, it's waiting for delegate_ to finish - // OnStartOpenConnection method call - // In these states, we'll close the SocketStream now. - if (next_state_ == STATE_TCP_CONNECT_COMPLETE || - next_state_ == STATE_AUTH_REQUIRED || - next_state_ == STATE_RESOLVE_PROTOCOL_COMPLETE) { - DoLoop(ERR_ABORTED); - return; - } - // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close - // the SocketStream. - // If it's writing now, we should defer the closing after the current - // writing is completed. - if (next_state_ == STATE_READ_WRITE && !current_write_buf_.get()) - DoLoop(ERR_ABORTED); - - // In other next_state_, we'll wait for callback of other APIs, such as - // ResolveProxy(). -} - -void SocketStream::Finish(int result) { - DCHECK(base::MessageLoop::current()) - << "The current base::MessageLoop must exist"; - DCHECK(base::MessageLoopForIO::IsCurrent()) - << "The current base::MessageLoop must be TYPE_IO"; - DCHECK_LE(result, OK); - if (result == OK) - result = ERR_CONNECTION_CLOSED; - DCHECK_EQ(next_state_, STATE_NONE); - DVLOG(1) << "Finish result=" << ErrorToString(result); - - metrics_->OnClose(); - - if (result != ERR_CONNECTION_CLOSED && delegate_) - delegate_->OnError(this, result); - if (result != ERR_PROTOCOL_SWITCHED && delegate_) - delegate_->OnClose(this); - delegate_ = NULL; - - Release(); -} - -int SocketStream::DidEstablishConnection() { - if (!connection_->socket() || !connection_->socket()->IsConnected()) { - next_state_ = STATE_CLOSE; - return ERR_CONNECTION_FAILED; - } - next_state_ = STATE_READ_WRITE; - metrics_->OnConnected(); - - net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT); - if (delegate_) - delegate_->OnConnected(this, max_pending_send_allowed_); - - return OK; -} - -int SocketStream::DidReceiveData(int result) { - DCHECK(read_buf_.get()); - DCHECK_GT(result, 0); - net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_RECEIVED); - int len = result; - metrics_->OnRead(len); - if (delegate_) { - // Notify recevied data to delegate. - delegate_->OnReceivedData(this, read_buf_->data(), len); - } - read_buf_ = NULL; - return OK; -} - -void SocketStream::DidSendData(int result) { - DCHECK_GT(result, 0); - DCHECK(current_write_buf_.get()); - net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_SENT); - - int bytes_sent = result; - - metrics_->OnWrite(bytes_sent); - - current_write_buf_->DidConsume(result); - - if (current_write_buf_->BytesRemaining()) - return; - - size_t bytes_freed = current_write_buf_->size(); - - current_write_buf_ = NULL; - - // We freed current_write_buf_ and this instance is now able to accept more - // data via SendData() (note that DidConsume() doesn't free consumed memory). - // We can tell that to delegate_ by calling OnSentData(). - if (delegate_) - delegate_->OnSentData(this, bytes_freed); -} - -void SocketStream::OnIOCompleted(int result) { - DoLoop(result); -} - -void SocketStream::OnReadCompleted(int result) { - if (result == 0) { - // 0 indicates end-of-file, so socket was closed. - // Don't close the socket if it's still writing. - server_closed_ = true; - } else if (result > 0 && read_buf_.get()) { - result = DidReceiveData(result); - } - DoLoop(result); -} - -void SocketStream::OnWriteCompleted(int result) { - waiting_for_write_completion_ = false; - if (result > 0) { - DidSendData(result); - result = OK; - } - DoLoop(result); -} - -void SocketStream::DoLoop(int result) { - if (next_state_ == STATE_NONE) - return; - - // If context was not set, close immediately. - if (!context_) - next_state_ = STATE_CLOSE; - - do { - State state = next_state_; - next_state_ = STATE_NONE; - switch (state) { - case STATE_BEFORE_CONNECT: - DCHECK_EQ(OK, result); - result = DoBeforeConnect(); - break; - case STATE_BEFORE_CONNECT_COMPLETE: - result = DoBeforeConnectComplete(result); - break; - case STATE_RESOLVE_PROXY: - DCHECK_EQ(OK, result); - result = DoResolveProxy(); - break; - case STATE_RESOLVE_PROXY_COMPLETE: - result = DoResolveProxyComplete(result); - break; - case STATE_RESOLVE_HOST: - DCHECK_EQ(OK, result); - result = DoResolveHost(); - break; - case STATE_RESOLVE_HOST_COMPLETE: - result = DoResolveHostComplete(result); - break; - case STATE_RESOLVE_PROTOCOL: - result = DoResolveProtocol(result); - break; - case STATE_RESOLVE_PROTOCOL_COMPLETE: - result = DoResolveProtocolComplete(result); - break; - case STATE_TCP_CONNECT: - result = DoTcpConnect(result); - break; - case STATE_TCP_CONNECT_COMPLETE: - result = DoTcpConnectComplete(result); - break; - case STATE_GENERATE_PROXY_AUTH_TOKEN: - result = DoGenerateProxyAuthToken(); - break; - case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE: - result = DoGenerateProxyAuthTokenComplete(result); - break; - case STATE_WRITE_TUNNEL_HEADERS: - DCHECK_EQ(OK, result); - result = DoWriteTunnelHeaders(); - break; - case STATE_WRITE_TUNNEL_HEADERS_COMPLETE: - result = DoWriteTunnelHeadersComplete(result); - break; - case STATE_READ_TUNNEL_HEADERS: - DCHECK_EQ(OK, result); - result = DoReadTunnelHeaders(); - break; - case STATE_READ_TUNNEL_HEADERS_COMPLETE: - result = DoReadTunnelHeadersComplete(result); - break; - case STATE_SOCKS_CONNECT: - DCHECK_EQ(OK, result); - result = DoSOCKSConnect(); - break; - case STATE_SOCKS_CONNECT_COMPLETE: - result = DoSOCKSConnectComplete(result); - break; - case STATE_SECURE_PROXY_CONNECT: - DCHECK_EQ(OK, result); - result = DoSecureProxyConnect(); - break; - case STATE_SECURE_PROXY_CONNECT_COMPLETE: - result = DoSecureProxyConnectComplete(result); - break; - case STATE_SECURE_PROXY_HANDLE_CERT_ERROR: - result = DoSecureProxyHandleCertError(result); - break; - case STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE: - result = DoSecureProxyHandleCertErrorComplete(result); - break; - case STATE_SSL_CONNECT: - DCHECK_EQ(OK, result); - result = DoSSLConnect(); - break; - case STATE_SSL_CONNECT_COMPLETE: - result = DoSSLConnectComplete(result); - break; - case STATE_SSL_HANDLE_CERT_ERROR: - result = DoSSLHandleCertError(result); - break; - case STATE_SSL_HANDLE_CERT_ERROR_COMPLETE: - result = DoSSLHandleCertErrorComplete(result); - break; - case STATE_READ_WRITE: - result = DoReadWrite(result); - break; - case STATE_AUTH_REQUIRED: - // It might be called when DoClose is called while waiting in - // STATE_AUTH_REQUIRED. - Finish(result); - return; - case STATE_CLOSE: - DCHECK_LE(result, OK); - Finish(result); - return; - default: - NOTREACHED() << "bad state " << state; - Finish(result); - return; - } - if (state == STATE_RESOLVE_PROTOCOL && result == ERR_PROTOCOL_SWITCHED) - continue; - // If the connection is not established yet and had actual errors, - // record the error. In next iteration, it will close the connection. - if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) { - net_log_.EndEventWithNetErrorCode( - NetLog::TYPE_SOCKET_STREAM_CONNECT, result); - } - } while (result != ERR_IO_PENDING); -} - -int SocketStream::DoBeforeConnect() { - next_state_ = STATE_BEFORE_CONNECT_COMPLETE; - if (!context_ || !context_->network_delegate()) - return OK; - - int result = context_->network_delegate()->NotifyBeforeSocketStreamConnect( - this, io_callback_); - if (result != OK && result != ERR_IO_PENDING) - next_state_ = STATE_CLOSE; - - return result; -} - -int SocketStream::DoBeforeConnectComplete(int result) { - DCHECK_NE(ERR_IO_PENDING, result); - - if (result == OK) - next_state_ = STATE_RESOLVE_PROXY; - else - next_state_ = STATE_CLOSE; - - return result; -} - -int SocketStream::DoResolveProxy() { - DCHECK(context_); - DCHECK(!pac_request_); - next_state_ = STATE_RESOLVE_PROXY_COMPLETE; - - if (!proxy_url_.is_valid()) { - next_state_ = STATE_CLOSE; - return ERR_INVALID_ARGUMENT; - } - - // TODO(toyoshim): Check server advertisement of SPDY through the HTTP - // Alternate-Protocol header, then switch to SPDY if SPDY is available. - // Usually we already have a session to the SPDY server because JavaScript - // running WebSocket itself would be served by SPDY. But, in some situation - // (E.g. Used by Chrome Extensions or used for cross origin connection), this - // connection might be the first one. At that time, we should check - // Alternate-Protocol header here for ws:// or TLS NPN extension for wss:// . - - return context_->proxy_service()->ResolveProxy( - proxy_url_, net::LOAD_NORMAL, &proxy_info_, io_callback_, &pac_request_, - NULL, net_log_); -} - -int SocketStream::DoResolveProxyComplete(int result) { - pac_request_ = NULL; - if (result != OK) { - DVLOG(1) << "Failed to resolve proxy: " << result; - if (delegate_) - delegate_->OnError(this, result); - proxy_info_.UseDirect(); - } - if (proxy_info_.is_direct()) { - // If proxy was not found for original URL (i.e. websocket URL), - // try again with https URL, like Safari implementation. - // Note that we don't want to use http proxy, because we'll use tunnel - // proxy using CONNECT method, which is used by https proxy. - if (!proxy_url_.SchemeIs("https")) { - const std::string scheme = "https"; - GURL::Replacements repl; - repl.SetSchemeStr(scheme); - proxy_url_ = url_.ReplaceComponents(repl); - DVLOG(1) << "Try https proxy: " << proxy_url_; - next_state_ = STATE_RESOLVE_PROXY; - return OK; - } - } - - if (proxy_info_.is_empty()) { - // No proxies/direct to choose from. This happens when we don't support any - // of the proxies in the returned list. - return ERR_NO_SUPPORTED_PROXIES; - } - - next_state_ = STATE_RESOLVE_HOST; - return OK; -} - -int SocketStream::DoResolveHost() { - next_state_ = STATE_RESOLVE_HOST_COMPLETE; - - DCHECK(!proxy_info_.is_empty()); - if (proxy_info_.is_direct()) - proxy_mode_ = kDirectConnection; - else if (proxy_info_.proxy_server().is_socks()) - proxy_mode_ = kSOCKSProxy; - else - proxy_mode_ = kTunnelProxy; - - // Determine the host and port to connect to. - HostPortPair host_port_pair; - if (proxy_mode_ != kDirectConnection) { - host_port_pair = proxy_info_.proxy_server().host_port_pair(); - } else { - host_port_pair = HostPortPair::FromURL(url_); - } - - HostResolver::RequestInfo resolve_info(host_port_pair); - - DCHECK(context_->host_resolver()); - resolver_.reset(new SingleRequestHostResolver(context_->host_resolver())); - return resolver_->Resolve(resolve_info, - DEFAULT_PRIORITY, - &addresses_, - base::Bind(&SocketStream::OnIOCompleted, this), - net_log_); -} - -int SocketStream::DoResolveHostComplete(int result) { - if (result == OK) - next_state_ = STATE_RESOLVE_PROTOCOL; - else - next_state_ = STATE_CLOSE; - // TODO(ukai): if error occured, reconsider proxy after error. - return result; -} - -int SocketStream::DoResolveProtocol(int result) { - DCHECK_EQ(OK, result); - - if (!delegate_) { - next_state_ = STATE_CLOSE; - return result; - } - - next_state_ = STATE_RESOLVE_PROTOCOL_COMPLETE; - result = delegate_->OnStartOpenConnection(this, io_callback_); - if (result == ERR_IO_PENDING) - metrics_->OnWaitConnection(); - else if (result != OK && result != ERR_PROTOCOL_SWITCHED) - next_state_ = STATE_CLOSE; - return result; -} - -int SocketStream::DoResolveProtocolComplete(int result) { - DCHECK_NE(ERR_IO_PENDING, result); - - if (result == ERR_PROTOCOL_SWITCHED) { - next_state_ = STATE_CLOSE; - metrics_->OnCountWireProtocolType( - SocketStreamMetrics::WIRE_PROTOCOL_SPDY); - } else if (result == OK) { - next_state_ = STATE_TCP_CONNECT; - metrics_->OnCountWireProtocolType( - SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET); - } else { - next_state_ = STATE_CLOSE; - } - return result; -} - -int SocketStream::DoTcpConnect(int result) { - if (result != OK) { - next_state_ = STATE_CLOSE; - return result; - } - next_state_ = STATE_TCP_CONNECT_COMPLETE; - DCHECK(factory_); - connection_->SetSocket( - factory_->CreateTransportClientSocket(addresses_, - net_log_.net_log(), - net_log_.source())); - metrics_->OnStartConnection(); - return connection_->socket()->Connect(io_callback_); -} - -int SocketStream::DoTcpConnectComplete(int result) { - // TODO(ukai): if error occured, reconsider proxy after error. - if (result != OK) { - next_state_ = STATE_CLOSE; - return result; - } - - if (proxy_mode_ == kTunnelProxy) { - if (proxy_info_.is_https()) - next_state_ = STATE_SECURE_PROXY_CONNECT; - else - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - } else if (proxy_mode_ == kSOCKSProxy) { - next_state_ = STATE_SOCKS_CONNECT; - } else if (is_secure()) { - next_state_ = STATE_SSL_CONNECT; - } else { - result = DidEstablishConnection(); - } - return result; -} - -int SocketStream::DoGenerateProxyAuthToken() { - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; - if (!proxy_auth_controller_.get()) { - DCHECK(context_); - DCHECK(context_->http_transaction_factory()); - DCHECK(context_->http_transaction_factory()->GetSession()); - HttpNetworkSession* session = - context_->http_transaction_factory()->GetSession(); - const char* scheme = proxy_info_.is_https() ? "https://" : "http://"; - GURL auth_url(scheme + - proxy_info_.proxy_server().host_port_pair().ToString()); - proxy_auth_controller_ = - new HttpAuthController(HttpAuth::AUTH_PROXY, - auth_url, - session->http_auth_cache(), - session->http_auth_handler_factory()); - } - HttpRequestInfo request_info; - request_info.url = url_; - request_info.method = "CONNECT"; - return proxy_auth_controller_->MaybeGenerateAuthToken( - &request_info, io_callback_, net_log_); -} - -int SocketStream::DoGenerateProxyAuthTokenComplete(int result) { - if (result != OK) { - next_state_ = STATE_CLOSE; - return result; - } - - next_state_ = STATE_WRITE_TUNNEL_HEADERS; - return result; -} - -int SocketStream::DoWriteTunnelHeaders() { - DCHECK_EQ(kTunnelProxy, proxy_mode_); - - next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE; - - if (!tunnel_request_headers_.get()) { - metrics_->OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION); - tunnel_request_headers_ = new RequestHeaders(); - tunnel_request_headers_bytes_sent_ = 0; - } - if (tunnel_request_headers_->headers_.empty()) { - HttpRequestHeaders request_headers; - request_headers.SetHeader("Host", GetHostAndOptionalPort(url_)); - request_headers.SetHeader("Proxy-Connection", "keep-alive"); - if (proxy_auth_controller_.get() && proxy_auth_controller_->HaveAuth()) - proxy_auth_controller_->AddAuthorizationHeader(&request_headers); - tunnel_request_headers_->headers_ = base::StringPrintf( - "CONNECT %s HTTP/1.1\r\n" - "%s", - GetHostAndPort(url_).c_str(), - request_headers.ToString().c_str()); - } - tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_); - int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() - - tunnel_request_headers_bytes_sent_); - DCHECK_GT(buf_len, 0); - return connection_->socket()->Write( - tunnel_request_headers_.get(), buf_len, io_callback_); -} - -int SocketStream::DoWriteTunnelHeadersComplete(int result) { - DCHECK_EQ(kTunnelProxy, proxy_mode_); - - if (result < 0) { - next_state_ = STATE_CLOSE; - return result; - } - - tunnel_request_headers_bytes_sent_ += result; - if (tunnel_request_headers_bytes_sent_ < - tunnel_request_headers_->headers_.size()) { - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - } else { - // Handling a cert error or a client cert request requires reconnection. - // DoWriteTunnelHeaders() will be called again. - // Thus |tunnel_request_headers_bytes_sent_| should be reset to 0 for - // sending |tunnel_request_headers_| correctly. - tunnel_request_headers_bytes_sent_ = 0; - next_state_ = STATE_READ_TUNNEL_HEADERS; - } - return OK; -} - -int SocketStream::DoReadTunnelHeaders() { - DCHECK_EQ(kTunnelProxy, proxy_mode_); - - next_state_ = STATE_READ_TUNNEL_HEADERS_COMPLETE; - - if (!tunnel_response_headers_.get()) { - tunnel_response_headers_ = new ResponseHeaders(); - tunnel_response_headers_capacity_ = kMaxTunnelResponseHeadersSize; - tunnel_response_headers_->Realloc(tunnel_response_headers_capacity_); - tunnel_response_headers_len_ = 0; - } - - int buf_len = tunnel_response_headers_capacity_ - - tunnel_response_headers_len_; - tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_); - CHECK(tunnel_response_headers_->data()); - - return connection_->socket()->Read( - tunnel_response_headers_.get(), buf_len, io_callback_); -} - -int SocketStream::DoReadTunnelHeadersComplete(int result) { - DCHECK_EQ(kTunnelProxy, proxy_mode_); - - if (result < 0) { - next_state_ = STATE_CLOSE; - return result; - } - - if (result == 0) { - // 0 indicates end-of-file, so socket was closed. - next_state_ = STATE_CLOSE; - return ERR_CONNECTION_CLOSED; - } - - tunnel_response_headers_len_ += result; - DCHECK(tunnel_response_headers_len_ <= tunnel_response_headers_capacity_); - - int eoh = HttpUtil::LocateEndOfHeaders( - tunnel_response_headers_->headers(), tunnel_response_headers_len_, 0); - if (eoh == -1) { - if (tunnel_response_headers_len_ >= kMaxTunnelResponseHeadersSize) { - next_state_ = STATE_CLOSE; - return ERR_RESPONSE_HEADERS_TOO_BIG; - } - - next_state_ = STATE_READ_TUNNEL_HEADERS; - return OK; - } - // DidReadResponseHeaders - scoped_refptr<HttpResponseHeaders> headers; - headers = new HttpResponseHeaders( - HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh)); - if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) { - // Require the "HTTP/1.x" status line. - next_state_ = STATE_CLOSE; - return ERR_TUNNEL_CONNECTION_FAILED; - } - switch (headers->response_code()) { - case 200: // OK - if (is_secure()) { - DCHECK_EQ(eoh, tunnel_response_headers_len_); - next_state_ = STATE_SSL_CONNECT; - } else { - result = DidEstablishConnection(); - if (result < 0) { - next_state_ = STATE_CLOSE; - return result; - } - if ((eoh < tunnel_response_headers_len_) && delegate_) - delegate_->OnReceivedData( - this, tunnel_response_headers_->headers() + eoh, - tunnel_response_headers_len_ - eoh); - } - return OK; - case 407: // Proxy Authentication Required. - if (proxy_mode_ != kTunnelProxy) - return ERR_UNEXPECTED_PROXY_AUTH; - - result = proxy_auth_controller_->HandleAuthChallenge( - headers, false, true, net_log_); - if (result != OK) - return result; - DCHECK(!proxy_info_.is_empty()); - next_state_ = STATE_AUTH_REQUIRED; - if (proxy_auth_controller_->HaveAuth()) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this)); - return ERR_IO_PENDING; - } - if (delegate_) { - // Wait until RestartWithAuth or Close is called. - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&SocketStream::DoAuthRequired, this)); - return ERR_IO_PENDING; - } - break; - default: - break; - } - next_state_ = STATE_CLOSE; - return ERR_TUNNEL_CONNECTION_FAILED; -} - -int SocketStream::DoSOCKSConnect() { - DCHECK_EQ(kSOCKSProxy, proxy_mode_); - - next_state_ = STATE_SOCKS_CONNECT_COMPLETE; - - HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_)); - - DCHECK(!proxy_info_.is_empty()); - scoped_ptr<StreamSocket> s; - if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) { - s.reset(new SOCKS5ClientSocket(connection_.Pass(), req_info)); - } else { - s.reset(new SOCKSClientSocket(connection_.Pass(), - req_info, - DEFAULT_PRIORITY, - context_->host_resolver())); - } - connection_.reset(new ClientSocketHandle); - connection_->SetSocket(s.Pass()); - metrics_->OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION); - return connection_->socket()->Connect(io_callback_); -} - -int SocketStream::DoSOCKSConnectComplete(int result) { - DCHECK_EQ(kSOCKSProxy, proxy_mode_); - - if (result == OK) { - if (is_secure()) - next_state_ = STATE_SSL_CONNECT; - else - result = DidEstablishConnection(); - } else { - next_state_ = STATE_CLOSE; - } - return result; -} - -int SocketStream::DoSecureProxyConnect() { - DCHECK(factory_); - SSLClientSocketContext ssl_context; - ssl_context.cert_verifier = context_->cert_verifier(); - ssl_context.transport_security_state = context_->transport_security_state(); - ssl_context.channel_id_service = context_->channel_id_service(); - scoped_ptr<StreamSocket> socket(factory_->CreateSSLClientSocket( - connection_.Pass(), - proxy_info_.proxy_server().host_port_pair(), - proxy_ssl_config_, - ssl_context)); - connection_.reset(new ClientSocketHandle); - connection_->SetSocket(socket.Pass()); - next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE; - metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION); - return connection_->socket()->Connect(io_callback_); -} - -int SocketStream::DoSecureProxyConnectComplete(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - // Reconnect with client authentication. - if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) - return HandleCertificateRequest(result, &proxy_ssl_config_); - - if (IsCertificateError(result)) - next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR; - else if (result == OK) - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - else - next_state_ = STATE_CLOSE; - return result; -} - -int SocketStream::DoSecureProxyHandleCertError(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - DCHECK(IsCertificateError(result)); - result = HandleCertificateError(result); - if (result == ERR_IO_PENDING) - next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE; - else - next_state_ = STATE_CLOSE; - return result; -} - -int SocketStream::DoSecureProxyHandleCertErrorComplete(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - if (result == OK) { - if (!connection_->socket()->IsConnectedAndIdle()) - return AllowCertErrorForReconnection(&proxy_ssl_config_); - next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN; - } else { - next_state_ = STATE_CLOSE; - } - return result; -} - -int SocketStream::DoSSLConnect() { - DCHECK(factory_); - SSLClientSocketContext ssl_context; - ssl_context.cert_verifier = context_->cert_verifier(); - ssl_context.transport_security_state = context_->transport_security_state(); - ssl_context.channel_id_service = context_->channel_id_service(); - scoped_ptr<StreamSocket> socket( - factory_->CreateSSLClientSocket(connection_.Pass(), - HostPortPair::FromURL(url_), - server_ssl_config_, - ssl_context)); - connection_.reset(new ClientSocketHandle); - connection_->SetSocket(socket.Pass()); - next_state_ = STATE_SSL_CONNECT_COMPLETE; - metrics_->OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION); - return connection_->socket()->Connect(io_callback_); -} - -int SocketStream::DoSSLConnectComplete(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - // Reconnect with client authentication. - if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) - return HandleCertificateRequest(result, &server_ssl_config_); - - if (IsCertificateError(result)) - next_state_ = STATE_SSL_HANDLE_CERT_ERROR; - else if (result == OK) - result = DidEstablishConnection(); - else - next_state_ = STATE_CLOSE; - return result; -} - -int SocketStream::DoSSLHandleCertError(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - DCHECK(IsCertificateError(result)); - result = HandleCertificateError(result); - if (result == OK || result == ERR_IO_PENDING) - next_state_ = STATE_SSL_HANDLE_CERT_ERROR_COMPLETE; - else - next_state_ = STATE_CLOSE; - return result; -} - -int SocketStream::DoSSLHandleCertErrorComplete(int result) { - DCHECK_EQ(STATE_NONE, next_state_); - // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible. - // If we use HTTPS and this is the first connection to the SPDY server, - // we should take care of TLS NPN extension here. - - if (result == OK) { - if (!connection_->socket()->IsConnectedAndIdle()) - return AllowCertErrorForReconnection(&server_ssl_config_); - result = DidEstablishConnection(); - } else { - next_state_ = STATE_CLOSE; - } - return result; -} - -int SocketStream::DoReadWrite(int result) { - if (result < OK) { - next_state_ = STATE_CLOSE; - return result; - } - if (!connection_->socket() || !connection_->socket()->IsConnected()) { - next_state_ = STATE_CLOSE; - return ERR_CONNECTION_CLOSED; - } - - // If client has requested close(), and there's nothing to write, then - // let's close the socket. - // We don't care about receiving data after the socket is closed. - if (closing_ && !current_write_buf_.get() && pending_write_bufs_.empty()) { - connection_->socket()->Disconnect(); - next_state_ = STATE_CLOSE; - return OK; - } - - next_state_ = STATE_READ_WRITE; - - // If server already closed the socket, we don't try to read. - if (!server_closed_) { - if (!read_buf_.get()) { - // No read pending and server didn't close the socket. - read_buf_ = new IOBuffer(kReadBufferSize); - result = connection_->socket()->Read( - read_buf_.get(), - kReadBufferSize, - base::Bind(&SocketStream::OnReadCompleted, base::Unretained(this))); - if (result > 0) { - return DidReceiveData(result); - } else if (result == 0) { - // 0 indicates end-of-file, so socket was closed. - next_state_ = STATE_CLOSE; - server_closed_ = true; - return ERR_CONNECTION_CLOSED; - } - // If read is pending, try write as well. - // Otherwise, return the result and do next loop (to close the - // connection). - if (result != ERR_IO_PENDING) { - next_state_ = STATE_CLOSE; - server_closed_ = true; - return result; - } - } - // Read is pending. - DCHECK(read_buf_.get()); - } - - if (waiting_for_write_completion_) - return ERR_IO_PENDING; - - if (!current_write_buf_.get()) { - if (pending_write_bufs_.empty()) { - // Nothing buffered for send. - return ERR_IO_PENDING; - } - - current_write_buf_ = new DrainableIOBuffer( - pending_write_bufs_.front().get(), pending_write_bufs_.front()->size()); - pending_write_bufs_.pop_front(); - } - - result = connection_->socket()->Write( - current_write_buf_.get(), - current_write_buf_->BytesRemaining(), - base::Bind(&SocketStream::OnWriteCompleted, base::Unretained(this))); - - if (result == ERR_IO_PENDING) { - waiting_for_write_completion_ = true; - } else if (result < 0) { - // Shortcut. Enter STATE_CLOSE now by changing next_state_ here than by - // calling DoReadWrite() again with the error code. - next_state_ = STATE_CLOSE; - } else if (result > 0) { - // Write is not pending. Return OK and do next loop. - DidSendData(result); - result = OK; - } - - return result; -} - -GURL SocketStream::ProxyAuthOrigin() const { - DCHECK(!proxy_info_.is_empty()); - return GURL("http://" + - proxy_info_.proxy_server().host_port_pair().ToString()); -} - -int SocketStream::HandleCertificateRequest(int result, SSLConfig* ssl_config) { - if (ssl_config->send_client_cert) { - // We already have performed SSL client authentication once and failed. - return result; - } - - DCHECK(connection_->socket()); - scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo; - SSLClientSocket* ssl_socket = - static_cast<SSLClientSocket*>(connection_->socket()); - ssl_socket->GetSSLCertRequestInfo(cert_request_info.get()); - - HttpTransactionFactory* factory = context_->http_transaction_factory(); - if (!factory) - return result; - scoped_refptr<HttpNetworkSession> session = factory->GetSession(); - if (!session.get()) - return result; - - // If the user selected one of the certificates in client_certs or declined - // to provide one for this server before, use the past decision - // automatically. - scoped_refptr<X509Certificate> client_cert; - if (!session->ssl_client_auth_cache()->Lookup( - cert_request_info->host_and_port, &client_cert)) { - return result; - } - - // Note: |client_cert| may be NULL, indicating that the caller - // wishes to proceed anonymously (eg: continue the handshake - // without sending a client cert) - // - // Check that the certificate selected is still a certificate the server - // is likely to accept, based on the criteria supplied in the - // CertificateRequest message. - const std::vector<std::string>& cert_authorities = - cert_request_info->cert_authorities; - if (client_cert.get() && !cert_authorities.empty() && - !client_cert->IsIssuedByEncoded(cert_authorities)) { - return result; - } - - ssl_config->send_client_cert = true; - ssl_config->client_cert = client_cert; - next_state_ = STATE_TCP_CONNECT; - return OK; -} - -int SocketStream::AllowCertErrorForReconnection(SSLConfig* ssl_config) { - DCHECK(ssl_config); - // The SSL handshake didn't finish, or the server closed the SSL connection. - // So, we should restart establishing connection with the certificate in - // allowed bad certificates in |ssl_config|. - // See also net/http/http_network_transaction.cc HandleCertificateError() and - // RestartIgnoringLastError(). - SSLClientSocket* ssl_socket = - static_cast<SSLClientSocket*>(connection_->socket()); - SSLInfo ssl_info; - ssl_socket->GetSSLInfo(&ssl_info); - if (ssl_info.cert.get() == NULL || - ssl_config->IsAllowedBadCert(ssl_info.cert.get(), NULL)) { - // If we already have the certificate in the set of allowed bad - // certificates, we did try it and failed again, so we should not - // retry again: the connection should fail at last. - next_state_ = STATE_CLOSE; - return ERR_UNEXPECTED; - } - // Add the bad certificate to the set of allowed certificates in the - // SSL config object. - SSLConfig::CertAndStatus bad_cert; - if (!X509Certificate::GetDEREncoded(ssl_info.cert->os_cert_handle(), - &bad_cert.der_cert)) { - next_state_ = STATE_CLOSE; - return ERR_UNEXPECTED; - } - bad_cert.cert_status = ssl_info.cert_status; - ssl_config->allowed_bad_certs.push_back(bad_cert); - // Restart connection ignoring the bad certificate. - connection_->socket()->Disconnect(); - connection_->SetSocket(scoped_ptr<StreamSocket>()); - next_state_ = STATE_TCP_CONNECT; - return OK; -} - -void SocketStream::DoAuthRequired() { - if (delegate_ && proxy_auth_controller_.get()) - delegate_->OnAuthRequired(this, proxy_auth_controller_->auth_info().get()); - else - DoLoop(ERR_UNEXPECTED); -} - -void SocketStream::DoRestartWithAuth() { - DCHECK_EQ(next_state_, STATE_AUTH_REQUIRED); - tunnel_request_headers_ = NULL; - tunnel_request_headers_bytes_sent_ = 0; - tunnel_response_headers_ = NULL; - tunnel_response_headers_capacity_ = 0; - tunnel_response_headers_len_ = 0; - - next_state_ = STATE_TCP_CONNECT; - DoLoop(OK); -} - -int SocketStream::HandleCertificateError(int result) { - DCHECK(IsCertificateError(result)); - SSLClientSocket* ssl_socket = - static_cast<SSLClientSocket*>(connection_->socket()); - DCHECK(ssl_socket); - - if (!context_) - return result; - - if (SSLClientSocket::IgnoreCertError(result, LOAD_IGNORE_ALL_CERT_ERRORS)) { - const HttpNetworkSession::Params* session_params = - context_->GetNetworkSessionParams(); - if (session_params && session_params->ignore_certificate_errors) - return OK; - } - - if (!delegate_) - return result; - - SSLInfo ssl_info; - ssl_socket->GetSSLInfo(&ssl_info); - - TransportSecurityState* state = context_->transport_security_state(); - const bool fatal = state && state->ShouldSSLErrorsBeFatal(url_.host()); - - delegate_->OnSSLCertificateError(this, ssl_info, fatal); - return ERR_IO_PENDING; -} - -CookieStore* SocketStream::cookie_store() const { - return cookie_store_.get(); -} - -} // namespace net diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h deleted file mode 100644 index 7387eb6..0000000 --- a/net/socket_stream/socket_stream.h +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_H_ -#define NET_SOCKET_STREAM_SOCKET_STREAM_H_ - -#include <deque> -#include <map> -#include <string> - -#include "base/memory/linked_ptr.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "net/base/address_list.h" -#include "net/base/completion_callback.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/base/net_export.h" -#include "net/base/net_log.h" -#include "net/base/privacy_mode.h" -#include "net/cookies/cookie_store.h" -#include "net/proxy/proxy_service.h" -#include "net/ssl/ssl_config_service.h" -#include "net/url_request/url_request.h" - -namespace net { - -class AuthChallengeInfo; -class CertVerifier; -class ChannelIDService; -class ClientSocketFactory; -class ClientSocketHandle; -class CookieOptions; -class HostResolver; -class HttpAuthController; -class SSLInfo; -class SingleRequestHostResolver; -class SocketStreamMetrics; -class TransportSecurityState; -class URLRequestContext; - -// SocketStream is used to implement Web Sockets. -// It provides plain full-duplex stream with proxy and SSL support. -// For proxy authentication, only basic mechanisum is supported. It will try -// authentication identity for proxy URL first. If server requires proxy -// authentication, it will try authentication identity for realm that server -// requests. -class NET_EXPORT SocketStream - : public base::RefCountedThreadSafe<SocketStream> { - public: - // Derive from this class and add your own data members to associate extra - // information with a SocketStream. Use GetUserData(key) and - // SetUserData(key, data). - class UserData { - public: - UserData() {} - virtual ~UserData() {} - }; - - class NET_EXPORT Delegate { - public: - virtual int OnStartOpenConnection(SocketStream* socket, - const CompletionCallback& callback); - - // Called when a socket stream has been connected. The socket stream is - // allowed to buffer pending send data at most |max_pending_send_allowed| - // bytes. A client of the socket stream should keep track of how much - // pending send data it has and must not call SendData() if the pending - // data goes over |max_pending_send_allowed| bytes. - virtual void OnConnected(SocketStream* socket, - int max_pending_send_allowed) = 0; - - // Called when |amount_sent| bytes of data are sent. - virtual void OnSentData(SocketStream* socket, - int amount_sent) = 0; - - // Called when |len| bytes of |data| are received. - virtual void OnReceivedData(SocketStream* socket, - const char* data, int len) = 0; - - // Called when the socket stream has been closed. - virtual void OnClose(SocketStream* socket) = 0; - - // Called when proxy authentication required. - // The delegate should call RestartWithAuth() if credential for |auth_info| - // is found in password database, or call Close() to close the connection. - virtual void OnAuthRequired(SocketStream* socket, - AuthChallengeInfo* auth_info); - - // Called when using SSL and the server responds with a certificate with an - // error. The delegate should call CancelBecauseOfCertError() or - // ContinueDespiteCertError() to resume connection handling. - virtual void OnSSLCertificateError(SocketStream* socket, - const SSLInfo& ssl_info, - bool fatal); - - // Called when an error occured. - // This is only for error reporting to the delegate. - // |error| is net::Error. - virtual void OnError(const SocketStream* socket, int error) {} - - // Called when reading cookies to allow the delegate to block access to the - // cookie. - virtual bool CanGetCookies(SocketStream* socket, const GURL& url); - - // Called when a cookie is set to allow the delegate to block access to the - // cookie. - virtual bool CanSetCookie(SocketStream* request, - const GURL& url, - const std::string& cookie_line, - CookieOptions* options); - - protected: - virtual ~Delegate() {} - }; - - SocketStream(const GURL& url, Delegate* delegate, URLRequestContext* context, - CookieStore* cookie_store); - - // The user data allows the clients to associate data with this job. - // Multiple user data values can be stored under different keys. - // This job will TAKE OWNERSHIP of the given data pointer, and will - // delete the object if it is changed or the job is destroyed. - UserData* GetUserData(const void* key) const; - void SetUserData(const void* key, UserData* data); - - const GURL& url() const { return url_; } - bool is_secure() const; - const AddressList& address_list() const { return addresses_; } - Delegate* delegate() const { return delegate_; } - int max_pending_send_allowed() const { return max_pending_send_allowed_; } - - URLRequestContext* context() { return context_; } - - const SSLConfig& server_ssl_config() const { return server_ssl_config_; } - PrivacyMode privacy_mode() const { return privacy_mode_; } - void CheckPrivacyMode(); - - BoundNetLog* net_log() { return &net_log_; } - - // Opens the connection on the IO thread. - // Once the connection is established, calls delegate's OnConnected. - virtual void Connect(); - - // Buffers |data| of |len| bytes for send and returns true if successful. - // If size of buffered data exceeds |max_pending_send_allowed_|, sends no - // data and returns false. |len| must be positive. - virtual bool SendData(const char* data, int len); - - // Requests to close the connection. - // Once the connection is closed, calls delegate's OnClose. - virtual void Close(); - - // Restarts with authentication info. - // Should be used for response of OnAuthRequired. - virtual void RestartWithAuth(const AuthCredentials& credentials); - - // Detach delegate. Call before delegate is deleted. - // Once delegate is detached, close the socket stream and never call delegate - // back. - virtual void DetachDelegate(); - - // Detach the context. - virtual void DetachContext(); - - const ProxyServer& proxy_server() const; - - // Sets an alternative ClientSocketFactory. Doesn't take ownership of - // |factory|. For testing purposes only. - void SetClientSocketFactory(ClientSocketFactory* factory); - - // Cancels the connection because of an error. - // |error| is net::Error which represents the error. - void CancelWithError(int error); - - // Cancels the connection because of receiving a certificate with an error. - void CancelWithSSLError(const SSLInfo& ssl_info); - - // Continues to establish the connection in spite of an error. Usually this - // case happens because users allow certificate with an error by manual - // actions on alert dialog or browser cached such kinds of user actions. - void ContinueDespiteError(); - - CookieStore* cookie_store() const; - - protected: - friend class base::RefCountedThreadSafe<SocketStream>; - virtual ~SocketStream(); - - Delegate* delegate_; - - private: - FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, IOPending); - FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, SwitchAfterPending); - FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, - NullContextSocketStreamShouldNotCrash); - - friend class WebSocketThrottleTest; - - typedef std::map<const void*, linked_ptr<UserData> > UserDataMap; - typedef std::deque< scoped_refptr<IOBufferWithSize> > PendingDataQueue; - - class RequestHeaders : public IOBuffer { - public: - RequestHeaders() : IOBuffer() {} - - void SetDataOffset(size_t offset) { - data_ = const_cast<char*>(headers_.data()) + offset; - } - - std::string headers_; - - private: - ~RequestHeaders() override; - }; - - class ResponseHeaders : public IOBuffer { - public: - ResponseHeaders(); - - void SetDataOffset(size_t offset) { data_ = headers_.get() + offset; } - char* headers() const { return headers_.get(); } - void Reset() { headers_.reset(); } - void Realloc(size_t new_size); - - private: - ~ResponseHeaders() override; - - scoped_ptr<char, base::FreeDeleter> headers_; - }; - - enum State { - STATE_NONE, - STATE_BEFORE_CONNECT, - STATE_BEFORE_CONNECT_COMPLETE, - STATE_RESOLVE_PROXY, - STATE_RESOLVE_PROXY_COMPLETE, - STATE_RESOLVE_HOST, - STATE_RESOLVE_HOST_COMPLETE, - STATE_RESOLVE_PROTOCOL, - STATE_RESOLVE_PROTOCOL_COMPLETE, - STATE_TCP_CONNECT, - STATE_TCP_CONNECT_COMPLETE, - STATE_GENERATE_PROXY_AUTH_TOKEN, - STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE, - STATE_WRITE_TUNNEL_HEADERS, - STATE_WRITE_TUNNEL_HEADERS_COMPLETE, - STATE_READ_TUNNEL_HEADERS, - STATE_READ_TUNNEL_HEADERS_COMPLETE, - STATE_SOCKS_CONNECT, - STATE_SOCKS_CONNECT_COMPLETE, - STATE_SECURE_PROXY_CONNECT, - STATE_SECURE_PROXY_CONNECT_COMPLETE, - STATE_SECURE_PROXY_HANDLE_CERT_ERROR, - STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE, - STATE_SSL_CONNECT, - STATE_SSL_CONNECT_COMPLETE, - STATE_SSL_HANDLE_CERT_ERROR, - STATE_SSL_HANDLE_CERT_ERROR_COMPLETE, - STATE_READ_WRITE, - STATE_AUTH_REQUIRED, - STATE_CLOSE, - }; - - enum ProxyMode { - kDirectConnection, // If using a direct connection - kTunnelProxy, // If using a tunnel (CONNECT method as HTTPS) - kSOCKSProxy, // If using a SOCKS proxy - }; - - // Use the same number as HttpNetworkTransaction::kMaxHeaderBufSize. - enum { kMaxTunnelResponseHeadersSize = 32768 }; // 32 kilobytes. - - // Used for WebSocketThrottleTest. - void set_addresses(const AddressList& addresses); - - void DoClose(); - - // Finishes the job. - // Calls OnError and OnClose of delegate, and no more - // notifications will be sent to delegate. - void Finish(int result); - - int DidEstablishConnection(); - int DidReceiveData(int result); - // Given the number of bytes sent, - // - notifies the |delegate_| and |metrics_| of this event. - // - drains sent data from |current_write_buf_|. - // - if |current_write_buf_| has been fully sent, sets NULL to - // |current_write_buf_| to get ready for next write. - // and then, returns OK. - void DidSendData(int result); - - void OnIOCompleted(int result); - void OnReadCompleted(int result); - void OnWriteCompleted(int result); - - void DoLoop(int result); - - int DoBeforeConnect(); - int DoBeforeConnectComplete(int result); - int DoResolveProxy(); - int DoResolveProxyComplete(int result); - int DoResolveHost(); - int DoResolveHostComplete(int result); - int DoResolveProtocol(int result); - int DoResolveProtocolComplete(int result); - int DoTcpConnect(int result); - int DoTcpConnectComplete(int result); - int DoGenerateProxyAuthToken(); - int DoGenerateProxyAuthTokenComplete(int result); - int DoWriteTunnelHeaders(); - int DoWriteTunnelHeadersComplete(int result); - int DoReadTunnelHeaders(); - int DoReadTunnelHeadersComplete(int result); - int DoSOCKSConnect(); - int DoSOCKSConnectComplete(int result); - int DoSecureProxyConnect(); - int DoSecureProxyConnectComplete(int result); - int DoSecureProxyHandleCertError(int result); - int DoSecureProxyHandleCertErrorComplete(int result); - int DoSSLConnect(); - int DoSSLConnectComplete(int result); - int DoSSLHandleCertError(int result); - int DoSSLHandleCertErrorComplete(int result); - int DoReadWrite(int result); - - GURL ProxyAuthOrigin() const; - int HandleAuthChallenge(const HttpResponseHeaders* headers); - int HandleCertificateRequest(int result, SSLConfig* ssl_config); - void DoAuthRequired(); - void DoRestartWithAuth(); - - int HandleCertificateError(int result); - int AllowCertErrorForReconnection(SSLConfig* ssl_config); - - // Returns the sum of the size of buffers in |pending_write_bufs_|. - size_t GetTotalSizeOfPendingWriteBufs() const; - - BoundNetLog net_log_; - - GURL url_; - // The number of bytes allowed to be buffered in this object. If the size of - // buffered data which is - // current_write_buf_.BytesRemaining() + - // sum of the size of buffers in |pending_write_bufs_| - // exceeds this limit, SendData() fails. - int max_pending_send_allowed_; - URLRequestContext* context_; - - UserDataMap user_data_; - - State next_state_; - ClientSocketFactory* factory_; - - ProxyMode proxy_mode_; - - GURL proxy_url_; - ProxyService::PacRequest* pac_request_; - ProxyInfo proxy_info_; - - scoped_refptr<HttpAuthController> proxy_auth_controller_; - - scoped_refptr<RequestHeaders> tunnel_request_headers_; - size_t tunnel_request_headers_bytes_sent_; - scoped_refptr<ResponseHeaders> tunnel_response_headers_; - int tunnel_response_headers_capacity_; - int tunnel_response_headers_len_; - - scoped_ptr<SingleRequestHostResolver> resolver_; - AddressList addresses_; - scoped_ptr<ClientSocketHandle> connection_; - - SSLConfig server_ssl_config_; - SSLConfig proxy_ssl_config_; - PrivacyMode privacy_mode_; - - CompletionCallback io_callback_; - - scoped_refptr<IOBuffer> read_buf_; - int read_buf_size_; - - // Buffer to hold data to pass to socket_. - scoped_refptr<DrainableIOBuffer> current_write_buf_; - // True iff there's no error and this instance is waiting for completion of - // Write operation by socket_. - bool waiting_for_write_completion_; - PendingDataQueue pending_write_bufs_; - - bool closing_; - bool server_closed_; - - scoped_ptr<SocketStreamMetrics> metrics_; - - // Cookie store to use for this socket stream. - scoped_refptr<CookieStore> cookie_store_; - - DISALLOW_COPY_AND_ASSIGN(SocketStream); -}; - -} // namespace net - -#endif // NET_SOCKET_STREAM_SOCKET_STREAM_H_ diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc deleted file mode 100644 index 66da741..0000000 --- a/net/socket_stream/socket_stream_job.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2012 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/socket_stream/socket_stream_job.h" - -#include "base/memory/singleton.h" -#include "net/http/transport_security_state.h" -#include "net/socket_stream/socket_stream_job_manager.h" -#include "net/ssl/ssl_config_service.h" -#include "net/url_request/url_request_context.h" - -namespace net { - -// static -SocketStreamJob::ProtocolFactory* SocketStreamJob::RegisterProtocolFactory( - const std::string& scheme, ProtocolFactory* factory) { - return SocketStreamJobManager::GetInstance()->RegisterProtocolFactory( - scheme, factory); -} - -// static -SocketStreamJob* SocketStreamJob::CreateSocketStreamJob( - const GURL& url, - SocketStream::Delegate* delegate, - TransportSecurityState* sts, - SSLConfigService* ssl, - URLRequestContext* context, - CookieStore* cookie_store) { - GURL socket_url(url); - if (url.scheme() == "ws" && sts && - sts->ShouldUpgradeToSSL(url.host())) { - url::Replacements<char> replacements; - static const char kNewScheme[] = "wss"; - replacements.SetScheme(kNewScheme, url::Component(0, strlen(kNewScheme))); - socket_url = url.ReplaceComponents(replacements); - } - return SocketStreamJobManager::GetInstance()->CreateJob( - socket_url, delegate, context, cookie_store); -} - -SocketStreamJob::SocketStreamJob() {} - -SocketStream::UserData* SocketStreamJob::GetUserData(const void* key) const { - return socket_->GetUserData(key); -} - -void SocketStreamJob::SetUserData(const void* key, - SocketStream::UserData* data) { - socket_->SetUserData(key, data); -} - -void SocketStreamJob::Connect() { - socket_->Connect(); -} - -bool SocketStreamJob::SendData(const char* data, int len) { - return socket_->SendData(data, len); -} - -void SocketStreamJob::Close() { - socket_->Close(); -} - -void SocketStreamJob::RestartWithAuth(const AuthCredentials& credentials) { - socket_->RestartWithAuth(credentials); -} - -void SocketStreamJob::CancelWithError(int error) { - socket_->CancelWithError(error); -} - -void SocketStreamJob::CancelWithSSLError(const net::SSLInfo& ssl_info) { - socket_->CancelWithSSLError(ssl_info); -} - -void SocketStreamJob::ContinueDespiteError() { - socket_->ContinueDespiteError(); -} - -void SocketStreamJob::DetachDelegate() { - socket_->DetachDelegate(); -} - -void SocketStreamJob::DetachContext() { - if (socket_.get()) - socket_->DetachContext(); -} - -SocketStreamJob::~SocketStreamJob() {} - -} // namespace net diff --git a/net/socket_stream/socket_stream_job.h b/net/socket_stream/socket_stream_job.h deleted file mode 100644 index 9fc27d9..0000000 --- a/net/socket_stream/socket_stream_job.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_ -#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_ - -#include <string> - -#include "base/memory/ref_counted.h" -#include "net/base/net_export.h" -#include "net/socket_stream/socket_stream.h" - -class GURL; - -namespace net { - -class CookieStore; -class SSLConfigService; -class SSLInfo; -class TransportSecurityState; - -// SocketStreamJob represents full-duplex communication over SocketStream. -// If a protocol (e.g. WebSocket protocol) needs to inspect/modify data -// over SocketStream, you can implement protocol specific job (e.g. -// WebSocketJob) to do some work on data over SocketStream. -// Registers the protocol specific SocketStreamJob by RegisterProtocolFactory -// and call CreateSocketStreamJob to create SocketStreamJob for the URL. -class NET_EXPORT SocketStreamJob - : public base::RefCountedThreadSafe<SocketStreamJob> { - public: - // Callback function implemented by protocol handlers to create new jobs. - typedef SocketStreamJob* (ProtocolFactory)(const GURL& url, - SocketStream::Delegate* delegate, - URLRequestContext* context, - CookieStore* cookie_store); - - static ProtocolFactory* RegisterProtocolFactory(const std::string& scheme, - ProtocolFactory* factory); - - static SocketStreamJob* CreateSocketStreamJob( - const GURL& url, - SocketStream::Delegate* delegate, - TransportSecurityState* sts, - SSLConfigService* ssl, - URLRequestContext* context, - CookieStore* cookie_store); - - SocketStreamJob(); - void InitSocketStream(SocketStream* socket) { - socket_ = socket; - } - - virtual SocketStream::UserData* GetUserData(const void* key) const; - virtual void SetUserData(const void* key, SocketStream::UserData* data); - - URLRequestContext* context() const { - return socket_.get() ? socket_->context() : 0; - } - CookieStore* cookie_store() const { - return socket_.get() ? socket_->cookie_store() : 0; - } - - virtual void Connect(); - - virtual bool SendData(const char* data, int len); - - virtual void Close(); - - virtual void RestartWithAuth(const AuthCredentials& credentials); - - virtual void CancelWithError(int error); - - virtual void CancelWithSSLError(const net::SSLInfo& ssl_info); - - virtual void ContinueDespiteError(); - - virtual void DetachDelegate(); - - virtual void DetachContext(); - - protected: - friend class WebSocketJobTest; - friend class base::RefCountedThreadSafe<SocketStreamJob>; - virtual ~SocketStreamJob(); - - scoped_refptr<SocketStream> socket_; - - DISALLOW_COPY_AND_ASSIGN(SocketStreamJob); -}; - -} // namespace net - -#endif // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_ diff --git a/net/socket_stream/socket_stream_job_manager.cc b/net/socket_stream/socket_stream_job_manager.cc deleted file mode 100644 index 6418be4..0000000 --- a/net/socket_stream/socket_stream_job_manager.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 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/socket_stream/socket_stream_job_manager.h" - -#include "base/memory/singleton.h" - -namespace net { - -SocketStreamJobManager::SocketStreamJobManager() { -} - -SocketStreamJobManager::~SocketStreamJobManager() { -} - -// static -SocketStreamJobManager* SocketStreamJobManager::GetInstance() { - return Singleton<SocketStreamJobManager>::get(); -} - -SocketStreamJob* SocketStreamJobManager::CreateJob( - const GURL& url, SocketStream::Delegate* delegate, - URLRequestContext* context, CookieStore* cookie_store) const { - // If url is invalid, create plain SocketStreamJob, which will close - // the socket immediately. - if (!url.is_valid()) { - SocketStreamJob* job = new SocketStreamJob(); - job->InitSocketStream(new SocketStream(url, delegate, context, - cookie_store)); - return job; - } - - const std::string& scheme = url.scheme(); // already lowercase - - base::AutoLock locked(lock_); - FactoryMap::const_iterator found = factories_.find(scheme); - if (found != factories_.end()) { - SocketStreamJob* job = found->second(url, delegate, context, cookie_store); - if (job) - return job; - } - SocketStreamJob* job = new SocketStreamJob(); - job->InitSocketStream(new SocketStream(url, delegate, context, cookie_store)); - return job; -} - -SocketStreamJob::ProtocolFactory* -SocketStreamJobManager::RegisterProtocolFactory( - const std::string& scheme, SocketStreamJob::ProtocolFactory* factory) { - base::AutoLock locked(lock_); - - SocketStreamJob::ProtocolFactory* old_factory; - FactoryMap::iterator found = factories_.find(scheme); - if (found != factories_.end()) { - old_factory = found->second; - } else { - old_factory = NULL; - } - if (factory) { - factories_[scheme] = factory; - } else if (found != factories_.end()) { - factories_.erase(found); - } - return old_factory; -} - -} // namespace net diff --git a/net/socket_stream/socket_stream_job_manager.h b/net/socket_stream/socket_stream_job_manager.h deleted file mode 100644 index 2363fb5..0000000 --- a/net/socket_stream/socket_stream_job_manager.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2010 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. - -#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_ -#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_ - -#include <map> -#include <string> - -#include "net/socket_stream/socket_stream.h" -#include "net/socket_stream/socket_stream_job.h" - -template <typename T> struct DefaultSingletonTraits; -class GURL; - -namespace net { - -class SocketStreamJobManager { - public: - // Returns the singleton instance. - static SocketStreamJobManager* GetInstance(); - - SocketStreamJob* CreateJob( - const GURL& url, SocketStream::Delegate* delegate, - URLRequestContext* context, CookieStore* cookie_store) const; - - SocketStreamJob::ProtocolFactory* RegisterProtocolFactory( - const std::string& scheme, SocketStreamJob::ProtocolFactory* factory); - - private: - friend struct DefaultSingletonTraits<SocketStreamJobManager>; - typedef std::map<std::string, SocketStreamJob::ProtocolFactory*> FactoryMap; - - SocketStreamJobManager(); - ~SocketStreamJobManager(); - - mutable base::Lock lock_; - FactoryMap factories_; - - DISALLOW_COPY_AND_ASSIGN(SocketStreamJobManager); -}; - -} // namespace net - -#endif // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_ diff --git a/net/socket_stream/socket_stream_metrics.cc b/net/socket_stream/socket_stream_metrics.cc deleted file mode 100644 index e026887..0000000 --- a/net/socket_stream/socket_stream_metrics.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2011 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/socket_stream/socket_stream_metrics.h" - -#include <string.h> - -#include "base/metrics/histogram.h" -#include "base/time/time.h" -#include "url/gurl.h" - -namespace net { - -SocketStreamMetrics::SocketStreamMetrics(const GURL& url) - : received_bytes_(0), - received_counts_(0), - sent_bytes_(0), - sent_counts_(0) { - ProtocolType protocol_type = PROTOCOL_UNKNOWN; - if (url.SchemeIs("ws")) - protocol_type = PROTOCOL_WEBSOCKET; - else if (url.SchemeIs("wss")) - protocol_type = PROTOCOL_WEBSOCKET_SECURE; - - UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ProtocolType", - protocol_type, NUM_PROTOCOL_TYPES); -} - -SocketStreamMetrics::~SocketStreamMetrics() {} - -void SocketStreamMetrics::OnWaitConnection() { - wait_start_time_ = base::TimeTicks::Now(); -} - -void SocketStreamMetrics::OnStartConnection() { - connect_start_time_ = base::TimeTicks::Now(); - if (!wait_start_time_.is_null()) - UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionLatency", - connect_start_time_ - wait_start_time_); - OnCountConnectionType(ALL_CONNECTIONS); -} - -void SocketStreamMetrics::OnConnected() { - connect_establish_time_ = base::TimeTicks::Now(); - UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionEstablish", - connect_establish_time_ - connect_start_time_); -} - -void SocketStreamMetrics::OnRead(int len) { - received_bytes_ += len; - ++received_counts_; -} - -void SocketStreamMetrics::OnWrite(int len) { - sent_bytes_ += len; - ++sent_counts_; -} - -void SocketStreamMetrics::OnClose() { - base::TimeTicks closed_time = base::TimeTicks::Now(); - if (!connect_establish_time_.is_null()) { - UMA_HISTOGRAM_LONG_TIMES("Net.SocketStream.Duration", - closed_time - connect_establish_time_); - UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedBytes", - received_bytes_); - UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedCounts", - received_counts_); - UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentBytes", - sent_bytes_); - UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentCounts", - sent_counts_); - } -} - -void SocketStreamMetrics::OnCountConnectionType(ConnectionType type) { - UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ConnectionType", type, - NUM_CONNECTION_TYPES); -} - -void SocketStreamMetrics::OnCountWireProtocolType(WireProtocolType type) { - UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.WireProtocolType", type, - NUM_WIRE_PROTOCOL_TYPES); -} - -} // namespace net diff --git a/net/socket_stream/socket_stream_metrics.h b/net/socket_stream/socket_stream_metrics.h deleted file mode 100644 index 0040a9a..0000000 --- a/net/socket_stream/socket_stream_metrics.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011 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. -// -// Collect metrics of SocketStream usage. -// TODO(ukai): collect WebSocket specific metrics (e.g. handshake time, etc). - -#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_ -#define NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_ - -#include "base/basictypes.h" -#include "base/time/time.h" -#include "net/base/net_export.h" - -class GURL; - -namespace net { - -class NET_EXPORT_PRIVATE SocketStreamMetrics { - public: - enum ProtocolType { - PROTOCOL_UNKNOWN, - PROTOCOL_WEBSOCKET, - PROTOCOL_WEBSOCKET_SECURE, - NUM_PROTOCOL_TYPES, - }; - - enum ConnectionType { - CONNECTION_NONE, - ALL_CONNECTIONS, - TUNNEL_CONNECTION, - SOCKS_CONNECTION, - SSL_CONNECTION, - SECURE_PROXY_CONNECTION, - NUM_CONNECTION_TYPES, - }; - - enum WireProtocolType { - WIRE_PROTOCOL_WEBSOCKET, - WIRE_PROTOCOL_SPDY, - NUM_WIRE_PROTOCOL_TYPES, - }; - - explicit SocketStreamMetrics(const GURL& url); - ~SocketStreamMetrics(); - - void OnWaitConnection(); - void OnStartConnection(); - void OnConnected(); - void OnRead(int len); - void OnWrite(int len); - void OnClose(); - void OnCountConnectionType(ConnectionType type); - void OnCountWireProtocolType(WireProtocolType type); - - private: - base::TimeTicks wait_start_time_; - base::TimeTicks connect_start_time_; - base::TimeTicks connect_establish_time_; - int received_bytes_; - int received_counts_; - int sent_bytes_; - int sent_counts_; - - DISALLOW_COPY_AND_ASSIGN(SocketStreamMetrics); -}; - -} // namespace net - -#endif // NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_ diff --git a/net/socket_stream/socket_stream_metrics_unittest.cc b/net/socket_stream/socket_stream_metrics_unittest.cc deleted file mode 100644 index 219e692..0000000 --- a/net/socket_stream/socket_stream_metrics_unittest.cc +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) 2012 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/socket_stream/socket_stream_metrics.h" - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/statistics_recorder.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" -#include "url/gurl.h" - -using base::Histogram; -using base::HistogramBase; -using base::HistogramSamples; -using base::StatisticsRecorder; - -namespace net { - -TEST(SocketStreamMetricsTest, ProtocolType) { - // First we'll preserve the original values. We need to do this - // as histograms can get affected by other tests. In particular, - // SocketStreamTest and WebSocketTest can affect the histograms. - scoped_ptr<HistogramSamples> original; - HistogramBase* histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType"); - if (histogram) { - original = histogram->SnapshotSamples(); - } - - SocketStreamMetrics unknown(GURL("unknown://www.example.com/")); - SocketStreamMetrics ws1(GURL("ws://www.example.com/")); - SocketStreamMetrics ws2(GURL("ws://www.example.com/")); - SocketStreamMetrics wss1(GURL("wss://www.example.com/")); - SocketStreamMetrics wss2(GURL("wss://www.example.com/")); - SocketStreamMetrics wss3(GURL("wss://www.example.com/")); - - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - - scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples()); - if (original.get()) { - samples->Subtract(*original); // Cancel the original values. - } - EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::PROTOCOL_UNKNOWN)); - EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET)); - EXPECT_EQ(3, - samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET_SECURE)); -} - -TEST(SocketStreamMetricsTest, ConnectionType) { - // First we'll preserve the original values. - scoped_ptr<HistogramSamples> original; - HistogramBase* histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType"); - if (histogram) { - original = histogram->SnapshotSamples(); - } - - SocketStreamMetrics metrics(GURL("ws://www.example.com/")); - for (int i = 0; i < 1; ++i) - metrics.OnStartConnection(); - for (int i = 0; i < 2; ++i) - metrics.OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION); - for (int i = 0; i < 3; ++i) - metrics.OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION); - for (int i = 0; i < 4; ++i) - metrics.OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION); - - - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - - scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples()); - if (original.get()) { - samples->Subtract(*original); // Cancel the original values. - } - EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::ALL_CONNECTIONS)); - EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::TUNNEL_CONNECTION)); - EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::SOCKS_CONNECTION)); - EXPECT_EQ(4, samples->GetCount(SocketStreamMetrics::SSL_CONNECTION)); -} - -TEST(SocketStreamMetricsTest, WireProtocolType) { - // First we'll preserve the original values. - scoped_ptr<HistogramSamples> original; - HistogramBase* histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType"); - if (histogram) { - original = histogram->SnapshotSamples(); - } - - SocketStreamMetrics metrics(GURL("ws://www.example.com/")); - for (int i = 0; i < 3; ++i) - metrics.OnCountWireProtocolType( - SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET); - for (int i = 0; i < 7; ++i) - metrics.OnCountWireProtocolType(SocketStreamMetrics::WIRE_PROTOCOL_SPDY); - - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - - scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples()); - if (original.get()) { - samples->Subtract(*original); // Cancel the original values. - } - EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET)); - EXPECT_EQ(7, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_SPDY)); -} - -TEST(SocketStreamMetricsTest, OtherNumbers) { - // First we'll preserve the original values. - int64 original_received_bytes = 0; - int64 original_received_counts = 0; - int64 original_sent_bytes = 0; - int64 original_sent_counts = 0; - - scoped_ptr<HistogramSamples> original; - - HistogramBase* histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes"); - if (histogram) { - original = histogram->SnapshotSamples(); - original_received_bytes = original->sum(); - } - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts"); - if (histogram) { - original = histogram->SnapshotSamples(); - original_received_counts = original->sum(); - } - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes"); - if (histogram) { - original = histogram->SnapshotSamples(); - original_sent_bytes = original->sum(); - } - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts"); - if (histogram) { - original = histogram->SnapshotSamples(); - original_sent_counts = original->sum(); - } - - SocketStreamMetrics metrics(GURL("ws://www.example.com/")); - metrics.OnWaitConnection(); - metrics.OnStartConnection(); - metrics.OnConnected(); - metrics.OnRead(1); - metrics.OnRead(10); - metrics.OnWrite(2); - metrics.OnWrite(20); - metrics.OnWrite(200); - metrics.OnClose(); - - scoped_ptr<HistogramSamples> samples; - - // ConnectionLatency. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionLatency"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - // We don't check the contents of the histogram as it's time sensitive. - - // ConnectionEstablish. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionEstablish"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - // We don't check the contents of the histogram as it's time sensitive. - - // Duration. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.Duration"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - // We don't check the contents of the histogram as it's time sensitive. - - // ReceivedBytes. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - samples = histogram->SnapshotSamples(); - EXPECT_EQ(11, samples->sum() - original_received_bytes); // 11 bytes read. - - // ReceivedCounts. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - samples = histogram->SnapshotSamples(); - EXPECT_EQ(2, samples->sum() - original_received_counts); // 2 read requests. - - // SentBytes. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - samples = histogram->SnapshotSamples(); - EXPECT_EQ(222, samples->sum() - original_sent_bytes); // 222 bytes sent. - - // SentCounts. - histogram = - StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts"); - ASSERT_TRUE(histogram != NULL); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags()); - samples = histogram->SnapshotSamples(); - EXPECT_EQ(3, samples->sum() - original_sent_counts); // 3 write requests. -} - -} // namespace net diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc deleted file mode 100644 index b5ee002..0000000 --- a/net/socket_stream/socket_stream_unittest.cc +++ /dev/null @@ -1,1041 +0,0 @@ -// Copyright (c) 2012 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/socket_stream/socket_stream.h" - -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/strings/utf_string_conversions.h" -#include "net/base/auth.h" -#include "net/base/net_log.h" -#include "net/base/net_log_unittest.h" -#include "net/base/test_completion_callback.h" -#include "net/dns/mock_host_resolver.h" -#include "net/http/http_network_session.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/socket_test_util.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -using base::ASCIIToUTF16; - -namespace net { - -namespace { - -struct SocketStreamEvent { - enum EventType { - EVENT_START_OPEN_CONNECTION, EVENT_CONNECTED, EVENT_SENT_DATA, - EVENT_RECEIVED_DATA, EVENT_CLOSE, EVENT_AUTH_REQUIRED, EVENT_ERROR, - }; - - SocketStreamEvent(EventType type, - SocketStream* socket_stream, - int num, - const std::string& str, - AuthChallengeInfo* auth_challenge_info, - int error) - : event_type(type), socket(socket_stream), number(num), data(str), - auth_info(auth_challenge_info), error_code(error) {} - - EventType event_type; - SocketStream* socket; - int number; - std::string data; - scoped_refptr<AuthChallengeInfo> auth_info; - int error_code; -}; - -class SocketStreamEventRecorder : public SocketStream::Delegate { - public: - // |callback| will be run when the OnClose() or OnError() method is called. - // For OnClose(), |callback| is called with OK. For OnError(), it's called - // with the error code. - explicit SocketStreamEventRecorder(const CompletionCallback& callback) - : callback_(callback) {} - ~SocketStreamEventRecorder() override {} - - void SetOnStartOpenConnection( - const base::Callback<int(SocketStreamEvent*)>& callback) { - on_start_open_connection_ = callback; - } - void SetOnConnected( - const base::Callback<void(SocketStreamEvent*)>& callback) { - on_connected_ = callback; - } - void SetOnSentData( - const base::Callback<void(SocketStreamEvent*)>& callback) { - on_sent_data_ = callback; - } - void SetOnReceivedData( - const base::Callback<void(SocketStreamEvent*)>& callback) { - on_received_data_ = callback; - } - void SetOnClose(const base::Callback<void(SocketStreamEvent*)>& callback) { - on_close_ = callback; - } - void SetOnAuthRequired( - const base::Callback<void(SocketStreamEvent*)>& callback) { - on_auth_required_ = callback; - } - void SetOnError(const base::Callback<void(SocketStreamEvent*)>& callback) { - on_error_ = callback; - } - - int OnStartOpenConnection(SocketStream* socket, - const CompletionCallback& callback) override { - connection_callback_ = callback; - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - socket, 0, std::string(), NULL, OK)); - if (!on_start_open_connection_.is_null()) - return on_start_open_connection_.Run(&events_.back()); - return OK; - } - void OnConnected(SocketStream* socket, - int num_pending_send_allowed) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_CONNECTED, - socket, num_pending_send_allowed, std::string(), - NULL, OK)); - if (!on_connected_.is_null()) - on_connected_.Run(&events_.back()); - } - void OnSentData(SocketStream* socket, int amount_sent) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_SENT_DATA, socket, - amount_sent, std::string(), NULL, OK)); - if (!on_sent_data_.is_null()) - on_sent_data_.Run(&events_.back()); - } - void OnReceivedData(SocketStream* socket, - const char* data, - int len) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_RECEIVED_DATA, socket, len, - std::string(data, len), NULL, OK)); - if (!on_received_data_.is_null()) - on_received_data_.Run(&events_.back()); - } - void OnClose(SocketStream* socket) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_CLOSE, socket, 0, - std::string(), NULL, OK)); - if (!on_close_.is_null()) - on_close_.Run(&events_.back()); - if (!callback_.is_null()) - callback_.Run(OK); - } - void OnAuthRequired(SocketStream* socket, - AuthChallengeInfo* auth_info) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_AUTH_REQUIRED, socket, 0, - std::string(), auth_info, OK)); - if (!on_auth_required_.is_null()) - on_auth_required_.Run(&events_.back()); - } - void OnError(const SocketStream* socket, int error) override { - events_.push_back( - SocketStreamEvent(SocketStreamEvent::EVENT_ERROR, NULL, 0, - std::string(), NULL, error)); - if (!on_error_.is_null()) - on_error_.Run(&events_.back()); - if (!callback_.is_null()) - callback_.Run(error); - } - - void DoClose(SocketStreamEvent* event) { - event->socket->Close(); - } - void DoRestartWithAuth(SocketStreamEvent* event) { - VLOG(1) << "RestartWithAuth username=" << credentials_.username() - << " password=" << credentials_.password(); - event->socket->RestartWithAuth(credentials_); - } - void SetAuthInfo(const AuthCredentials& credentials) { - credentials_ = credentials; - } - // Wakes up the SocketStream waiting for completion of OnStartOpenConnection() - // of its delegate. - void CompleteConnection(int result) { - connection_callback_.Run(result); - } - - const std::vector<SocketStreamEvent>& GetSeenEvents() const { - return events_; - } - - private: - std::vector<SocketStreamEvent> events_; - base::Callback<int(SocketStreamEvent*)> on_start_open_connection_; - base::Callback<void(SocketStreamEvent*)> on_connected_; - base::Callback<void(SocketStreamEvent*)> on_sent_data_; - base::Callback<void(SocketStreamEvent*)> on_received_data_; - base::Callback<void(SocketStreamEvent*)> on_close_; - base::Callback<void(SocketStreamEvent*)> on_auth_required_; - base::Callback<void(SocketStreamEvent*)> on_error_; - const CompletionCallback callback_; - CompletionCallback connection_callback_; - AuthCredentials credentials_; - - DISALLOW_COPY_AND_ASSIGN(SocketStreamEventRecorder); -}; - -// This is used for the test OnErrorDetachDelegate. -class SelfDeletingDelegate : public SocketStream::Delegate { - public: - // |callback| must cause the test message loop to exit when called. - explicit SelfDeletingDelegate(const CompletionCallback& callback) - : socket_stream_(), callback_(callback) {} - - ~SelfDeletingDelegate() override {} - - // Call DetachDelegate(), delete |this|, then run the callback. - void OnError(const SocketStream* socket, int error) override { - // callback_ will be deleted when we delete |this|, so copy it to call it - // afterwards. - CompletionCallback callback = callback_; - socket_stream_->DetachDelegate(); - delete this; - callback.Run(OK); - } - - // This can't be passed in the constructor because this object needs to be - // created before SocketStream. - void set_socket_stream(const scoped_refptr<SocketStream>& socket_stream) { - socket_stream_ = socket_stream; - EXPECT_EQ(socket_stream_->delegate(), this); - } - - void OnConnected(SocketStream* socket, - int max_pending_send_allowed) override { - ADD_FAILURE() << "OnConnected() should not be called"; - } - void OnSentData(SocketStream* socket, int amount_sent) override { - ADD_FAILURE() << "OnSentData() should not be called"; - } - void OnReceivedData(SocketStream* socket, - const char* data, - int len) override { - ADD_FAILURE() << "OnReceivedData() should not be called"; - } - void OnClose(SocketStream* socket) override { - ADD_FAILURE() << "OnClose() should not be called"; - } - - private: - scoped_refptr<SocketStream> socket_stream_; - const CompletionCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(SelfDeletingDelegate); -}; - -class TestURLRequestContextWithProxy : public TestURLRequestContext { - public: - explicit TestURLRequestContextWithProxy(const std::string& proxy) - : TestURLRequestContext(true) { - context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy)); - Init(); - } - ~TestURLRequestContextWithProxy() override {} -}; - -class TestSocketStreamNetworkDelegate : public TestNetworkDelegate { - public: - TestSocketStreamNetworkDelegate() - : before_connect_result_(OK) {} - ~TestSocketStreamNetworkDelegate() override {} - - int OnBeforeSocketStreamConnect(SocketStream* stream, - const CompletionCallback& callback) override { - return before_connect_result_; - } - - void SetBeforeConnectResult(int result) { - before_connect_result_ = result; - } - - private: - int before_connect_result_; -}; - -} // namespace - -class SocketStreamTest : public PlatformTest { - public: - ~SocketStreamTest() override {} - void SetUp() override { - mock_socket_factory_.reset(); - handshake_request_ = kWebSocketHandshakeRequest; - handshake_response_ = kWebSocketHandshakeResponse; - } - void TearDown() override { mock_socket_factory_.reset(); } - - virtual void SetWebSocketHandshakeMessage( - const char* request, const char* response) { - handshake_request_ = request; - handshake_response_ = response; - } - virtual void AddWebSocketMessage(const std::string& message) { - messages_.push_back(message); - } - - virtual MockClientSocketFactory* GetMockClientSocketFactory() { - mock_socket_factory_.reset(new MockClientSocketFactory); - return mock_socket_factory_.get(); - } - - // Functions for SocketStreamEventRecorder to handle calls to the - // SocketStream::Delegate methods from the SocketStream. - - virtual void DoSendWebSocketHandshake(SocketStreamEvent* event) { - event->socket->SendData( - handshake_request_.data(), handshake_request_.size()); - } - - virtual void DoCloseFlushPendingWriteTest(SocketStreamEvent* event) { - // handshake response received. - for (size_t i = 0; i < messages_.size(); i++) { - std::vector<char> frame; - frame.push_back('\0'); - frame.insert(frame.end(), messages_[i].begin(), messages_[i].end()); - frame.push_back('\xff'); - EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size())); - } - // Actual StreamSocket close must happen after all frames queued by - // SendData above are sent out. - event->socket->Close(); - } - - virtual void DoCloseFlushPendingWriteTestWithSetContextNull( - SocketStreamEvent* event) { - event->socket->DetachContext(); - // handshake response received. - for (size_t i = 0; i < messages_.size(); i++) { - std::vector<char> frame; - frame.push_back('\0'); - frame.insert(frame.end(), messages_[i].begin(), messages_[i].end()); - frame.push_back('\xff'); - EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size())); - } - // Actual StreamSocket close must happen after all frames queued by - // SendData above are sent out. - event->socket->Close(); - } - - virtual void DoFailByTooBigDataAndClose(SocketStreamEvent* event) { - std::string frame(event->number + 1, 0x00); - VLOG(1) << event->number; - EXPECT_FALSE(event->socket->SendData(&frame[0], frame.size())); - event->socket->Close(); - } - - virtual int DoSwitchToSpdyTest(SocketStreamEvent* event) { - return ERR_PROTOCOL_SWITCHED; - } - - // Notifies |io_test_callback_| of that this method is called, and keeps the - // SocketStream waiting. - virtual int DoIOPending(SocketStreamEvent* event) { - io_test_callback_.callback().Run(OK); - return ERR_IO_PENDING; - } - - static const char kWebSocketHandshakeRequest[]; - static const char kWebSocketHandshakeResponse[]; - - protected: - TestCompletionCallback io_test_callback_; - - private: - std::string handshake_request_; - std::string handshake_response_; - std::vector<std::string> messages_; - - scoped_ptr<MockClientSocketFactory> mock_socket_factory_; -}; - -const char SocketStreamTest::kWebSocketHandshakeRequest[] = - "GET /demo HTTP/1.1\r\n" - "Host: example.com\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Upgrade: WebSocket\r\n" - "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" - "Origin: http://example.com\r\n" - "\r\n" - "^n:ds[4U"; - -const char SocketStreamTest::kWebSocketHandshakeResponse[] = - "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Location: ws://example.com/demo\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "\r\n" - "8jKS'y:G*Co,Wxa-"; - -TEST_F(SocketStreamTest, CloseFlushPendingWrite) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind( - &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this))); - delegate->SetOnReceivedData(base::Bind( - &SocketStreamTest::DoCloseFlushPendingWriteTest, - base::Unretained(this))); - - TestURLRequestContext context; - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - MockWrite data_writes[] = { - MockWrite(SocketStreamTest::kWebSocketHandshakeRequest), - MockWrite(ASYNC, "\0message1\xff", 10), - MockWrite(ASYNC, "\0message2\xff", 10) - }; - MockRead data_reads[] = { - MockRead(SocketStreamTest::kWebSocketHandshakeResponse), - // Server doesn't close the connection after handshake. - MockRead(ASYNC, ERR_IO_PENDING) - }; - AddWebSocketMessage("message1"); - AddWebSocketMessage("message2"); - - DelayedSocketData data_provider( - 1, data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - - MockClientSocketFactory* mock_socket_factory = - GetMockClientSocketFactory(); - mock_socket_factory->AddSocketDataProvider(&data_provider); - - socket_stream->SetClientSocketFactory(mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - EXPECT_TRUE(data_provider.at_read_eof()); - EXPECT_TRUE(data_provider.at_write_eof()); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(7U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type); -} - -TEST_F(SocketStreamTest, ResolveFailure) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - - // Make resolver fail. - TestURLRequestContext context; - scoped_ptr<MockHostResolver> mock_host_resolver( - new MockHostResolver()); - mock_host_resolver->rules()->AddSimulatedFailure("example.com"); - context.set_host_resolver(mock_host_resolver.get()); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - // No read/write on socket is expected. - StaticSocketDataProvider data_provider(NULL, 0, NULL, 0); - MockClientSocketFactory* mock_socket_factory = - GetMockClientSocketFactory(); - mock_socket_factory->AddSocketDataProvider(&data_provider); - socket_stream->SetClientSocketFactory(mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(2U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type); -} - -TEST_F(SocketStreamTest, ExceedMaxPendingSendAllowed) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind( - &SocketStreamTest::DoFailByTooBigDataAndClose, base::Unretained(this))); - - TestURLRequestContext context; - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - DelayedSocketData data_provider(1, NULL, 0, NULL, 0); - - MockClientSocketFactory* mock_socket_factory = - GetMockClientSocketFactory(); - mock_socket_factory->AddSocketDataProvider(&data_provider); - - socket_stream->SetClientSocketFactory(mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(4U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type); -} - -TEST_F(SocketStreamTest, BasicAuthProxy) { - MockClientSocketFactory mock_socket_factory; - MockWrite data_writes1[] = { - MockWrite("CONNECT example.com:80 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - MockRead data_reads1[] = { - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("\r\n"), - }; - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - mock_socket_factory.AddSocketDataProvider(&data1); - - MockWrite data_writes2[] = { - MockWrite("CONNECT example.com:80 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead data_reads2[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n"), - MockRead("Proxy-agent: Apache/2.2.8\r\n"), - MockRead("\r\n"), - // SocketStream::DoClose is run asynchronously. Socket can be read after - // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate - // server doesn't close the connection. - MockRead(ASYNC, ERR_IO_PENDING) - }; - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - mock_socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose, - base::Unretained(delegate.get()))); - delegate->SetAuthInfo(AuthCredentials(ASCIIToUTF16("foo"), - ASCIIToUTF16("bar"))); - delegate->SetOnAuthRequired(base::Bind( - &SocketStreamEventRecorder::DoRestartWithAuth, - base::Unretained(delegate.get()))); - - TestURLRequestContextWithProxy context("myproxy:70"); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->SetClientSocketFactory(&mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(5U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_AUTH_REQUIRED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[2].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[3].event_type); - EXPECT_EQ(ERR_ABORTED, events[3].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type); - - // TODO(eroman): Add back NetLogTest here... -} - -TEST_F(SocketStreamTest, BasicAuthProxyWithAuthCache) { - MockClientSocketFactory mock_socket_factory; - MockWrite data_writes[] = { - // WebSocket(SocketStream) always uses CONNECT when it is configured to use - // proxy so the port may not be 443. - MockWrite("CONNECT example.com:80 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n"), - MockRead("Proxy-agent: Apache/2.2.8\r\n"), - MockRead("\r\n"), - MockRead(ASYNC, ERR_IO_PENDING) - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - mock_socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback test_callback; - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - TestURLRequestContextWithProxy context("myproxy:70"); - HttpAuthCache* auth_cache = - context.http_transaction_factory()->GetSession()->http_auth_cache(); - auth_cache->Add(GURL("http://myproxy:70"), - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - AuthCredentials(ASCIIToUTF16("foo"), - ASCIIToUTF16("bar")), - "/"); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->SetClientSocketFactory(&mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(4U, events.size()); - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(ERR_ABORTED, events[2].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type); -} - -TEST_F(SocketStreamTest, WSSBasicAuthProxyWithAuthCache) { - MockClientSocketFactory mock_socket_factory; - MockWrite data_writes1[] = { - MockWrite("CONNECT example.com:443 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n"), - MockRead("Proxy-agent: Apache/2.2.8\r\n"), - MockRead("\r\n"), - MockRead(ASYNC, ERR_IO_PENDING) - }; - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - mock_socket_factory.AddSocketDataProvider(&data1); - - SSLSocketDataProvider data2(ASYNC, OK); - mock_socket_factory.AddSSLSocketDataProvider(&data2); - - TestCompletionCallback test_callback; - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - TestURLRequestContextWithProxy context("myproxy:70"); - HttpAuthCache* auth_cache = - context.http_transaction_factory()->GetSession()->http_auth_cache(); - auth_cache->Add(GURL("http://myproxy:70"), - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - AuthCredentials(ASCIIToUTF16("foo"), - ASCIIToUTF16("bar")), - "/"); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("wss://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->SetClientSocketFactory(&mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(4U, events.size()); - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(ERR_ABORTED, events[2].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type); -} - -TEST_F(SocketStreamTest, IOPending) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnStartOpenConnection(base::Bind( - &SocketStreamTest::DoIOPending, base::Unretained(this))); - delegate->SetOnConnected(base::Bind( - &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this))); - delegate->SetOnReceivedData(base::Bind( - &SocketStreamTest::DoCloseFlushPendingWriteTest, - base::Unretained(this))); - - TestURLRequestContext context; - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - MockWrite data_writes[] = { - MockWrite(SocketStreamTest::kWebSocketHandshakeRequest), - MockWrite(ASYNC, "\0message1\xff", 10), - MockWrite(ASYNC, "\0message2\xff", 10) - }; - MockRead data_reads[] = { - MockRead(SocketStreamTest::kWebSocketHandshakeResponse), - // Server doesn't close the connection after handshake. - MockRead(ASYNC, ERR_IO_PENDING) - }; - AddWebSocketMessage("message1"); - AddWebSocketMessage("message2"); - - DelayedSocketData data_provider( - 1, data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - - MockClientSocketFactory* mock_socket_factory = - GetMockClientSocketFactory(); - mock_socket_factory->AddSocketDataProvider(&data_provider); - - socket_stream->SetClientSocketFactory(mock_socket_factory); - - socket_stream->Connect(); - io_test_callback_.WaitForResult(); - EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE, - socket_stream->next_state_); - delegate->CompleteConnection(OK); - - EXPECT_EQ(OK, test_callback.WaitForResult()); - - EXPECT_TRUE(data_provider.at_read_eof()); - EXPECT_TRUE(data_provider.at_write_eof()); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(7U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type); -} - -TEST_F(SocketStreamTest, SwitchToSpdy) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnStartOpenConnection(base::Bind( - &SocketStreamTest::DoSwitchToSpdyTest, base::Unretained(this))); - - TestURLRequestContext context; - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->Connect(); - - EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult()); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(2U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type); - EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code); -} - -TEST_F(SocketStreamTest, SwitchAfterPending) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnStartOpenConnection(base::Bind( - &SocketStreamTest::DoIOPending, base::Unretained(this))); - - TestURLRequestContext context; - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->Connect(); - io_test_callback_.WaitForResult(); - - EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE, - socket_stream->next_state_); - delegate->CompleteConnection(ERR_PROTOCOL_SWITCHED); - - EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult()); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(2U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type); - EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code); -} - -// Test a connection though a secure proxy. -TEST_F(SocketStreamTest, SecureProxyConnectError) { - MockClientSocketFactory mock_socket_factory; - MockWrite data_writes[] = { - MockWrite("CONNECT example.com:80 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n") - }; - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n"), - MockRead("Proxy-agent: Apache/2.2.8\r\n"), - MockRead("\r\n"), - // SocketStream::DoClose is run asynchronously. Socket can be read after - // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate - // server doesn't close the connection. - MockRead(ASYNC, ERR_IO_PENDING) - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - mock_socket_factory.AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR); - mock_socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback test_callback; - TestURLRequestContextWithProxy context("https://myproxy:70"); - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->SetClientSocketFactory(&mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(3U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type); - EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, events[1].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[2].event_type); -} - -// Test a connection though a secure proxy. -TEST_F(SocketStreamTest, SecureProxyConnect) { - MockClientSocketFactory mock_socket_factory; - MockWrite data_writes[] = { - MockWrite("CONNECT example.com:80 HTTP/1.1\r\n" - "Host: example.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n") - }; - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n"), - MockRead("Proxy-agent: Apache/2.2.8\r\n"), - MockRead("\r\n"), - // SocketStream::DoClose is run asynchronously. Socket can be read after - // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate - // server doesn't close the connection. - MockRead(ASYNC, ERR_IO_PENDING) - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - mock_socket_factory.AddSocketDataProvider(&data); - SSLSocketDataProvider ssl(SYNCHRONOUS, OK); - mock_socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback test_callback; - TestURLRequestContextWithProxy context("https://myproxy:70"); - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->SetClientSocketFactory(&mock_socket_factory); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(4U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type); - EXPECT_EQ(ERR_ABORTED, events[2].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type); -} - -TEST_F(SocketStreamTest, BeforeConnectFailed) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - - TestURLRequestContext context; - TestSocketStreamNetworkDelegate network_delegate; - network_delegate.SetBeforeConnectResult(ERR_ACCESS_DENIED); - context.set_network_delegate(&network_delegate); - - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - - socket_stream->Connect(); - - test_callback.WaitForResult(); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(2U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type); - EXPECT_EQ(ERR_ACCESS_DENIED, events[0].error_code); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type); -} - -// Check that a connect failure, followed by the delegate calling DetachDelegate -// and deleting itself in the OnError callback, is handled correctly. -TEST_F(SocketStreamTest, OnErrorDetachDelegate) { - MockClientSocketFactory mock_socket_factory; - TestCompletionCallback test_callback; - - // SelfDeletingDelegate is self-owning; we just need a pointer to it to - // connect it and the SocketStream. - SelfDeletingDelegate* delegate = - new SelfDeletingDelegate(test_callback.callback()); - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider data; - data.set_connect_data(mock_connect); - mock_socket_factory.AddSocketDataProvider(&data); - - TestURLRequestContext context; - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://localhost:9998/echo"), delegate, - &context, NULL)); - socket_stream->SetClientSocketFactory(&mock_socket_factory); - delegate->set_socket_stream(socket_stream); - // The delegate pointer will become invalid during the test. Set it to NULL to - // avoid holding a dangling pointer. - delegate = NULL; - - socket_stream->Connect(); - - EXPECT_EQ(OK, test_callback.WaitForResult()); -} - -TEST_F(SocketStreamTest, NullContextSocketStreamShouldNotCrash) { - TestCompletionCallback test_callback; - - scoped_ptr<SocketStreamEventRecorder> delegate( - new SocketStreamEventRecorder(test_callback.callback())); - TestURLRequestContext context; - scoped_refptr<SocketStream> socket_stream( - new SocketStream(GURL("ws://example.com/demo"), delegate.get(), - &context, NULL)); - delegate->SetOnStartOpenConnection(base::Bind( - &SocketStreamTest::DoIOPending, base::Unretained(this))); - delegate->SetOnConnected(base::Bind( - &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this))); - delegate->SetOnReceivedData(base::Bind( - &SocketStreamTest::DoCloseFlushPendingWriteTestWithSetContextNull, - base::Unretained(this))); - - MockWrite data_writes[] = { - MockWrite(SocketStreamTest::kWebSocketHandshakeRequest), - }; - MockRead data_reads[] = { - MockRead(SocketStreamTest::kWebSocketHandshakeResponse), - }; - AddWebSocketMessage("message1"); - AddWebSocketMessage("message2"); - - DelayedSocketData data_provider( - 1, data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - - MockClientSocketFactory* mock_socket_factory = GetMockClientSocketFactory(); - mock_socket_factory->AddSocketDataProvider(&data_provider); - socket_stream->SetClientSocketFactory(mock_socket_factory); - - socket_stream->Connect(); - io_test_callback_.WaitForResult(); - delegate->CompleteConnection(OK); - EXPECT_EQ(OK, test_callback.WaitForResult()); - - EXPECT_TRUE(data_provider.at_read_eof()); - EXPECT_TRUE(data_provider.at_write_eof()); - - const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents(); - ASSERT_EQ(5U, events.size()); - - EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION, - events[0].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type); - EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type); -} - -} // namespace net diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index 1421b55..1bbafe5 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h @@ -37,8 +37,6 @@ class SpdyNetworkTransactionTest; class SpdyProxyClientSocketTest; class SpdySessionTest; class SpdyStreamTest; -class SpdyWebSocketStreamTest; -class WebSocketJobTest; class SpdyFramer; class SpdyFrameBuilder; @@ -624,8 +622,6 @@ class NET_EXPORT_PRIVATE SpdyFramer { friend class net::SpdyProxyClientSocketTest; friend class net::SpdySessionTest; friend class net::SpdyStreamTest; - friend class net::SpdyWebSocketStreamTest; - friend class net::WebSocketJobTest; friend class test::TestSpdyVisitor; private: diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 0faab29..7a5060b 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc @@ -373,7 +373,6 @@ SpdySessionDependencies::SpdySessionDependencies(NextProto protocol) force_spdy_over_ssl(false), force_spdy_always(false), use_alternate_protocols(false), - enable_websocket_over_spdy(false), net_log(NULL) { DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; @@ -407,7 +406,6 @@ SpdySessionDependencies::SpdySessionDependencies( force_spdy_over_ssl(false), force_spdy_always(false), use_alternate_protocols(false), - enable_websocket_over_spdy(false), net_log(NULL) { DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; } @@ -467,7 +465,6 @@ net::HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( params.force_spdy_over_ssl = session_deps->force_spdy_over_ssl; params.force_spdy_always = session_deps->force_spdy_always; params.use_alternate_protocols = session_deps->use_alternate_protocols; - params.enable_websocket_over_spdy = session_deps->enable_websocket_over_spdy; params.net_log = session_deps->net_log; return params; } diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h index e91800d..178d2e1 100644 --- a/net/spdy/spdy_test_util_common.h +++ b/net/spdy/spdy_test_util_common.h @@ -222,7 +222,6 @@ struct SpdySessionDependencies { bool force_spdy_over_ssl; bool force_spdy_always; bool use_alternate_protocols; - bool enable_websocket_over_spdy; NetLog* net_log; }; diff --git a/net/spdy/spdy_websocket_stream.cc b/net/spdy/spdy_websocket_stream.cc deleted file mode 100644 index 54e668c..0000000 --- a/net/spdy/spdy_websocket_stream.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2012 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/spdy/spdy_websocket_stream.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/spdy/spdy_framer.h" -#include "net/spdy/spdy_protocol.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_stream.h" -#include "url/gurl.h" - -namespace net { - -SpdyWebSocketStream::SpdyWebSocketStream( - const base::WeakPtr<SpdySession>& spdy_session, Delegate* delegate) - : spdy_session_(spdy_session), - pending_send_data_length_(0), - delegate_(delegate), - weak_ptr_factory_(this) { - DCHECK(spdy_session_.get()); - DCHECK(delegate_); -} - -SpdyWebSocketStream::~SpdyWebSocketStream() { - delegate_ = NULL; - Close(); -} - -int SpdyWebSocketStream::InitializeStream(const GURL& url, - RequestPriority request_priority, - const BoundNetLog& net_log) { - if (!spdy_session_) - return ERR_SOCKET_NOT_CONNECTED; - - int rv = stream_request_.StartRequest( - SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url, request_priority, net_log, - base::Bind(&SpdyWebSocketStream::OnSpdyStreamCreated, - weak_ptr_factory_.GetWeakPtr())); - - if (rv == OK) { - stream_ = stream_request_.ReleaseStream(); - DCHECK(stream_.get()); - stream_->SetDelegate(this); - } - return rv; -} - -int SpdyWebSocketStream::SendRequest(scoped_ptr<SpdyHeaderBlock> headers) { - if (!stream_.get()) { - NOTREACHED(); - return ERR_UNEXPECTED; - } - int result = stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND); - if (result < OK && result != ERR_IO_PENDING) - Close(); - return result; -} - -int SpdyWebSocketStream::SendData(const char* data, int length) { - if (!stream_.get()) { - NOTREACHED(); - return ERR_UNEXPECTED; - } - DCHECK_GE(length, 0); - pending_send_data_length_ = static_cast<size_t>(length); - scoped_refptr<IOBuffer> buf(new IOBuffer(length)); - memcpy(buf->data(), data, length); - stream_->SendData(buf.get(), length, MORE_DATA_TO_SEND); - return ERR_IO_PENDING; -} - -void SpdyWebSocketStream::Close() { - if (stream_.get()) { - stream_->Close(); - DCHECK(!stream_.get()); - } -} - -void SpdyWebSocketStream::OnRequestHeadersSent() { - DCHECK(delegate_); - delegate_->OnSentSpdyHeaders(); -} - -SpdyResponseHeadersStatus SpdyWebSocketStream::OnResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) { - DCHECK(delegate_); - delegate_->OnSpdyResponseHeadersUpdated(response_headers); - return RESPONSE_HEADERS_ARE_COMPLETE; -} - -void SpdyWebSocketStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { - DCHECK(delegate_); - delegate_->OnReceivedSpdyData(buffer.Pass()); -} - -void SpdyWebSocketStream::OnDataSent() { - DCHECK(delegate_); - delegate_->OnSentSpdyData(pending_send_data_length_); - pending_send_data_length_ = 0; -} - -void SpdyWebSocketStream::OnClose(int status) { - stream_.reset(); - - // Destruction without Close() call OnClose() with delegate_ being NULL. - if (!delegate_) - return; - Delegate* delegate = delegate_; - delegate_ = NULL; - delegate->OnCloseSpdyStream(); -} - -void SpdyWebSocketStream::OnSpdyStreamCreated(int result) { - DCHECK_NE(ERR_IO_PENDING, result); - if (result == OK) { - stream_ = stream_request_.ReleaseStream(); - DCHECK(stream_.get()); - stream_->SetDelegate(this); - } - DCHECK(delegate_); - delegate_->OnCreatedSpdyStream(result); -} - -} // namespace net diff --git a/net/spdy/spdy_websocket_stream.h b/net/spdy/spdy_websocket_stream.h deleted file mode 100644 index 854afbf..0000000 --- a/net/spdy/spdy_websocket_stream.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef NET_SPDY_SPDY_WEBSOCKET_STREAM_H_ -#define NET_SPDY_SPDY_WEBSOCKET_STREAM_H_ - -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "net/base/completion_callback.h" -#include "net/base/request_priority.h" -#include "net/spdy/spdy_framer.h" -#include "net/spdy/spdy_header_block.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_stream.h" - -namespace net { - -// The SpdyWebSocketStream is a WebSocket-specific type of stream known to a -// SpdySession. WebSocket's opening handshake is converted to SPDY's -// SYN_STREAM/SYN_REPLY. WebSocket frames are encapsulated as SPDY data frames. -class NET_EXPORT_PRIVATE SpdyWebSocketStream - : public SpdyStream::Delegate { - public: - // Delegate handles asynchronous events. - class NET_EXPORT_PRIVATE Delegate { - public: - // Called when InitializeStream() finishes asynchronously. This delegate is - // called if InitializeStream() returns ERR_IO_PENDING. |status| indicates - // network error. - virtual void OnCreatedSpdyStream(int status) = 0; - - // Called on corresponding to OnSendHeadersComplete() or SPDY's SYN frame - // has been sent. - virtual void OnSentSpdyHeaders() = 0; - - // Called on corresponding to OnResponseHeadersUpdated() or - // SPDY's SYN_STREAM, SYN_REPLY, or HEADERS frames are - // received. This callback may be called multiple times as SPDY's - // delegate does. - virtual void OnSpdyResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) = 0; - - // Called when data is sent. - virtual void OnSentSpdyData(size_t bytes_sent) = 0; - - // Called when data is received. - virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) = 0; - - // Called when SpdyStream is closed. - virtual void OnCloseSpdyStream() = 0; - - protected: - virtual ~Delegate() {} - }; - - SpdyWebSocketStream(const base::WeakPtr<SpdySession>& spdy_session, - Delegate* delegate); - ~SpdyWebSocketStream() override; - - // Initializes SPDY stream for the WebSocket. - // It might create SPDY stream asynchronously. In this case, this method - // returns ERR_IO_PENDING and call OnCreatedSpdyStream delegate with result - // after completion. In other cases, delegate does not be called. - int InitializeStream(const GURL& url, - RequestPriority request_priority, - const BoundNetLog& stream_net_log); - - int SendRequest(scoped_ptr<SpdyHeaderBlock> headers); - int SendData(const char* data, int length); - void Close(); - - // SpdyStream::Delegate - void OnRequestHeadersSent() override; - SpdyResponseHeadersStatus OnResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) override; - void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override; - void OnDataSent() override; - void OnClose(int status) override; - - private: - friend class SpdyWebSocketStreamTest; - FRIEND_TEST_ALL_PREFIXES(SpdyWebSocketStreamTest, Basic); - - void OnSpdyStreamCreated(int status); - - SpdyStreamRequest stream_request_; - base::WeakPtr<SpdyStream> stream_; - const base::WeakPtr<SpdySession> spdy_session_; - size_t pending_send_data_length_; - Delegate* delegate_; - - base::WeakPtrFactory<SpdyWebSocketStream> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStream); -}; - -} // namespace net - -#endif // NET_SPDY_SPDY_WEBSOCKET_STREAM_H_ diff --git a/net/spdy/spdy_websocket_stream_unittest.cc b/net/spdy/spdy_websocket_stream_unittest.cc deleted file mode 100644 index fc54884..0000000 --- a/net/spdy/spdy_websocket_stream_unittest.cc +++ /dev/null @@ -1,669 +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/spdy/spdy_websocket_stream.h" - -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "net/base/completion_callback.h" -#include "net/proxy/proxy_server.h" -#include "net/socket/next_proto.h" -#include "net/socket/ssl_client_socket.h" -#include "net/spdy/spdy_http_utils.h" -#include "net/spdy/spdy_protocol.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_websocket_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -namespace { - -struct SpdyWebSocketStreamEvent { - enum EventType { - EVENT_CREATED, - EVENT_SENT_HEADERS, - EVENT_RECEIVED_HEADER, - EVENT_SENT_DATA, - EVENT_RECEIVED_DATA, - EVENT_CLOSE, - }; - SpdyWebSocketStreamEvent(EventType type, - const SpdyHeaderBlock& headers, - int result, - const std::string& data) - : event_type(type), - headers(headers), - result(result), - data(data) {} - - EventType event_type; - SpdyHeaderBlock headers; - int result; - std::string data; -}; - -class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate { - public: - explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback) - : callback_(callback) {} - ~SpdyWebSocketStreamEventRecorder() override {} - - typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback; - - void SetOnCreated(const StreamEventCallback& callback) { - on_created_ = callback; - } - void SetOnSentHeaders(const StreamEventCallback& callback) { - on_sent_headers_ = callback; - } - void SetOnReceivedHeader(const StreamEventCallback& callback) { - on_received_header_ = callback; - } - void SetOnSentData(const StreamEventCallback& callback) { - on_sent_data_ = callback; - } - void SetOnReceivedData(const StreamEventCallback& callback) { - on_received_data_ = callback; - } - void SetOnClose(const StreamEventCallback& callback) { - on_close_ = callback; - } - - void OnCreatedSpdyStream(int result) override { - events_.push_back( - SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED, - SpdyHeaderBlock(), - result, - std::string())); - if (!on_created_.is_null()) - on_created_.Run(&events_.back()); - } - void OnSentSpdyHeaders() override { - events_.push_back( - SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - SpdyHeaderBlock(), - OK, - std::string())); - if (!on_sent_data_.is_null()) - on_sent_data_.Run(&events_.back()); - } - void OnSpdyResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) override { - events_.push_back( - SpdyWebSocketStreamEvent( - SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - response_headers, - OK, - std::string())); - if (!on_received_header_.is_null()) - on_received_header_.Run(&events_.back()); - } - void OnSentSpdyData(size_t bytes_sent) override { - events_.push_back( - SpdyWebSocketStreamEvent( - SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - SpdyHeaderBlock(), - static_cast<int>(bytes_sent), - std::string())); - if (!on_sent_data_.is_null()) - on_sent_data_.Run(&events_.back()); - } - void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override { - std::string buffer_data; - size_t buffer_len = 0; - if (buffer) { - buffer_len = buffer->GetRemainingSize(); - buffer_data.append(buffer->GetRemainingData(), buffer_len); - } - events_.push_back( - SpdyWebSocketStreamEvent( - SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - SpdyHeaderBlock(), - buffer_len, - buffer_data)); - if (!on_received_data_.is_null()) - on_received_data_.Run(&events_.back()); - } - void OnCloseSpdyStream() override { - events_.push_back( - SpdyWebSocketStreamEvent( - SpdyWebSocketStreamEvent::EVENT_CLOSE, - SpdyHeaderBlock(), - OK, - std::string())); - if (!on_close_.is_null()) - on_close_.Run(&events_.back()); - if (!callback_.is_null()) - callback_.Run(OK); - } - - const std::vector<SpdyWebSocketStreamEvent>& GetSeenEvents() const { - return events_; - } - - private: - std::vector<SpdyWebSocketStreamEvent> events_; - StreamEventCallback on_created_; - StreamEventCallback on_sent_headers_; - StreamEventCallback on_received_header_; - StreamEventCallback on_sent_data_; - StreamEventCallback on_received_data_; - StreamEventCallback on_close_; - CompletionCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder); -}; - -} // namespace - -class SpdyWebSocketStreamTest - : public ::testing::Test, - public ::testing::WithParamInterface<NextProto> { - public: - OrderedSocketData* data() { return data_.get(); } - - void DoSendHelloFrame(SpdyWebSocketStreamEvent* event) { - // Record the actual stream_id. - created_stream_id_ = websocket_stream_->stream_->stream_id(); - websocket_stream_->SendData(kMessageFrame, kMessageFrameLength); - } - - void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) { - websocket_stream_->SendData(kClosingFrame, kClosingFrameLength); - } - - void DoClose(SpdyWebSocketStreamEvent* event) { - websocket_stream_->Close(); - } - - void DoSync(SpdyWebSocketStreamEvent* event) { - sync_callback_.callback().Run(OK); - } - - protected: - SpdyWebSocketStreamTest() - : spdy_util_(GetParam()), - spdy_settings_id_to_set_(SETTINGS_MAX_CONCURRENT_STREAMS), - spdy_settings_flags_to_set_(SETTINGS_FLAG_PLEASE_PERSIST), - spdy_settings_value_to_set_(1), - session_deps_(GetParam()), - stream_id_(0), - created_stream_id_(0) {} - virtual ~SpdyWebSocketStreamTest() {} - - void SetUp() override { - 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); - - spdy_settings_to_send_[spdy_settings_id_to_set_] = - SettingsFlagsAndValue( - SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_); - } - - void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); } - - void Prepare(SpdyStreamId stream_id) { - stream_id_ = stream_id; - - request_frame_.reset(spdy_util_.ConstructSpdyWebSocketSynStream( - stream_id_, - "/echo", - "example.com", - "http://example.com/wsdemo")); - - response_frame_.reset( - spdy_util_.ConstructSpdyWebSocketSynReply(stream_id_)); - - message_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame( - kMessageFrame, - kMessageFrameLength, - stream_id_, - false)); - - closing_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame( - kClosingFrame, - kClosingFrameLength, - stream_id_, - false)); - - closing_frame_fin_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame( - kClosingFrame, - kClosingFrameLength, - stream_id_, - true)); - } - - void InitSession(MockRead* reads, size_t reads_count, - MockWrite* writes, size_t writes_count) { - data_.reset(new OrderedSocketData(reads, reads_count, - writes, writes_count)); - session_deps_.socket_factory->AddSocketDataProvider(data_.get()); - http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); - session_ = CreateInsecureSpdySession( - http_session_, spdy_session_key_, BoundNetLog()); - } - - void SendRequest() { - scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); - spdy_util_.SetHeader("path", "/echo", headers.get()); - spdy_util_.SetHeader("host", "example.com", headers.get()); - spdy_util_.SetHeader("version", "WebSocket/13", headers.get()); - spdy_util_.SetHeader("scheme", "ws", headers.get()); - spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get()); - websocket_stream_->SendRequest(headers.Pass()); - } - - SpdyWebSocketTestUtil spdy_util_; - SpdySettingsIds spdy_settings_id_to_set_; - SpdySettingsFlags spdy_settings_flags_to_set_; - uint32 spdy_settings_value_to_set_; - SettingsMap spdy_settings_to_send_; - SpdySessionDependencies session_deps_; - scoped_ptr<OrderedSocketData> data_; - scoped_refptr<HttpNetworkSession> http_session_; - base::WeakPtr<SpdySession> session_; - scoped_ptr<SpdyWebSocketStream> websocket_stream_; - SpdyStreamId stream_id_; - SpdyStreamId created_stream_id_; - scoped_ptr<SpdyFrame> request_frame_; - scoped_ptr<SpdyFrame> response_frame_; - scoped_ptr<SpdyFrame> message_frame_; - scoped_ptr<SpdyFrame> closing_frame_; - scoped_ptr<SpdyFrame> closing_frame_fin_; - HostPortPair host_port_pair_; - SpdySessionKey spdy_session_key_; - TestCompletionCallback completion_callback_; - TestCompletionCallback sync_callback_; - - static const char kMessageFrame[]; - static const char kClosingFrame[]; - static const size_t kMessageFrameLength; - static const size_t kClosingFrameLength; -}; - -INSTANTIATE_TEST_CASE_P( - NextProto, - SpdyWebSocketStreamTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); - -// TODO(toyoshim): Replace old framing data to new one, then use HEADERS and -// data frames. -const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello"; -const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0"; -const size_t SpdyWebSocketStreamTest::kMessageFrameLength = - arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1; -const size_t SpdyWebSocketStreamTest::kClosingFrameLength = - arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1; - -TEST_P(SpdyWebSocketStreamTest, Basic) { - Prepare(1); - MockWrite writes[] = { - CreateMockWrite(*request_frame_.get(), 1), - CreateMockWrite(*message_frame_.get(), 3), - CreateMockWrite(*closing_frame_.get(), 5) - }; - - MockRead reads[] = { - CreateMockRead(*response_frame_.get(), 2), - CreateMockRead(*message_frame_.get(), 4), - // Skip sequence 6 to notify closing has been sent. - CreateMockRead(*closing_frame_.get(), 7), - MockRead(SYNCHRONOUS, 0, 8) // EOF cause OnCloseSpdyStream event. - }; - - InitSession(reads, arraysize(reads), writes, arraysize(writes)); - - SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback()); - delegate.SetOnReceivedHeader( - base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame, - base::Unretained(this))); - delegate.SetOnReceivedData( - base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame, - base::Unretained(this))); - - websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate)); - - BoundNetLog net_log; - GURL url("ws://example.com/echo"); - ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log)); - - ASSERT_TRUE(websocket_stream_->stream_.get()); - - SendRequest(); - - completion_callback_.WaitForResult(); - - EXPECT_EQ(stream_id_, created_stream_id_); - - websocket_stream_.reset(); - - const std::vector<SpdyWebSocketStreamEvent>& events = - delegate.GetSeenEvents(); - ASSERT_EQ(7U, events.size()); - - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - events[0].event_type); - EXPECT_EQ(OK, events[0].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - events[1].event_type); - EXPECT_EQ(OK, events[1].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[2].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[3].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[4].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[5].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, - events[6].event_type); - EXPECT_EQ(OK, events[6].result); - - // EOF close SPDY session. - EXPECT_FALSE( - HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_)); - EXPECT_TRUE(data()->at_read_eof()); - EXPECT_TRUE(data()->at_write_eof()); -} - -// A SPDY websocket may still send it's close frame after -// recieving a close with SPDY stream FIN. -TEST_P(SpdyWebSocketStreamTest, RemoteCloseWithFin) { - Prepare(1); - MockWrite writes[] = { - CreateMockWrite(*request_frame_.get(), 1), - CreateMockWrite(*closing_frame_.get(), 4), - }; - MockRead reads[] = { - CreateMockRead(*response_frame_.get(), 2), - CreateMockRead(*closing_frame_fin_.get(), 3), - MockRead(SYNCHRONOUS, 0, 5) // EOF cause OnCloseSpdyStream event. - }; - InitSession(reads, arraysize(reads), writes, arraysize(writes)); - - SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback()); - delegate.SetOnReceivedData( - base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame, - base::Unretained(this))); - - websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate)); - BoundNetLog net_log; - GURL url("ws://example.com/echo"); - ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log)); - - SendRequest(); - completion_callback_.WaitForResult(); - websocket_stream_.reset(); - - const std::vector<SpdyWebSocketStreamEvent>& events = - delegate.GetSeenEvents(); - EXPECT_EQ(5U, events.size()); - - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - events[0].event_type); - EXPECT_EQ(OK, events[0].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - events[1].event_type); - EXPECT_EQ(OK, events[1].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[2].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[2].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[3].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[3].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, - events[4].event_type); - EXPECT_EQ(OK, events[4].result); - - // EOF closes SPDY session. - EXPECT_FALSE( - HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_)); - EXPECT_TRUE(data()->at_read_eof()); - EXPECT_TRUE(data()->at_write_eof()); -} - -TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) { - Prepare(1); - MockWrite writes[] = { - CreateMockWrite(*request_frame_.get(), 1), - CreateMockWrite(*message_frame_.get(), 3) - }; - - MockRead reads[] = { - CreateMockRead(*response_frame_.get(), 2), - CreateMockRead(*message_frame_.get(), 4), - MockRead(ASYNC, ERR_IO_PENDING, 5) - }; - - InitSession(reads, arraysize(reads), writes, arraysize(writes)); - - SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback()); - delegate.SetOnReceivedHeader( - base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame, - base::Unretained(this))); - delegate.SetOnReceivedData( - base::Bind(&SpdyWebSocketStreamTest::DoSync, - base::Unretained(this))); - - websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate)); - - BoundNetLog net_log; - GURL url("ws://example.com/echo"); - ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log)); - - SendRequest(); - - sync_callback_.WaitForResult(); - - // WebSocketStream destruction remove its SPDY stream from the session. - EXPECT_TRUE(session_->IsStreamActive(stream_id_)); - websocket_stream_.reset(); - EXPECT_FALSE(session_->IsStreamActive(stream_id_)); - - const std::vector<SpdyWebSocketStreamEvent>& events = - delegate.GetSeenEvents(); - ASSERT_GE(4U, events.size()); - - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - events[0].event_type); - EXPECT_EQ(OK, events[0].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - events[1].event_type); - EXPECT_EQ(OK, events[1].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[2].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[3].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result); - - EXPECT_TRUE( - HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_)); - EXPECT_TRUE(data()->at_read_eof()); - EXPECT_TRUE(data()->at_write_eof()); -} - -TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) { - Prepare(1); - MockWrite writes[] = { - CreateMockWrite(*request_frame_.get(), 1), - CreateMockWrite(*message_frame_.get(), 3), - CreateMockWrite(*closing_frame_.get(), 5) - }; - - MockRead reads[] = { - CreateMockRead(*response_frame_.get(), 2), - CreateMockRead(*message_frame_.get(), 4), - MockRead(ASYNC, ERR_IO_PENDING, 6) - }; - - InitSession(reads, arraysize(reads), writes, arraysize(writes)); - - SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback()); - delegate.SetOnReceivedHeader( - base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame, - base::Unretained(this))); - delegate.SetOnReceivedData( - base::Bind(&SpdyWebSocketStreamTest::DoClose, - base::Unretained(this))); - - websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate)); - - BoundNetLog net_log; - GURL url("ws://example.com/echo"); - ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log)); - - SendRequest(); - - completion_callback_.WaitForResult(); - - // SPDY stream has already been removed from the session by Close(). - EXPECT_FALSE(session_->IsStreamActive(stream_id_)); - websocket_stream_.reset(); - - const std::vector<SpdyWebSocketStreamEvent>& events = - delegate.GetSeenEvents(); - ASSERT_EQ(5U, events.size()); - - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - events[0].event_type); - EXPECT_EQ(OK, events[0].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - events[1].event_type); - EXPECT_EQ(OK, events[1].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[2].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[3].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type); - - EXPECT_TRUE( - HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_)); -} - -TEST_P(SpdyWebSocketStreamTest, IOPending) { - Prepare(1); - scoped_ptr<SpdyFrame> settings_frame( - spdy_util_.ConstructSpdySettings(spdy_settings_to_send_)); - scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); - MockWrite writes[] = { - CreateMockWrite(*settings_ack, 1), - CreateMockWrite(*request_frame_.get(), 2), - CreateMockWrite(*message_frame_.get(), 4), - CreateMockWrite(*closing_frame_.get(), 6) - }; - - MockRead reads[] = { - CreateMockRead(*settings_frame.get(), 0), - CreateMockRead(*response_frame_.get(), 3), - CreateMockRead(*message_frame_.get(), 5), - CreateMockRead(*closing_frame_.get(), 7), - MockRead(SYNCHRONOUS, 0, 8) // EOF cause OnCloseSpdyStream event. - }; - - DeterministicSocketData data(reads, arraysize(reads), - writes, arraysize(writes)); - session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); - http_session_ = - SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); - - session_ = CreateInsecureSpdySession( - http_session_, spdy_session_key_, BoundNetLog()); - - // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another - // WebSocketStream under test. - SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback())); - - scoped_ptr<SpdyWebSocketStream> block_stream( - new SpdyWebSocketStream(session_, &block_delegate)); - BoundNetLog block_net_log; - GURL block_url("ws://example.com/block"); - ASSERT_EQ(OK, - block_stream->InitializeStream(block_url, HIGHEST, block_net_log)); - - data.RunFor(1); - - // Create a WebSocketStream under test. - SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback()); - delegate.SetOnCreated( - base::Bind(&SpdyWebSocketStreamTest::DoSync, - base::Unretained(this))); - delegate.SetOnReceivedHeader( - base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame, - base::Unretained(this))); - delegate.SetOnReceivedData( - base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame, - base::Unretained(this))); - - websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate)); - BoundNetLog net_log; - GURL url("ws://example.com/echo"); - ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream( - url, HIGHEST, net_log)); - - // Delete the fist stream to allow create the second stream. - block_stream.reset(); - ASSERT_EQ(OK, sync_callback_.WaitForResult()); - - SendRequest(); - - data.RunFor(8); - completion_callback_.WaitForResult(); - - websocket_stream_.reset(); - - const std::vector<SpdyWebSocketStreamEvent>& block_events = - block_delegate.GetSeenEvents(); - ASSERT_EQ(0U, block_events.size()); - - const std::vector<SpdyWebSocketStreamEvent>& events = - delegate.GetSeenEvents(); - ASSERT_EQ(8U, events.size()); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED, - events[0].event_type); - EXPECT_EQ(0, events[0].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS, - events[1].event_type); - EXPECT_EQ(OK, events[1].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER, - events[2].event_type); - EXPECT_EQ(OK, events[2].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[3].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[4].event_type); - EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA, - events[5].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA, - events[6].event_type); - EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result); - EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, - events[7].event_type); - EXPECT_EQ(OK, events[7].result); - - // EOF close SPDY session. - EXPECT_FALSE( - HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_)); - EXPECT_TRUE(data.at_read_eof()); - EXPECT_TRUE(data.at_write_eof()); -} - -} // namespace net diff --git a/net/spdy/spdy_websocket_test_util.cc b/net/spdy/spdy_websocket_test_util.cc deleted file mode 100644 index b1ef81b..0000000 --- a/net/spdy/spdy_websocket_test_util.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 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/spdy/spdy_websocket_test_util.h" - -#include "net/spdy/buffered_spdy_framer.h" -#include "net/spdy/spdy_http_utils.h" - -namespace net { - -const bool kDefaultCompressed = false; - -SpdyWebSocketTestUtil::SpdyWebSocketTestUtil( - NextProto protocol) : spdy_util_(protocol) {} - -std::string SpdyWebSocketTestUtil::GetHeader(const SpdyHeaderBlock& headers, - const std::string& key) const { - SpdyHeaderBlock::const_iterator it = headers.find(GetHeaderKey(key)); - return (it == headers.end()) ? "" : it->second; -} - -void SpdyWebSocketTestUtil::SetHeader( - const std::string& key, - const std::string& value, - SpdyHeaderBlock* headers) const { - (*headers)[GetHeaderKey(key)] = value; -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynStream( - int stream_id, - const char* path, - const char* host, - const char* origin) { - scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); - SetHeader("path", path, headers.get()); - SetHeader("host", host, headers.get()); - SetHeader("version", "WebSocket/13", headers.get()); - SetHeader("scheme", "ws", headers.get()); - SetHeader("origin", origin, headers.get()); - return spdy_util_.ConstructSpdySyn( - stream_id, *headers, HIGHEST, false, false); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynReply( - int stream_id) { - SpdyHeaderBlock block; - SetHeader("status", "101", &block); - return spdy_util_.ConstructSpdyReply(stream_id, block); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeRequestFrame( - scoped_ptr<SpdyHeaderBlock> headers, - SpdyStreamId stream_id, - RequestPriority request_priority) { - return spdy_util_.ConstructSpdySyn( - stream_id, *headers, request_priority, kDefaultCompressed, false); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeResponseFrame( - scoped_ptr<SpdyHeaderBlock> headers, - SpdyStreamId stream_id, - RequestPriority request_priority) { - return spdy_util_.ConstructSpdyReply(stream_id, *headers); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHeadersFrame( - int stream_id, - const char* length, - bool fin) { - scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); - SetHeader("opcode", "1", headers.get()); // text frame - SetHeader("length", length, headers.get()); - SetHeader("fin", fin ? "1" : "0", headers.get()); - return spdy_util_.ConstructSpdySyn(stream_id, *headers, LOWEST, false, false); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketDataFrame( - const char* data, - int len, - SpdyStreamId stream_id, - bool fin) { - - // Construct SPDY data frame. - BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); - return framer.CreateDataFrame( - stream_id, - data, - len, - fin ? DATA_FLAG_FIN : DATA_FLAG_NONE); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettings( - const SettingsMap& settings) const { - return spdy_util_.ConstructSpdySettings(settings); -} - -SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettingsAck() const { - return spdy_util_.ConstructSpdySettingsAck(); -} - -SpdyMajorVersion SpdyWebSocketTestUtil::spdy_version() const { - return spdy_util_.spdy_version(); -} - -std::string SpdyWebSocketTestUtil::GetHeaderKey( - const std::string& key) const { - return (spdy_util_.is_spdy2() ? "" : ":") + key; -} - -} // namespace net diff --git a/net/spdy/spdy_websocket_test_util.h b/net/spdy/spdy_websocket_test_util.h deleted file mode 100644 index 14c8c02..0000000 --- a/net/spdy/spdy_websocket_test_util.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 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. - -#ifndef NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_ -#define NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_ - -#include "net/base/request_priority.h" -#include "net/spdy/spdy_header_block.h" -#include "net/spdy/spdy_protocol.h" -#include "net/spdy/spdy_test_util_common.h" - -namespace net { - -class SpdyWebSocketTestUtil { - public: - explicit SpdyWebSocketTestUtil(NextProto protocol); - - // Returns the value corresponding to the given key (passed through - // GetHeaderKey()), or the empty string if none exists. - std::string GetHeader(const SpdyHeaderBlock& headers, - const std::string& key) const; - - // Adds the given key/value pair to |headers|, passing the key - // through GetHeaderKey(). - void SetHeader(const std::string& key, - const std::string& value, - SpdyHeaderBlock* headers) const; - - // Constructs a standard SPDY SYN_STREAM frame for WebSocket over - // SPDY opening handshake. - SpdyFrame* ConstructSpdyWebSocketSynStream(int stream_id, - const char* path, - const char* host, - const char* origin); - - // Constructs a standard SPDY SYN_REPLY packet to match the - // WebSocket over SPDY opening handshake. - SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id); - - // Constructs a WebSocket over SPDY handshake request packet. - SpdyFrame* ConstructSpdyWebSocketHandshakeRequestFrame( - scoped_ptr<SpdyHeaderBlock> headers, - SpdyStreamId stream_id, - RequestPriority request_priority); - - // Constructs a WebSocket over SPDY handshake response packet. - SpdyFrame* ConstructSpdyWebSocketHandshakeResponseFrame( - scoped_ptr<SpdyHeaderBlock> headers, - SpdyStreamId stream_id, - RequestPriority request_priority); - - // Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY. - SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id, - const char* length, - bool fin); - - // Constructs a WebSocket over SPDY data packet. - SpdyFrame* ConstructSpdyWebSocketDataFrame(const char* data, - int len, - SpdyStreamId stream_id, - bool fin); - - // Forwards to |spdy_util_|. - SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const; - SpdyFrame* ConstructSpdySettingsAck() const; - SpdyMajorVersion spdy_version() const; - - private: - // Modify the header key based on the SPDY version and return it. - std::string GetHeaderKey(const std::string& key) const; - - SpdyTestUtil spdy_util_; -}; - -} // namespace net - -#endif // NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_ diff --git a/net/websockets/PRESUBMIT.py b/net/websockets/PRESUBMIT.py deleted file mode 100644 index 1da441c..0000000 --- a/net/websockets/PRESUBMIT.py +++ /dev/null @@ -1,57 +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. - -"""Chromium presubmit script for src/net/websockets. - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts -for more details on the presubmit API built into gcl. -""" - - -# TODO(ricea): Remove this once the old implementation has been removed and the -# list of files in the README file is no longer needed. -def _CheckReadMeComplete(input_api, output_api): - """Verifies that any new files have been added to the README file. - - Checks that if any source files were added in this CL, that they were - also added to the README file. We do not warn about pre-existing - errors, as that would be annoying. - - Args: - input_api: The InputApi object provided by the presubmit framework. - output_api: The OutputApi object provided by the framework. - - Returns: - A list of zero or more PresubmitPromptWarning objects. - """ - # None passed to AffectedSourceFiles means "use the default filter", which - # does what we want, ie. returns files in the CL with filenames that look like - # source code. - added_source_filenames = set(input_api.basename(af.LocalPath()) - for af in input_api.AffectedSourceFiles(None) - if af.Action().startswith('A')) - if not added_source_filenames: - return [] - readme = input_api.AffectedSourceFiles( - lambda af: af.LocalPath().endswith('/README')) - if not readme: - return [output_api.PresubmitPromptWarning( - 'One or more files were added to net/websockets without being added\n' - 'to net/websockets/README.\n', added_source_filenames)] - readme_added_filenames = set(line.strip() for line in readme[0].NewContents() - if line.strip() in added_source_filenames) - if readme_added_filenames < added_source_filenames: - return [output_api.PresubmitPromptWarning( - 'One or more files added to net/websockets but not found in the README ' - 'file.\n', added_source_filenames - readme_added_filenames)] - else: - return [] - - -def CheckChangeOnUpload(input_api, output_api): - return _CheckReadMeComplete(input_api, output_api) - - -def CheckChangeOnCommit(input_api, output_api): - return _CheckReadMeComplete(input_api, output_api) diff --git a/net/websockets/README b/net/websockets/README deleted file mode 100644 index efe7a59..0000000 --- a/net/websockets/README +++ /dev/null @@ -1,91 +0,0 @@ -This directory contains files related to Chromium's WebSocket -implementation. See http://www.websocket.org/ for an explanation of WebSockets. - -As of April 2013, the contents of this directory are in a transitional state, -and contain parts of two different WebSocket implementations. - -The following files are part of the legacy implementation. The legacy -implementation performs WebSocket framing within Blink and presents a -low-level socket-like interface to the renderer process. It is described in the -design doc at -https://docs.google.com/a/google.com/document/d/1_R6YjCIrm4kikJ3YeapcOU2Keqr3lVUPd-OeaIJ93qQ/preview - -websocket_handshake_handler_test.cc -websocket_handshake_handler_spdy_test.cc -websocket_job.cc -websocket_job.h -websocket_job_test.cc -websocket_net_log_params.cc -websocket_net_log_params.h -websocket_net_log_params_test.cc -websocket_throttle.cc -websocket_throttle.h -websocket_throttle_test.cc - -The following files are part of the new implementation. The new implementation -performs framing and implements protocol semantics in the browser process, and -presents a high-level interface to the renderer process similar to a -multiplexing proxy. This is the default implementation from M38. - -websocket_basic_handshake_stream.cc -websocket_basic_handshake_stream.h -websocket_basic_stream.cc -websocket_basic_stream.h -websocket_basic_stream_test.cc -websocket_channel.cc -websocket_channel.h -websocket_channel_test.cc -websocket_deflate_predictor.h -websocket_deflate_predictor_impl.cc -websocket_deflate_predictor_impl.h -websocket_deflate_predictor_impl_test.cc -websocket_deflate_stream.cc -websocket_deflate_stream.h -websocket_deflate_stream_test.cc -websocket_deflater.cc -websocket_deflater.h -websocket_deflater_test.cc -websocket_errors.cc -websocket_errors.h -websocket_errors_test.cc -websocket_event_interface.h -websocket_extension.cc -websocket_extension.h -websocket_extension_parser.cc -websocket_extension_parser.h -websocket_extension_parser_test.cc -websocket_frame.cc -websocket_frame.h -websocket_frame_parser.cc -websocket_frame_parser.h -websocket_frame_parser_test.cc -websocket_frame_test.cc -websocket_frame_perftest.cc -websocket_handshake_stream_base.h -websocket_handshake_stream_create_helper.cc -websocket_handshake_stream_create_helper.h -websocket_handshake_stream_create_helper_test.cc -websocket_handshake_request_info.cc -websocket_handshake_request_info.h -websocket_handshake_response_info.cc -websocket_handshake_response_info.h -websocket_inflater.cc -websocket_inflater.h -websocket_inflater_test.cc -websocket_mux.h -websocket_stream.cc -websocket_stream.h -websocket_stream_test.cc -websocket_test_util.cc -websocket_test_util.h - -These files are shared between the old and new implementations. - -websocket_handshake_constants.cc -websocket_handshake_constants.h -websocket_handshake_handler.cc -websocket_handshake_handler.h - -A pre-submit check helps us keep this README file up-to-date: - -PRESUBMIT.py diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc index 6324710..6bcc230 100644 --- a/net/websockets/websocket_handshake_handler.cc +++ b/net/websockets/websocket_handshake_handler.cc @@ -4,346 +4,12 @@ #include "net/websockets/websocket_handshake_handler.h" -#include <limits> - #include "base/base64.h" +#include "base/logging.h" #include "base/sha1.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_tokenizer.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_util.h" #include "net/websockets/websocket_handshake_constants.h" -#include "url/gurl.h" namespace net { -namespace { - -const int kVersionHeaderValueForRFC6455 = 13; - -// Splits |handshake_message| into Status-Line or Request-Line (including CRLF) -// and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake -// response). -void ParseHandshakeHeader( - const char* handshake_message, int len, - std::string* request_line, - std::string* headers) { - size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n"); - if (i == base::StringPiece::npos) { - *request_line = std::string(handshake_message, len); - *headers = ""; - return; - } - // |request_line| includes \r\n. - *request_line = std::string(handshake_message, i + 2); - - int header_len = len - (i + 2) - 2; - if (header_len > 0) { - // |handshake_message| includes trailing \r\n\r\n. - // |headers| doesn't include 2nd \r\n. - *headers = std::string(handshake_message + i + 2, header_len); - } else { - *headers = ""; - } -} - -void FetchHeaders(const std::string& headers, - const char* const headers_to_get[], - size_t headers_to_get_len, - std::vector<std::string>* values) { - net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n"); - while (iter.GetNext()) { - for (size_t i = 0; i < headers_to_get_len; i++) { - if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), - headers_to_get[i])) { - values->push_back(iter.values()); - } - } - } -} - -bool GetHeaderName(std::string::const_iterator line_begin, - std::string::const_iterator line_end, - std::string::const_iterator* name_begin, - std::string::const_iterator* name_end) { - std::string::const_iterator colon = std::find(line_begin, line_end, ':'); - if (colon == line_end) { - return false; - } - *name_begin = line_begin; - *name_end = colon; - if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin)) - return false; - net::HttpUtil::TrimLWS(name_begin, name_end); - return true; -} - -// Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that -// is, lines that are not formatted as "<name>: <value>\r\n". -std::string FilterHeaders( - const std::string& headers, - const char* const headers_to_remove[], - size_t headers_to_remove_len) { - std::string filtered_headers; - - base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n"); - while (lines.GetNext()) { - std::string::const_iterator line_begin = lines.token_begin(); - std::string::const_iterator line_end = lines.token_end(); - std::string::const_iterator name_begin; - std::string::const_iterator name_end; - bool should_remove = false; - if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) { - for (size_t i = 0; i < headers_to_remove_len; ++i) { - if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) { - should_remove = true; - break; - } - } - } - if (!should_remove) { - filtered_headers.append(line_begin, line_end); - filtered_headers.append("\r\n"); - } - } - return filtered_headers; -} - -bool CheckVersionInRequest(const std::string& request_headers) { - std::vector<std::string> values; - const char* const headers_to_get[1] = { - websockets::kSecWebSocketVersionLowercase}; - FetchHeaders(request_headers, headers_to_get, 1, &values); - DCHECK_LE(values.size(), 1U); - if (values.empty()) - return false; - - int version; - bool conversion_success = base::StringToInt(values[0], &version); - if (!conversion_success) - return false; - - return version == kVersionHeaderValueForRFC6455; -} - -// Append a header to a string. Equivalent to -// response_message += header + ": " + value + "\r\n" -// but avoids unnecessary allocations and copies. -void AppendHeader(const base::StringPiece& header, - const base::StringPiece& value, - std::string* response_message) { - static const char kColonSpace[] = ": "; - const size_t kColonSpaceSize = sizeof(kColonSpace) - 1; - static const char kCrNl[] = "\r\n"; - const size_t kCrNlSize = sizeof(kCrNl) - 1; - - size_t extra_size = - header.size() + kColonSpaceSize + value.size() + kCrNlSize; - response_message->reserve(response_message->size() + extra_size); - response_message->append(header.begin(), header.end()); - response_message->append(kColonSpace, kColonSpace + kColonSpaceSize); - response_message->append(value.begin(), value.end()); - response_message->append(kCrNl, kCrNl + kCrNlSize); -} - -} // namespace - -WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler() - : original_length_(0), - raw_length_(0) {} - -bool WebSocketHandshakeRequestHandler::ParseRequest( - const char* data, int length) { - DCHECK_GT(length, 0); - std::string input(data, length); - int input_header_length = - HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0); - if (input_header_length <= 0) - return false; - - ParseHandshakeHeader(input.data(), - input_header_length, - &request_line_, - &headers_); - - if (!CheckVersionInRequest(headers_)) { - NOTREACHED(); - return false; - } - - original_length_ = input_header_length; - return true; -} - -size_t WebSocketHandshakeRequestHandler::original_length() const { - return original_length_; -} - -void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing( - const std::string& name, const std::string& value) { - DCHECK(!headers_.empty()); - HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_); -} - -void WebSocketHandshakeRequestHandler::RemoveHeaders( - const char* const headers_to_remove[], - size_t headers_to_remove_len) { - DCHECK(!headers_.empty()); - headers_ = FilterHeaders( - headers_, headers_to_remove, headers_to_remove_len); -} - -HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo( - const GURL& url, std::string* challenge) { - HttpRequestInfo request_info; - request_info.url = url; - size_t method_end = base::StringPiece(request_line_).find_first_of(" "); - if (method_end != base::StringPiece::npos) - request_info.method = std::string(request_line_.data(), method_end); - - request_info.extra_headers.Clear(); - request_info.extra_headers.AddHeadersFromString(headers_); - - request_info.extra_headers.RemoveHeader(websockets::kUpgrade); - request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection); - - std::string key; - bool header_present = request_info.extra_headers.GetHeader( - websockets::kSecWebSocketKey, &key); - DCHECK(header_present); - request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey); - *challenge = key; - return request_info; -} - -bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( - const GURL& url, - SpdyHeaderBlock* headers, - std::string* challenge, - int spdy_protocol_version) { - // Construct opening handshake request headers as a SPDY header block. - // For details, see WebSocket Layering over SPDY/3 Draft 8. - if (spdy_protocol_version <= 2) { - (*headers)["path"] = url.path(); - (*headers)["version"] = "WebSocket/13"; - (*headers)["scheme"] = url.scheme(); - } else { - (*headers)[":path"] = url.path(); - (*headers)[":version"] = "WebSocket/13"; - (*headers)[":scheme"] = url.scheme(); - } - - HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n"); - while (iter.GetNext()) { - if (LowerCaseEqualsASCII(iter.name_begin(), - iter.name_end(), - websockets::kUpgradeLowercase) || - LowerCaseEqualsASCII( - iter.name_begin(), iter.name_end(), "connection") || - LowerCaseEqualsASCII(iter.name_begin(), - iter.name_end(), - websockets::kSecWebSocketVersionLowercase)) { - // These headers must be ignored. - continue; - } else if (LowerCaseEqualsASCII(iter.name_begin(), - iter.name_end(), - websockets::kSecWebSocketKeyLowercase)) { - *challenge = iter.values(); - // Sec-WebSocket-Key is not sent to the server. - continue; - } else if (LowerCaseEqualsASCII( - iter.name_begin(), iter.name_end(), "host") || - LowerCaseEqualsASCII( - iter.name_begin(), iter.name_end(), "origin") || - LowerCaseEqualsASCII( - iter.name_begin(), - iter.name_end(), - websockets::kSecWebSocketProtocolLowercase) || - LowerCaseEqualsASCII( - iter.name_begin(), - iter.name_end(), - websockets::kSecWebSocketExtensionsLowercase)) { - // TODO(toyoshim): Some WebSocket extensions may not be compatible with - // SPDY. We should omit them from a Sec-WebSocket-Extension header. - std::string name; - if (spdy_protocol_version <= 2) - name = base::StringToLowerASCII(iter.name()); - else - name = ":" + base::StringToLowerASCII(iter.name()); - (*headers)[name] = iter.values(); - continue; - } - // Others should be sent out to |headers|. - std::string name = base::StringToLowerASCII(iter.name()); - SpdyHeaderBlock::iterator found = headers->find(name); - if (found == headers->end()) { - (*headers)[name] = iter.values(); - } else { - // For now, websocket doesn't use multiple headers, but follows to http. - found->second.append(1, '\0'); // +=() doesn't append 0's - found->second.append(iter.values()); - } - } - - return true; -} - -std::string WebSocketHandshakeRequestHandler::GetRawRequest() { - DCHECK(!request_line_.empty()); - DCHECK(!headers_.empty()); - - std::string raw_request = request_line_ + headers_ + "\r\n"; - raw_length_ = raw_request.size(); - return raw_request; -} - -size_t WebSocketHandshakeRequestHandler::raw_length() const { - DCHECK_GT(raw_length_, 0); - return raw_length_; -} - -WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() - : original_header_length_(0) {} - -WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} - -size_t WebSocketHandshakeResponseHandler::ParseRawResponse( - const char* data, int length) { - DCHECK_GT(length, 0); - if (HasResponse()) { - DCHECK(!status_line_.empty()); - // headers_ might be empty for wrong response from server. - - return 0; - } - - size_t old_original_length = original_.size(); - - original_.append(data, length); - // TODO(ukai): fail fast when response gives wrong status code. - original_header_length_ = HttpUtil::LocateEndOfHeaders( - original_.data(), original_.size(), 0); - if (!HasResponse()) - return length; - - ParseHandshakeHeader(original_.data(), - original_header_length_, - &status_line_, - &headers_); - int header_size = status_line_.size() + headers_.size(); - DCHECK_GE(original_header_length_, header_size); - header_separator_ = std::string(original_.data() + header_size, - original_header_length_ - header_size); - return original_header_length_ - old_original_length; -} - -bool WebSocketHandshakeResponseHandler::HasResponse() const { - return original_header_length_ > 0 && - static_cast<size_t>(original_header_length_) <= original_.size(); -} void ComputeSecWebSocketAccept(const std::string& key, std::string* accept) { @@ -354,145 +20,4 @@ void ComputeSecWebSocketAccept(const std::string& key, base::Base64Encode(hash, accept); } -bool WebSocketHandshakeResponseHandler::ParseResponseInfo( - const HttpResponseInfo& response_info, - const std::string& challenge) { - if (!response_info.headers.get()) - return false; - - // TODO(ricea): Eliminate all the reallocations and string copies. - std::string response_message; - response_message = response_info.headers->GetStatusLine(); - response_message += "\r\n"; - - AppendHeader(websockets::kUpgrade, - websockets::kWebSocketLowercase, - &response_message); - - AppendHeader( - HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message); - - std::string websocket_accept; - ComputeSecWebSocketAccept(challenge, &websocket_accept); - AppendHeader( - websockets::kSecWebSocketAccept, websocket_accept, &response_message); - - void* iter = NULL; - std::string name; - std::string value; - while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { - AppendHeader(name, value, &response_message); - } - response_message += "\r\n"; - - return ParseRawResponse(response_message.data(), - response_message.size()) == response_message.size(); -} - -bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( - const SpdyHeaderBlock& headers, - const std::string& challenge, - int spdy_protocol_version) { - SpdyHeaderBlock::const_iterator status; - if (spdy_protocol_version <= 2) - status = headers.find("status"); - else - status = headers.find(":status"); - if (status == headers.end()) - return false; - - std::string hash = - base::SHA1HashString(challenge + websockets::kWebSocketGuid); - std::string websocket_accept; - base::Base64Encode(hash, &websocket_accept); - - std::string response_message = base::StringPrintf( - "%s %s\r\n", websockets::kHttpProtocolVersion, status->second.c_str()); - - AppendHeader( - websockets::kUpgrade, websockets::kWebSocketLowercase, &response_message); - AppendHeader( - HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message); - AppendHeader( - websockets::kSecWebSocketAccept, websocket_accept, &response_message); - - for (SpdyHeaderBlock::const_iterator iter = headers.begin(); - iter != headers.end(); - ++iter) { - // For each value, if the server sends a NUL-separated list of values, - // we separate that back out into individual headers for each value - // in the list. - if ((spdy_protocol_version <= 2 && - LowerCaseEqualsASCII(iter->first, "status")) || - (spdy_protocol_version >= 3 && - LowerCaseEqualsASCII(iter->first, ":status"))) { - // The status value is already handled as the first line of - // |response_message|. Just skip here. - continue; - } - const std::string& value = iter->second; - size_t start = 0; - size_t end = 0; - do { - end = value.find('\0', start); - std::string tval; - if (end != std::string::npos) - tval = value.substr(start, (end - start)); - else - tval = value.substr(start); - if (spdy_protocol_version >= 3 && - (LowerCaseEqualsASCII(iter->first, - websockets::kSecWebSocketProtocolSpdy3) || - LowerCaseEqualsASCII(iter->first, - websockets::kSecWebSocketExtensionsSpdy3))) - AppendHeader(iter->first.substr(1), tval, &response_message); - else - AppendHeader(iter->first, tval, &response_message); - start = end + 1; - } while (end != std::string::npos); - } - response_message += "\r\n"; - - return ParseRawResponse(response_message.data(), - response_message.size()) == response_message.size(); -} - -void WebSocketHandshakeResponseHandler::GetHeaders( - const char* const headers_to_get[], - size_t headers_to_get_len, - std::vector<std::string>* values) { - DCHECK(HasResponse()); - DCHECK(!status_line_.empty()); - // headers_ might be empty for wrong response from server. - if (headers_.empty()) - return; - - FetchHeaders(headers_, headers_to_get, headers_to_get_len, values); -} - -void WebSocketHandshakeResponseHandler::RemoveHeaders( - const char* const headers_to_remove[], - size_t headers_to_remove_len) { - DCHECK(HasResponse()); - DCHECK(!status_line_.empty()); - // headers_ might be empty for wrong response from server. - if (headers_.empty()) - return; - - headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len); -} - -std::string WebSocketHandshakeResponseHandler::GetRawResponse() const { - DCHECK(HasResponse()); - return original_.substr(0, original_header_length_); -} - -std::string WebSocketHandshakeResponseHandler::GetResponse() { - DCHECK(HasResponse()); - DCHECK(!status_line_.empty()); - // headers_ might be empty for wrong response from server. - - return status_line_ + headers_ + header_separator_; -} - } // namespace net diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h index 73af66d..c65e6d9 100644 --- a/net/websockets/websocket_handshake_handler.h +++ b/net/websockets/websocket_handshake_handler.h @@ -1,124 +1,19 @@ // Copyright (c) 2012 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. -// -// WebSocketHandshake*Handler handles WebSocket handshake request message -// from WebKit renderer process, and WebSocket handshake response message -// from WebSocket server. -// It modifies messages for the following reason: -// - We don't trust WebKit renderer process, so we'll not expose HttpOnly -// cookies to the renderer process, so handles HttpOnly cookies in -// browser process. -// + #ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_ #define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_ #include <string> -#include <vector> - -#include "net/base/net_export.h" -#include "net/http/http_request_info.h" -#include "net/http/http_response_info.h" -#include "net/spdy/spdy_header_block.h" namespace net { +// Given a WebSocket handshake challenge, compute the correct response. +// TODO(ricea): There should probably be a test for this. void ComputeSecWebSocketAccept(const std::string& key, std::string* accept); -class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler { - public: - WebSocketHandshakeRequestHandler(); - ~WebSocketHandshakeRequestHandler() {} - - // Parses WebSocket handshake request from renderer process. - // It assumes a WebSocket handshake request message is given at once, and - // no other data is added to the request message. - bool ParseRequest(const char* data, int length); - - size_t original_length() const; - - // Appends the header value pair for |name| and |value|, if |name| doesn't - // exist. - void AppendHeaderIfMissing(const std::string& name, - const std::string& value); - // Removes the headers that matches (case insensitive). - void RemoveHeaders(const char* const headers_to_remove[], - size_t headers_to_remove_len); - - // Gets request info to open WebSocket connection and fills challenge data in - // |challenge|. - HttpRequestInfo GetRequestInfo(const GURL& url, std::string* challenge); - // Gets request as SpdyHeaderBlock. - // Also, fills challenge data in |challenge|. - bool GetRequestHeaderBlock(const GURL& url, - SpdyHeaderBlock* headers, - std::string* challenge, - int spdy_protocol_version); - // Gets WebSocket handshake raw request message to open WebSocket - // connection. - std::string GetRawRequest(); - // Calling raw_length is valid only after GetRawRequest() call. - size_t raw_length() const; - - private: - std::string request_line_; - std::string headers_; - int original_length_; - int raw_length_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeRequestHandler); -}; - -class NET_EXPORT_PRIVATE WebSocketHandshakeResponseHandler { - public: - WebSocketHandshakeResponseHandler(); - ~WebSocketHandshakeResponseHandler(); - - // Parses WebSocket handshake response from WebSocket server. - // Returns number of bytes in |data| used for WebSocket handshake response - // message. If it already got whole WebSocket handshake response message, - // returns zero. In other words, [data + returned value, data + length) will - // be WebSocket frame data after handshake response message. - // TODO(ukai): fail fast when response gives wrong status code. - size_t ParseRawResponse(const char* data, int length); - // Returns true if it already parses full handshake response message. - bool HasResponse() const; - // Parses WebSocket handshake response info given as HttpResponseInfo. - bool ParseResponseInfo(const HttpResponseInfo& response_info, - const std::string& challenge); - // Parses WebSocket handshake response as SpdyHeaderBlock. - bool ParseResponseHeaderBlock(const SpdyHeaderBlock& headers, - const std::string& challenge, - int spdy_protocol_version); - - // Gets the headers value. - void GetHeaders(const char* const headers_to_get[], - size_t headers_to_get_len, - std::vector<std::string>* values); - // Removes the headers that matches (case insensitive). - void RemoveHeaders(const char* const headers_to_remove[], - size_t headers_to_remove_len); - - // Gets raw WebSocket handshake response received from WebSocket server. - std::string GetRawResponse() const; - - // Gets WebSocket handshake response message sent to renderer process. - std::string GetResponse(); - - private: - // Original bytes input by using ParseRawResponse(). - std::string original_; - // Number of bytes actually used for the handshake response in |original_|. - int original_header_length_; - - std::string status_line_; - std::string headers_; - std::string header_separator_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeResponseHandler); -}; - } // namespace net #endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_ diff --git a/net/websockets/websocket_handshake_handler_spdy_test.cc b/net/websockets/websocket_handshake_handler_spdy_test.cc deleted file mode 100644 index 064bdcf..0000000 --- a/net/websockets/websocket_handshake_handler_spdy_test.cc +++ /dev/null @@ -1,187 +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_handshake_handler.h" - -#include <string> - -#include "net/socket/next_proto.h" -#include "net/spdy/spdy_header_block.h" -#include "net/spdy/spdy_websocket_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace net { - -namespace { - -class WebSocketHandshakeHandlerSpdyTest - : public ::testing::Test, - public ::testing::WithParamInterface<NextProto> { - protected: - WebSocketHandshakeHandlerSpdyTest() : spdy_util_(GetParam()) {} - - SpdyWebSocketTestUtil spdy_util_; -}; - -INSTANTIATE_TEST_CASE_P( - NextProto, - WebSocketHandshakeHandlerSpdyTest, - testing::Values(kProtoDeprecatedSPDY2, - kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); - -TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponse) { - WebSocketHandshakeRequestHandler request_handler; - - static const char kHandshakeRequestMessage[] = - "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-Extensions: foo\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n"; - - EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - - GURL url("ws://example.com/demo"); - std::string challenge; - SpdyHeaderBlock headers; - ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, - &headers, - &challenge, - spdy_util_.spdy_version())); - - EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path")); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty()); - EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host")); - EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin")); - EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol")); - EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions")); - EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme")); - EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version")); - - static const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; - - EXPECT_EQ(expected_challenge, challenge); - - headers.clear(); - - spdy_util_.SetHeader("status", "101 Switching Protocols", &headers); - spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers); - spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers); - - WebSocketHandshakeResponseHandler response_handler; - EXPECT_TRUE(response_handler.ParseResponseHeaderBlock( - headers, challenge, spdy_util_.spdy_version())); - EXPECT_TRUE(response_handler.HasResponse()); - - // Note that order of sec-websocket-* is sensitive with hash_map order. - static const char kHandshakeResponseExpectedMessage[] = - "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-extensions: foo\r\n" - "sec-websocket-protocol: sample\r\n" - "\r\n"; - - EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); -} - -TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponseWithCookies) { - WebSocketHandshakeRequestHandler request_handler; - - // Note that websocket won't use multiple headers in request now. - static const char kHandshakeRequestMessage[] = - "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-Extensions: foo\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" - "\r\n"; - - EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - - GURL url("ws://example.com/demo"); - std::string challenge; - SpdyHeaderBlock headers; - ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url, - &headers, - &challenge, - spdy_util_.spdy_version())); - - EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path")); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty()); - EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty()); - EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host")); - EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin")); - EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol")); - EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions")); - EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme")); - EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version")); - EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1", - headers["cookie"]); - - const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ=="; - - EXPECT_EQ(expected_challenge, challenge); - - headers.clear(); - - spdy_util_.SetHeader("status", "101 Switching Protocols", &headers); - spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers); - spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers); - std::string cookie = "WK-websocket-test=1"; - cookie.append(1, '\0'); - cookie += "WK-websocket-test-httponly=1; HttpOnly"; - headers["set-cookie"] = cookie; - - - WebSocketHandshakeResponseHandler response_handler; - EXPECT_TRUE(response_handler.ParseResponseHeaderBlock( - headers, challenge, spdy_util_.spdy_version())); - EXPECT_TRUE(response_handler.HasResponse()); - - // Note that order of sec-websocket-* is sensitive with hash_map order. - static const char kHandshakeResponseExpectedMessage[] = - "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-extensions: foo\r\n" - "sec-websocket-protocol: sample\r\n" - "set-cookie: WK-websocket-test=1\r\n" - "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" - "\r\n"; - - EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); -} - -} // namespace - -} // namespace net diff --git a/net/websockets/websocket_handshake_handler_test.cc b/net/websockets/websocket_handshake_handler_test.cc index e59a982..8eff571 100644 --- a/net/websockets/websocket_handshake_handler_test.cc +++ b/net/websockets/websocket_handshake_handler_test.cc @@ -4,238 +4,14 @@ #include "net/websockets/websocket_handshake_handler.h" -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_util.h" -#include "url/gurl.h" - #include "testing/gtest/include/gtest/gtest.h" -namespace { - -const char* const kCookieHeaders[] = { - "cookie", "cookie2" -}; - -const char* const kSetCookieHeaders[] = { - "set-cookie", "set-cookie2" -}; - -} // namespace - namespace net { -TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequest) { - WebSocketHandshakeRequestHandler handler; - - static const char kHandshakeRequestMessage[] = - "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" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n"; - - EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - - handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); - - EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest()); -} - -TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) { - WebSocketHandshakeRequestHandler handler; - - static const char kHandshakeRequestMessage[] = - "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" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Cookie: WK-websocket-test=1\r\n" - "\r\n"; - - EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - - handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); - - handler.AppendHeaderIfMissing("Cookie", - "WK-websocket-test=1; " - "WK-websocket-test-httponly=1"); - - static const char kHandshakeRequestExpectedMessage[] = - "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" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Version: 13\r\n" - "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n" - "\r\n"; - - EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest()); -} - -TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) { - WebSocketHandshakeResponseHandler handler; - - static const char kHandshakeResponseMessage[] = - "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"; - - EXPECT_EQ(strlen(kHandshakeResponseMessage), - handler.ParseRawResponse(kHandshakeResponseMessage, - strlen(kHandshakeResponseMessage))); - EXPECT_TRUE(handler.HasResponse()); - - handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders)); - - EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse()); -} - -TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) { - WebSocketHandshakeResponseHandler handler; - - static const char kHandshakeResponseMessage[] = - "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: WK-websocket-test-1\r\n" - "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n" - "\r\n"; - - EXPECT_EQ(strlen(kHandshakeResponseMessage), - handler.ParseRawResponse(kHandshakeResponseMessage, - strlen(kHandshakeResponseMessage))); - EXPECT_TRUE(handler.HasResponse()); - std::vector<std::string> cookies; - handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies); - ASSERT_EQ(2U, cookies.size()); - EXPECT_EQ("WK-websocket-test-1", cookies[0]); - EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]); - handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders)); - - static const char kHandshakeResponseExpectedMessage[] = - "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"; - - EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse()); -} - -TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) { - WebSocketHandshakeResponseHandler handler; - - static const char kBadMessage[] = "\n\n\r\net-Location: w"; - EXPECT_EQ(2U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage))); - EXPECT_TRUE(handler.HasResponse()); - EXPECT_EQ("\n\n", handler.GetResponse()); -} - -TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) { - WebSocketHandshakeResponseHandler handler; - - static const char kBadMessage[] = "\n\r\n\r\net-Location: w"; - EXPECT_EQ(3U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage))); - EXPECT_TRUE(handler.HasResponse()); - EXPECT_EQ("\n\r\n", handler.GetResponse()); -} - -TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) { - WebSocketHandshakeRequestHandler request_handler; - - static const char kHandshakeRequestMessage[] = - "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" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n"; - - EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage, - strlen(kHandshakeRequestMessage))); - - GURL url("ws://example.com/demo"); - std::string challenge; - const HttpRequestInfo& request_info = - request_handler.GetRequestInfo(url, &challenge); - - EXPECT_EQ(url, request_info.url); - EXPECT_EQ("GET", request_info.method); - EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade")); - EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection")); - EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key")); - std::string value; - EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value)); - EXPECT_EQ("example.com", value); - EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Origin", - &value)); - EXPECT_EQ("http://example.com", value); - EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol", - &value)); - EXPECT_EQ("sample", value); - - EXPECT_EQ("dGhlIHNhbXBsZSBub25jZQ==", challenge); - - static const char kHandshakeResponseHeader[] = - "HTTP/1.1 101 Switching Protocols\r\n" - "Sec-WebSocket-Protocol: sample\r\n"; - - std::string raw_headers = - HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader, - strlen(kHandshakeResponseHeader)); - HttpResponseInfo response_info; - response_info.headers = new HttpResponseHeaders(raw_headers); - - EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(), - "HTTP/1.1 101 ", false)); - EXPECT_FALSE(response_info.headers->HasHeader("Upgrade")); - EXPECT_FALSE(response_info.headers->HasHeader("Connection")); - EXPECT_FALSE(response_info.headers->HasHeader("Sec-WebSocket-Accept")); - EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol", - "sample")); - - WebSocketHandshakeResponseHandler response_handler; - - EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge)); - EXPECT_TRUE(response_handler.HasResponse()); +namespace { - static const char kHandshakeResponseExpectedMessage[] = - "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"; +// TODO(ricea): Put a test for ComputeSecWebSocketAccept() here. - EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse()); -} +} // namespace } // namespace net diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc deleted file mode 100644 index eb653fa..0000000 --- a/net/websockets/websocket_job.cc +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright (c) 2012 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 <algorithm> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/base/net_log.h" -#include "net/cookies/cookie_store.h" -#include "net/http/http_network_session.h" -#include "net/http/http_transaction_factory.h" -#include "net/http/http_util.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_session_pool.h" -#include "net/url_request/url_request_context.h" -#include "net/websockets/websocket_handshake_handler.h" -#include "net/websockets/websocket_net_log_params.h" -#include "net/websockets/websocket_throttle.h" -#include "url/gurl.h" - -static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes. - -namespace { - -// lower-case header names. -const char* const kCookieHeaders[] = { - "cookie", "cookie2" -}; -const char* const kSetCookieHeaders[] = { - "set-cookie", "set-cookie2" -}; - -net::SocketStreamJob* WebSocketJobFactory( - const GURL& url, net::SocketStream::Delegate* delegate, - net::URLRequestContext* context, net::CookieStore* cookie_store) { - net::WebSocketJob* job = new net::WebSocketJob(delegate); - job->InitSocketStream(new net::SocketStream(url, job, context, cookie_store)); - return job; -} - -class WebSocketJobInitSingleton { - private: - friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>; - WebSocketJobInitSingleton() { - net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory); - net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory); - } -}; - -static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init = - LAZY_INSTANCE_INITIALIZER; - -} // anonymous namespace - -namespace net { - -// static -void WebSocketJob::EnsureInit() { - g_websocket_job_init.Get(); -} - -WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate) - : delegate_(delegate), - state_(INITIALIZED), - waiting_(false), - handshake_request_(new WebSocketHandshakeRequestHandler), - handshake_response_(new WebSocketHandshakeResponseHandler), - started_to_send_handshake_request_(false), - handshake_request_sent_(0), - response_cookies_save_index_(0), - spdy_protocol_version_(0), - save_next_cookie_running_(false), - callback_pending_(false), - weak_ptr_factory_(this), - weak_ptr_factory_for_send_pending_(this) { -} - -WebSocketJob::~WebSocketJob() { - DCHECK_EQ(CLOSED, state_); - DCHECK(!delegate_); - DCHECK(!socket_.get()); -} - -void WebSocketJob::Connect() { - DCHECK(socket_.get()); - DCHECK_EQ(state_, INITIALIZED); - state_ = CONNECTING; - socket_->Connect(); -} - -bool WebSocketJob::SendData(const char* data, int len) { - switch (state_) { - case INITIALIZED: - return false; - - case CONNECTING: - return SendHandshakeRequest(data, len); - - case OPEN: - { - scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len); - memcpy(buffer->data(), data, len); - if (current_send_buffer_.get() || !send_buffer_queue_.empty()) { - send_buffer_queue_.push_back(buffer); - return true; - } - current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len); - return SendDataInternal(current_send_buffer_->data(), - current_send_buffer_->BytesRemaining()); - } - - case CLOSING: - case CLOSED: - return false; - } - return false; -} - -void WebSocketJob::Close() { - if (state_ == CLOSED) - return; - - state_ = CLOSING; - if (current_send_buffer_.get()) { - // Will close in SendPending. - return; - } - state_ = CLOSED; - CloseInternal(); -} - -void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) { - state_ = CONNECTING; - socket_->RestartWithAuth(credentials); -} - -void WebSocketJob::DetachDelegate() { - state_ = CLOSED; - WebSocketThrottle::GetInstance()->RemoveFromQueue(this); - - scoped_refptr<WebSocketJob> protect(this); - weak_ptr_factory_.InvalidateWeakPtrs(); - weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs(); - - delegate_ = NULL; - if (socket_.get()) - socket_->DetachDelegate(); - socket_ = NULL; - if (!callback_.is_null()) { - waiting_ = false; - callback_.Reset(); - Release(); // Balanced with OnStartOpenConnection(). - } -} - -int WebSocketJob::OnStartOpenConnection( - SocketStream* socket, const CompletionCallback& callback) { - DCHECK(callback_.is_null()); - state_ = CONNECTING; - - addresses_ = socket->address_list(); - if (!WebSocketThrottle::GetInstance()->PutInQueue(this)) { - return ERR_WS_THROTTLE_QUEUE_TOO_LARGE; - } - - if (delegate_) { - int result = delegate_->OnStartOpenConnection(socket, callback); - DCHECK_EQ(OK, result); - } - if (waiting_) { - // PutInQueue() may set |waiting_| true for throttling. In this case, - // Wakeup() will be called later. - callback_ = callback; - AddRef(); // Balanced when callback_ is cleared. - return ERR_IO_PENDING; - } - return TrySpdyStream(); -} - -void WebSocketJob::OnConnected( - SocketStream* socket, int max_pending_send_allowed) { - if (state_ == CLOSED) - return; - DCHECK_EQ(CONNECTING, state_); - if (delegate_) - delegate_->OnConnected(socket, max_pending_send_allowed); -} - -void WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) { - DCHECK_NE(INITIALIZED, state_); - DCHECK_GT(amount_sent, 0); - if (state_ == CLOSED) - return; - if (state_ == CONNECTING) { - OnSentHandshakeRequest(socket, amount_sent); - return; - } - if (delegate_) { - DCHECK(state_ == OPEN || state_ == CLOSING); - if (!current_send_buffer_.get()) { - VLOG(1) - << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent; - return; - } - current_send_buffer_->DidConsume(amount_sent); - if (current_send_buffer_->BytesRemaining() > 0) - return; - - // We need to report amount_sent of original buffer size, instead of - // amount sent to |socket|. - amount_sent = current_send_buffer_->size(); - DCHECK_GT(amount_sent, 0); - current_send_buffer_ = NULL; - if (!weak_ptr_factory_for_send_pending_.HasWeakPtrs()) { - base::MessageLoopForIO::current()->PostTask( - FROM_HERE, - base::Bind(&WebSocketJob::SendPending, - weak_ptr_factory_for_send_pending_.GetWeakPtr())); - } - delegate_->OnSentData(socket, amount_sent); - } -} - -void WebSocketJob::OnReceivedData( - SocketStream* socket, const char* data, int len) { - DCHECK_NE(INITIALIZED, state_); - if (state_ == CLOSED) - return; - if (state_ == CONNECTING) { - OnReceivedHandshakeResponse(socket, data, len); - return; - } - DCHECK(state_ == OPEN || state_ == CLOSING); - if (delegate_ && len > 0) - delegate_->OnReceivedData(socket, data, len); -} - -void WebSocketJob::OnClose(SocketStream* socket) { - state_ = CLOSED; - WebSocketThrottle::GetInstance()->RemoveFromQueue(this); - - scoped_refptr<WebSocketJob> protect(this); - weak_ptr_factory_.InvalidateWeakPtrs(); - - SocketStream::Delegate* delegate = delegate_; - delegate_ = NULL; - socket_ = NULL; - if (!callback_.is_null()) { - waiting_ = false; - callback_.Reset(); - Release(); // Balanced with OnStartOpenConnection(). - } - if (delegate) - delegate->OnClose(socket); -} - -void WebSocketJob::OnAuthRequired( - SocketStream* socket, AuthChallengeInfo* auth_info) { - if (delegate_) - delegate_->OnAuthRequired(socket, auth_info); -} - -void WebSocketJob::OnSSLCertificateError( - SocketStream* socket, const SSLInfo& ssl_info, bool fatal) { - if (delegate_) - delegate_->OnSSLCertificateError(socket, ssl_info, fatal); -} - -void WebSocketJob::OnError(const SocketStream* socket, int error) { - if (delegate_ && error != ERR_PROTOCOL_SWITCHED) - delegate_->OnError(socket, error); -} - -void WebSocketJob::OnCreatedSpdyStream(int result) { - DCHECK(spdy_websocket_stream_.get()); - DCHECK(socket_.get()); - DCHECK_NE(ERR_IO_PENDING, result); - - if (state_ == CLOSED) { - result = ERR_ABORTED; - } else if (result == OK) { - state_ = CONNECTING; - result = ERR_PROTOCOL_SWITCHED; - } else { - spdy_websocket_stream_.reset(); - } - - CompleteIO(result); -} - -void WebSocketJob::OnSentSpdyHeaders() { - DCHECK_NE(INITIALIZED, state_); - if (state_ != CONNECTING) - return; - size_t original_length = handshake_request_->original_length(); - handshake_request_.reset(); - if (delegate_) - delegate_->OnSentData(socket_.get(), original_length); -} - -void WebSocketJob::OnSpdyResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) { - DCHECK_NE(INITIALIZED, state_); - if (state_ != CONNECTING) - return; - // TODO(toyoshim): Fallback to non-spdy connection? - handshake_response_->ParseResponseHeaderBlock(response_headers, - challenge_, - spdy_protocol_version_); - - SaveCookiesAndNotifyHeadersComplete(); -} - -void WebSocketJob::OnSentSpdyData(size_t bytes_sent) { - DCHECK_NE(INITIALIZED, state_); - DCHECK_NE(CONNECTING, state_); - if (state_ == CLOSED) - return; - if (!spdy_websocket_stream_.get()) - return; - OnSentData(socket_.get(), static_cast<int>(bytes_sent)); -} - -void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) { - DCHECK_NE(INITIALIZED, state_); - DCHECK_NE(CONNECTING, state_); - if (state_ == CLOSED) - return; - if (!spdy_websocket_stream_.get()) - return; - if (buffer) { - OnReceivedData( - socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize()); - } else { - OnReceivedData(socket_.get(), NULL, 0); - } -} - -void WebSocketJob::OnCloseSpdyStream() { - spdy_websocket_stream_.reset(); - OnClose(socket_.get()); -} - -bool WebSocketJob::SendHandshakeRequest(const char* data, int len) { - DCHECK_EQ(state_, CONNECTING); - if (started_to_send_handshake_request_) - return false; - if (!handshake_request_->ParseRequest(data, len)) - return false; - - AddCookieHeaderAndSend(); - return true; -} - -void WebSocketJob::AddCookieHeaderAndSend() { - bool allow = true; - if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies())) - allow = false; - - if (socket_.get() && delegate_ && state_ == CONNECTING) { - handshake_request_->RemoveHeaders(kCookieHeaders, - arraysize(kCookieHeaders)); - if (allow && socket_->cookie_store()) { - // Add cookies, including HttpOnly cookies. - CookieOptions cookie_options; - cookie_options.set_include_httponly(); - socket_->cookie_store()->GetCookiesWithOptionsAsync( - GetURLForCookies(), cookie_options, - base::Bind(&WebSocketJob::LoadCookieCallback, - weak_ptr_factory_.GetWeakPtr())); - } else { - DoSendData(); - } - } -} - -void WebSocketJob::LoadCookieCallback(const std::string& cookie) { - if (!cookie.empty()) - // TODO(tyoshino): Sending cookie means that connection doesn't need - // PRIVACY_MODE_ENABLED as cookies may be server-bound and channel id - // wouldn't negatively affect privacy anyway. Need to restart connection - // or refactor to determine cookie status prior to connecting. - handshake_request_->AppendHeaderIfMissing("Cookie", cookie); - DoSendData(); -} - -void WebSocketJob::DoSendData() { - if (spdy_websocket_stream_.get()) { - scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); - handshake_request_->GetRequestHeaderBlock( - socket_->url(), headers.get(), &challenge_, spdy_protocol_version_); - spdy_websocket_stream_->SendRequest(headers.Pass()); - } else { - const std::string& handshake_request = - handshake_request_->GetRawRequest(); - handshake_request_sent_ = 0; - socket_->net_log()->AddEvent( - NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS, - base::Bind(&NetLogWebSocketHandshakeCallback, &handshake_request)); - socket_->SendData(handshake_request.data(), - handshake_request.size()); - } - // Just buffered in |handshake_request_|. - started_to_send_handshake_request_ = true; -} - -void WebSocketJob::OnSentHandshakeRequest( - SocketStream* socket, int amount_sent) { - DCHECK_EQ(state_, CONNECTING); - handshake_request_sent_ += amount_sent; - DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length()); - if (handshake_request_sent_ >= handshake_request_->raw_length()) { - // handshake request has been sent. - // notify original size of handshake request to delegate. - // Reset the handshake_request_ first in case this object is deleted by the - // delegate. - size_t original_length = handshake_request_->original_length(); - handshake_request_.reset(); - if (delegate_) - delegate_->OnSentData(socket, original_length); - } -} - -void WebSocketJob::OnReceivedHandshakeResponse( - SocketStream* socket, const char* data, int len) { - DCHECK_EQ(state_, CONNECTING); - if (handshake_response_->HasResponse()) { - // If we already has handshake response, received data should be frame - // data, not handshake message. - received_data_after_handshake_.insert( - received_data_after_handshake_.end(), data, data + len); - return; - } - - size_t response_length = handshake_response_->ParseRawResponse(data, len); - if (!handshake_response_->HasResponse()) { - // not yet. we need more data. - return; - } - // handshake message is completed. - std::string raw_response = handshake_response_->GetRawResponse(); - socket_->net_log()->AddEvent( - NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS, - base::Bind(&NetLogWebSocketHandshakeCallback, &raw_response)); - if (len - response_length > 0) { - // If we received extra data, it should be frame data. - DCHECK(received_data_after_handshake_.empty()); - received_data_after_handshake_.assign(data + response_length, data + len); - } - SaveCookiesAndNotifyHeadersComplete(); -} - -void WebSocketJob::SaveCookiesAndNotifyHeadersComplete() { - // handshake message is completed. - DCHECK(handshake_response_->HasResponse()); - - // Extract cookies from the handshake response into a temporary vector. - response_cookies_.clear(); - response_cookies_save_index_ = 0; - - handshake_response_->GetHeaders( - kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_); - - // Now, loop over the response cookies, and attempt to persist each. - SaveNextCookie(); -} - -void WebSocketJob::NotifyHeadersComplete() { - // Remove cookie headers, with malformed headers preserved. - // Actual handshake should be done in Blink. - handshake_response_->RemoveHeaders( - kSetCookieHeaders, arraysize(kSetCookieHeaders)); - std::string handshake_response = handshake_response_->GetResponse(); - handshake_response_.reset(); - std::vector<char> received_data(handshake_response.begin(), - handshake_response.end()); - received_data.insert(received_data.end(), - received_data_after_handshake_.begin(), - received_data_after_handshake_.end()); - received_data_after_handshake_.clear(); - - state_ = OPEN; - - DCHECK(!received_data.empty()); - if (delegate_) - delegate_->OnReceivedData( - socket_.get(), &received_data.front(), received_data.size()); - - WebSocketThrottle::GetInstance()->RemoveFromQueue(this); -} - -void WebSocketJob::SaveNextCookie() { - if (!socket_.get() || !delegate_ || state_ != CONNECTING) - return; - - callback_pending_ = false; - save_next_cookie_running_ = true; - - if (socket_->cookie_store()) { - GURL url_for_cookies = GetURLForCookies(); - - CookieOptions options; - options.set_include_httponly(); - - // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since - // CookieMonster's asynchronous operation APIs queue the callback to run it - // on the thread where the API was called, there won't be race. I.e. unless - // the callback is run synchronously, it won't be run in parallel with this - // method. - while (!callback_pending_ && - response_cookies_save_index_ < response_cookies_.size()) { - std::string cookie = response_cookies_[response_cookies_save_index_]; - response_cookies_save_index_++; - - if (!delegate_->CanSetCookie( - socket_.get(), url_for_cookies, cookie, &options)) - continue; - - callback_pending_ = true; - socket_->cookie_store()->SetCookieWithOptionsAsync( - url_for_cookies, cookie, options, - base::Bind(&WebSocketJob::OnCookieSaved, - weak_ptr_factory_.GetWeakPtr())); - } - } - - save_next_cookie_running_ = false; - - if (callback_pending_) - return; - - response_cookies_.clear(); - response_cookies_save_index_ = 0; - - NotifyHeadersComplete(); -} - -void WebSocketJob::OnCookieSaved(bool cookie_status) { - // Tell the caller of SetCookieWithOptionsAsync() that this completion - // callback is invoked. - // - If the caller checks callback_pending earlier than this callback, the - // caller exits to let this method continue iteration. - // - Otherwise, the caller continues iteration. - callback_pending_ = false; - - // Resume SaveNextCookie if the caller of SetCookieWithOptionsAsync() exited - // the loop. Otherwise, return. - if (save_next_cookie_running_) - return; - - SaveNextCookie(); -} - -GURL WebSocketJob::GetURLForCookies() const { - GURL url = socket_->url(); - std::string scheme = socket_->is_secure() ? "https" : "http"; - url::Replacements<char> replacements; - replacements.SetScheme(scheme.c_str(), url::Component(0, scheme.length())); - return url.ReplaceComponents(replacements); -} - -const AddressList& WebSocketJob::address_list() const { - return addresses_; -} - -int WebSocketJob::TrySpdyStream() { - if (!socket_.get()) - return ERR_FAILED; - - // Check if we have a SPDY session available. - HttpTransactionFactory* factory = - socket_->context()->http_transaction_factory(); - if (!factory) - return OK; - scoped_refptr<HttpNetworkSession> session = factory->GetSession(); - if (!session.get() || !session->params().enable_websocket_over_spdy) - return OK; - SpdySessionPool* spdy_pool = session->spdy_session_pool(); - PrivacyMode privacy_mode = socket_->privacy_mode(); - const SpdySessionKey key(HostPortPair::FromURL(socket_->url()), - socket_->proxy_server(), privacy_mode); - // Forbid wss downgrade to SPDY without SSL. - // TODO(toyoshim): Does it realize the same policy with HTTP? - base::WeakPtr<SpdySession> spdy_session = - spdy_pool->FindAvailableSession(key, *socket_->net_log()); - if (!spdy_session) - return OK; - - SSLInfo ssl_info; - bool was_npn_negotiated; - NextProto protocol_negotiated = kProtoUnknown; - bool use_ssl = spdy_session->GetSSLInfo( - &ssl_info, &was_npn_negotiated, &protocol_negotiated); - if (socket_->is_secure() && !use_ssl) - return OK; - - // Create SpdyWebSocketStream. - spdy_protocol_version_ = spdy_session->GetProtocolVersion(); - spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this)); - - int result = spdy_websocket_stream_->InitializeStream( - socket_->url(), MEDIUM, *socket_->net_log()); - if (result == OK) { - OnConnected(socket_.get(), kMaxPendingSendAllowed); - return ERR_PROTOCOL_SWITCHED; - } - if (result != ERR_IO_PENDING) { - spdy_websocket_stream_.reset(); - return OK; - } - - return ERR_IO_PENDING; -} - -void WebSocketJob::SetWaiting() { - waiting_ = true; -} - -bool WebSocketJob::IsWaiting() const { - return waiting_; -} - -void WebSocketJob::Wakeup() { - if (!waiting_) - return; - waiting_ = false; - DCHECK(!callback_.is_null()); - base::MessageLoopForIO::current()->PostTask( - FROM_HERE, - base::Bind(&WebSocketJob::RetryPendingIO, - weak_ptr_factory_.GetWeakPtr())); -} - -void WebSocketJob::RetryPendingIO() { - int result = TrySpdyStream(); - - // In the case of ERR_IO_PENDING, CompleteIO() will be called from - // OnCreatedSpdyStream(). - if (result != ERR_IO_PENDING) - CompleteIO(result); -} - -void WebSocketJob::CompleteIO(int result) { - // |callback_| may be null if OnClose() or DetachDelegate() was called. - if (!callback_.is_null()) { - CompletionCallback callback = callback_; - callback_.Reset(); - callback.Run(result); - Release(); // Balanced with OnStartOpenConnection(). - } -} - -bool WebSocketJob::SendDataInternal(const char* data, int length) { - if (spdy_websocket_stream_.get()) - return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length); - if (socket_.get()) - return socket_->SendData(data, length); - return false; -} - -void WebSocketJob::CloseInternal() { - if (spdy_websocket_stream_.get()) - spdy_websocket_stream_->Close(); - if (socket_.get()) - socket_->Close(); -} - -void WebSocketJob::SendPending() { - if (current_send_buffer_.get()) - return; - - // Current buffer has been sent. Try next if any. - if (send_buffer_queue_.empty()) { - // No more data to send. - if (state_ == CLOSING) - CloseInternal(); - return; - } - - scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front(); - send_buffer_queue_.pop_front(); - current_send_buffer_ = - new DrainableIOBuffer(next_buffer.get(), next_buffer->size()); - SendDataInternal(current_send_buffer_->data(), - current_send_buffer_->BytesRemaining()); -} - -} // namespace net diff --git a/net/websockets/websocket_job.h b/net/websockets/websocket_job.h deleted file mode 100644 index bad06cf..0000000 --- a/net/websockets/websocket_job.h +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_JOB_H_ -#define NET_WEBSOCKETS_WEBSOCKET_JOB_H_ - -#include <deque> -#include <string> -#include <vector> - -#include "base/memory/weak_ptr.h" -#include "net/base/address_list.h" -#include "net/base/completion_callback.h" -#include "net/socket_stream/socket_stream_job.h" -#include "net/spdy/spdy_header_block.h" -#include "net/spdy/spdy_websocket_stream.h" - -class GURL; - -namespace net { - -class DrainableIOBuffer; -class SSLInfo; -class WebSocketHandshakeRequestHandler; -class WebSocketHandshakeResponseHandler; - -// WebSocket protocol specific job on SocketStream. -// It captures WebSocket handshake message and handles cookie operations. -// Chrome security policy doesn't allow renderer process (except dev tools) -// see HttpOnly cookies, so it injects cookie header in handshake request and -// strips set-cookie headers in handshake response. -// TODO(ukai): refactor websocket.cc to use this. -class NET_EXPORT WebSocketJob - : public SocketStreamJob, - public SocketStream::Delegate, - public SpdyWebSocketStream::Delegate { - public: - // This is state of WebSocket, not SocketStream. - enum State { - INITIALIZED = -1, - CONNECTING = 0, - OPEN = 1, - CLOSING = 2, - CLOSED = 3, - }; - - explicit WebSocketJob(SocketStream::Delegate* delegate); - - static void EnsureInit(); - - State state() const { return state_; } - void Connect() override; - bool SendData(const char* data, int len) override; - void Close() override; - void RestartWithAuth(const AuthCredentials& credentials) override; - void DetachDelegate() override; - - // SocketStream::Delegate methods. - int OnStartOpenConnection(SocketStream* socket, - const CompletionCallback& callback) override; - void OnConnected(SocketStream* socket, int max_pending_send_allowed) override; - void OnSentData(SocketStream* socket, int amount_sent) override; - void OnReceivedData(SocketStream* socket, const char* data, int len) override; - void OnClose(SocketStream* socket) override; - void OnAuthRequired(SocketStream* socket, - AuthChallengeInfo* auth_info) override; - void OnSSLCertificateError(SocketStream* socket, - const SSLInfo& ssl_info, - bool fatal) override; - void OnError(const SocketStream* socket, int error) override; - - // SpdyWebSocketStream::Delegate methods. - void OnCreatedSpdyStream(int status) override; - void OnSentSpdyHeaders() override; - void OnSpdyResponseHeadersUpdated( - const SpdyHeaderBlock& response_headers) override; - void OnSentSpdyData(size_t bytes_sent) override; - void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override; - void OnCloseSpdyStream() override; - - private: - friend class WebSocketThrottle; - friend class WebSocketJobTest; - ~WebSocketJob() override; - - bool SendHandshakeRequest(const char* data, int len); - void AddCookieHeaderAndSend(); - void LoadCookieCallback(const std::string& cookie); - - void OnSentHandshakeRequest(SocketStream* socket, int amount_sent); - // Parses received data into handshake_response_. When finished receiving the - // response, calls SaveCookiesAndNotifyHeadersComplete(). - void OnReceivedHandshakeResponse( - SocketStream* socket, const char* data, int len); - // Saves received cookies to the cookie store, and then notifies the - // delegate_ of completion of handshake. - void SaveCookiesAndNotifyHeadersComplete(); - void SaveNextCookie(); - void OnCookieSaved(bool cookie_status); - // Clears variables for handling cookies, rebuilds handshake string excluding - // cookies, and then pass the handshake string to delegate_. - void NotifyHeadersComplete(); - void DoSendData(); - - GURL GetURLForCookies() const; - - const AddressList& address_list() const; - int TrySpdyStream(); - void SetWaiting(); - bool IsWaiting() const; - void Wakeup(); - void RetryPendingIO(); - void CompleteIO(int result); - - bool SendDataInternal(const char* data, int length); - void CloseInternal(); - void SendPending(); - - SocketStream::Delegate* delegate_; - State state_; - bool waiting_; - AddressList addresses_; - CompletionCallback callback_; // for throttling. - - scoped_ptr<WebSocketHandshakeRequestHandler> handshake_request_; - scoped_ptr<WebSocketHandshakeResponseHandler> handshake_response_; - - bool started_to_send_handshake_request_; - size_t handshake_request_sent_; - - std::vector<std::string> response_cookies_; - size_t response_cookies_save_index_; - - std::deque<scoped_refptr<IOBufferWithSize> > send_buffer_queue_; - scoped_refptr<DrainableIOBuffer> current_send_buffer_; - std::vector<char> received_data_after_handshake_; - - int spdy_protocol_version_; - scoped_ptr<SpdyWebSocketStream> spdy_websocket_stream_; - std::string challenge_; - - bool save_next_cookie_running_; - bool callback_pending_; - - base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_; - base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_for_send_pending_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketJob); -}; - -} // namespace - -#endif // NET_WEBSOCKETS_WEBSOCKET_JOB_H_ diff --git a/net/websockets/websocket_job_test.cc b/net/websockets/websocket_job_test.cc deleted file mode 100644 index c84af8f..0000000 --- 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 diff --git a/net/websockets/websocket_net_log_params.cc b/net/websockets/websocket_net_log_params.cc deleted file mode 100644 index dd9bdde..0000000 --- a/net/websockets/websocket_net_log_params.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2012 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_net_log_params.h" - -#include "base/strings/stringprintf.h" -#include "base/values.h" - -namespace net { - -base::Value* NetLogWebSocketHandshakeCallback( - const std::string* headers, - NetLog::LogLevel /* log_level */) { - base::DictionaryValue* dict = new base::DictionaryValue(); - base::ListValue* header_list = new base::ListValue(); - - size_t last = 0; - size_t headers_size = headers->size(); - size_t pos = 0; - while (pos <= headers_size) { - if (pos == headers_size || - ((*headers)[pos] == '\r' && - pos + 1 < headers_size && (*headers)[pos + 1] == '\n')) { - std::string entry = headers->substr(last, pos - last); - pos += 2; - last = pos; - - header_list->Append(new base::StringValue(entry)); - - if (entry.empty()) { - // Dump WebSocket key3. - std::string key; - for (; pos < headers_size; ++pos) { - key += base::StringPrintf("\\x%02x", (*headers)[pos] & 0xff); - } - header_list->Append(new base::StringValue(key)); - break; - } - } else { - ++pos; - } - } - - dict->Set("headers", header_list); - return dict; -} - -} // namespace net diff --git a/net/websockets/websocket_net_log_params.h b/net/websockets/websocket_net_log_params.h deleted file mode 100644 index 45dabb0..0000000 --- a/net/websockets/websocket_net_log_params.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_ -#define NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_ - -#include <string> - -#include "net/base/net_export.h" -#include "net/base/net_log.h" - -namespace net { - -NET_EXPORT_PRIVATE base::Value* NetLogWebSocketHandshakeCallback( - const std::string* headers, - NetLog::LogLevel /* log_level */); - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_ diff --git a/net/websockets/websocket_net_log_params_test.cc b/net/websockets/websocket_net_log_params_test.cc deleted file mode 100644 index d6d2a0d..0000000 --- a/net/websockets/websocket_net_log_params_test.cc +++ /dev/null @@ -1,50 +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_net_log_params.h" - -#include <string> - -#include "base/callback.h" -#include "base/memory/scoped_ptr.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(NetLogWebSocketHandshakeParameterTest, ToValue) { - base::ListValue* list = new base::ListValue(); - list->Append(new base::StringValue("GET /demo HTTP/1.1")); - list->Append(new base::StringValue("Host: example.com")); - list->Append(new base::StringValue("Connection: Upgrade")); - list->Append(new base::StringValue("Sec-WebSocket-Key2: 12998 5 Y3 1 .P00")); - list->Append(new base::StringValue("Sec-WebSocket-Protocol: sample")); - list->Append(new base::StringValue("Upgrade: WebSocket")); - list->Append(new base::StringValue( - "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5")); - list->Append(new base::StringValue("Origin: http://example.com")); - list->Append(new base::StringValue(std::string())); - list->Append(new base::StringValue( - "\\x00\\x01\\x0a\\x0d\\xff\\xfe\\x0d\\x0a")); - - base::DictionaryValue expected; - expected.Set("headers", list); - - const std::string key("\x00\x01\x0a\x0d\xff\xfe\x0d\x0a", 8); - const std::string testInput = - "GET /demo HTTP/1.1\r\n" - "Host: example.com\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Upgrade: WebSocket\r\n" - "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" - "Origin: http://example.com\r\n" - "\r\n" + - key; - - scoped_ptr<base::Value> actual( - net::NetLogWebSocketHandshakeCallback(&testInput, - net::NetLog::LOG_ALL)); - - EXPECT_TRUE(expected.Equals(actual.get())); -} diff --git a/net/websockets/websocket_throttle.cc b/net/websockets/websocket_throttle.cc deleted file mode 100644 index 59e73fd..0000000 --- a/net/websockets/websocket_throttle.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2012 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_throttle.h" - -#include <algorithm> -#include <set> -#include <string> -#include <utility> - -#include "base/memory/singleton.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "net/base/io_buffer.h" -#include "net/socket_stream/socket_stream.h" -#include "net/websockets/websocket_job.h" - -namespace net { - -namespace { - -const size_t kMaxWebSocketJobsThrottled = 1024; - -} // namespace - -WebSocketThrottle::WebSocketThrottle() { -} - -WebSocketThrottle::~WebSocketThrottle() { - DCHECK(queue_.empty()); - DCHECK(addr_map_.empty()); -} - -// static -WebSocketThrottle* WebSocketThrottle::GetInstance() { - return Singleton<WebSocketThrottle>::get(); -} - -bool WebSocketThrottle::PutInQueue(WebSocketJob* job) { - if (queue_.size() >= kMaxWebSocketJobsThrottled) - return false; - - queue_.push_back(job); - const AddressList& address_list = job->address_list(); - std::set<IPEndPoint> address_set; - for (AddressList::const_iterator addr_iter = address_list.begin(); - addr_iter != address_list.end(); - ++addr_iter) { - const IPEndPoint& address = *addr_iter; - // If |address| is already processed, don't do it again. - if (!address_set.insert(address).second) - continue; - - ConnectingAddressMap::iterator iter = addr_map_.find(address); - if (iter == addr_map_.end()) { - ConnectingAddressMap::iterator new_queue = - addr_map_.insert(make_pair(address, ConnectingQueue())).first; - new_queue->second.push_back(job); - } else { - DCHECK(!iter->second.empty()); - iter->second.push_back(job); - job->SetWaiting(); - DVLOG(1) << "Waiting on " << address.ToString(); - } - } - - return true; -} - -void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) { - ConnectingQueue::iterator queue_iter = - std::find(queue_.begin(), queue_.end(), job); - if (queue_iter == queue_.end()) - return; - queue_.erase(queue_iter); - - std::set<WebSocketJob*> wakeup_candidates; - - const AddressList& resolved_address_list = job->address_list(); - std::set<IPEndPoint> address_set; - for (AddressList::const_iterator addr_iter = resolved_address_list.begin(); - addr_iter != resolved_address_list.end(); - ++addr_iter) { - const IPEndPoint& address = *addr_iter; - // If |address| is already processed, don't do it again. - if (!address_set.insert(address).second) - continue; - - ConnectingAddressMap::iterator map_iter = addr_map_.find(address); - DCHECK(map_iter != addr_map_.end()); - - ConnectingQueue& per_address_queue = map_iter->second; - DCHECK(!per_address_queue.empty()); - // Job may not be front of the queue if the socket is closed while waiting. - ConnectingQueue::iterator per_address_queue_iter = - std::find(per_address_queue.begin(), per_address_queue.end(), job); - bool was_front = false; - if (per_address_queue_iter != per_address_queue.end()) { - was_front = (per_address_queue_iter == per_address_queue.begin()); - per_address_queue.erase(per_address_queue_iter); - } - if (per_address_queue.empty()) { - addr_map_.erase(map_iter); - } else if (was_front) { - // The new front is a wake-up candidate. - wakeup_candidates.insert(per_address_queue.front()); - } - } - - WakeupSocketIfNecessary(wakeup_candidates); -} - -void WebSocketThrottle::WakeupSocketIfNecessary( - const std::set<WebSocketJob*>& wakeup_candidates) { - for (std::set<WebSocketJob*>::const_iterator iter = wakeup_candidates.begin(); - iter != wakeup_candidates.end(); - ++iter) { - WebSocketJob* job = *iter; - if (!job->IsWaiting()) - continue; - - bool should_wakeup = true; - const AddressList& resolved_address_list = job->address_list(); - for (AddressList::const_iterator addr_iter = resolved_address_list.begin(); - addr_iter != resolved_address_list.end(); - ++addr_iter) { - const IPEndPoint& address = *addr_iter; - ConnectingAddressMap::iterator map_iter = addr_map_.find(address); - DCHECK(map_iter != addr_map_.end()); - const ConnectingQueue& per_address_queue = map_iter->second; - if (job != per_address_queue.front()) { - should_wakeup = false; - break; - } - } - if (should_wakeup) - job->Wakeup(); - } -} - -} // namespace net diff --git a/net/websockets/websocket_throttle.h b/net/websockets/websocket_throttle.h deleted file mode 100644 index 0b7a39f..0000000 --- a/net/websockets/websocket_throttle.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_ -#define NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_ - -#include <deque> -#include <map> -#include <set> -#include <string> - -#include "net/base/ip_endpoint.h" -#include "net/base/net_export.h" - -template <typename T> struct DefaultSingletonTraits; - -namespace net { - -class SocketStream; -class WebSocketJob; - -// SocketStreamThrottle for WebSocket protocol. -// Implements the client-side requirements in the spec. -// http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol -// 4.1 Handshake -// 1. If the user agent already has a Web Socket connection to the -// remote host (IP address) identified by /host/, even if known by -// another name, wait until that connection has been established or -// for that connection to have failed. -class NET_EXPORT_PRIVATE WebSocketThrottle { - public: - // Returns the singleton instance. - static WebSocketThrottle* GetInstance(); - - // Puts |job| in |queue_| and queues for the destination addresses - // of |job|. - // If other job is using the same destination address, set |job| waiting. - // - // Returns true if successful. If the number of pending jobs will exceed - // the limit, does nothing and returns false. - bool PutInQueue(WebSocketJob* job); - - // Removes |job| from |queue_| and queues for the destination addresses - // of |job|, and then wakes up jobs that can now resume establishing a - // connection. - void RemoveFromQueue(WebSocketJob* job); - - private: - typedef std::deque<WebSocketJob*> ConnectingQueue; - typedef std::map<IPEndPoint, ConnectingQueue> ConnectingAddressMap; - - WebSocketThrottle(); - ~WebSocketThrottle(); - friend struct DefaultSingletonTraits<WebSocketThrottle>; - - // Examines if any of the given jobs can resume establishing a connection. If - // for all per-address queues for each resolved addresses - // (job->address_list()) of a job, the job is at the front of the queues, the - // job can resume establishing a connection, so wakes up the job. - void WakeupSocketIfNecessary( - const std::set<WebSocketJob*>& wakeup_candidates); - - // Key: string of host's address. Value: queue of sockets for the address. - ConnectingAddressMap addr_map_; - - // Queue of sockets for websockets in opening state. - ConnectingQueue queue_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketThrottle); -}; - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_ diff --git a/net/websockets/websocket_throttle_test.cc b/net/websockets/websocket_throttle_test.cc deleted file mode 100644 index 4e27c83..0000000 --- a/net/websockets/websocket_throttle_test.cc +++ /dev/null @@ -1,359 +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_throttle.h" - -#include <string> - -#include "base/message_loop/message_loop.h" -#include "net/base/address_list.h" -#include "net/base/test_completion_callback.h" -#include "net/socket_stream/socket_stream.h" -#include "net/url_request/url_request_test_util.h" -#include "net/websockets/websocket_job.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" -#include "url/gurl.h" - -namespace net { - -namespace { - -class DummySocketStreamDelegate : public SocketStream::Delegate { - public: - DummySocketStreamDelegate() {} - ~DummySocketStreamDelegate() override {} - void OnConnected(SocketStream* socket, - int max_pending_send_allowed) override {} - void OnSentData(SocketStream* socket, int amount_sent) override {} - void OnReceivedData(SocketStream* socket, - const char* data, - int len) override {} - void OnClose(SocketStream* socket) override {} -}; - -class WebSocketThrottleTestContext : public TestURLRequestContext { - public: - explicit WebSocketThrottleTestContext(bool enable_websocket_over_spdy) - : TestURLRequestContext(true) { - HttpNetworkSession::Params params; - params.enable_websocket_over_spdy = enable_websocket_over_spdy; - Init(); - } -}; - -} // namespace - -class WebSocketThrottleTest : public PlatformTest { - protected: - static IPEndPoint MakeAddr(int a1, int a2, int a3, int a4) { - IPAddressNumber ip; - ip.push_back(a1); - ip.push_back(a2); - ip.push_back(a3); - ip.push_back(a4); - return IPEndPoint(ip, 0); - } - - static void MockSocketStreamConnect( - SocketStream* socket, const AddressList& list) { - socket->set_addresses(list); - // TODO(toyoshim): We should introduce additional tests on cases via proxy. - socket->proxy_info_.UseDirect(); - // In SocketStream::Connect(), it adds reference to socket, which is - // balanced with SocketStream::Finish() that is finally called from - // SocketStream::Close() or SocketStream::DetachDelegate(), when - // next_state_ is not STATE_NONE. - // If next_state_ is STATE_NONE, SocketStream::Close() or - // SocketStream::DetachDelegate() won't call SocketStream::Finish(), - // so Release() won't be called. Thus, we don't need socket->AddRef() - // here. - DCHECK_EQ(socket->next_state_, SocketStream::STATE_NONE); - } -}; - -TEST_F(WebSocketThrottleTest, Throttle) { - // TODO(toyoshim): We need to consider both spdy-enabled and spdy-disabled - // configuration. - WebSocketThrottleTestContext context(true); - DummySocketStreamDelegate delegate; - - // For host1: 1.2.3.4, 1.2.3.5, 1.2.3.6 - AddressList addr; - addr.push_back(MakeAddr(1, 2, 3, 4)); - addr.push_back(MakeAddr(1, 2, 3, 5)); - addr.push_back(MakeAddr(1, 2, 3, 6)); - scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s1( - new SocketStream(GURL("ws://host1/"), w1.get(), &context, NULL)); - w1->InitSocketStream(s1.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr); - - DVLOG(1) << "socket1"; - TestCompletionCallback callback_s1; - // Trying to open connection to host1 will start without wait. - EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback())); - - // Now connecting to host1, so waiting queue looks like - // Address | head -> tail - // 1.2.3.4 | w1 - // 1.2.3.5 | w1 - // 1.2.3.6 | w1 - - // For host2: 1.2.3.4 - addr.clear(); - addr.push_back(MakeAddr(1, 2, 3, 4)); - scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s2( - new SocketStream(GURL("ws://host2/"), w2.get(), &context, NULL)); - w2->InitSocketStream(s2.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s2.get(), addr); - - DVLOG(1) << "socket2"; - TestCompletionCallback callback_s2; - // Trying to open connection to host2 will wait for w1. - EXPECT_EQ(ERR_IO_PENDING, - w2->OnStartOpenConnection(s2.get(), callback_s2.callback())); - // Now waiting queue looks like - // Address | head -> tail - // 1.2.3.4 | w1 w2 - // 1.2.3.5 | w1 - // 1.2.3.6 | w1 - - // For host3: 1.2.3.5 - addr.clear(); - addr.push_back(MakeAddr(1, 2, 3, 5)); - scoped_refptr<WebSocketJob> w3(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s3( - new SocketStream(GURL("ws://host3/"), w3.get(), &context, NULL)); - w3->InitSocketStream(s3.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s3.get(), addr); - - DVLOG(1) << "socket3"; - TestCompletionCallback callback_s3; - // Trying to open connection to host3 will wait for w1. - EXPECT_EQ(ERR_IO_PENDING, - w3->OnStartOpenConnection(s3.get(), callback_s3.callback())); - // Address | head -> tail - // 1.2.3.4 | w1 w2 - // 1.2.3.5 | w1 w3 - // 1.2.3.6 | w1 - - // For host4: 1.2.3.4, 1.2.3.6 - addr.clear(); - addr.push_back(MakeAddr(1, 2, 3, 4)); - addr.push_back(MakeAddr(1, 2, 3, 6)); - scoped_refptr<WebSocketJob> w4(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s4( - new SocketStream(GURL("ws://host4/"), w4.get(), &context, NULL)); - w4->InitSocketStream(s4.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s4.get(), addr); - - DVLOG(1) << "socket4"; - TestCompletionCallback callback_s4; - // Trying to open connection to host4 will wait for w1, w2. - EXPECT_EQ(ERR_IO_PENDING, - w4->OnStartOpenConnection(s4.get(), callback_s4.callback())); - // Address | head -> tail - // 1.2.3.4 | w1 w2 w4 - // 1.2.3.5 | w1 w3 - // 1.2.3.6 | w1 w4 - - // For host5: 1.2.3.6 - addr.clear(); - addr.push_back(MakeAddr(1, 2, 3, 6)); - scoped_refptr<WebSocketJob> w5(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s5( - new SocketStream(GURL("ws://host5/"), w5.get(), &context, NULL)); - w5->InitSocketStream(s5.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s5.get(), addr); - - DVLOG(1) << "socket5"; - TestCompletionCallback callback_s5; - // Trying to open connection to host5 will wait for w1, w4 - EXPECT_EQ(ERR_IO_PENDING, - w5->OnStartOpenConnection(s5.get(), callback_s5.callback())); - // Address | head -> tail - // 1.2.3.4 | w1 w2 w4 - // 1.2.3.5 | w1 w3 - // 1.2.3.6 | w1 w4 w5 - - // For host6: 1.2.3.6 - addr.clear(); - addr.push_back(MakeAddr(1, 2, 3, 6)); - scoped_refptr<WebSocketJob> w6(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s6( - new SocketStream(GURL("ws://host6/"), w6.get(), &context, NULL)); - w6->InitSocketStream(s6.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s6.get(), addr); - - DVLOG(1) << "socket6"; - TestCompletionCallback callback_s6; - // Trying to open connection to host6 will wait for w1, w4, w5 - EXPECT_EQ(ERR_IO_PENDING, - w6->OnStartOpenConnection(s6.get(), callback_s6.callback())); - // Address | head -> tail - // 1.2.3.4 | w1 w2 w4 - // 1.2.3.5 | w1 w3 - // 1.2.3.6 | w1 w4 w5 w6 - - // Receive partial response on w1, still connecting. - DVLOG(1) << "socket1 1"; - static const char kHeader[] = "HTTP/1.1 101 WebSocket Protocol\r\n"; - w1->OnReceivedData(s1.get(), kHeader, sizeof(kHeader) - 1); - EXPECT_FALSE(callback_s2.have_result()); - EXPECT_FALSE(callback_s3.have_result()); - EXPECT_FALSE(callback_s4.have_result()); - EXPECT_FALSE(callback_s5.have_result()); - EXPECT_FALSE(callback_s6.have_result()); - - // Receive rest of handshake response on w1. - DVLOG(1) << "socket1 2"; - static const char kHeader2[] = - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: http://www.google.com\r\n" - "Sec-WebSocket-Location: ws://websocket.chromium.org\r\n" - "\r\n" - "8jKS'y:G*Co,Wxa-"; - w1->OnReceivedData(s1.get(), kHeader2, sizeof(kHeader2) - 1); - base::MessageLoopForIO::current()->RunUntilIdle(); - // Now, w1 is open. - EXPECT_EQ(WebSocketJob::OPEN, w1->state()); - // So, w2 and w3 can start connecting. w4 needs to wait w2 (1.2.3.4) - EXPECT_TRUE(callback_s2.have_result()); - EXPECT_TRUE(callback_s3.have_result()); - EXPECT_FALSE(callback_s4.have_result()); - // Address | head -> tail - // 1.2.3.4 | w2 w4 - // 1.2.3.5 | w3 - // 1.2.3.6 | w4 w5 w6 - - // Closing s1 doesn't change waiting queue. - DVLOG(1) << "socket1 close"; - w1->OnClose(s1.get()); - base::MessageLoopForIO::current()->RunUntilIdle(); - EXPECT_FALSE(callback_s4.have_result()); - s1->DetachDelegate(); - // Address | head -> tail - // 1.2.3.4 | w2 w4 - // 1.2.3.5 | w3 - // 1.2.3.6 | w4 w5 w6 - - // w5 can close while waiting in queue. - DVLOG(1) << "socket5 close"; - // w5 close() closes SocketStream that change state to STATE_CLOSE, calls - // DoLoop(), so OnClose() callback will be called. - w5->OnClose(s5.get()); - base::MessageLoopForIO::current()->RunUntilIdle(); - EXPECT_FALSE(callback_s4.have_result()); - // Address | head -> tail - // 1.2.3.4 | w2 w4 - // 1.2.3.5 | w3 - // 1.2.3.6 | w4 w6 - s5->DetachDelegate(); - - // w6 close abnormally (e.g. renderer finishes) while waiting in queue. - DVLOG(1) << "socket6 close abnormally"; - w6->DetachDelegate(); - base::MessageLoopForIO::current()->RunUntilIdle(); - EXPECT_FALSE(callback_s4.have_result()); - // Address | head -> tail - // 1.2.3.4 | w2 w4 - // 1.2.3.5 | w3 - // 1.2.3.6 | w4 - - // Closing s2 kicks w4 to start connecting. - DVLOG(1) << "socket2 close"; - w2->OnClose(s2.get()); - base::MessageLoopForIO::current()->RunUntilIdle(); - EXPECT_TRUE(callback_s4.have_result()); - // Address | head -> tail - // 1.2.3.4 | w4 - // 1.2.3.5 | w3 - // 1.2.3.6 | w4 - s2->DetachDelegate(); - - DVLOG(1) << "socket3 close"; - w3->OnClose(s3.get()); - base::MessageLoopForIO::current()->RunUntilIdle(); - s3->DetachDelegate(); - w4->OnClose(s4.get()); - s4->DetachDelegate(); - DVLOG(1) << "Done"; - base::MessageLoopForIO::current()->RunUntilIdle(); -} - -TEST_F(WebSocketThrottleTest, NoThrottleForDuplicateAddress) { - WebSocketThrottleTestContext context(true); - DummySocketStreamDelegate delegate; - - // For localhost: 127.0.0.1, 127.0.0.1 - AddressList addr; - addr.push_back(MakeAddr(127, 0, 0, 1)); - addr.push_back(MakeAddr(127, 0, 0, 1)); - scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s1( - new SocketStream(GURL("ws://localhost/"), w1.get(), &context, NULL)); - w1->InitSocketStream(s1.get()); - WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr); - - DVLOG(1) << "socket1"; - TestCompletionCallback callback_s1; - // Trying to open connection to localhost will start without wait. - EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback())); - - DVLOG(1) << "socket1 close"; - w1->OnClose(s1.get()); - s1->DetachDelegate(); - DVLOG(1) << "Done"; - base::MessageLoopForIO::current()->RunUntilIdle(); -} - -// A connection should not be blocked by another connection to the same IP -// with a different port. -TEST_F(WebSocketThrottleTest, NoThrottleForDistinctPort) { - WebSocketThrottleTestContext context(false); - DummySocketStreamDelegate delegate; - IPAddressNumber localhost; - ParseIPLiteralToNumber("127.0.0.1", &localhost); - - // socket1: 127.0.0.1:80 - scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s1( - new SocketStream(GURL("ws://localhost:80/"), w1.get(), &context, NULL)); - w1->InitSocketStream(s1.get()); - MockSocketStreamConnect(s1.get(), - AddressList::CreateFromIPAddress(localhost, 80)); - - DVLOG(1) << "connecting socket1"; - TestCompletionCallback callback_s1; - // Trying to open connection to localhost:80 will start without waiting. - EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback())); - - // socket2: 127.0.0.1:81 - scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate)); - scoped_refptr<SocketStream> s2( - new SocketStream(GURL("ws://localhost:81/"), w2.get(), &context, NULL)); - w2->InitSocketStream(s2.get()); - MockSocketStreamConnect(s2.get(), - AddressList::CreateFromIPAddress(localhost, 81)); - - DVLOG(1) << "connecting socket2"; - TestCompletionCallback callback_s2; - // Trying to open connection to localhost:81 will start without waiting. - EXPECT_EQ(OK, w2->OnStartOpenConnection(s2.get(), callback_s2.callback())); - - DVLOG(1) << "closing socket1"; - w1->OnClose(s1.get()); - s1->DetachDelegate(); - - DVLOG(1) << "closing socket2"; - w2->OnClose(s2.get()); - s2->DetachDelegate(); - DVLOG(1) << "Done"; - base::MessageLoopForIO::current()->RunUntilIdle(); -} - -} // namespace net diff --git a/storage/common/fileapi/file_system_util.cc b/storage/common/fileapi/file_system_util.cc index 13ef05a..353225e4 100644 --- a/storage/common/fileapi/file_system_util.cc +++ b/storage/common/fileapi/file_system_util.cc @@ -488,8 +488,6 @@ base::File::Error NetErrorToFileError(int error) { return base::File::FILE_ERROR_NOT_FOUND; case net::ERR_ACCESS_DENIED: return base::File::FILE_ERROR_ACCESS_DENIED; - case net::ERR_TOO_MANY_SOCKET_STREAMS: - return base::File::FILE_ERROR_TOO_MANY_OPENED; case net::ERR_OUT_OF_MEMORY: return base::File::FILE_ERROR_NO_MEMORY; case net::ERR_FILE_NO_SPACE: |