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 /net/socket_stream | |
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}
Diffstat (limited to 'net/socket_stream')
-rw-r--r-- | net/socket_stream/socket_stream.cc | 1353 | ||||
-rw-r--r-- | net/socket_stream/socket_stream.h | 404 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job.cc | 92 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job.h | 94 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job_manager.cc | 68 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job_manager.h | 46 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_metrics.cc | 86 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_metrics.h | 70 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_metrics_unittest.cc | 221 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_unittest.cc | 1041 |
10 files changed, 0 insertions, 3475 deletions
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 |