Chromium Code Reviews| Index: net/socket/ssl_client_socket_pool.cc | 
| diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc | 
| index b335e46b1f95330864f82f380a9f69f5e23153ee..be9b07537528eba18c12f8186e074d9fe90b9f5b 100644 | 
| --- a/net/socket/ssl_client_socket_pool.cc | 
| +++ b/net/socket/ssl_client_socket_pool.cc | 
| @@ -130,7 +130,9 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name, | 
| ? "pm/" + context.ssl_session_cache_shard | 
| : context.ssl_session_cache_shard)), | 
| callback_( | 
| - base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))) {} | 
| + base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))), | 
| + version_interference_probe_(false), | 
| + version_interference_probe_error_(OK) {} | 
| SSLConnectJob::~SSLConnectJob() { | 
| } | 
| @@ -236,7 +238,10 @@ int SSLConnectJob::DoTransportConnect() { | 
| } | 
| int SSLConnectJob::DoTransportConnectComplete(int result) { | 
| - connection_attempts_ = transport_socket_handle_->connection_attempts(); | 
| + connection_attempts_.insert( | 
| + connection_attempts_.end(), | 
| + transport_socket_handle_->connection_attempts().begin(), | 
| + transport_socket_handle_->connection_attempts().end()); | 
| if (result == OK) { | 
| next_state_ = STATE_SSL_CONNECT; | 
| transport_socket_handle_->socket()->GetPeerAddress(&server_address_); | 
| @@ -321,9 +326,15 @@ int SSLConnectJob::DoSSLConnect() { | 
| connect_timing_.ssl_start = base::TimeTicks::Now(); | 
| + SSLConfig ssl_config = params_->ssl_config(); | 
| + if (version_interference_probe_) { | 
| + DCHECK_EQ(SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max); | 
| + ssl_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2; | 
| + ssl_config.version_interference_probe = true; | 
| 
 
mmenke
2017/04/10 19:08:46
It seems a little bit silly that we're exposing th
 
davidben
2017/04/10 19:52:25
Very little magic, but some. I'd prefer the SSL se
 
mmenke
2017/04/10 19:55:05
That's unfortunate, but I'll defer to you on that.
 
 | 
| + } | 
| ssl_socket_ = client_socket_factory_->CreateSSLClientSocket( | 
| - std::move(transport_socket_handle_), params_->host_and_port(), | 
| - params_->ssl_config(), context_); | 
| + std::move(transport_socket_handle_), params_->host_and_port(), ssl_config, | 
| + context_); | 
| return ssl_socket_->Connect(callback_); | 
| } | 
| @@ -346,6 +357,32 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { | 
| return ERR_ALPN_NEGOTIATION_FAILED; | 
| } | 
| + // Perform a TLS 1.3 version interference probe on various connection | 
| + // errors. The retry will never produce a successful connection but may map | 
| + // errors to ERR_SSL_VERSION_INTERFERENCE, which signals a probable | 
| + // version-interfering middlebox. | 
| + if (params_->ssl_config().version_max == SSL_PROTOCOL_VERSION_TLS1_3 && | 
| + !params_->ssl_config().deprecated_cipher_suites_enabled && | 
| + !version_interference_probe_) { | 
| + if (result == ERR_CONNECTION_CLOSED || result == ERR_SSL_PROTOCOL_ERROR || | 
| + result == ERR_SSL_VERSION_OR_CIPHER_MISMATCH || | 
| + result == ERR_CONNECTION_RESET || | 
| + result == ERR_SSL_BAD_RECORD_MAC_ALERT) { | 
| + // Report the error code for each time a version interference probe is | 
| + // triggered. | 
| + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceProbeTrigger", | 
| + std::abs(result)); | 
| 
 
mmenke
2017/04/10 19:08:46
I think std::abs is declared in <math>?
 
davidben
2017/04/10 19:52:25
cstdlib, apparently.
 
 | 
| + net_log().AddEventWithNetErrorCode( | 
| + NetLogEventType::SSL_VERSION_INTERFERENCE_PROBE, result); | 
| + | 
| + ResetStateForRetry(); | 
| + version_interference_probe_ = true; | 
| + version_interference_probe_error_ = result; | 
| 
 
mmenke
2017/04/10 19:08:46
This was the error that triggered the probe, not t
 
davidben
2017/04/10 19:52:25
What about version_interference_error_ just so it'
 
mmenke
2017/04/10 19:55:06
SGTM
 
 | 
| + next_state_ = GetInitialState(params_->GetConnectionType()); | 
| + return OK; | 
| + } | 
| + } | 
| + | 
| const std::string& host = params_->host_and_port().host(); | 
| bool is_google = | 
| host == "google.com" || | 
| @@ -450,6 +487,14 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { | 
| std::abs(result)); | 
| } | 
| + if (result == ERR_SSL_VERSION_INTERFERENCE) { | 
| + // Record the error code version interference was detected at. | 
| + DCHECK(version_interference_probe_); | 
| + DCHECK_NE(OK, version_interference_probe_error_); | 
| + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceError", | 
| + std::abs(version_interference_probe_error_)); | 
| + } | 
| + | 
| if (result == OK || IsCertificateError(result)) { | 
| SetSocket(std::move(ssl_socket_)); | 
| } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { | 
| @@ -480,6 +525,13 @@ int SSLConnectJob::ConnectInternal() { | 
| return DoLoop(OK); | 
| } | 
| +void SSLConnectJob::ResetStateForRetry() { | 
| + transport_socket_handle_.reset(); | 
| + ssl_socket_.reset(); | 
| + error_response_info_ = HttpResponseInfo(); | 
| + server_address_ = IPEndPoint(); | 
| +} | 
| + | 
| SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory( | 
| TransportClientSocketPool* transport_pool, | 
| SOCKSClientSocketPool* socks_pool, |