Index: net/http/http_network_transaction.cc |
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc |
index 159d07eeafd737cdf5f3f75da0a2584fa683a431..99a02ba41e5a5f23f3feced21cce881725094ae8 100644 |
--- a/net/http/http_network_transaction.cc |
+++ b/net/http/http_network_transaction.cc |
@@ -182,7 +182,7 @@ int HttpNetworkTransaction::RestartIgnoringLastError( |
if (connection_.socket()->IsConnected()) { |
next_state_ = STATE_WRITE_HEADERS; |
} else { |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
next_state_ = STATE_INIT_CONNECTION; |
} |
@@ -306,7 +306,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { |
reused_socket_ = true; |
} else { |
next_state_ = STATE_INIT_CONNECTION; |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
} |
@@ -356,8 +356,10 @@ LoadState HttpNetworkTransaction::GetLoadState() const { |
switch (next_state_) { |
case STATE_RESOLVE_PROXY_COMPLETE: |
return LOAD_STATE_RESOLVING_PROXY_FOR_URL; |
- case STATE_INIT_CONNECTION_COMPLETE: |
- return connection_.GetLoadState(); |
+ case STATE_RESOLVE_HOST_COMPLETE: |
+ return LOAD_STATE_RESOLVING_HOST; |
+ case STATE_TCP_CONNECT_COMPLETE: |
+ return LOAD_STATE_CONNECTING; |
case STATE_WRITE_HEADERS_COMPLETE: |
case STATE_WRITE_BODY_COMPLETE: |
return LOAD_STATE_SENDING_REQUEST; |
@@ -378,10 +380,10 @@ uint64 HttpNetworkTransaction::GetUploadProgress() const { |
} |
HttpNetworkTransaction::~HttpNetworkTransaction() { |
- // If we still have an open socket, then make sure to disconnect it so we |
- // don't try to reuse it later on. |
+ // If we still have an open socket, then make sure to close it so we don't |
+ // try to reuse it later on. |
if (connection_.is_initialized()) |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
if (pac_request_) |
session_->proxy_service()->CancelPacRequest(pac_request_); |
@@ -429,6 +431,24 @@ int HttpNetworkTransaction::DoLoop(int result) { |
rv = DoInitConnectionComplete(rv); |
TRACE_EVENT_END("http.init_conn", request_, request_->url.spec()); |
break; |
+ case STATE_RESOLVE_HOST: |
+ DCHECK_EQ(OK, rv); |
+ TRACE_EVENT_BEGIN("http.resolve_host", request_, request_->url.spec()); |
+ rv = DoResolveHost(); |
+ break; |
+ case STATE_RESOLVE_HOST_COMPLETE: |
+ rv = DoResolveHostComplete(rv); |
+ TRACE_EVENT_END("http.resolve_host", request_, request_->url.spec()); |
+ break; |
+ case STATE_TCP_CONNECT: |
+ DCHECK_EQ(OK, rv); |
+ TRACE_EVENT_BEGIN("http.connect", request_, request_->url.spec()); |
+ rv = DoTCPConnect(); |
+ break; |
+ case STATE_TCP_CONNECT_COMPLETE: |
+ rv = DoTCPConnectComplete(rv); |
+ TRACE_EVENT_END("http.connect", request_, request_->url.spec()); |
+ break; |
case STATE_SSL_CONNECT: |
DCHECK_EQ(OK, rv); |
TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec()); |
@@ -538,41 +558,83 @@ int HttpNetworkTransaction::DoInitConnection() { |
// Build the string used to uniquely identify connections of this type. |
std::string connection_group; |
- std::string host; |
- int port; |
- if (using_proxy_ || using_tunnel_) { |
- ProxyServer proxy_server = proxy_info_.proxy_server(); |
- connection_group = "proxy/" + proxy_server.ToURI() + "/"; |
- host = proxy_server.HostNoBrackets(); |
- port = proxy_server.port(); |
- } else { |
- host = request_->url.HostNoBrackets(); |
- port = request_->url.EffectiveIntPort(); |
- } |
+ if (using_proxy_ || using_tunnel_) |
+ connection_group = "proxy/" + proxy_info_.proxy_server().ToURI() + "/"; |
if (!using_proxy_) |
connection_group.append(request_->url.GetOrigin().spec()); |
DCHECK(!connection_group.empty()); |
- int rv = connection_.Init(connection_group, host, port, request_->priority, |
- &io_callback_); |
- return rv; |
+ return connection_.Init(connection_group, request_->priority, &io_callback_); |
} |
int HttpNetworkTransaction::DoInitConnectionComplete(int result) { |
if (result < 0) |
- return ReconsiderProxyAfterError(result); |
+ return result; |
DCHECK(connection_.is_initialized()); |
// Set the reused_socket_ flag to indicate that we are using a keep-alive |
// connection. This flag is used to handle errors that occur while we are |
// trying to reuse a keep-alive connection. |
- reused_socket_ = connection_.is_reused(); |
+ reused_socket_ = (connection_.socket() != NULL); |
if (reused_socket_) { |
next_state_ = STATE_WRITE_HEADERS; |
} else { |
- // Now we have a TCP connected socket. Perform other connection setup as |
- // needed. |
+ next_state_ = STATE_RESOLVE_HOST; |
+ } |
+ return OK; |
+} |
+ |
+int HttpNetworkTransaction::DoResolveHost() { |
+ next_state_ = STATE_RESOLVE_HOST_COMPLETE; |
+ |
+ std::string host; |
+ int port; |
+ |
+ // Determine the host and port to connect to. |
+ if (using_proxy_ || using_tunnel_) { |
+ ProxyServer proxy_server = proxy_info_.proxy_server(); |
+ host = proxy_server.HostNoBrackets(); |
+ port = proxy_server.port(); |
+ } else { |
+ // Direct connection |
+ host = request_->url.HostNoBrackets(); |
+ port = request_->url.EffectiveIntPort(); |
+ } |
+ |
+ host_resolution_start_time_ = base::Time::Now(); |
+ |
+ DidStartDnsResolution(host, this); |
+ return resolver_.Resolve(host, port, &addresses_, &io_callback_); |
+} |
+ |
+int HttpNetworkTransaction::DoResolveHostComplete(int result) { |
+ bool ok = (result == OK); |
+ DidFinishDnsResolutionWithStatus(ok, request_->referrer, this); |
+ if (ok) { |
+ next_state_ = STATE_TCP_CONNECT; |
+ } else { |
+ result = ReconsiderProxyAfterError(result); |
+ } |
+ return result; |
+} |
+ |
+int HttpNetworkTransaction::DoTCPConnect() { |
+ next_state_ = STATE_TCP_CONNECT_COMPLETE; |
+ |
+ DCHECK(!connection_.socket()); |
+ |
+ connect_start_time_ = base::Time::Now(); |
+ |
+ ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_); |
+ connection_.set_socket(s); |
+ return connection_.socket()->Connect(&io_callback_); |
+} |
+ |
+int HttpNetworkTransaction::DoTCPConnectComplete(int result) { |
+ // If we are using a direct SSL connection, then go ahead and establish the |
+ // SSL connection, now. Otherwise, we need to first issue a CONNECT request. |
+ if (result == OK) { |
LogTCPConnectedMetrics(); |
if (using_ssl_ && !using_tunnel_) { |
next_state_ = STATE_SSL_CONNECT; |
@@ -581,8 +643,10 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { |
if (using_tunnel_) |
establishing_tunnel_ = true; |
} |
+ } else { |
+ result = ReconsiderProxyAfterError(result); |
} |
- return OK; |
+ return result; |
} |
int HttpNetworkTransaction::DoSSLConnect() { |
@@ -883,7 +947,7 @@ int HttpNetworkTransaction::DoReadBodyComplete(int result) { |
if (done) { |
LogTransactionMetrics(); |
if (!keep_alive) |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
// The next Read call will return 0 (EOF). |
} |
@@ -955,6 +1019,15 @@ int HttpNetworkTransaction::DoDrainBodyForAuthRestartComplete(int result) { |
} |
void HttpNetworkTransaction::LogTCPConnectedMetrics() const { |
+ DCHECK(connect_start_time_ != base::Time()); |
+ base::TimeDelta connect_duration = |
+ base::Time::Now() - connect_start_time_; |
+ |
+ UMA_HISTOGRAM_CLIPPED_TIMES(FieldTrial::MakeName( |
+ "Net.TCP_Connection_Latency", "DnsImpact").data(), connect_duration, |
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10), |
+ 100); |
+ |
base::TimeDelta host_resolution_and_tcp_connection_latency = |
base::Time::Now() - host_resolution_start_time_; |
@@ -1227,7 +1300,7 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { |
// This could be a TLS-intolerant server or an SSL 3.0 server that |
// chose a TLS-only cipher suite. Turn off TLS 1.0 and retry. |
ssl_config_.tls1_enabled = false; |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
next_state_ = STATE_INIT_CONNECTION; |
error = OK; |
@@ -1290,7 +1363,7 @@ bool HttpNetworkTransaction::ShouldResendRequest() const { |
} |
void HttpNetworkTransaction::ResetConnectionAndRequestForResend() { |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
// There are two reasons we need to clear request_headers_. 1) It contains |
// the real request headers, but we may need to resend the CONNECT request |
@@ -1335,7 +1408,7 @@ int HttpNetworkTransaction::ReconsiderProxyAfterError(int error) { |
int rv = session_->proxy_service()->ReconsiderProxyAfterError( |
request_->url, &proxy_info_, &io_callback_, &pac_request_); |
if (rv == OK || rv == ERR_IO_PENDING) { |
- connection_.socket()->Disconnect(); |
+ connection_.set_socket(NULL); |
connection_.Reset(); |
DCHECK(!request_headers_bytes_sent_); |
next_state_ = STATE_RESOLVE_PROXY_COMPLETE; |