Commit c3308d79 authored by tbansal's avatar tbansal Committed by Commit bot

Race TCP connections to proxies with QUIC connections

After the default job finishes proxy resolution, it queries
ProxyDelegate on whether the resolved proxy supports an
alternative proxy server or not. If yes, a new job is
started. This job is provided the alternative proxy server,
and races with the main job.

If the alternative proxy server is found to be broken, the
ProxyDelegate is notified.

Changes to DataReductionProxyDelegate will be in a
subsequent CL.

BUG=343579

Review-Url: https://codereview.chromium.org/2260623002
Cr-Commit-Position: refs/heads/master@{#414884}
parent 390ccf8f
...@@ -95,6 +95,14 @@ void DataReductionProxyDelegate::OnTunnelHeadersReceived( ...@@ -95,6 +95,14 @@ void DataReductionProxyDelegate::OnTunnelHeadersReceived(
const net::HttpResponseHeaders& response_headers) { const net::HttpResponseHeaders& response_headers) {
} }
void DataReductionProxyDelegate::GetAlternativeProxy(
const GURL& url,
const net::ProxyServer& resolved_proxy_server,
net::ProxyServer* alternative_proxy_server) const {}
void DataReductionProxyDelegate::OnAlternativeProxyBroken(
const net::ProxyServer& alternative_proxy_server) {}
void OnResolveProxyHandler(const GURL& url, void OnResolveProxyHandler(const GURL& url,
const std::string& method, const std::string& method,
const net::ProxyConfig& data_reduction_proxy_config, const net::ProxyConfig& data_reduction_proxy_config,
......
...@@ -61,6 +61,12 @@ class DataReductionProxyDelegate : public net::ProxyDelegate { ...@@ -61,6 +61,12 @@ class DataReductionProxyDelegate : public net::ProxyDelegate {
const net::HostPortPair& origin, const net::HostPortPair& origin,
const net::HostPortPair& proxy_server, const net::HostPortPair& proxy_server,
const net::HttpResponseHeaders& response_headers) override; const net::HttpResponseHeaders& response_headers) override;
void GetAlternativeProxy(
const GURL& url,
const net::ProxyServer& resolved_proxy_server,
net::ProxyServer* alternative_proxy_server) const override;
void OnAlternativeProxyBroken(
const net::ProxyServer& alternative_proxy_server) override;
private: private:
const DataReductionProxyConfig* config_; const DataReductionProxyConfig* config_;
......
...@@ -68,6 +68,21 @@ class NET_EXPORT ProxyDelegate { ...@@ -68,6 +68,21 @@ class NET_EXPORT ProxyDelegate {
// allowed to push cross-origin resources. // allowed to push cross-origin resources.
virtual bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) = 0; virtual bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) = 0;
// Called after the proxy is resolved but before the connection is
// established. |resolved_proxy_server| is the proxy server resolved by the
// proxy service for fetching |url|. Sets |alternative_proxy_server| to an
// alternative proxy server, if one is available to fetch |url|.
// |alternative_proxy_server| is owned by the caller, and is guaranteed to be
// non-null.
virtual void GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const = 0;
// Notifies the ProxyDelegate that |alternative_proxy_server| is broken.
virtual void OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) = 0;
private: private:
DISALLOW_COPY_AND_ASSIGN(ProxyDelegate); DISALLOW_COPY_AND_ASSIGN(ProxyDelegate);
}; };
......
...@@ -13,7 +13,8 @@ namespace net { ...@@ -13,7 +13,8 @@ namespace net {
TestProxyDelegate::TestProxyDelegate() TestProxyDelegate::TestProxyDelegate()
: on_before_tunnel_request_called_(false), : on_before_tunnel_request_called_(false),
on_tunnel_request_completed_called_(false), on_tunnel_request_completed_called_(false),
on_tunnel_headers_received_called_(false) {} on_tunnel_headers_received_called_(false),
get_alternative_proxy_invocations_(0) {}
TestProxyDelegate::~TestProxyDelegate() {} TestProxyDelegate::~TestProxyDelegate() {}
...@@ -79,4 +80,21 @@ bool TestProxyDelegate::IsTrustedSpdyProxy( ...@@ -79,4 +80,21 @@ bool TestProxyDelegate::IsTrustedSpdyProxy(
return proxy_server.is_valid() && trusted_spdy_proxy_ == proxy_server; return proxy_server.is_valid() && trusted_spdy_proxy_ == proxy_server;
} }
void TestProxyDelegate::GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const {
EXPECT_TRUE(resolved_proxy_server.is_valid());
EXPECT_FALSE(alternative_proxy_server->is_valid());
*alternative_proxy_server = alternative_proxy_server_;
get_alternative_proxy_invocations_++;
}
void TestProxyDelegate::OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) {
EXPECT_TRUE(alternative_proxy_server.is_valid());
EXPECT_EQ(alternative_proxy_server_, alternative_proxy_server);
alternative_proxy_server_ = ProxyServer();
}
} // namespace net } // namespace net
\ No newline at end of file
...@@ -65,6 +65,24 @@ class TestProxyDelegate : public ProxyDelegate { ...@@ -65,6 +65,24 @@ class TestProxyDelegate : public ProxyDelegate {
const HostPortPair& proxy_server, const HostPortPair& proxy_server,
const HttpResponseHeaders& response_headers) override; const HttpResponseHeaders& response_headers) override;
bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override; bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override;
void GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const override;
void OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) override;
void set_alternative_proxy_server(
const ProxyServer& alternative_proxy_server) {
alternative_proxy_server_ = alternative_proxy_server;
}
const ProxyServer& alternative_proxy_server() const {
return alternative_proxy_server_;
}
int get_alternative_proxy_invocations() const {
return get_alternative_proxy_invocations_;
}
private: private:
bool on_before_tunnel_request_called_; bool on_before_tunnel_request_called_;
...@@ -76,6 +94,10 @@ class TestProxyDelegate : public ProxyDelegate { ...@@ -76,6 +94,10 @@ class TestProxyDelegate : public ProxyDelegate {
HostPortPair on_tunnel_headers_received_origin_; HostPortPair on_tunnel_headers_received_origin_;
HostPortPair on_tunnel_headers_received_proxy_server_; HostPortPair on_tunnel_headers_received_proxy_server_;
std::string on_tunnel_headers_received_status_line_; std::string on_tunnel_headers_received_status_line_;
ProxyServer alternative_proxy_server_;
// Number of times GetAlternativeProxy() method has been called.
mutable int get_alternative_proxy_invocations_;
}; };
} // namespace net } // namespace net
......
...@@ -63,7 +63,25 @@ class DefaultJobFactory : public HttpStreamFactoryImpl::JobFactory { ...@@ -63,7 +63,25 @@ class DefaultJobFactory : public HttpStreamFactoryImpl::JobFactory {
return new HttpStreamFactoryImpl::Job( return new HttpStreamFactoryImpl::Job(
delegate, job_type, session, request_info, priority, server_ssl_config, delegate, job_type, session, request_info, priority, server_ssl_config,
proxy_ssl_config, destination, origin_url, alternative_service, proxy_ssl_config, destination, origin_url, alternative_service,
net_log); ProxyServer(), net_log);
}
HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type,
HttpNetworkSession* session,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HostPortPair destination,
GURL origin_url,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) override {
return new HttpStreamFactoryImpl::Job(
delegate, job_type, session, request_info, priority, server_ssl_config,
proxy_ssl_config, destination, origin_url, AlternativeService(),
alternative_proxy_server, net_log);
} }
}; };
} // anonymous namespace } // anonymous namespace
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "net/base/port_util.h" #include "net/base/port_util.h"
#include "net/base/proxy_delegate.h"
#include "net/cert/cert_verifier.h" #include "net/cert/cert_verifier.h"
#include "net/http/bidirectional_stream_impl.h" #include "net/http/bidirectional_stream_impl.h"
#include "net/http/http_basic_stream.h" #include "net/http/http_basic_stream.h"
...@@ -161,6 +162,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, ...@@ -161,6 +162,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
destination, destination,
origin_url, origin_url,
AlternativeService(), AlternativeService(),
ProxyServer(),
net_log) {} net_log) {}
HttpStreamFactoryImpl::Job::Job(Delegate* delegate, HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
...@@ -173,6 +175,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, ...@@ -173,6 +175,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
HostPortPair destination, HostPortPair destination,
GURL origin_url, GURL origin_url,
AlternativeService alternative_service, AlternativeService alternative_service,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) NetLog* net_log)
: request_info_(request_info), : request_info_(request_info),
priority_(priority), priority_(priority),
...@@ -188,6 +191,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, ...@@ -188,6 +191,7 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
origin_url_(origin_url), origin_url_(origin_url),
alternative_service_(alternative_service), alternative_service_(alternative_service),
delegate_(delegate), delegate_(delegate),
alternative_proxy_server_(alternative_proxy_server),
job_type_(job_type), job_type_(job_type),
using_ssl_(false), using_ssl_(false),
using_spdy_(false), using_spdy_(false),
...@@ -205,6 +209,24 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate, ...@@ -205,6 +209,24 @@ HttpStreamFactoryImpl::Job::Job(Delegate* delegate,
stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM), stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM),
ptr_factory_(this) { ptr_factory_(this) {
DCHECK(session); DCHECK(session);
// The job can't have alternative service and alternative proxy server set at
// the same time since alternative services are used for requests that are
// fetched directly, while the alternative proxy server is used for requests
// that should be fetched using proxy.
DCHECK(alternative_service_.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL ||
!alternative_proxy_server_.is_valid());
DCHECK(!alternative_proxy_server_.is_valid() ||
!(IsSpdyAlternative() || IsQuicAlternative()));
// If either the alternative service protocol is specified or if the
// alternative proxy server is valid, then the job type must be set to
// either ALTERNATIVE or PRECONNECT.
DCHECK((alternative_service_.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL &&
!alternative_proxy_server_.is_valid()) ||
(job_type_ == ALTERNATIVE || job_type_ == PRECONNECT));
// If the alternative proxy server is valid, then the job type must be
// set to ALTERNATIVE.
DCHECK(!alternative_proxy_server_.is_valid() || job_type_ == ALTERNATIVE);
if (IsSpdyAlternative()) { if (IsSpdyAlternative()) {
DCHECK(origin_url_.SchemeIs("https")); DCHECK(origin_url_.SchemeIs("https"));
} }
...@@ -701,6 +723,12 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() { ...@@ -701,6 +723,12 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() {
return OK; return OK;
} }
// If an alternative proxy server was provided, use that.
if (alternative_proxy_server_.is_valid()) {
proxy_info_.UseProxyServer(alternative_proxy_server_);
return OK;
}
return session_->proxy_service()->ResolveProxy( return session_->proxy_service()->ResolveProxy(
origin_url_, request_info_.method, &proxy_info_, io_callback_, origin_url_, request_info_.method, &proxy_info_, io_callback_,
&pac_request_, session_->params().proxy_delegate, net_log_); &pac_request_, session_->params().proxy_delegate, net_log_);
...@@ -738,6 +766,11 @@ int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) { ...@@ -738,6 +766,11 @@ int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) {
} }
next_state_ = STATE_WAIT; next_state_ = STATE_WAIT;
delegate_->OnResolveProxyComplete(this, request_info_, priority_,
server_ssl_config_, proxy_ssl_config_,
stream_type_);
return OK; return OK;
} }
...@@ -1394,6 +1427,14 @@ int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { ...@@ -1394,6 +1427,14 @@ int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) {
if (request_info_.load_flags & LOAD_BYPASS_PROXY) if (request_info_.load_flags & LOAD_BYPASS_PROXY)
return error; return error;
// Alternative proxy server job should not use fallback proxies, and instead
// return. This would resume the main job (if possible) which may try the
// fallback proxies.
if (alternative_proxy_server_.is_valid()) {
DCHECK_EQ(STATE_NONE, next_state_);
return error;
}
if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) { if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) {
session_->ssl_client_auth_cache()->Remove( session_->ssl_client_auth_cache()->Remove(
proxy_info_.proxy_server().host_port_pair()); proxy_info_.proxy_server().host_port_pair());
...@@ -1474,15 +1515,30 @@ void HttpStreamFactoryImpl::Job::ReportJobSucceededForRequest() { ...@@ -1474,15 +1515,30 @@ void HttpStreamFactoryImpl::Job::ReportJobSucceededForRequest() {
void HttpStreamFactoryImpl::Job::MarkOtherJobComplete(const Job& job) { void HttpStreamFactoryImpl::Job::MarkOtherJobComplete(const Job& job) {
DCHECK_EQ(STATUS_RUNNING, other_job_status_); DCHECK_EQ(STATUS_RUNNING, other_job_status_);
DCHECK(!other_job_alternative_proxy_server_.is_valid());
other_job_status_ = job.job_status_; other_job_status_ = job.job_status_;
other_job_alternative_service_ = job.alternative_service_; other_job_alternative_service_ = job.alternative_service_;
other_job_alternative_proxy_server_ = job.alternative_proxy_server_;
// At most one job can have a valid |alternative_proxy_server_|.
DCHECK(!alternative_proxy_server_.is_valid() ||
!other_job_alternative_proxy_server_.is_valid());
MaybeMarkAlternativeServiceBroken(); MaybeMarkAlternativeServiceBroken();
} }
void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() { void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() {
// At least one job should not be an alternative job.
DCHECK(alternative_service_.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL ||
other_job_alternative_service_.protocol ==
UNINITIALIZED_ALTERNATE_PROTOCOL);
if (job_status_ == STATUS_RUNNING || other_job_status_ == STATUS_RUNNING) if (job_status_ == STATUS_RUNNING || other_job_status_ == STATUS_RUNNING)
return; return;
MaybeNotifyAlternativeProxyServerBroken();
if (IsSpdyAlternative() || IsQuicAlternative()) { if (IsSpdyAlternative() || IsQuicAlternative()) {
if (job_status_ == STATUS_BROKEN && other_job_status_ == STATUS_SUCCEEDED) { if (job_status_ == STATUS_BROKEN && other_job_status_ == STATUS_SUCCEEDED) {
HistogramBrokenAlternateProtocolLocation( HistogramBrokenAlternateProtocolLocation(
...@@ -1503,6 +1559,47 @@ void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() { ...@@ -1503,6 +1559,47 @@ void HttpStreamFactoryImpl::Job::MaybeMarkAlternativeServiceBroken() {
} }
} }
void HttpStreamFactoryImpl::Job::MaybeNotifyAlternativeProxyServerBroken()
const {
if (!alternative_proxy_server_.is_valid() &&
!other_job_alternative_proxy_server_.is_valid()) {
// Neither of the two jobs used an alternative proxy server.
return;
}
// Neither this job, nor the other job should have used the alternative
// service.
DCHECK_EQ(UNINITIALIZED_ALTERNATE_PROTOCOL, alternative_service_.protocol);
DCHECK_EQ(UNINITIALIZED_ALTERNATE_PROTOCOL,
other_job_alternative_service_.protocol);
ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
if (!proxy_delegate)
return;
if (alternative_proxy_server_.is_valid()) {
// |this| connected to the alternative proxy server.
if ((job_status_ == STATUS_BROKEN || job_status_ == STATUS_FAILED) &&
other_job_status_ == STATUS_SUCCEEDED) {
// Notify ProxyDelegate.
proxy_delegate->OnAlternativeProxyBroken(alternative_proxy_server_);
}
return;
}
if (other_job_alternative_proxy_server_.is_valid()) {
// Other job connected to the alternative proxy server.
if (job_status_ == STATUS_SUCCEEDED &&
(other_job_status_ == STATUS_BROKEN ||
other_job_status_ == STATUS_FAILED)) {
// Notify ProxyDelegate.
proxy_delegate->OnAlternativeProxyBroken(
other_job_alternative_proxy_server_);
}
return;
}
}
ClientSocketPoolManager::SocketGroupType ClientSocketPoolManager::SocketGroupType
HttpStreamFactoryImpl::Job::GetSocketGroup() const { HttpStreamFactoryImpl::Job::GetSocketGroup() const {
std::string scheme = origin_url_.scheme(); std::string scheme = origin_url_.scheme();
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "net/http/http_request_info.h" #include "net/http/http_request_info.h"
#include "net/http/http_stream_factory_impl.h" #include "net/http/http_stream_factory_impl.h"
#include "net/log/net_log.h" #include "net/log/net_log.h"
#include "net/proxy/proxy_server.h"
#include "net/proxy/proxy_service.h" #include "net/proxy/proxy_service.h"
#include "net/quic/chromium/quic_stream_factory.h" #include "net/quic/chromium/quic_stream_factory.h"
#include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_handle.h"
...@@ -35,6 +36,7 @@ class HttpAuthController; ...@@ -35,6 +36,7 @@ class HttpAuthController;
class HttpNetworkSession; class HttpNetworkSession;
class HttpStream; class HttpStream;
class SpdySessionPool; class SpdySessionPool;
struct SSLConfig;
class QuicHttpStream; class QuicHttpStream;
// An HttpStreamRequestImpl exists for each stream which is in progress of being // An HttpStreamRequestImpl exists for each stream which is in progress of being
...@@ -96,6 +98,16 @@ class HttpStreamFactoryImpl::Job { ...@@ -96,6 +98,16 @@ class HttpStreamFactoryImpl::Job {
const ProxyInfo& used_proxy_info, const ProxyInfo& used_proxy_info,
HttpAuthController* auth_controller) = 0; HttpAuthController* auth_controller) = 0;
// Invoked when |job| has completed proxy resolution. The delegate may
// create an alternative proxy server job to fetch the request.
virtual void OnResolveProxyComplete(
Job* job,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::StreamType stream_type) = 0;
// Invoked to notify the Request and Factory of the readiness of new // Invoked to notify the Request and Factory of the readiness of new
// SPDY session. // SPDY session.
virtual void OnNewSpdySessionReady( virtual void OnNewSpdySessionReady(
...@@ -156,9 +168,14 @@ class HttpStreamFactoryImpl::Job { ...@@ -156,9 +168,14 @@ class HttpStreamFactoryImpl::Job {
GURL origin_url, GURL origin_url,
NetLog* net_log); NetLog* net_log);
// Constructor for alternative Job. // Constructor for the alternative Job. The Job is owned by |delegate|, hence
// Job is owned by |delegate|, hence |delegate| is valid for the // |delegate| is valid for the lifetime of the Job. If |alternative_service|
// lifetime of the Job. // is initialized, then the Job will use the alternative service. On the
// other hand, if |alternative_proxy_server| is a valid proxy server, then the
// job will use that instead of using ProxyService for proxy resolution.
// Further, if |alternative_proxy_server| is a valid but bad proxy, then
// fallback proxies are not used. It is illegal to call this with an
// initialized |alternative_service|, and a valid |alternative_proxy_server|.
Job(Delegate* delegate, Job(Delegate* delegate,
JobType job_type, JobType job_type,
HttpNetworkSession* session, HttpNetworkSession* session,
...@@ -169,6 +186,7 @@ class HttpStreamFactoryImpl::Job { ...@@ -169,6 +186,7 @@ class HttpStreamFactoryImpl::Job {
HostPortPair destination, HostPortPair destination,
GURL origin_url, GURL origin_url,
AlternativeService alternative_service, AlternativeService alternative_service,
const ProxyServer& alternative_proxy_server,
NetLog* net_log); NetLog* net_log);
virtual ~Job(); virtual ~Job();
...@@ -364,6 +382,11 @@ class HttpStreamFactoryImpl::Job { ...@@ -364,6 +382,11 @@ class HttpStreamFactoryImpl::Job {
void MaybeMarkAlternativeServiceBroken(); void MaybeMarkAlternativeServiceBroken();
// May notify proxy delegate that the alternative proxy server is broken. The
// alternative proxy server is considered as broken if the alternative proxy
// server job failed, but the main job was successful.
void MaybeNotifyAlternativeProxyServerBroken() const;
ClientSocketPoolManager::SocketGroupType GetSocketGroup() const; ClientSocketPoolManager::SocketGroupType GetSocketGroup() const;
void MaybeCopyConnectionAttemptsFromSocketOrHandle(); void MaybeCopyConnectionAttemptsFromSocketOrHandle();
...@@ -412,7 +435,14 @@ class HttpStreamFactoryImpl::Job { ...@@ -412,7 +435,14 @@ class HttpStreamFactoryImpl::Job {
// Unowned. |this| job is owned by |delegate_|. // Unowned. |this| job is owned by |delegate_|.
Delegate* delegate_; Delegate* delegate_;
JobType job_type_; // Alternative proxy server that should be used by |this| to fetch the
// request.
const ProxyServer alternative_proxy_server_;
// Alternative proxy server for the other job.
ProxyServer other_job_alternative_proxy_server_;
const JobType job_type_;
// True if handling a HTTPS request, or using SPDY with SSL // True if handling a HTTPS request, or using SPDY with SSL
bool using_ssl_; bool using_ssl_;
...@@ -479,7 +509,7 @@ class HttpStreamFactoryImpl::JobFactory { ...@@ -479,7 +509,7 @@ class HttpStreamFactoryImpl::JobFactory {
public: public:
virtual ~JobFactory() {} virtual ~JobFactory() {}
// Creates an alternative Job. // Creates an alternative service Job.
virtual HttpStreamFactoryImpl::Job* CreateJob( virtual HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate, HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type, HttpStreamFactoryImpl::JobType job_type,
...@@ -493,6 +523,20 @@ class HttpStreamFactoryImpl::JobFactory { ...@@ -493,6 +523,20 @@ class HttpStreamFactoryImpl::JobFactory {
AlternativeService alternative_service, AlternativeService alternative_service,
NetLog* net_log) = 0; NetLog* net_log) = 0;
// Creates an alternative proxy server Job.
virtual HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type,
HttpNetworkSession* session,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HostPortPair destination,
GURL origin_url,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) = 0;
// Creates a non-alternative Job. // Creates a non-alternative Job.
virtual HttpStreamFactoryImpl::Job* CreateJob( virtual HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate, HttpStreamFactoryImpl::Job::Delegate* delegate,
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/values.h" #include "base/values.h"
#include "net/base/host_mapping_rules.h" #include "net/base/host_mapping_rules.h"
#include "net/base/proxy_delegate.h"
#include "net/http/bidirectional_stream_impl.h" #include "net/http/bidirectional_stream_impl.h"
#include "net/http/transport_security_state.h" #include "net/http/transport_security_state.h"
#include "net/proxy/proxy_server.h"
#include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session.h"
namespace net { namespace net {
...@@ -38,6 +40,7 @@ HttpStreamFactoryImpl::JobController::JobController( ...@@ -38,6 +40,7 @@ HttpStreamFactoryImpl::JobController::JobController(
job_bound_(false), job_bound_(false),
main_job_is_blocked_(false), main_job_is_blocked_(false),
bound_job_(nullptr), bound_job_(nullptr),
can_start_alternative_proxy_job_(false),
ptr_factory_(this) { ptr_factory_(this) {
DCHECK(factory); DCHECK(factory);
} }
...@@ -355,6 +358,45 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth( ...@@ -355,6 +358,45 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth(
auth_controller); auth_controller);
} }
void HttpStreamFactoryImpl::JobController::OnResolveProxyComplete(
Job* job,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::StreamType stream_type) {
DCHECK(job);
ProxyServer alternative_proxy_server;
if (!ShouldCreateAlternativeProxyServerJob(job, job->proxy_info(),
request_info.url,
&alternative_proxy_server)) {
return;
}
DCHECK(main_job_);
DCHECK_EQ(MAIN, job->job_type());
DCHECK(!alternative_job_);
DCHECK(!main_job_is_blocked_);
HostPortPair destination(HostPortPair::FromURL(request_info.url));
GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
alternative_job_.reset(job_factory_->CreateJob(
this, ALTERNATIVE, session_, request_info, priority, server_ssl_config,
proxy_ssl_config, destination, origin_url, alternative_proxy_server,
job->net_log().net_log()));
AttachJob(alternative_job_.get());
can_start_alternative_proxy_job_ = false;
main_job_is_blocked_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&HttpStreamFactoryImpl::Job::Start,
base::Unretained(alternative_job_.get()),
request_->stream_type()));
}
void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady( void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
Job* job, Job* job,
const base::WeakPtr<SpdySession>& spdy_session, const base::WeakPtr<SpdySession>& spdy_session,
...@@ -607,6 +649,8 @@ void HttpStreamFactoryImpl::JobController::CreateJobs( ...@@ -607,6 +649,8 @@ void HttpStreamFactoryImpl::JobController::CreateJobs(
main_job_is_blocked_ = true; main_job_is_blocked_ = true;
alternative_job_->Start(request_->stream_type()); alternative_job_->Start(request_->stream_type());
} else {
can_start_alternative_proxy_job_ = true;
} }
// Even if |alternative_job| has already finished, it will not have notified // Even if |alternative_job| has already finished, it will not have notified
// the request yet, since we defer that to the next iteration of the // the request yet, since we defer that to the next iteration of the
...@@ -895,4 +939,73 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal( ...@@ -895,4 +939,73 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
return first_alternative_service; return first_alternative_service;
} }
bool HttpStreamFactoryImpl::JobController::
ShouldCreateAlternativeProxyServerJob(
Job* job,
const ProxyInfo& proxy_info,
const GURL& url,
ProxyServer* alternative_proxy_server) const {
DCHECK(!alternative_proxy_server->is_valid());
if (!can_start_alternative_proxy_job_) {
// Either an alternative service job or an alternative proxy server job has
// already been started.
return false;
}
if (job->job_type() == ALTERNATIVE) {
// If |job| is using alternative service, then alternative proxy server
// should not be used.
return false;
}
if (job->job_type() == PRECONNECT) {
// Preconnects should be fetched using only the main job to keep the
// resource utilization down.
return false;
}
if (proxy_info.is_empty() || proxy_info.is_direct() || proxy_info.is_quic()) {
// Alternative proxy server job can be created only if |job| fetches the
// |request_| through a non-QUIC proxy.
return false;
}
if (!url.SchemeIs(url::kHttpScheme)) {
// Only HTTP URLs can be fetched through alternative proxy server, since the
// alternative proxy server may not support fetching of URLs with other
// schemes.
return false;
}
ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
if (!proxy_delegate)
return false;
proxy_delegate->GetAlternativeProxy(url, proxy_info.proxy_server(),
alternative_proxy_server);
if (!alternative_proxy_server->is_valid())
return false;
DCHECK(!(*alternative_proxy_server == proxy_info.proxy_server()));
if (!alternative_proxy_server->is_https() &&
!alternative_proxy_server->is_quic()) {
// Alternative proxy server should be a secure server.
return false;
}
if (alternative_proxy_server->is_quic()) {
// Check that QUIC is enabled globally, and it is not disabled on
// the specified port.
if (!session_->params().enable_quic ||
session_->quic_stream_factory()->IsQuicDisabled(
alternative_proxy_server->host_port_pair().port())) {
return false;
}
}
return true;
}
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_ #ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_
#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_ #define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_CONTROLLER_H_
#include "net/base/host_port_pair.h"
#include "net/http/http_stream_factory_impl_job.h" #include "net/http/http_stream_factory_impl_job.h"
#include "net/http/http_stream_factory_impl_request.h" #include "net/http/http_stream_factory_impl_request.h"
...@@ -114,6 +115,14 @@ class HttpStreamFactoryImpl::JobController ...@@ -114,6 +115,14 @@ class HttpStreamFactoryImpl::JobController
const ProxyInfo& used_proxy_info, const ProxyInfo& used_proxy_info,
HttpAuthController* auth_controller) override; HttpAuthController* auth_controller) override;
void OnResolveProxyComplete(
Job* job,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HttpStreamRequest::StreamType stream_type) override;
// Invoked to notify the Request and Factory of the readiness of new // Invoked to notify the Request and Factory of the readiness of new
// SPDY session. // SPDY session.
void OnNewSpdySessionReady(Job* job, void OnNewSpdySessionReady(Job* job,
...@@ -215,6 +224,16 @@ class HttpStreamFactoryImpl::JobController ...@@ -215,6 +224,16 @@ class HttpStreamFactoryImpl::JobController
// Remove session from the SpdySessionRequestMap. // Remove session from the SpdySessionRequestMap.
void RemoveRequestFromSpdySessionRequestMap(); void RemoveRequestFromSpdySessionRequestMap();
// Returns true if the |request_| can be fetched via an alternative
// proxy server, and sets |alternative_proxy_server| to the available
// alternative proxy server. |alternative_proxy_server| should not be null,
// and is owned by the caller.
bool ShouldCreateAlternativeProxyServerJob(
Job* job,
const ProxyInfo& proxy_info_,
const GURL& url,
ProxyServer* alternative_proxy_server) const;
HttpStreamFactoryImpl* factory_; HttpStreamFactoryImpl* factory_;
HttpNetworkSession* session_; HttpNetworkSession* session_;
JobFactory* job_factory_; JobFactory* job_factory_;
...@@ -249,6 +268,9 @@ class HttpStreamFactoryImpl::JobController ...@@ -249,6 +268,9 @@ class HttpStreamFactoryImpl::JobController
// It will be nulled when the |request_| is finished. // It will be nulled when the |request_| is finished.
Job* bound_job_; Job* bound_job_;
// True if an alternative proxy server job can be started to fetch |request_|.
bool can_start_alternative_proxy_job_;
base::WeakPtrFactory<JobController> ptr_factory_; base::WeakPtrFactory<JobController> ptr_factory_;
}; };
......
...@@ -46,6 +46,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob( ...@@ -46,6 +46,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob(
HostPortPair destination, HostPortPair destination,
GURL origin_url, GURL origin_url,
AlternativeService alternative_service, AlternativeService alternative_service,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) NetLog* net_log)
: HttpStreamFactoryImpl::Job(delegate, : HttpStreamFactoryImpl::Job(delegate,
job_type, job_type,
...@@ -57,6 +58,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob( ...@@ -57,6 +58,7 @@ MockHttpStreamFactoryImplJob::MockHttpStreamFactoryImplJob(
destination, destination,
origin_url, origin_url,
alternative_service, alternative_service,
alternative_proxy_server,
net_log) {} net_log) {}
MockHttpStreamFactoryImplJob::~MockHttpStreamFactoryImplJob() {} MockHttpStreamFactoryImplJob::~MockHttpStreamFactoryImplJob() {}
...@@ -106,7 +108,29 @@ HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob( ...@@ -106,7 +108,29 @@ HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob(
DCHECK(!alternative_job_); DCHECK(!alternative_job_);
alternative_job_ = new MockHttpStreamFactoryImplJob( alternative_job_ = new MockHttpStreamFactoryImplJob(
delegate, job_type, session, request_info, priority, SSLConfig(), delegate, job_type, session, request_info, priority, SSLConfig(),
SSLConfig(), destination, origin_url, alternative_service, nullptr); SSLConfig(), destination, origin_url, alternative_service, ProxyServer(),
nullptr);
return alternative_job_;
}
HttpStreamFactoryImpl::Job* TestJobFactory::CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type,
HttpNetworkSession* session,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HostPortPair destination,
GURL origin_url,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) {
DCHECK(!alternative_job_);
alternative_job_ = new MockHttpStreamFactoryImplJob(
delegate, job_type, session, request_info, priority, SSLConfig(),
SSLConfig(), destination, origin_url, AlternativeService(),
alternative_proxy_server, nullptr);
return alternative_job_; return alternative_job_;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "net/http/http_stream_factory_impl_job.h" #include "net/http/http_stream_factory_impl_job.h"
#include "net/http/http_stream_factory_impl_job_controller.h" #include "net/http/http_stream_factory_impl_job_controller.h"
#include "net/proxy/proxy_info.h" #include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
using testing::_; using testing::_;
...@@ -112,6 +113,7 @@ class MockHttpStreamFactoryImplJob : public HttpStreamFactoryImpl::Job { ...@@ -112,6 +113,7 @@ class MockHttpStreamFactoryImplJob : public HttpStreamFactoryImpl::Job {
HostPortPair destination, HostPortPair destination,
GURL origin_url, GURL origin_url,
AlternativeService alternative_service, AlternativeService alternative_service,
const ProxyServer& alternative_proxy_server,
NetLog* net_log); NetLog* net_log);
~MockHttpStreamFactoryImplJob() override; ~MockHttpStreamFactoryImplJob() override;
...@@ -154,6 +156,19 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory { ...@@ -154,6 +156,19 @@ class TestJobFactory : public HttpStreamFactoryImpl::JobFactory {
AlternativeService alternative_service, AlternativeService alternative_service,
NetLog* net_log) override; NetLog* net_log) override;
HttpStreamFactoryImpl::Job* CreateJob(
HttpStreamFactoryImpl::Job::Delegate* delegate,
HttpStreamFactoryImpl::JobType job_type,
HttpNetworkSession* session,
const HttpRequestInfo& request_info,
RequestPriority priority,
const SSLConfig& server_ssl_config,
const SSLConfig& proxy_ssl_config,
HostPortPair destination,
GURL origin_url,
const ProxyServer& alternative_proxy_server,
NetLog* net_log) override;
MockHttpStreamFactoryImplJob* main_job() const { return main_job_; } MockHttpStreamFactoryImplJob* main_job() const { return main_job_; }
MockHttpStreamFactoryImplJob* alternative_job() const { MockHttpStreamFactoryImplJob* alternative_job() const {
return alternative_job_; return alternative_job_;
......
...@@ -223,6 +223,12 @@ class TestResolveProxyDelegate : public ProxyDelegate { ...@@ -223,6 +223,12 @@ class TestResolveProxyDelegate : public ProxyDelegate {
bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override {
return true; return true;
} }
void GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const override {}
void OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) override {}
private: private:
bool on_resolve_proxy_called_; bool on_resolve_proxy_called_;
...@@ -260,6 +266,12 @@ class TestProxyFallbackProxyDelegate : public ProxyDelegate { ...@@ -260,6 +266,12 @@ class TestProxyFallbackProxyDelegate : public ProxyDelegate {
bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override {
return true; return true;
} }
void GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const override {}
void OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) override {}
bool on_proxy_fallback_called() const { bool on_proxy_fallback_called() const {
return on_proxy_fallback_called_; return on_proxy_fallback_called_;
......
...@@ -232,6 +232,12 @@ class TestProxyDelegateWithProxyInfo : public ProxyDelegate { ...@@ -232,6 +232,12 @@ class TestProxyDelegateWithProxyInfo : public ProxyDelegate {
bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override {
return true; return true;
} }
void GetAlternativeProxy(
const GURL& url,
const ProxyServer& resolved_proxy_server,
ProxyServer* alternative_proxy_server) const override {}
void OnAlternativeProxyBroken(
const ProxyServer& alternative_proxy_server) override {}
private: private:
ResolvedProxyInfo resolved_proxy_info_; ResolvedProxyInfo resolved_proxy_info_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment