This source file includes following definitions.
- OnStartOpenConnection
- OnAuthRequired
- OnSSLCertificateError
- CanGetCookies
- CanSetCookie
- Realloc
- cookie_store_
- GetUserData
- SetUserData
- is_secure
- DetachContext
- CheckPrivacyMode
- Connect
- GetTotalSizeOfPendingWriteBufs
- SendData
- Close
- RestartWithAuth
- DetachDelegate
- proxy_server
- SetClientSocketFactory
- CancelWithError
- CancelWithSSLError
- ContinueDespiteError
- set_addresses
- DoClose
- Finish
- DidEstablishConnection
- DidReceiveData
- DidSendData
- OnIOCompleted
- OnReadCompleted
- OnWriteCompleted
- DoLoop
- DoBeforeConnect
- DoBeforeConnectComplete
- DoResolveProxy
- DoResolveProxyComplete
- DoResolveHost
- DoResolveHostComplete
- DoResolveProtocol
- DoResolveProtocolComplete
- DoTcpConnect
- DoTcpConnectComplete
- DoGenerateProxyAuthToken
- DoGenerateProxyAuthTokenComplete
- DoWriteTunnelHeaders
- DoWriteTunnelHeadersComplete
- DoReadTunnelHeaders
- DoReadTunnelHeadersComplete
- DoSOCKSConnect
- DoSOCKSConnectComplete
- DoSecureProxyConnect
- DoSecureProxyConnectComplete
- DoSecureProxyHandleCertError
- DoSecureProxyHandleCertErrorComplete
- DoSSLConnect
- DoSSLConnectComplete
- DoSSLHandleCertError
- DoSSLHandleCertErrorComplete
- DoReadWrite
- ProxyAuthOrigin
- HandleCertificateRequest
- AllowCertErrorForReconnection
- DoAuthRequired
- DoRestartWithAuth
- HandleCertificateError
- cookie_store
#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/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;
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) {
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),
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_)
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;
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();
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()) {
total_buffered_bytes += current_write_buf_->size();
}
total_buffered_bytes += GetTotalSizeOfPendingWriteBufs();
if (total_buffered_bytes > max_pending_send_allowed_)
return false;
pending_write_bufs_.push_back(make_scoped_refptr(
new IOBufferWithSize(len)));
memcpy(pending_write_bufs_.back()->data(), data, len);
if (!current_write_buf_.get()) {
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_ == 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;
if (next_state_ == STATE_NONE)
return;
net_log_.AddEvent(NetLog::TYPE_CANCELLED);
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_ == STATE_TCP_CONNECT_COMPLETE ||
next_state_ == STATE_AUTH_REQUIRED ||
next_state_ == STATE_RESOLVE_PROTOCOL_COMPLETE) {
DoLoop(ERR_ABORTED);
return;
}
if (next_state_ == STATE_READ_WRITE && !current_write_buf_.get())
DoLoop(ERR_ABORTED);
}
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_) {
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;
if (delegate_)
delegate_->OnSentData(this, bytes_freed);
}
void SocketStream::OnIOCompleted(int result) {
DoLoop(result);
}
void SocketStream::OnReadCompleted(int result) {
if (result == 0) {
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_)
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:
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 (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;
}
return context_->proxy_service()->ResolveProxy(
proxy_url_, &proxy_info_, io_callback_, &pac_request_, 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_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()) {
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;
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;
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) {
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 {
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) {
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;
}
scoped_refptr<HttpResponseHeaders> headers;
headers = new HttpResponseHeaders(
HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh));
if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
next_state_ = STATE_CLOSE;
return ERR_TUNNEL_CONNECTION_FAILED;
}
switch (headers->response_code()) {
case 200:
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:
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_) {
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.server_bound_cert_service = context_->server_bound_cert_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_);
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.server_bound_cert_service = context_->server_bound_cert_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_);
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_);
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 (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_closed_) {
if (!read_buf_.get()) {
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) {
next_state_ = STATE_CLOSE;
server_closed_ = true;
return ERR_CONNECTION_CLOSED;
}
if (result != ERR_IO_PENDING) {
next_state_ = STATE_CLOSE;
server_closed_ = true;
return result;
}
}
DCHECK(read_buf_.get());
}
if (waiting_for_write_completion_)
return ERR_IO_PENDING;
if (!current_write_buf_.get()) {
if (pending_write_bufs_.empty()) {
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) {
next_state_ = STATE_CLOSE;
} else if (result > 0) {
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) {
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;
scoped_refptr<X509Certificate> client_cert;
if (!session->ssl_client_auth_cache()->Lookup(
cert_request_info->host_and_port, &client_cert)) {
return result;
}
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);
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)) {
next_state_ = STATE_CLOSE;
return ERR_UNEXPECTED;
}
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);
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::DomainState domain_state;
const bool fatal = context_->transport_security_state() &&
context_->transport_security_state()->GetDomainState(url_.host(),
SSLConfigService::IsSNIAvailable(context_->ssl_config_service()),
&domain_state) &&
domain_state.ShouldSSLErrorsBeFatal();
delegate_->OnSSLCertificateError(this, ssl_info, fatal);
return ERR_IO_PENDING;
}
CookieStore* SocketStream::cookie_store() const {
return cookie_store_;
}
}