#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "net/http/http_response_info.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_status_code.h"
-#include "net/http/http_stream_base.h"
+#include "net/http/http_stream.h"
#include "net/http/http_stream_factory.h"
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "url/gurl.h"
-
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
-#include <algorithm>
-#include "net/proxy/proxy_server.h"
-#endif
-
-
-using base::Time;
-using base::TimeDelta;
+#include "url/url_canon.h"
namespace net {
HttpNetworkSession* session,
const HttpResponseHeaders& headers,
const HostPortPair& http_host_port_pair) {
- std::string alternate_protocol_str;
-
- if (!headers.EnumerateHeader(NULL, kAlternateProtocolHeader,
- &alternate_protocol_str)) {
- // Header is not present.
+ if (!headers.HasHeader(kAlternateProtocolHeader))
return;
+
+ std::vector<std::string> alternate_protocol_values;
+ void* iter = NULL;
+ std::string alternate_protocol_str;
+ while (headers.EnumerateHeader(&iter, kAlternateProtocolHeader,
+ &alternate_protocol_str)) {
+ alternate_protocol_values.push_back(alternate_protocol_str);
}
session->http_stream_factory()->ProcessAlternateProtocol(
session->http_server_properties(),
- alternate_protocol_str,
+ alternate_protocol_values,
http_host_port_pair,
*session);
}
-// Returns true if |error| is a client certificate authentication error.
-bool IsClientCertificateError(int error) {
- switch (error) {
- case ERR_BAD_SSL_CLIENT_AUTH_CERT:
- case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
- case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
- case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
- return true;
- default:
- return false;
- }
-}
-
base::Value* NetLogSSLVersionFallbackCallback(
const GURL* url,
int net_error,
request_(NULL),
priority_(priority),
headers_valid_(false),
- logged_response_time_(false),
fallback_error_code_(ERR_SSL_INAPPROPRIATE_FALLBACK),
request_headers_(),
read_buf_len_(0),
stream_->Close(true /* not reusable */);
} else {
// Otherwise, we try to drain the response body.
- HttpStreamBase* stream = stream_.release();
+ HttpStream* stream = stream_.release();
stream->Drain(session_);
}
}
net_log_ = net_log;
request_ = request_info;
- start_time_ = base::Time::Now();
if (request_->load_flags & LOAD_DISABLE_CERT_REVOCATION_CHECKING) {
server_ssl_config_.rev_checking_enabled = false;
// We should call connection_->set_idle_time(), but this doesn't occur
// often enough to be worth the trouble.
stream_->SetConnectionReused();
- new_stream =
- static_cast<HttpStream*>(stream_.get())->RenewStreamForAuth();
+ new_stream = stream_->RenewStreamForAuth();
}
if (!new_stream) {
if (!stream_.get())
return UploadProgress();
- // TODO(bashi): This cast is temporary. Remove later.
- return static_cast<HttpStream*>(stream_.get())->GetUploadProgress();
+ return stream_->GetUploadProgress();
}
void HttpNetworkTransaction::SetQuicServerInfo(
before_network_start_callback_ = callback;
}
+void HttpNetworkTransaction::SetBeforeProxyHeadersSentCallback(
+ const BeforeProxyHeadersSentCallback& callback) {
+ before_proxy_headers_sent_callback_ = callback;
+}
+
int HttpNetworkTransaction::ResumeNetworkStart() {
DCHECK_EQ(next_state_, STATE_CREATE_STREAM);
return DoLoop(OK);
void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- HttpStreamBase* stream) {
+ HttpStream* stream) {
DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
DCHECK(stream_request_.get());
const HttpResponseInfo& response_info,
const SSLConfig& used_ssl_config,
const ProxyInfo& used_proxy_info,
- HttpStreamBase* stream) {
+ HttpStream* stream) {
DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_);
headers_valid_ = true;
}
void HttpNetworkTransaction::OnIOComplete(int result) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424359 HttpNetworkTransaction::OnIOComplete 1"));
+
int rv = DoLoop(result);
+
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424359 is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "424359 HttpNetworkTransaction::OnIOComplete 2"));
+
if (rv != ERR_IO_PENDING)
DoCallback(rv);
}
&request_headers_);
request_headers_.MergeFrom(request_->extra_headers);
+
+ if (using_proxy && !before_proxy_headers_sent_callback_.is_null())
+ before_proxy_headers_sent_callback_.Run(proxy_info_, &request_headers_);
+
response_.did_use_http_auth =
request_headers_.HasHeader(HttpRequestHeaders::kAuthorization) ||
request_headers_.HasHeader(HttpRequestHeaders::kProxyAuthorization);
return OK;
}
- // After we call RestartWithAuth a new response_time will be recorded, and
- // we need to be cautious about incorrectly logging the duration across the
- // authentication activity.
- if (result == OK)
- LogTransactionConnectedMetrics();
-
// ERR_CONNECTION_CLOSED is treated differently at this point; if partial
// response headers were received, we do the best we can to make sense of it
// and send it back up the stack.
*request_,
request_headers_,
proxy_info_.proxy_server(),
- *response_.headers);
+ *response_.headers.get());
}
return OK;
}
// Clean up connection if we are done.
if (done) {
- LogTransactionMetrics();
stream_->Close(!keep_alive);
// Note: we don't reset the stream here. We've closed it, but we still
// need it around so that callers can call methods such as
return OK;
}
-void HttpNetworkTransaction::LogTransactionConnectedMetrics() {
- if (logged_response_time_)
- return;
-
- logged_response_time_ = true;
-
- base::TimeDelta total_duration = response_.response_time - start_time_;
-
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.Transaction_Connected",
- total_duration,
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
- 100);
-
- bool reused_socket = stream_->IsConnectionReused();
- if (!reused_socket) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.Transaction_Connected_New_b",
- total_duration,
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
- 100);
- }
-
- // Currently, non-HIGHEST priority requests are frame or sub-frame resource
- // types. This will change when we also prioritize certain subresources like
- // css, js, etc.
- if (priority_ != HIGHEST) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.Priority_High_Latency_b",
- total_duration,
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
- 100);
- } else {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.Priority_Low_Latency_b",
- total_duration,
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
- 100);
- }
-}
-
-void HttpNetworkTransaction::LogTransactionMetrics() const {
- base::TimeDelta duration = base::Time::Now() -
- response_.request_time;
- if (60 < duration.InMinutes())
- return;
-
- base::TimeDelta total_duration = base::Time::Now() - start_time_;
-
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.Transaction_Latency_b", duration,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 100);
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.Transaction_Latency_Total",
- total_duration,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10), 100);
-
- if (!stream_->IsConnectionReused()) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Net.Transaction_Latency_Total_New_Connection",
- total_duration, base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10), 100);
- }
-}
-
int HttpNetworkTransaction::HandleCertificateRequest(int error) {
// There are two paths through which the server can request a certificate
// from us. The first is during the initial handshake, the second is
uint16 version_max = server_ssl_config_.version_max;
switch (error) {
+ case ERR_CONNECTION_CLOSED:
case ERR_SSL_PROTOCOL_ERROR:
case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
if (version_max >= SSL_PROTOCOL_VERSION_TLS1 &&
should_fallback = true;
}
break;
+ case ERR_CONNECTION_RESET:
+ if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
+ version_max > server_ssl_config_.version_min) {
+ // Some network devices that inspect application-layer packets seem to
+ // inject TCP reset packets to break the connections when they see TLS
+ // 1.1 in ClientHello or ServerHello. See http://crbug.com/130293.
+ //
+ // Only allow ERR_CONNECTION_RESET to trigger a fallback from TLS 1.1 or
+ // 1.2. We don't lose much in this fallback because the explicit IV for
+ // CBC mode in TLS 1.1 is approximated by record splitting in TLS
+ // 1.0. The fallback will be more painful for TLS 1.2 when we have GCM
+ // support.
+ //
+ // ERR_CONNECTION_RESET is a common network error, so we don't want it
+ // to trigger a version fallback in general, especially the TLS 1.0 ->
+ // SSL 3.0 fallback, which would drop TLS extensions.
+ version_max--;
+ should_fallback = true;
+ }
+ break;
case ERR_SSL_BAD_RECORD_MAC_ALERT:
if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
version_max > server_ssl_config_.version_min) {
proxy_info_.proxy_server().host_port_pair().ToString());
}
case HttpAuth::AUTH_SERVER:
+ if (ForWebSocketHandshake()) {
+ const GURL& url = request_->url;
+ url::Replacements<char> ws_to_http;
+ if (url.SchemeIs("ws")) {
+ ws_to_http.SetScheme("http", url::Component(0, 4));
+ } else {
+ DCHECK(url.SchemeIs("wss"));
+ ws_to_http.SetScheme("https", url::Component(0, 5));
+ }
+ return url.ReplaceComponents(ws_to_http);
+ }
return request_->url;
default:
return GURL();