Switch gcm connection_factory_impl.cc to using services/network/proxy_resolving_client_socket.h
This CL migrates gcm to using proxy_resolving_client_socket.h/cc. As a part of network servicification, we are reducing the //net's API surface. connection_factory_impl.cc calls into static net::InitSocketHandleForTlsConnect(), which will not be exposed by network service. This CL migrates gcm off that static function. Bug: 817094 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_mojo Change-Id: If5a6df107603c676412b971a3d74284a1d01cfc0 Reviewed-on: https://chromium-review.googlesource.com/952333 Reviewed-by: Asanka Herath <asanka@chromium.org> Reviewed-by: Sergey Ulanov <sergeyu@chromium.org> Reviewed-by: Ilya Sherman <isherman@chromium.org> Reviewed-by: Steven Valdez <svaldez@chromium.org> Reviewed-by: Nicolas Zea (slow) <zea@chromium.org> Commit-Queue: Helen Li <xunjieli@chromium.org> Cr-Commit-Position: refs/heads/master@{#544537}
This commit is contained in:
content/browser/renderer_host/p2p
google_apis/gcm
jingle/glue
net/socket
remoting/signaling
services/network
proxy_resolving_client_socket.ccproxy_resolving_client_socket.hproxy_resolving_client_socket_factory.ccproxy_resolving_client_socket_factory.hproxy_resolving_client_socket_unittest.cc
tools/metrics/histograms
@ -126,7 +126,8 @@ bool P2PSocketHostTcpBase::Init(const net::IPEndPoint& local_address,
|
||||
// The default SSLConfig is good enough for us for now.
|
||||
const net::SSLConfig ssl_config;
|
||||
socket_ = proxy_resolving_socket_factory_->CreateSocket(
|
||||
ssl_config, GURL("https://" + dest_host_port_pair.ToString()));
|
||||
ssl_config, GURL("https://" + dest_host_port_pair.ToString()),
|
||||
false /*use_tls*/);
|
||||
|
||||
int status = socket_->Connect(
|
||||
base::Bind(&P2PSocketHostTcpBase::OnConnected,
|
||||
|
@ -67,6 +67,7 @@ component("gcm") {
|
||||
"//base",
|
||||
"//base/third_party/dynamic_annotations",
|
||||
"//net",
|
||||
"//services/network:network_service",
|
||||
"//third_party/leveldatabase",
|
||||
"//url",
|
||||
]
|
||||
|
@ -10,4 +10,5 @@ include_rules = [
|
||||
"+google", # For third_party/protobuf/src.
|
||||
"+net",
|
||||
"+third_party/leveldatabase",
|
||||
"+services/network",
|
||||
]
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "net/socket/client_socket_handle.h"
|
||||
#include "net/socket/client_socket_pool_manager.h"
|
||||
#include "net/ssl/ssl_config_service.h"
|
||||
#include "services/network/proxy_resolving_client_socket.h"
|
||||
|
||||
namespace gcm {
|
||||
|
||||
@ -61,9 +62,6 @@ ConnectionFactoryImpl::ConnectionFactoryImpl(
|
||||
backoff_policy_(backoff_policy),
|
||||
gcm_network_session_(gcm_network_session),
|
||||
http_network_session_(http_network_session),
|
||||
net_log_(
|
||||
net::NetLogWithSource::Make(net_log, net::NetLogSourceType::SOCKET)),
|
||||
proxy_resolve_request_(NULL),
|
||||
connecting_(false),
|
||||
waiting_for_backoff_(false),
|
||||
waiting_for_network_online_(false),
|
||||
@ -79,11 +77,6 @@ ConnectionFactoryImpl::ConnectionFactoryImpl(
|
||||
ConnectionFactoryImpl::~ConnectionFactoryImpl() {
|
||||
CloseSocket();
|
||||
net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
|
||||
if (proxy_resolve_request_) {
|
||||
gcm_network_session_->proxy_resolution_service()->CancelRequest(
|
||||
proxy_resolve_request_);
|
||||
proxy_resolve_request_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::Initialize(
|
||||
@ -299,11 +292,11 @@ GURL ConnectionFactoryImpl::GetCurrentEndpoint() const {
|
||||
}
|
||||
|
||||
net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() {
|
||||
if (!socket_handle_.socket())
|
||||
if (!socket_)
|
||||
return net::IPEndPoint();
|
||||
|
||||
net::IPEndPoint ip_endpoint;
|
||||
int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint);
|
||||
int result = socket_->GetPeerAddress(&ip_endpoint);
|
||||
if (result != net::OK)
|
||||
return net::IPEndPoint();
|
||||
|
||||
@ -318,7 +311,7 @@ void ConnectionFactoryImpl::ConnectImpl() {
|
||||
void ConnectionFactoryImpl::StartConnection() {
|
||||
DCHECK(!IsEndpointReachable());
|
||||
// TODO(zea): Make this a dcheck again. crbug.com/462319
|
||||
CHECK(!socket_handle_.socket());
|
||||
CHECK(!socket_);
|
||||
|
||||
// TODO(zea): if the network is offline, don't attempt to connect.
|
||||
// See crbug.com/396687
|
||||
@ -327,13 +320,14 @@ void ConnectionFactoryImpl::StartConnection() {
|
||||
GURL current_endpoint = GetCurrentEndpoint();
|
||||
recorder_->RecordConnectionInitiated(current_endpoint.host());
|
||||
UpdateFromHttpNetworkSession();
|
||||
int status = gcm_network_session_->proxy_resolution_service()->ResolveProxy(
|
||||
current_endpoint, std::string(), &proxy_info_,
|
||||
base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
&proxy_resolve_request_, NULL, net_log_);
|
||||
net::SSLConfig ssl_config;
|
||||
gcm_network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
|
||||
socket_ = std::make_unique<network::ProxyResolvingClientSocket>(
|
||||
gcm_network_session_, ssl_config, current_endpoint, true /*use_tls*/);
|
||||
int status = socket_->Connect(base::BindRepeating(
|
||||
&ConnectionFactoryImpl::OnConnectDone, weak_ptr_factory_.GetWeakPtr()));
|
||||
if (status != net::ERR_IO_PENDING)
|
||||
OnProxyResolveDone(status);
|
||||
OnConnectDone(status);
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::InitHandler() {
|
||||
@ -381,8 +375,7 @@ void ConnectionFactoryImpl::InitHandler() {
|
||||
"but does not have any effect on other Google Cloud messages."
|
||||
)");
|
||||
|
||||
connection_handler_->Init(login_request, traffic_annotation,
|
||||
socket_handle_.socket());
|
||||
connection_handler_->Init(login_request, traffic_annotation, socket_.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<net::BackoffEntry> ConnectionFactoryImpl::CreateBackoffEntry(
|
||||
@ -405,15 +398,8 @@ base::TimeTicks ConnectionFactoryImpl::NowTicks() {
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::OnConnectDone(int result) {
|
||||
DCHECK_NE(net::ERR_IO_PENDING, result);
|
||||
if (result != net::OK) {
|
||||
// If the connection fails, try another proxy.
|
||||
result = ReconsiderProxyAfterError(result);
|
||||
// ReconsiderProxyAfterError either returns an error (in which case it is
|
||||
// not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering
|
||||
// another proxy.
|
||||
DCHECK_NE(result, net::OK);
|
||||
if (result == net::ERR_IO_PENDING)
|
||||
return; // Proxy reconsideration pending. Return.
|
||||
LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
|
||||
UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", false);
|
||||
recorder_->RecordConnectionFailure(result);
|
||||
@ -436,9 +422,6 @@ void ConnectionFactoryImpl::OnConnectDone(int result) {
|
||||
|
||||
UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", true);
|
||||
UMA_HISTOGRAM_COUNTS("GCM.ConnectionEndpoint", next_endpoint_);
|
||||
UMA_HISTOGRAM_BOOLEAN("GCM.ConnectedViaProxy",
|
||||
!(proxy_info_.is_empty() || proxy_info_.is_direct()));
|
||||
ReportSuccessfulProxyConnection();
|
||||
recorder_->RecordConnectionSuccess();
|
||||
|
||||
// Reset the endpoint back to the default.
|
||||
@ -478,106 +461,15 @@ void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
|
||||
listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP());
|
||||
}
|
||||
|
||||
// This has largely been copied from
|
||||
// HttpStreamFactoryImpl::Job::DoResolveProxyComplete. This should be
|
||||
// refactored into some common place.
|
||||
void ConnectionFactoryImpl::OnProxyResolveDone(int status) {
|
||||
proxy_resolve_request_ = NULL;
|
||||
DVLOG(1) << "Proxy resolution status: " << status;
|
||||
|
||||
DCHECK_NE(status, net::ERR_IO_PENDING);
|
||||
if (status == net::OK) {
|
||||
// Remove unsupported proxies from the list.
|
||||
proxy_info_.RemoveProxiesWithoutScheme(
|
||||
net::ProxyServer::SCHEME_DIRECT |
|
||||
net::ProxyServer::SCHEME_HTTP | net::ProxyServer::SCHEME_HTTPS |
|
||||
net::ProxyServer::SCHEME_SOCKS4 | net::ProxyServer::SCHEME_SOCKS5);
|
||||
|
||||
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.
|
||||
status = net::ERR_NO_SUPPORTED_PROXIES;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != net::OK) {
|
||||
// Failed to resolve proxy. Retry later.
|
||||
OnConnectDone(status);
|
||||
return;
|
||||
}
|
||||
|
||||
DVLOG(1) << "Resolved proxy with PAC:" << proxy_info_.ToPacString();
|
||||
|
||||
net::SSLConfig ssl_config;
|
||||
gcm_network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
|
||||
status = net::InitSocketHandleForTlsConnect(
|
||||
net::HostPortPair::FromURL(GetCurrentEndpoint()),
|
||||
gcm_network_session_,
|
||||
proxy_info_,
|
||||
ssl_config,
|
||||
ssl_config,
|
||||
net::PRIVACY_MODE_DISABLED,
|
||||
net_log_,
|
||||
&socket_handle_,
|
||||
base::Bind(&ConnectionFactoryImpl::OnConnectDone,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
if (status != net::ERR_IO_PENDING)
|
||||
OnConnectDone(status);
|
||||
}
|
||||
|
||||
// This has largely been copied from
|
||||
// HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError. This should be
|
||||
// refactored into some common place.
|
||||
// This method reconsiders the proxy on certain errors. If it does reconsider
|
||||
// a proxy it always returns ERR_IO_PENDING and posts a call to
|
||||
// OnProxyResolveDone with the result of the reconsideration.
|
||||
int ConnectionFactoryImpl::ReconsiderProxyAfterError(int error) {
|
||||
DCHECK(!proxy_resolve_request_);
|
||||
DCHECK_NE(error, net::OK);
|
||||
DCHECK_NE(error, net::ERR_IO_PENDING);
|
||||
|
||||
// Check if the error was a proxy failure.
|
||||
if (!net::CanFalloverToNextProxy(&error))
|
||||
return error;
|
||||
|
||||
net::SSLConfig ssl_config;
|
||||
gcm_network_session_->ssl_config_service()->GetSSLConfig(&ssl_config);
|
||||
if (proxy_info_.is_https() && ssl_config.send_client_cert) {
|
||||
gcm_network_session_->ssl_client_auth_cache()->Remove(
|
||||
proxy_info_.proxy_server().host_port_pair());
|
||||
}
|
||||
|
||||
if (!proxy_info_.Fallback(error, net_log_)) {
|
||||
// There was nothing left to fall-back to, so fail the transaction
|
||||
// with the last connection error we got.
|
||||
return error;
|
||||
}
|
||||
|
||||
CloseSocket();
|
||||
|
||||
// If there is new proxy info, post OnProxyResolveDone to retry it.
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::Bind(&ConnectionFactoryImpl::OnProxyResolveDone,
|
||||
weak_ptr_factory_.GetWeakPtr(), net::OK));
|
||||
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::ReportSuccessfulProxyConnection() {
|
||||
if (gcm_network_session_ && gcm_network_session_->proxy_resolution_service())
|
||||
gcm_network_session_->proxy_resolution_service()->ReportSuccess(proxy_info_,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::CloseSocket() {
|
||||
// The connection handler needs to be reset, else it'll attempt to keep using
|
||||
// the destroyed socket.
|
||||
if (connection_handler_)
|
||||
connection_handler_->Reset();
|
||||
|
||||
if (socket_handle_.socket() && socket_handle_.socket()->IsConnected())
|
||||
socket_handle_.socket()->Disconnect();
|
||||
socket_handle_.Reset();
|
||||
if (socket_)
|
||||
socket_->Disconnect();
|
||||
socket_ = nullptr;
|
||||
}
|
||||
|
||||
void ConnectionFactoryImpl::UpdateFromHttpNetworkSession() {
|
||||
|
@ -18,11 +18,12 @@
|
||||
#include "net/base/backoff_entry.h"
|
||||
#include "net/base/network_change_notifier.h"
|
||||
#include "net/log/net_log_with_source.h"
|
||||
#include "net/proxy_resolution/proxy_info.h"
|
||||
#include "net/proxy_resolution/proxy_resolution_service.h"
|
||||
#include "net/socket/client_socket_handle.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace network {
|
||||
class ProxyResolvingClientSocket;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class HttpNetworkSession;
|
||||
class NetLog;
|
||||
@ -123,12 +124,6 @@ class GCM_EXPORT ConnectionFactoryImpl :
|
||||
// handshake. On connection/handshake failure, goes into backoff.
|
||||
void ConnectImpl();
|
||||
|
||||
// Proxy resolution and connection functions.
|
||||
void OnProxyResolveDone(int status);
|
||||
void OnProxyConnectDone(int status);
|
||||
int ReconsiderProxyAfterError(int error);
|
||||
void ReportSuccessfulProxyConnection();
|
||||
|
||||
// Closes the local socket if one is present, and resets connection handler.
|
||||
void CloseSocket();
|
||||
|
||||
@ -157,15 +152,8 @@ class GCM_EXPORT ConnectionFactoryImpl :
|
||||
// HTTP Network session. If set, is used for extracting proxy auth
|
||||
// credentials. If nullptr, is ignored.
|
||||
net::HttpNetworkSession* http_network_session_;
|
||||
// Net log to use in connection attempts.
|
||||
net::NetLogWithSource net_log_;
|
||||
// The current proxy resolution request, if one exists. Owned by the proxy
|
||||
// service.
|
||||
net::ProxyResolutionService::Request* proxy_resolve_request_;
|
||||
// The current proxy info.
|
||||
net::ProxyInfo proxy_info_;
|
||||
// The handle to the socket for the current connection, if one exists.
|
||||
net::ClientSocketHandle socket_handle_;
|
||||
std::unique_ptr<network::ProxyResolvingClientSocket> socket_;
|
||||
// Current backoff entry.
|
||||
std::unique_ptr<net::BackoffEntry> backoff_entry_;
|
||||
// Backoff entry from previous connection attempt. Updated on each login
|
||||
|
@ -39,7 +39,8 @@ XmppClientSocketFactory::CreateTransportClientSocket(
|
||||
const net::HostPortPair& host_and_port) {
|
||||
// TODO(akalin): Use socket pools.
|
||||
auto transport_socket = proxy_resolving_socket_factory_.CreateSocket(
|
||||
ssl_config_, GURL("https://" + host_and_port.ToString()));
|
||||
ssl_config_, GURL("https://" + host_and_port.ToString()),
|
||||
false /*use_tls*/);
|
||||
return (use_fake_ssl_client_socket_
|
||||
? std::unique_ptr<net::StreamSocket>(
|
||||
new FakeSSLClientSocket(std::move(transport_socket)))
|
||||
|
@ -427,6 +427,8 @@ int InitSocketHandleForRawConnect(const HostPortPair& host_port_pair,
|
||||
|
||||
int InitSocketHandleForTlsConnect(const HostPortPair& endpoint,
|
||||
HttpNetworkSession* session,
|
||||
int request_load_flags,
|
||||
RequestPriority request_priority,
|
||||
const ProxyInfo& proxy_info,
|
||||
const SSLConfig& ssl_config_for_origin,
|
||||
const SSLConfig& ssl_config_for_proxy,
|
||||
@ -436,8 +438,6 @@ int InitSocketHandleForTlsConnect(const HostPortPair& endpoint,
|
||||
const CompletionCallback& callback) {
|
||||
DCHECK(socket_handle);
|
||||
HttpRequestHeaders request_extra_headers;
|
||||
int request_load_flags = 0;
|
||||
RequestPriority request_priority = MEDIUM;
|
||||
return InitSocketPoolHelper(
|
||||
ClientSocketPoolManager::SSL_GROUP, endpoint, request_extra_headers,
|
||||
request_load_flags, request_priority, session, proxy_info,
|
||||
|
@ -146,6 +146,7 @@ int InitSocketHandleForWebSocketRequest(
|
||||
const OnHostResolutionCallback& resolution_callback,
|
||||
const CompletionCallback& callback);
|
||||
|
||||
// Deprecated: Please do not use this outside of //net and //services/network.
|
||||
// A helper method that uses the passed in proxy information to initialize a
|
||||
// ClientSocketHandle with the relevant socket pool. Use this method for
|
||||
// a raw socket connection to a host-port pair (that needs to tunnel through
|
||||
@ -163,6 +164,7 @@ NET_EXPORT int InitSocketHandleForRawConnect(
|
||||
ClientSocketHandle* socket_handle,
|
||||
const CompletionCallback& callback);
|
||||
|
||||
// Deprecated: Please do not use this outside of //net and //services/network.
|
||||
// A helper method that uses the passed in proxy information to initialize a
|
||||
// ClientSocketHandle with the relevant socket pool. Use this method for
|
||||
// a raw socket connection with TLS negotiation to a host-port pair (that needs
|
||||
@ -170,6 +172,8 @@ NET_EXPORT int InitSocketHandleForRawConnect(
|
||||
NET_EXPORT int InitSocketHandleForTlsConnect(
|
||||
const HostPortPair& host_port_pair,
|
||||
HttpNetworkSession* session,
|
||||
int request_load_flags,
|
||||
RequestPriority request_priority,
|
||||
const ProxyInfo& proxy_info,
|
||||
const SSLConfig& ssl_config_for_origin,
|
||||
const SSLConfig& ssl_config_for_proxy,
|
||||
|
@ -1212,6 +1212,7 @@ int MockSSLClientSocket::Write(
|
||||
|
||||
int MockSSLClientSocket::Connect(const CompletionCallback& callback) {
|
||||
DCHECK(transport_->socket()->IsConnected());
|
||||
data_->is_connect_data_consumed = true;
|
||||
if (data_->connect.result == OK)
|
||||
connected_ = true;
|
||||
if (data_->connect.mode == ASYNC) {
|
||||
|
@ -360,6 +360,9 @@ struct SSLSocketDataProvider {
|
||||
SSLSocketDataProvider(const SSLSocketDataProvider& other);
|
||||
~SSLSocketDataProvider();
|
||||
|
||||
// Returns whether MockConnect data has been consumed.
|
||||
bool ConnectDataConsumed() const { return is_connect_data_consumed; }
|
||||
|
||||
// Result for Connect().
|
||||
MockConnect connect;
|
||||
|
||||
@ -374,6 +377,8 @@ struct SSLSocketDataProvider {
|
||||
|
||||
ChannelIDService* channel_id_service;
|
||||
base::Optional<NextProtoVector> next_protos_expected_in_ssl_config;
|
||||
|
||||
bool is_connect_data_consumed = false;
|
||||
};
|
||||
|
||||
// Uses the sequence_number field in the mock reads and writes to
|
||||
|
@ -190,7 +190,8 @@ void XmppSignalStrategy::Core::Connect() {
|
||||
net::SSLConfig(),
|
||||
GURL("https://" +
|
||||
net::HostPortPair(xmpp_server_config_.host, xmpp_server_config_.port)
|
||||
.ToString()));
|
||||
.ToString()),
|
||||
false /*use_tls*/);
|
||||
|
||||
int result = socket_->Connect(base::Bind(
|
||||
&Core::OnSocketConnected, base::Unretained(this)));
|
||||
|
@ -31,13 +31,17 @@ namespace network {
|
||||
ProxyResolvingClientSocket::ProxyResolvingClientSocket(
|
||||
net::HttpNetworkSession* network_session,
|
||||
const net::SSLConfig& ssl_config,
|
||||
const GURL& url)
|
||||
const GURL& url,
|
||||
bool use_tls)
|
||||
: network_session_(network_session),
|
||||
socket_handle_(std::make_unique<net::ClientSocketHandle>()),
|
||||
ssl_config_(ssl_config),
|
||||
proxy_resolve_request_(nullptr),
|
||||
url_(url),
|
||||
use_tls_(use_tls),
|
||||
net_log_(net::NetLogWithSource::Make(network_session_->net_log(),
|
||||
net::NetLogSourceType::SOCKET)),
|
||||
next_state_(STATE_NONE),
|
||||
weak_factory_(this) {
|
||||
// TODO(xunjieli): Handle invalid URLs more gracefully (at mojo API layer
|
||||
// or when the request is created).
|
||||
@ -51,8 +55,8 @@ ProxyResolvingClientSocket::~ProxyResolvingClientSocket() {
|
||||
int ProxyResolvingClientSocket::Read(net::IOBuffer* buf,
|
||||
int buf_len,
|
||||
const net::CompletionCallback& callback) {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->Read(buf, buf_len, callback);
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->Read(buf, buf_len, callback);
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
@ -61,21 +65,21 @@ int ProxyResolvingClientSocket::Write(
|
||||
int buf_len,
|
||||
const net::CompletionCallback& callback,
|
||||
const net::NetworkTrafficAnnotationTag& traffic_annotation) {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->Write(buf, buf_len, callback,
|
||||
traffic_annotation);
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->Write(buf, buf_len, callback,
|
||||
traffic_annotation);
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::SetReceiveBufferSize(int32_t size) {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->SetReceiveBufferSize(size);
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->SetReceiveBufferSize(size);
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::SetSendBufferSize(int32_t size) {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->SetSendBufferSize(size);
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->SetSendBufferSize(size);
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
@ -83,29 +87,16 @@ int ProxyResolvingClientSocket::Connect(
|
||||
const net::CompletionCallback& callback) {
|
||||
DCHECK(user_connect_callback_.is_null());
|
||||
|
||||
// First try to resolve the proxy.
|
||||
// TODO(xunjieli): Having a null ProxyDelegate is bad. Figure out how to
|
||||
// interact with the new interface for proxy delegate.
|
||||
// https://crbug.com/793071.
|
||||
int net_error = network_session_->proxy_resolution_service()->ResolveProxy(
|
||||
url_, "POST", &proxy_info_,
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxy,
|
||||
base::Unretained(this)),
|
||||
&proxy_resolve_request_, nullptr /*proxy_delegate*/, net_log_);
|
||||
if (net_error != net::ERR_IO_PENDING) {
|
||||
// Defer execution of ConnectToProxy instead of calling it
|
||||
// directly here for simplicity. From the caller's point of view,
|
||||
// the connect always happens asynchronously.
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy,
|
||||
weak_factory_.GetWeakPtr(), net_error));
|
||||
next_state_ = STATE_PROXY_RESOLVE;
|
||||
int result = DoLoop(net::OK);
|
||||
if (result == net::ERR_IO_PENDING) {
|
||||
user_connect_callback_ = callback;
|
||||
}
|
||||
user_connect_callback_ = callback;
|
||||
return net::ERR_IO_PENDING;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::Disconnect() {
|
||||
CloseTransportSocket();
|
||||
CloseSocket(true /*close_connection*/);
|
||||
if (proxy_resolve_request_) {
|
||||
network_session_->proxy_resolution_service()->CancelRequest(
|
||||
proxy_resolve_request_);
|
||||
@ -115,24 +106,24 @@ void ProxyResolvingClientSocket::Disconnect() {
|
||||
}
|
||||
|
||||
bool ProxyResolvingClientSocket::IsConnected() const {
|
||||
if (!transport_.get() || !transport_->socket())
|
||||
if (!socket_handle_->socket())
|
||||
return false;
|
||||
return transport_->socket()->IsConnected();
|
||||
return socket_handle_->socket()->IsConnected();
|
||||
}
|
||||
|
||||
bool ProxyResolvingClientSocket::IsConnectedAndIdle() const {
|
||||
if (!transport_.get() || !transport_->socket())
|
||||
if (!socket_handle_->socket())
|
||||
return false;
|
||||
return transport_->socket()->IsConnectedAndIdle();
|
||||
return socket_handle_->socket()->IsConnectedAndIdle();
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::GetPeerAddress(net::IPEndPoint* address) const {
|
||||
if (!transport_.get() || !transport_->socket()) {
|
||||
if (!socket_handle_->socket()) {
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
if (proxy_info_.is_direct())
|
||||
return transport_->socket()->GetPeerAddress(address);
|
||||
return socket_handle_->socket()->GetPeerAddress(address);
|
||||
|
||||
net::IPAddress ip_address;
|
||||
if (!ip_address.AssignFromIPLiteral(url_.HostNoBrackets())) {
|
||||
@ -146,44 +137,48 @@ int ProxyResolvingClientSocket::GetPeerAddress(net::IPEndPoint* address) const {
|
||||
|
||||
int ProxyResolvingClientSocket::GetLocalAddress(
|
||||
net::IPEndPoint* address) const {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->GetLocalAddress(address);
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->GetLocalAddress(address);
|
||||
return net::ERR_SOCKET_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
const net::NetLogWithSource& ProxyResolvingClientSocket::NetLog() const {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->NetLog();
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->NetLog();
|
||||
return net_log_;
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::SetSubresourceSpeculation() {
|
||||
if (transport_.get() && transport_->socket())
|
||||
transport_->socket()->SetSubresourceSpeculation();
|
||||
if (socket_handle_->socket())
|
||||
socket_handle_->socket()->SetSubresourceSpeculation();
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::SetOmniboxSpeculation() {
|
||||
if (transport_.get() && transport_->socket())
|
||||
transport_->socket()->SetOmniboxSpeculation();
|
||||
if (socket_handle_->socket())
|
||||
socket_handle_->socket()->SetOmniboxSpeculation();
|
||||
}
|
||||
|
||||
bool ProxyResolvingClientSocket::WasEverUsed() const {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->WasEverUsed();
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->WasEverUsed();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProxyResolvingClientSocket::WasAlpnNegotiated() const {
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->WasAlpnNegotiated();
|
||||
return false;
|
||||
}
|
||||
|
||||
net::NextProto ProxyResolvingClientSocket::GetNegotiatedProtocol() const {
|
||||
if (transport_.get() && transport_->socket())
|
||||
return transport_->socket()->GetNegotiatedProtocol();
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->GetNegotiatedProtocol();
|
||||
return net::kProtoUnknown;
|
||||
}
|
||||
|
||||
bool ProxyResolvingClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
|
||||
if (socket_handle_->socket())
|
||||
return socket_handle_->socket()->GetSSLInfo(ssl_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -201,11 +196,67 @@ void ProxyResolvingClientSocket::ApplySocketTag(const net::SocketTag& tag) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::ConnectToProxy(int net_error) {
|
||||
proxy_resolve_request_ = nullptr;
|
||||
void ProxyResolvingClientSocket::OnIOComplete(int result) {
|
||||
DCHECK_NE(net::ERR_IO_PENDING, result);
|
||||
int net_error = DoLoop(result);
|
||||
if (net_error != net::ERR_IO_PENDING)
|
||||
base::ResetAndReturn(&user_connect_callback_).Run(net_error);
|
||||
}
|
||||
|
||||
DCHECK_NE(net_error, net::ERR_IO_PENDING);
|
||||
if (net_error == net::OK) {
|
||||
int ProxyResolvingClientSocket::DoLoop(int result) {
|
||||
DCHECK_NE(next_state_, STATE_NONE);
|
||||
int rv = result;
|
||||
do {
|
||||
State state = next_state_;
|
||||
next_state_ = STATE_NONE;
|
||||
switch (state) {
|
||||
case STATE_PROXY_RESOLVE:
|
||||
DCHECK_EQ(net::OK, rv);
|
||||
rv = DoProxyResolve();
|
||||
break;
|
||||
case STATE_PROXY_RESOLVE_COMPLETE:
|
||||
rv = DoProxyResolveComplete(rv);
|
||||
break;
|
||||
case STATE_INIT_CONNECTION:
|
||||
DCHECK_EQ(net::OK, rv);
|
||||
rv = DoInitConnection();
|
||||
break;
|
||||
case STATE_INIT_CONNECTION_COMPLETE:
|
||||
rv = DoInitConnectionComplete(rv);
|
||||
break;
|
||||
case STATE_RESTART_TUNNEL_AUTH:
|
||||
rv = DoRestartTunnelAuth(rv);
|
||||
break;
|
||||
case STATE_RESTART_TUNNEL_AUTH_COMPLETE:
|
||||
rv = DoRestartTunnelAuthComplete(rv);
|
||||
break;
|
||||
default:
|
||||
NOTREACHED() << "bad state";
|
||||
rv = net::ERR_FAILED;
|
||||
break;
|
||||
}
|
||||
} while (rv != net::ERR_IO_PENDING && next_state_ != STATE_NONE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::DoProxyResolve() {
|
||||
next_state_ = STATE_PROXY_RESOLVE_COMPLETE;
|
||||
// TODO(xunjieli): Having a null ProxyDelegate is bad. Figure out how to
|
||||
// interact with the new interface for proxy delegate.
|
||||
// https://crbug.com/793071.
|
||||
// base::Unretained(this) is safe because resolution request is canceled when
|
||||
// |proxy_resolve_request_| is destroyed.
|
||||
return network_session_->proxy_resolution_service()->ResolveProxy(
|
||||
url_, "POST", &proxy_info_,
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::OnIOComplete,
|
||||
base::Unretained(this)),
|
||||
&proxy_resolve_request_, nullptr /*proxy_delegate*/, net_log_);
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::DoProxyResolveComplete(int result) {
|
||||
proxy_resolve_request_ = nullptr;
|
||||
if (result == net::OK) {
|
||||
next_state_ = STATE_INIT_CONNECTION;
|
||||
// Removes unsupported proxies from the list. Currently, this removes
|
||||
// just the SCHEME_QUIC proxy, which doesn't yet support tunneling.
|
||||
// TODO(xunjieli): Allow QUIC proxy once it supports tunneling.
|
||||
@ -217,82 +268,119 @@ void ProxyResolvingClientSocket::ConnectToProxy(int net_error) {
|
||||
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.
|
||||
net_error = net::ERR_NO_SUPPORTED_PROXIES;
|
||||
result = net::ERR_NO_SUPPORTED_PROXIES;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (net_error != net::OK) {
|
||||
CloseTransportSocket();
|
||||
base::ResetAndReturn(&user_connect_callback_).Run(net_error);
|
||||
return;
|
||||
}
|
||||
int ProxyResolvingClientSocket::DoInitConnection() {
|
||||
DCHECK(!socket_handle_->socket());
|
||||
|
||||
next_state_ = STATE_INIT_CONNECTION_COMPLETE;
|
||||
|
||||
transport_.reset(new net::ClientSocketHandle);
|
||||
// Now that the proxy is resolved, issue a socket connect.
|
||||
net::HostPortPair host_port_pair = net::HostPortPair::FromURL(url_);
|
||||
// Ignore socket limit set by socket pool for this type of socket.
|
||||
int request_load_flags = net::LOAD_IGNORE_LIMITS;
|
||||
net::RequestPriority request_priority = net::MAXIMUM_PRIORITY;
|
||||
|
||||
net_error = net::InitSocketHandleForRawConnect(
|
||||
// base::Unretained(this) is safe because request is canceled when
|
||||
// |socket_handle_| is destroyed.
|
||||
if (use_tls_) {
|
||||
return net::InitSocketHandleForTlsConnect(
|
||||
host_port_pair, network_session_, request_load_flags, request_priority,
|
||||
proxy_info_, ssl_config_, ssl_config_, net::PRIVACY_MODE_DISABLED,
|
||||
net_log_, socket_handle_.get(),
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::OnIOComplete,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
return net::InitSocketHandleForRawConnect(
|
||||
host_port_pair, network_session_, request_load_flags, request_priority,
|
||||
proxy_info_, ssl_config_, ssl_config_, net::PRIVACY_MODE_DISABLED,
|
||||
net_log_, transport_.get(),
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone,
|
||||
net_log_, socket_handle_.get(),
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::OnIOComplete,
|
||||
base::Unretained(this)));
|
||||
if (net_error != net::ERR_IO_PENDING) {
|
||||
// Since this method is always called asynchronously. it is OK to call
|
||||
// ConnectToProxyDone synchronously.
|
||||
ConnectToProxyDone(net_error);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::ConnectToProxyDone(int net_error) {
|
||||
if (net_error != net::OK) {
|
||||
// If the connection fails, try another proxy.
|
||||
net_error = ReconsiderProxyAfterError(net_error);
|
||||
int ProxyResolvingClientSocket::DoInitConnectionComplete(int result) {
|
||||
if (result == net::ERR_PROXY_AUTH_REQUESTED) {
|
||||
if (use_tls_) {
|
||||
// Put the in-progress HttpProxyClientSocket into |socket_handle_| to
|
||||
// do tunnel auth. After auth completes, it's important to reset
|
||||
// |socket_handle_|, so it doesn't have a HttpProxyClientSocket when the
|
||||
// code expects an SSLClientSocket. The tunnel restart code is careful to
|
||||
// put it back to the socket pool before returning control to the rest of
|
||||
// this class.
|
||||
socket_handle_.reset(
|
||||
socket_handle_->release_pending_http_proxy_connection());
|
||||
}
|
||||
next_state_ = STATE_RESTART_TUNNEL_AUTH;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result != net::OK) {
|
||||
// ReconsiderProxyAfterError either returns an error (in which case it is
|
||||
// not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering
|
||||
// another proxy.
|
||||
DCHECK_NE(net_error, net::OK);
|
||||
if (net_error == net::ERR_IO_PENDING) {
|
||||
// Proxy reconsideration pending. Return.
|
||||
return;
|
||||
}
|
||||
CloseTransportSocket();
|
||||
} else {
|
||||
network_session_->proxy_resolution_service()->ReportSuccess(proxy_info_,
|
||||
nullptr);
|
||||
return ReconsiderProxyAfterError(result);
|
||||
}
|
||||
base::ResetAndReturn(&user_connect_callback_).Run(net_error);
|
||||
|
||||
network_session_->proxy_resolution_service()->ReportSuccess(proxy_info_,
|
||||
nullptr);
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::CloseTransportSocket() {
|
||||
if (transport_.get() && transport_->socket())
|
||||
transport_->socket()->Disconnect();
|
||||
transport_.reset();
|
||||
int ProxyResolvingClientSocket::DoRestartTunnelAuth(int result) {
|
||||
DCHECK_EQ(net::ERR_PROXY_AUTH_REQUESTED, result);
|
||||
|
||||
net::ProxyClientSocket* proxy_socket =
|
||||
static_cast<net::ProxyClientSocket*>(socket_handle_->socket());
|
||||
|
||||
if (proxy_socket->GetAuthController() &&
|
||||
proxy_socket->GetAuthController()->HaveAuth()) {
|
||||
next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE;
|
||||
// base::Unretained(this) is safe because |proxy_socket| is owned by this.
|
||||
return proxy_socket->RestartWithAuth(base::BindRepeating(
|
||||
&ProxyResolvingClientSocket::OnIOComplete, base::Unretained(this)));
|
||||
}
|
||||
// This socket is unusable if the underlying authentication handler doesn't
|
||||
// already have credentials. It is possible to overcome this hurdle and
|
||||
// finish the handshake if this class exposes an interface for an embedder to
|
||||
// supply credentials.
|
||||
CloseSocket(true /*close_connection*/);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ProxyResolvingClientSocket::DoRestartTunnelAuthComplete(int result) {
|
||||
if (result == net::ERR_PROXY_AUTH_REQUESTED) {
|
||||
// Handle multi-round auth challenge.
|
||||
next_state_ = STATE_RESTART_TUNNEL_AUTH;
|
||||
return result;
|
||||
}
|
||||
if (result == net::OK) {
|
||||
CloseSocket(false /*close_connection*/);
|
||||
// Now that the HttpProxyClientSocket is connected, release it as an idle
|
||||
// socket into the pool and start the connection process from the beginning.
|
||||
next_state_ = STATE_INIT_CONNECTION;
|
||||
return net::OK;
|
||||
}
|
||||
CloseSocket(true /*close_connection*/);
|
||||
return ReconsiderProxyAfterError(result);
|
||||
}
|
||||
|
||||
void ProxyResolvingClientSocket::CloseSocket(bool close_connection) {
|
||||
if (close_connection && socket_handle_->socket())
|
||||
socket_handle_->socket()->Disconnect();
|
||||
socket_handle_->Reset();
|
||||
}
|
||||
|
||||
// This method reconsiders the proxy on certain errors. If it does
|
||||
// reconsider a proxy it always returns ERR_IO_PENDING and posts a call to
|
||||
// ConnectToProxy with the result of the reconsideration.
|
||||
int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) {
|
||||
DCHECK(!socket_handle_->socket());
|
||||
DCHECK(!proxy_resolve_request_);
|
||||
DCHECK_NE(error, net::OK);
|
||||
DCHECK_NE(error, net::ERR_IO_PENDING);
|
||||
|
||||
if (error == net::ERR_PROXY_AUTH_REQUESTED) {
|
||||
net::ProxyClientSocket* proxy_socket =
|
||||
static_cast<net::ProxyClientSocket*>(transport_->socket());
|
||||
|
||||
if (proxy_socket->GetAuthController()->HaveAuth()) {
|
||||
return proxy_socket->RestartWithAuth(
|
||||
base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// Check if the error was a proxy failure.
|
||||
if (!net::CanFalloverToNextProxy(&error))
|
||||
return error;
|
||||
@ -307,14 +395,8 @@ int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) {
|
||||
if (!proxy_info_.Fallback(error, net_log_))
|
||||
return error;
|
||||
|
||||
CloseTransportSocket();
|
||||
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy,
|
||||
weak_factory_.GetWeakPtr(), net::OK));
|
||||
// Since we potentially have another try to go, set the return code code to
|
||||
// ERR_IO_PENDING.
|
||||
return net::ERR_IO_PENDING;
|
||||
next_state_ = STATE_INIT_CONNECTION;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
} // namespace network
|
||||
|
@ -50,10 +50,12 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingClientSocket
|
||||
// any sensitive data (like embedded usernames and passwords), and local data
|
||||
// (i.e. reference fragment) will be sanitized by
|
||||
// net::ProxyResolutionService::ResolveProxyHelper() before the url is
|
||||
// disclosed to the proxy. |network_session| must outlive |this|.
|
||||
// disclosed to the proxy. If |use_tls|, this will try to do a tls connect
|
||||
// instead of a regular tcp connect. |network_session| must outlive |this|.
|
||||
ProxyResolvingClientSocket(net::HttpNetworkSession* network_session,
|
||||
const net::SSLConfig& ssl_config,
|
||||
const GURL& url);
|
||||
const GURL& url,
|
||||
bool use_tls);
|
||||
~ProxyResolvingClientSocket() override;
|
||||
|
||||
// net::StreamSocket implementation.
|
||||
@ -88,29 +90,53 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingClientSocket
|
||||
void ApplySocketTag(const net::SocketTag& tag) override;
|
||||
|
||||
private:
|
||||
enum State {
|
||||
STATE_PROXY_RESOLVE,
|
||||
STATE_PROXY_RESOLVE_COMPLETE,
|
||||
STATE_INIT_CONNECTION,
|
||||
STATE_INIT_CONNECTION_COMPLETE,
|
||||
STATE_RESTART_TUNNEL_AUTH,
|
||||
STATE_RESTART_TUNNEL_AUTH_COMPLETE,
|
||||
STATE_DONE,
|
||||
STATE_NONE,
|
||||
};
|
||||
|
||||
FRIEND_TEST_ALL_PREFIXES(ProxyResolvingClientSocketTest, ConnectToProxy);
|
||||
FRIEND_TEST_ALL_PREFIXES(ProxyResolvingClientSocketTest, ReadWriteErrors);
|
||||
FRIEND_TEST_ALL_PREFIXES(ProxyResolvingClientSocketTest,
|
||||
ResetSocketAfterTunnelAuth);
|
||||
|
||||
void ConnectToProxy(int net_error);
|
||||
void ConnectToProxyDone(int net_error);
|
||||
void OnIOComplete(int result);
|
||||
|
||||
int DoLoop(int result);
|
||||
int DoProxyResolve();
|
||||
int DoProxyResolveComplete(int result);
|
||||
int DoInitConnection();
|
||||
int DoInitConnectionComplete(int result);
|
||||
int DoRestartTunnelAuth(int result);
|
||||
int DoRestartTunnelAuthComplete(int result);
|
||||
|
||||
void CloseSocket(bool close_connection);
|
||||
|
||||
void CloseTransportSocket();
|
||||
int ReconsiderProxyAfterError(int error);
|
||||
|
||||
net::HttpNetworkSession* network_session_;
|
||||
|
||||
// The transport socket.
|
||||
std::unique_ptr<net::ClientSocketHandle> transport_;
|
||||
std::unique_ptr<net::ClientSocketHandle> socket_handle_;
|
||||
|
||||
const net::SSLConfig ssl_config_;
|
||||
net::ProxyResolutionService::Request* proxy_resolve_request_;
|
||||
net::ProxyInfo proxy_info_;
|
||||
const GURL url_;
|
||||
const bool use_tls_;
|
||||
|
||||
net::NetLogWithSource net_log_;
|
||||
|
||||
// The callback passed to Connect().
|
||||
net::CompletionCallback user_connect_callback_;
|
||||
|
||||
State next_state_;
|
||||
|
||||
base::WeakPtrFactory<ProxyResolvingClientSocket> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProxyResolvingClientSocket);
|
||||
|
@ -70,7 +70,8 @@ ProxyResolvingClientSocketFactory::~ProxyResolvingClientSocketFactory() {}
|
||||
std::unique_ptr<ProxyResolvingClientSocket>
|
||||
ProxyResolvingClientSocketFactory::CreateSocket(
|
||||
const net::SSLConfig& ssl_config,
|
||||
const GURL& url) {
|
||||
const GURL& url,
|
||||
bool use_tls) {
|
||||
// |request_context|'s HttpAuthCache might have updates. For example, a user
|
||||
// might have since entered proxy credentials. Clear the http auth of
|
||||
// |network_session_| and copy over the data from |request_context|'s auth
|
||||
@ -83,7 +84,7 @@ ProxyResolvingClientSocketFactory::CreateSocket(
|
||||
->http_auth_cache();
|
||||
network_session_->http_auth_cache()->UpdateAllFrom(*other_auth_cache);
|
||||
return std::make_unique<ProxyResolvingClientSocket>(network_session_.get(),
|
||||
ssl_config, url);
|
||||
ssl_config, url, use_tls);
|
||||
}
|
||||
|
||||
} // namespace network
|
||||
|
@ -39,10 +39,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingClientSocketFactory {
|
||||
// doesn't need to explicitly sanitize the url, any sensitive data (like
|
||||
// embedded usernames and passwords), and local data (i.e. reference fragment)
|
||||
// will be sanitized by net::ProxyService::ResolveProxyHelper() before the url
|
||||
// is disclosed to the proxy.
|
||||
std::unique_ptr<ProxyResolvingClientSocket> CreateSocket(
|
||||
const net::SSLConfig& ssl_config,
|
||||
const GURL& url);
|
||||
// is disclosed to the proxy. If |use_tls|, tls connect will be used in
|
||||
// addition to tcp connect.
|
||||
std::unique_ptr<ProxyResolvingClientSocket>
|
||||
CreateSocket(const net::SSLConfig& ssl_config, const GURL& url, bool use_tls);
|
||||
|
||||
private:
|
||||
std::unique_ptr<net::HttpNetworkSession> network_session_;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "net/dns/mock_host_resolver.h"
|
||||
#include "net/proxy_resolution/mock_proxy_resolver.h"
|
||||
#include "net/proxy_resolution/proxy_config_service_fixed.h"
|
||||
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
||||
#include "net/proxy_resolution/proxy_resolution_service.h"
|
||||
#include "net/socket/client_socket_pool_manager.h"
|
||||
#include "net/socket/socket_test_util.h"
|
||||
@ -50,10 +51,13 @@ class TestURLRequestContextWithProxy : public net::TestURLRequestContext {
|
||||
|
||||
} // namespace
|
||||
|
||||
class ProxyResolvingClientSocketTest : public testing::Test {
|
||||
class ProxyResolvingClientSocketTest
|
||||
: public testing::Test,
|
||||
public testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
ProxyResolvingClientSocketTest()
|
||||
: context_with_proxy_("PROXY bad:99; PROXY maybe:80; DIRECT") {}
|
||||
: context_with_proxy_("PROXY bad:99; PROXY maybe:80; DIRECT"),
|
||||
use_tls_(GetParam()) {}
|
||||
|
||||
~ProxyResolvingClientSocketTest() override {}
|
||||
|
||||
@ -65,12 +69,17 @@ class ProxyResolvingClientSocketTest : public testing::Test {
|
||||
|
||||
base::test::ScopedTaskEnvironment scoped_task_environment_;
|
||||
TestURLRequestContextWithProxy context_with_proxy_;
|
||||
const bool use_tls_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/* no prefix */,
|
||||
ProxyResolvingClientSocketTest,
|
||||
::testing::Bool());
|
||||
|
||||
// Tests that the global socket pool limit
|
||||
// (ClientSocketPoolManager::max_sockets_per_group) doesn't apply to this
|
||||
// type of sockets.
|
||||
TEST_F(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
|
||||
const int kNumSockets = net::ClientSocketPoolManager::max_sockets_per_group(
|
||||
net::HttpNetworkSession::NORMAL_SOCKET_POOL) +
|
||||
10;
|
||||
@ -82,11 +91,15 @@ TEST_F(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
|
||||
"Proxy-Connection: keep-alive\r\n\r\n")};
|
||||
net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 Success\r\n\r\n")};
|
||||
std::vector<std::unique_ptr<net::StaticSocketDataProvider>> socket_data;
|
||||
std::vector<std::unique_ptr<net::SSLSocketDataProvider>> ssl_data;
|
||||
for (int i = 0; i < kNumSockets; ++i) {
|
||||
socket_data.push_back(std::make_unique<net::StaticSocketDataProvider>(
|
||||
reads, arraysize(reads), writes, arraysize(writes)));
|
||||
socket_data[i]->set_connect_data(net::MockConnect(net::ASYNC, net::OK));
|
||||
socket_factory.AddSocketDataProvider(socket_data[i].get());
|
||||
ssl_data.push_back(
|
||||
std::make_unique<net::SSLSocketDataProvider>(net::ASYNC, net::OK));
|
||||
socket_factory.AddSSLSocketDataProvider(ssl_data[i].get());
|
||||
}
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
@ -95,7 +108,7 @@ TEST_F(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
|
||||
for (int i = 0; i < kNumSockets; ++i) {
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
|
||||
@ -104,10 +117,11 @@ TEST_F(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
|
||||
for (int i = 0; i < kNumSockets; ++i) {
|
||||
EXPECT_TRUE(socket_data[i]->AllReadDataConsumed());
|
||||
EXPECT_TRUE(socket_data[i]->AllWriteDataConsumed());
|
||||
EXPECT_EQ(use_tls_, ssl_data[i]->ConnectDataConsumed());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ConnectError) {
|
||||
const struct TestData {
|
||||
// Whether the error is encountered synchronously as opposed to
|
||||
// asynchronously.
|
||||
@ -136,7 +150,7 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
|
||||
&socket_factory, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -152,7 +166,7 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
|
||||
}
|
||||
|
||||
// Tests that the connection is established to the proxy.
|
||||
TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ConnectToProxy) {
|
||||
const GURL kDestination("https://example.com:443");
|
||||
// Use a different port than that of |kDestination|.
|
||||
const int kProxyPort = 8009;
|
||||
@ -171,6 +185,9 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
|
||||
net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
|
||||
"Host: example.com:443\r\n"
|
||||
"Proxy-Connection: keep-alive\r\n\r\n")};
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
net::StaticSocketDataProvider socket_data(reads, arraysize(reads), writes,
|
||||
arraysize(writes));
|
||||
net::IPEndPoint remote_addr(net::IPAddress(127, 0, 0, 1),
|
||||
@ -183,7 +200,7 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
|
||||
&socket_factory, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -196,16 +213,42 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
|
||||
// proxy, so call private member to make sure address is correct.
|
||||
EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, status);
|
||||
status =
|
||||
socket->transport_->socket()->GetPeerAddress(&actual_remote_addr);
|
||||
socket->socket_handle_->socket()->GetPeerAddress(&actual_remote_addr);
|
||||
}
|
||||
EXPECT_EQ(net::OK, status);
|
||||
EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ProxyResolvingClientSocketTest, SocketDestroyedBeforeConnectComplete) {
|
||||
const GURL kDestination("https://example.com:443");
|
||||
net::StaticSocketDataProvider socket_data;
|
||||
socket_data.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
socket_factory.AddSocketDataProvider(&socket_data);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
auto context = std::make_unique<TestURLRequestContextWithProxy>("DIRECT");
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
socket.reset();
|
||||
// Makes sure there is no UAF and socket request is canceled properly.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
// Tests that connection itself is successful but an error occurred during
|
||||
// Read()/Write().
|
||||
TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ReadWriteErrors) {
|
||||
const GURL kDestination("http://example.com:80");
|
||||
const struct TestData {
|
||||
// Whether there is a read error as opposed to a write error.
|
||||
@ -254,12 +297,14 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
|
||||
socket_data.set_connect_data(
|
||||
net::MockConnect(net::ASYNC, net::OK, remote_addr));
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
socket_factory.AddSocketDataProvider(&socket_data);
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -272,7 +317,7 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
|
||||
// proxy, so call private member to make sure address is correct.
|
||||
EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, status);
|
||||
status =
|
||||
socket->transport_->socket()->GetPeerAddress(&actual_remote_addr);
|
||||
socket->socket_handle_->socket()->GetPeerAddress(&actual_remote_addr);
|
||||
}
|
||||
EXPECT_EQ(net::OK, status);
|
||||
EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
|
||||
@ -298,10 +343,11 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
|
||||
EXPECT_EQ(net::ERR_FAILED, read_write_result);
|
||||
EXPECT_TRUE(socket_data.AllReadDataConsumed());
|
||||
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ProxyResolvingClientSocketTest, ReportsBadProxies) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ReportsBadProxies) {
|
||||
const GURL kDestination("https://example.com:443");
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
|
||||
@ -319,12 +365,14 @@ TEST_F(ProxyResolvingClientSocketTest, ReportsBadProxies) {
|
||||
arraysize(writes));
|
||||
socket_data2.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
|
||||
socket_factory.AddSocketDataProvider(&socket_data2);
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -337,9 +385,127 @@ TEST_F(ProxyResolvingClientSocketTest, ReportsBadProxies) {
|
||||
EXPECT_EQ(1u, retry_info.size());
|
||||
net::ProxyRetryInfoMap::const_iterator iter = retry_info.find("bad:99");
|
||||
EXPECT_TRUE(iter != retry_info.end());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ResetSocketAfterTunnelAuth) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
const GURL kDestination("https://example.com:443");
|
||||
|
||||
// Initial connect without credentials. The server responds with a 407.
|
||||
net::MockWrite kConnectWrites1[] = {
|
||||
net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
|
||||
"Host: example.com:443\r\n"
|
||||
"Proxy-Connection: keep-alive\r\n"
|
||||
"\r\n")};
|
||||
net::MockRead kConnectReads1[] = {
|
||||
net::MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"
|
||||
"Proxy-Authenticate: Basic realm=\"test_realm\"\r\n"
|
||||
"\r\n")};
|
||||
|
||||
net::StaticSocketDataProvider kSocketData1(
|
||||
kConnectReads1, arraysize(kConnectReads1), kConnectWrites1,
|
||||
arraysize(kConnectWrites1));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData1);
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status),
|
||||
net::test::IsError(net::ERR_PROXY_AUTH_REQUESTED));
|
||||
// Make sure |socket_handle_| is closed appropriately.
|
||||
EXPECT_FALSE(socket->socket_handle_->socket());
|
||||
}
|
||||
|
||||
TEST_P(ProxyResolvingClientSocketTest, MultiroundAuth) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
const GURL kDestination("https://example.com:443");
|
||||
|
||||
// Initial connect without credentials. The server responds with a 407.
|
||||
net::MockWrite kConnectWrites1[] = {
|
||||
net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
|
||||
"Host: example.com:443\r\n"
|
||||
"Proxy-Connection: keep-alive\r\n"
|
||||
"\r\n")};
|
||||
net::MockRead kConnectReads1[] = {
|
||||
net::MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"
|
||||
"Proxy-Authenticate: Basic realm=\"test_realm\"\r\n"
|
||||
"\r\n")};
|
||||
|
||||
// Second connect attempt includes credentials for test_realm.
|
||||
net::MockWrite kConnectWrites2[] = {
|
||||
net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
|
||||
"Host: example.com:443\r\n"
|
||||
"Proxy-Connection: keep-alive\r\n"
|
||||
"Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==\r\n"
|
||||
"\r\n")};
|
||||
net::MockRead kConnectReads2[] = {
|
||||
net::MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"
|
||||
"Proxy-Authenticate: Basic realm=\"test_realm2\"\r\n"
|
||||
"\r\n")};
|
||||
|
||||
// Third connect attempt include credentials for test_realm2.
|
||||
net::MockWrite kConnectWrites3[] = {
|
||||
net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
|
||||
"Host: example.com:443\r\n"
|
||||
"Proxy-Connection: keep-alive\r\n"
|
||||
"Proxy-Authorization: Basic dXNlcjI6cGFzc3dvcmQy\r\n"
|
||||
"\r\n")};
|
||||
net::MockRead kConnectReads3[] = {
|
||||
net::MockRead("HTTP/1.1 200 Success\r\n\r\n")};
|
||||
|
||||
net::StaticSocketDataProvider kSocketData1(
|
||||
kConnectReads1, arraysize(kConnectReads1), kConnectWrites1,
|
||||
arraysize(kConnectWrites1));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData1);
|
||||
|
||||
net::StaticSocketDataProvider kSocketData2(
|
||||
kConnectReads2, arraysize(kConnectReads2), kConnectWrites2,
|
||||
arraysize(kConnectWrites2));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData2);
|
||||
net::StaticSocketDataProvider kSocketData3(
|
||||
kConnectReads3, arraysize(kConnectReads3), kConnectWrites3,
|
||||
arraysize(kConnectWrites3));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData3);
|
||||
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
net::HttpAuthCache* auth_cache =
|
||||
context_with_proxy_.http_transaction_factory()
|
||||
->GetSession()
|
||||
->http_auth_cache();
|
||||
|
||||
auth_cache->Add(GURL("http://bad:99"), "test_realm",
|
||||
net::HttpAuth::AUTH_SCHEME_BASIC,
|
||||
"Basic realm=\"test_realm\"",
|
||||
net::AuthCredentials(base::ASCIIToUTF16("user"),
|
||||
base::ASCIIToUTF16("password")),
|
||||
std::string());
|
||||
|
||||
auth_cache->Add(GURL("http://bad:99"), "test_realm2",
|
||||
net::HttpAuth::AUTH_SCHEME_BASIC,
|
||||
"Basic realm=\"test_realm2\"",
|
||||
net::AuthCredentials(base::ASCIIToUTF16("user2"),
|
||||
base::ASCIIToUTF16("password2")),
|
||||
std::string());
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
TEST_P(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
const GURL kDestination("https://example.com:443");
|
||||
|
||||
@ -373,6 +539,8 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
|
||||
kConnectReads2, arraysize(kConnectReads2), kConnectWrites2,
|
||||
arraysize(kConnectWrites2));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData2);
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
net::HttpAuthCache* auth_cache =
|
||||
context_with_proxy_.http_transaction_factory()
|
||||
@ -393,16 +561,17 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
// Make sure that if HttpAuthCache is updated e.g through normal URLRequests,
|
||||
// ProxyResolvingClientSocketFactory uses the latest cache for creating new
|
||||
// sockets.
|
||||
TEST_F(ProxyResolvingClientSocketTest, FactoryUsesLatestHTTPAuthCache) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, FactoryUsesLatestHTTPAuthCache) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, &context_with_proxy_);
|
||||
@ -449,16 +618,19 @@ TEST_F(ProxyResolvingClientSocketTest, FactoryUsesLatestHTTPAuthCache) {
|
||||
kConnectReads, arraysize(kConnectReads), kConnectWrites,
|
||||
arraysize(kConnectWrites));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData);
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
const GURL kDestination("https://example.com:443");
|
||||
|
||||
@ -476,6 +648,8 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
|
||||
kConnectReads, arraysize(kConnectReads), kConnectWrites,
|
||||
arraysize(kConnectWrites));
|
||||
socket_factory.AddSocketDataProvider(&kSocketData);
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
net::HttpAuthCache* auth_cache =
|
||||
context_with_proxy_.http_transaction_factory()
|
||||
@ -493,14 +667,15 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_NoCredentials) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_NoCredentials) {
|
||||
net::MockClientSocketFactory socket_factory;
|
||||
const GURL kDestination("https://example.com:443");
|
||||
|
||||
@ -524,7 +699,7 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_NoCredentials) {
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
@ -532,7 +707,7 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_NoCredentials) {
|
||||
}
|
||||
|
||||
// Make sure that url is sanitized before it is disclosed to the proxy.
|
||||
TEST_F(ProxyResolvingClientSocketTest, URLSanitized) {
|
||||
TEST_P(ProxyResolvingClientSocketTest, URLSanitized) {
|
||||
GURL url("http://username:password@www.example.com:79/?ref#hash#hash");
|
||||
|
||||
auto context = std::make_unique<net::TestURLRequestContext>(true);
|
||||
@ -555,7 +730,8 @@ TEST_F(ProxyResolvingClientSocketTest, URLSanitized) {
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
nullptr, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(), url);
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(), url,
|
||||
use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -572,18 +748,57 @@ TEST_F(ProxyResolvingClientSocketTest, URLSanitized) {
|
||||
resolver.pending_jobs()[0]->url());
|
||||
}
|
||||
|
||||
// Tests that socket is destroyed before proxy resolution can complete
|
||||
// asynchronously.
|
||||
TEST_P(ProxyResolvingClientSocketTest,
|
||||
SocketDestroyedBeforeProxyResolutionCompletes) {
|
||||
GURL url("http://www.example.com:79");
|
||||
|
||||
auto context = std::make_unique<net::TestURLRequestContext>(true);
|
||||
net::ProxyConfig proxy_config;
|
||||
proxy_config.set_pac_url(GURL("http://foopy/proxy.pac"));
|
||||
proxy_config.set_pac_mandatory(true);
|
||||
net::MockAsyncProxyResolver resolver;
|
||||
auto proxy_resolver_factory =
|
||||
std::make_unique<net::MockAsyncProxyResolverFactory>(false);
|
||||
net::MockAsyncProxyResolverFactory* proxy_resolver_factory_raw =
|
||||
proxy_resolver_factory.get();
|
||||
net::ProxyResolutionService service(
|
||||
std::make_unique<net::ProxyConfigServiceFixed>(
|
||||
net::ProxyConfigWithAnnotation(proxy_config,
|
||||
TRAFFIC_ANNOTATION_FOR_TESTS)),
|
||||
std::move(proxy_resolver_factory), nullptr);
|
||||
context->set_proxy_resolution_service(&service);
|
||||
context->Init();
|
||||
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
nullptr, context.get());
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(), url,
|
||||
use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, socket->Connect(callback.callback()));
|
||||
socket.reset();
|
||||
ASSERT_EQ(1u, proxy_resolver_factory_raw->pending_requests().size());
|
||||
proxy_resolver_factory_raw->pending_requests()[0]->CompleteNowWithForwarder(
|
||||
net::OK, &resolver);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
class ReconsiderProxyAfterErrorTest
|
||||
: public testing::Test,
|
||||
public testing::WithParamInterface<::testing::tuple<bool, int>> {
|
||||
public testing::WithParamInterface<::testing::tuple<bool, bool, int>> {
|
||||
public:
|
||||
ReconsiderProxyAfterErrorTest()
|
||||
: context_with_proxy_(
|
||||
"HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT") {}
|
||||
"HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT"),
|
||||
use_tls_(::testing::get<0>(GetParam())) {}
|
||||
|
||||
~ReconsiderProxyAfterErrorTest() override {}
|
||||
|
||||
base::test::ScopedTaskEnvironment scoped_task_environment_;
|
||||
TestURLRequestContextWithProxy context_with_proxy_;
|
||||
const bool use_tls_;
|
||||
};
|
||||
|
||||
// List of errors that are used in the proxy resolution tests.
|
||||
@ -600,12 +815,14 @@ const int kProxyTestMockErrors[] = {
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
/* no prefix */,
|
||||
ReconsiderProxyAfterErrorTest,
|
||||
testing::Combine(testing::Bool(), testing::ValuesIn(kProxyTestMockErrors)));
|
||||
testing::Combine(testing::Bool(),
|
||||
testing::Bool(),
|
||||
testing::ValuesIn(kProxyTestMockErrors)));
|
||||
|
||||
TEST_P(ReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) {
|
||||
net::IoMode io_mode =
|
||||
::testing::get<0>(GetParam()) ? net::SYNCHRONOUS : net::ASYNC;
|
||||
const int mock_error = ::testing::get<1>(GetParam());
|
||||
::testing::get<1>(GetParam()) ? net::SYNCHRONOUS : net::ASYNC;
|
||||
const int mock_error = ::testing::get<2>(GetParam());
|
||||
|
||||
// Before starting the test, verify that there are no proxies marked as bad.
|
||||
ASSERT_TRUE(context_with_proxy_.proxy_resolution_service()
|
||||
@ -628,13 +845,15 @@ TEST_P(ReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) {
|
||||
net::StaticSocketDataProvider data3;
|
||||
data3.set_connect_data(net::MockConnect(io_mode, net::OK));
|
||||
socket_factory.AddSocketDataProvider(&data3);
|
||||
net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
|
||||
socket_factory.AddSSLSocketDataProvider(&ssl_socket);
|
||||
|
||||
const GURL kDestination("https://example.com:443");
|
||||
ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
|
||||
&socket_factory, &context_with_proxy_);
|
||||
std::unique_ptr<ProxyResolvingClientSocket> socket =
|
||||
proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
|
||||
kDestination);
|
||||
kDestination, use_tls_);
|
||||
net::TestCompletionCallback callback;
|
||||
int status = socket->Connect(callback.callback());
|
||||
EXPECT_EQ(net::ERR_IO_PENDING, status);
|
||||
@ -646,6 +865,7 @@ TEST_P(ReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) {
|
||||
EXPECT_EQ(2u, retry_info.size()) << mock_error;
|
||||
EXPECT_NE(retry_info.end(), retry_info.find("https://badproxy:99"));
|
||||
EXPECT_NE(retry_info.end(), retry_info.find("https://badfallbackproxy:98"));
|
||||
EXPECT_EQ(use_tls_, ssl_socket.ConnectDataConsumed());
|
||||
}
|
||||
|
||||
} // namespace network
|
||||
|
@ -27250,6 +27250,9 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
|
||||
</histogram>
|
||||
|
||||
<histogram name="GCM.ConnectedViaProxy" enum="Boolean">
|
||||
<obsolete>
|
||||
Deprecated as of 03/2018 (M67).
|
||||
</obsolete>
|
||||
<owner>zea@chromium.org</owner>
|
||||
<summary>Whether the GCM connection was made via a proxy or not.</summary>
|
||||
</histogram>
|
||||
|
Reference in New Issue
Block a user