| Index: net/http/http_stream_factory_impl_job_controller.cc
|
| diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
|
| index 11a3d60cb596313ec703fbaee398129ed671d771..7784a2e00ccd581a9820d615b066a24e5206cdf0 100644
|
| --- a/net/http/http_stream_factory_impl_job_controller.cc
|
| +++ b/net/http/http_stream_factory_impl_job_controller.cc
|
| @@ -29,6 +29,22 @@
|
|
|
| namespace net {
|
|
|
| +namespace {
|
| +
|
| +// Returns parameters associated with the proxy resolution.
|
| +std::unique_ptr<base::Value> NetLogHttpStreamJobProxyServerResolved(
|
| + const ProxyServer& proxy_server,
|
| + NetLogCaptureMode /* capture_mode */) {
|
| + std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
|
| +
|
| + dict->SetString("proxy_server", proxy_server.is_valid()
|
| + ? proxy_server.ToPacString()
|
| + : std::string());
|
| + return std::move(dict);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| // The maximum time to wait for the alternate job to complete before resuming
|
| // the main job.
|
| const int kMaxDelayTimeForMainJobSecs = 3;
|
| @@ -51,7 +67,9 @@ HttpStreamFactoryImpl::JobController::JobController(
|
| const HttpRequestInfo& request_info,
|
| bool is_preconnect,
|
| bool enable_ip_based_pooling,
|
| - bool enable_alternative_services)
|
| + bool enable_alternative_services,
|
| + const SSLConfig& server_ssl_config,
|
| + const SSLConfig& proxy_ssl_config)
|
| : factory_(factory),
|
| session_(session),
|
| job_factory_(job_factory),
|
| @@ -65,8 +83,16 @@ HttpStreamFactoryImpl::JobController::JobController(
|
| main_job_is_blocked_(false),
|
| main_job_is_resumed_(false),
|
| bound_job_(nullptr),
|
| - can_start_alternative_proxy_job_(false),
|
| - privacy_mode_(PRIVACY_MODE_DISABLED),
|
| + can_start_alternative_proxy_job_(true),
|
| + next_state_(STATE_RESOLVE_PROXY),
|
| + pac_request_(nullptr),
|
| + io_callback_(
|
| + base::Bind(&JobController::OnIOComplete, base::Unretained(this))),
|
| + request_info_(request_info),
|
| + server_ssl_config_(server_ssl_config),
|
| + proxy_ssl_config_(proxy_ssl_config),
|
| + num_streams_(0),
|
| + priority_(IDLE),
|
| net_log_(
|
| NetLogWithSource::Make(session->net_log(),
|
| NetLogSourceType::HTTP_STREAM_JOB_CONTROLLER)),
|
| @@ -81,6 +107,8 @@ HttpStreamFactoryImpl::JobController::~JobController() {
|
| main_job_.reset();
|
| alternative_job_.reset();
|
| bound_job_ = nullptr;
|
| + if (pac_request_)
|
| + session_->proxy_service()->CancelPacRequest(pac_request_);
|
| net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER);
|
| }
|
|
|
| @@ -89,21 +117,19 @@ bool HttpStreamFactoryImpl::JobController::for_websockets() {
|
| }
|
|
|
| HttpStreamFactoryImpl::Request* HttpStreamFactoryImpl::JobController::Start(
|
| - const HttpRequestInfo& request_info,
|
| HttpStreamRequest::Delegate* delegate,
|
| WebSocketHandshakeStreamBase::CreateHelper*
|
| websocket_handshake_stream_create_helper,
|
| const NetLogWithSource& source_net_log,
|
| HttpStreamRequest::StreamType stream_type,
|
| - RequestPriority priority,
|
| - const SSLConfig& server_ssl_config,
|
| - const SSLConfig& proxy_ssl_config) {
|
| + RequestPriority priority) {
|
| DCHECK(factory_);
|
| DCHECK(!request_);
|
|
|
| - privacy_mode_ = request_info.privacy_mode;
|
| + stream_type_ = stream_type;
|
| + priority_ = priority;
|
|
|
| - request_ = new Request(request_info.url, this, delegate,
|
| + request_ = new Request(request_info_.url, this, delegate,
|
| websocket_handshake_stream_create_helper,
|
| source_net_log, stream_type);
|
| // Associates |net_log_| with |source_net_log|.
|
| @@ -112,47 +138,25 @@ HttpStreamFactoryImpl::Request* HttpStreamFactoryImpl::JobController::Start(
|
| net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER_BOUND,
|
| source_net_log.source().ToEventParametersCallback());
|
|
|
| - CreateJobs(request_info, priority, server_ssl_config, proxy_ssl_config,
|
| - delegate, stream_type);
|
| -
|
| + RunLoop(OK);
|
| return request_;
|
| }
|
|
|
| -void HttpStreamFactoryImpl::JobController::Preconnect(
|
| - int num_streams,
|
| - const HttpRequestInfo& request_info,
|
| - const SSLConfig& server_ssl_config,
|
| - const SSLConfig& proxy_ssl_config) {
|
| +void HttpStreamFactoryImpl::JobController::Preconnect(int num_streams) {
|
| DCHECK(!main_job_);
|
| DCHECK(!alternative_job_);
|
| DCHECK(is_preconnect_);
|
|
|
| - privacy_mode_ = request_info.privacy_mode;
|
| -
|
| - HostPortPair destination(HostPortPair::FromURL(request_info.url));
|
| - GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
|
| + stream_type_ = HttpStreamRequest::HTTP_STREAM;
|
| + num_streams_ = num_streams;
|
|
|
| - const AlternativeService alternative_service = GetAlternativeServiceFor(
|
| - request_info, nullptr, HttpStreamRequest::HTTP_STREAM);
|
| -
|
| - if (alternative_service.protocol != kProtoUnknown) {
|
| - destination = alternative_service.host_port_pair();
|
| - ignore_result(ApplyHostMappingRules(request_info.url, &destination));
|
| - }
|
| -
|
| - // Due to how the socket pools handle priorities and idle sockets, only IDLE
|
| - // priority currently makes sense for preconnects. The priority for
|
| - // preconnects is currently ignored (see RequestSocketsForPool()), but could
|
| - // be used at some point for proxy resolution or something.
|
| - main_job_.reset(job_factory_->CreateJob(
|
| - this, PRECONNECT, session_, request_info, IDLE, server_ssl_config,
|
| - proxy_ssl_config, destination, origin_url, alternative_service,
|
| - enable_ip_based_pooling_, session_->net_log()));
|
| - main_job_->Preconnect(num_streams);
|
| + RunLoop(OK);
|
| }
|
|
|
| LoadState HttpStreamFactoryImpl::JobController::GetLoadState() const {
|
| DCHECK(request_);
|
| + if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE)
|
| + return session_->proxy_service()->GetLoadState(pac_request_);
|
| DCHECK(main_job_ || alternative_job_);
|
| if (bound_job_)
|
| return bound_job_->GetLoadState();
|
| @@ -202,7 +206,7 @@ void HttpStreamFactoryImpl::JobController::OnStreamReady(
|
| const SSLConfig& used_ssl_config) {
|
| DCHECK(job);
|
|
|
| - factory_->OnStreamReady(job->proxy_info(), privacy_mode_);
|
| + factory_->OnStreamReady(job->proxy_info(), request_info_.privacy_mode);
|
|
|
| if (IsJobOrphaned(job)) {
|
| // We have bound a job to the associated Request, |job| has been orphaned.
|
| @@ -277,7 +281,11 @@ void HttpStreamFactoryImpl::JobController::OnStreamFailed(
|
| const SSLConfig& used_ssl_config) {
|
| if (job->job_type() == ALTERNATIVE) {
|
| DCHECK_EQ(alternative_job_.get(), job);
|
| - OnAlternativeJobFailed(status);
|
| + if (alternative_job_->alternative_proxy_server().is_valid()) {
|
| + OnAlternativeProxyJobFailed(status);
|
| + } else {
|
| + OnAlternativeServiceJobFailed(status);
|
| + }
|
| }
|
|
|
| MaybeResumeMainJob(job, base::TimeDelta());
|
| @@ -309,6 +317,11 @@ void HttpStreamFactoryImpl::JobController::OnStreamFailed(
|
| }
|
| }
|
|
|
| + status = ReconsiderProxyAfterError(job, status);
|
| + if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE) {
|
| + RunLoop(OK);
|
| + return;
|
| + }
|
| request_->OnStreamFailed(status, used_ssl_config);
|
| }
|
|
|
| @@ -399,46 +412,8 @@ void HttpStreamFactoryImpl::JobController::OnNeedsProxyAuth(
|
|
|
| bool HttpStreamFactoryImpl::JobController::OnInitConnection(
|
| const ProxyInfo& proxy_info) {
|
| - return factory_->OnInitConnection(*this, proxy_info, privacy_mode_);
|
| -}
|
| -
|
| -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,
|
| - enable_ip_based_pooling_, job->net_log().net_log()));
|
| -
|
| - can_start_alternative_proxy_job_ = false;
|
| - main_job_is_blocked_ = true;
|
| -
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(
|
| - &HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob,
|
| - ptr_factory_.GetWeakPtr()));
|
| + return factory_->OnInitConnection(*this, proxy_info,
|
| + request_info_.privacy_mode);
|
| }
|
|
|
| void HttpStreamFactoryImpl::JobController::OnNewSpdySessionReady(
|
| @@ -689,52 +664,173 @@ WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl::
|
| return request_->websocket_handshake_stream_create_helper();
|
| }
|
|
|
| -void HttpStreamFactoryImpl::JobController::CreateJobs(
|
| - const HttpRequestInfo& request_info,
|
| - RequestPriority priority,
|
| - const SSLConfig& server_ssl_config,
|
| - const SSLConfig& proxy_ssl_config,
|
| - HttpStreamRequest::Delegate* delegate,
|
| - HttpStreamRequest::StreamType stream_type) {
|
| +void HttpStreamFactoryImpl::JobController::OnIOComplete(int result) {
|
| + RunLoop(result);
|
| +}
|
| +
|
| +void HttpStreamFactoryImpl::JobController::RunLoop(int result) {
|
| + int rv = DoLoop(result);
|
| + if (rv == ERR_IO_PENDING)
|
| + return;
|
| + if (rv != OK) {
|
| + // DoLoop can only fail during proxy resolution step which happens before
|
| + // any jobs are created. Notify |request_| of the failure one message loop
|
| + // iteration later to avoid re-entrancy.
|
| + DCHECK(!main_job_);
|
| + DCHECK(!alternative_job_);
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&HttpStreamFactoryImpl::JobController::NotifyRequestFailed,
|
| + ptr_factory_.GetWeakPtr(), rv));
|
| + }
|
| +}
|
| +
|
| +int HttpStreamFactoryImpl::JobController::DoLoop(int rv) {
|
| + DCHECK_NE(next_state_, STATE_NONE);
|
| + do {
|
| + State state = next_state_;
|
| + next_state_ = STATE_NONE;
|
| + switch (state) {
|
| + case STATE_RESOLVE_PROXY:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoResolveProxy();
|
| + break;
|
| + case STATE_RESOLVE_PROXY_COMPLETE:
|
| + rv = DoResolveProxyComplete(rv);
|
| + break;
|
| + case STATE_CREATE_JOBS:
|
| + DCHECK_EQ(OK, rv);
|
| + rv = DoCreateJobs();
|
| + break;
|
| + default:
|
| + NOTREACHED() << "bad state";
|
| + break;
|
| + }
|
| + } while (next_state_ != STATE_NONE && rv != ERR_IO_PENDING);
|
| + return rv;
|
| +}
|
| +
|
| +int HttpStreamFactoryImpl::JobController::DoResolveProxy() {
|
| + DCHECK(!pac_request_);
|
| + DCHECK(session_);
|
| +
|
| + next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
|
| +
|
| + if (request_info_.load_flags & LOAD_BYPASS_PROXY) {
|
| + proxy_info_.UseDirect();
|
| + return OK;
|
| + }
|
| +
|
| + HostPortPair destination(HostPortPair::FromURL(request_info_.url));
|
| + GURL origin_url = ApplyHostMappingRules(request_info_.url, &destination);
|
| +
|
| + return session_->proxy_service()->ResolveProxy(
|
| + origin_url, request_info_.method, &proxy_info_, io_callback_,
|
| + &pac_request_, session_->params().proxy_delegate, net_log_);
|
| +}
|
| +
|
| +int HttpStreamFactoryImpl::JobController::DoResolveProxyComplete(int rv) {
|
| + DCHECK_NE(ERR_IO_PENDING, rv);
|
| +
|
| + pac_request_ = nullptr;
|
| + net_log_.AddEvent(
|
| + NetLogEventType::HTTP_STREAM_JOB_PROXY_SERVER_RESOLVED,
|
| + base::Bind(
|
| + &NetLogHttpStreamJobProxyServerResolved,
|
| + proxy_info_.is_empty() ? ProxyServer() : proxy_info_.proxy_server()));
|
| +
|
| + if (rv != OK)
|
| + return rv;
|
| + // Remove unsupported proxies from the list.
|
| + int supported_proxies = ProxyServer::SCHEME_DIRECT |
|
| + ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS |
|
| + ProxyServer::SCHEME_SOCKS4 |
|
| + ProxyServer::SCHEME_SOCKS5;
|
| + if (session_->IsQuicEnabled())
|
| + supported_proxies |= ProxyServer::SCHEME_QUIC;
|
| + proxy_info_.RemoveProxiesWithoutScheme(supported_proxies);
|
| +
|
| + if (proxy_info_.is_empty()) {
|
| + // No proxies/direct to choose from.
|
| + return ERR_NO_SUPPORTED_PROXIES;
|
| + }
|
| +
|
| + next_state_ = STATE_CREATE_JOBS;
|
| + return rv;
|
| +}
|
| +
|
| +int HttpStreamFactoryImpl::JobController::DoCreateJobs() {
|
| DCHECK(!main_job_);
|
| DCHECK(!alternative_job_);
|
| - HostPortPair destination(HostPortPair::FromURL(request_info.url));
|
| - GURL origin_url = ApplyHostMappingRules(request_info.url, &destination);
|
|
|
| - main_job_.reset(job_factory_->CreateJob(
|
| - this, MAIN, session_, request_info, priority, server_ssl_config,
|
| - proxy_ssl_config, destination, origin_url, enable_ip_based_pooling_,
|
| - net_log_.net_log()));
|
| + HostPortPair destination(HostPortPair::FromURL(request_info_.url));
|
| + GURL origin_url = ApplyHostMappingRules(request_info_.url, &destination);
|
|
|
| // Create an alternative job if alternative service is set up for this domain.
|
| const AlternativeService alternative_service =
|
| - GetAlternativeServiceFor(request_info, delegate, stream_type);
|
| -
|
| + GetAlternativeServiceFor(request_info_, delegate_, stream_type_);
|
| +
|
| + if (is_preconnect_) {
|
| + // Due to how the socket pools handle priorities and idle sockets, only IDLE
|
| + // priority currently makes sense for preconnects. The priority for
|
| + // preconnects is currently ignored (see RequestSocketsForPool()), but could
|
| + // be used at some point for proxy resolution or something.
|
| + main_job_.reset(job_factory_->CreateAltSvcJob(
|
| + this, PRECONNECT, session_, request_info_, IDLE, proxy_info_,
|
| + server_ssl_config_, proxy_ssl_config_, destination, origin_url,
|
| + alternative_service, enable_ip_based_pooling_, session_->net_log()));
|
| + main_job_->Preconnect(num_streams_);
|
| + return OK;
|
| + }
|
| + main_job_.reset(job_factory_->CreateMainJob(
|
| + this, MAIN, session_, request_info_, priority_, proxy_info_,
|
| + server_ssl_config_, proxy_ssl_config_, destination, origin_url,
|
| + enable_ip_based_pooling_, net_log_.net_log()));
|
| + // Alternative Service can only be set for HTTPS requests while Alternative
|
| + // Proxy is set for HTTP requests.
|
| if (alternative_service.protocol != kProtoUnknown) {
|
| // Never share connection with other jobs for FTP requests.
|
| DVLOG(1) << "Selected alternative service (host: "
|
| << alternative_service.host_port_pair().host()
|
| << " port: " << alternative_service.host_port_pair().port() << ")";
|
|
|
| - DCHECK(!request_info.url.SchemeIs(url::kFtpScheme));
|
| + DCHECK(!request_info_.url.SchemeIs(url::kFtpScheme));
|
| HostPortPair alternative_destination(alternative_service.host_port_pair());
|
| ignore_result(
|
| - ApplyHostMappingRules(request_info.url, &alternative_destination));
|
| + ApplyHostMappingRules(request_info_.url, &alternative_destination));
|
|
|
| - alternative_job_.reset(job_factory_->CreateJob(
|
| - this, ALTERNATIVE, session_, request_info, priority, server_ssl_config,
|
| - proxy_ssl_config, alternative_destination, origin_url,
|
| - alternative_service, enable_ip_based_pooling_, net_log_.net_log()));
|
| + alternative_job_.reset(job_factory_->CreateAltSvcJob(
|
| + this, ALTERNATIVE, session_, request_info_, priority_, proxy_info_,
|
| + server_ssl_config_, proxy_ssl_config_, alternative_destination,
|
| + origin_url, alternative_service, enable_ip_based_pooling_,
|
| + net_log_.net_log()));
|
|
|
| main_job_is_blocked_ = true;
|
| alternative_job_->Start(request_->stream_type());
|
| } else {
|
| - can_start_alternative_proxy_job_ = true;
|
| + ProxyServer alternative_proxy_server;
|
| + if (ShouldCreateAlternativeProxyServerJob(proxy_info_, request_info_.url,
|
| + &alternative_proxy_server)) {
|
| + DCHECK(!main_job_is_blocked_);
|
| + ProxyInfo alternative_proxy_info;
|
| + alternative_proxy_info.UseProxyServer(alternative_proxy_server);
|
| +
|
| + alternative_job_.reset(job_factory_->CreateAltProxyJob(
|
| + this, ALTERNATIVE, session_, request_info_, priority_,
|
| + alternative_proxy_info, server_ssl_config_, proxy_ssl_config_,
|
| + destination, origin_url, alternative_proxy_server,
|
| + enable_ip_based_pooling_, net_log_.net_log()));
|
| +
|
| + can_start_alternative_proxy_job_ = false;
|
| + main_job_is_blocked_ = true;
|
| + alternative_job_->Start(request_->stream_type());
|
| + }
|
| }
|
| // 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
|
| // MessageLoop, so starting |main_job_| is always safe.
|
| main_job_->Start(request_->stream_type());
|
| + return OK;
|
| }
|
|
|
| void HttpStreamFactoryImpl::JobController::BindJob(Job* job) {
|
| @@ -830,20 +926,14 @@ void HttpStreamFactoryImpl::JobController::MarkRequestComplete(
|
| request_->Complete(was_alpn_negotiated, negotiated_protocol, using_spdy);
|
| }
|
|
|
| -void HttpStreamFactoryImpl::JobController::OnAlternativeJobFailed(
|
| +void HttpStreamFactoryImpl::JobController::OnAlternativeServiceJobFailed(
|
| int net_error) {
|
| DCHECK_EQ(alternative_job_->job_type(), ALTERNATIVE);
|
| DCHECK_NE(OK, net_error);
|
| + DCHECK_NE(kProtoUnknown, alternative_job_->alternative_service().protocol);
|
|
|
| alternative_job_net_error_ = net_error;
|
| -
|
| - if (alternative_job_->alternative_proxy_server().is_valid()) {
|
| - failed_alternative_proxy_server_ =
|
| - alternative_job_->alternative_proxy_server();
|
| - } else {
|
| - DCHECK(!failed_alternative_proxy_server_.is_valid());
|
| - failed_alternative_service_ = alternative_job_->alternative_service();
|
| - }
|
| + failed_alternative_service_ = alternative_job_->alternative_service();
|
|
|
| if (IsJobOrphaned(alternative_job_.get())) {
|
| // If |request_| is gone then it must have been successfully served by
|
| @@ -854,32 +944,38 @@ void HttpStreamFactoryImpl::JobController::OnAlternativeJobFailed(
|
| }
|
| }
|
|
|
| +void HttpStreamFactoryImpl::JobController::OnAlternativeProxyJobFailed(
|
| + int net_error) {
|
| + DCHECK_EQ(alternative_job_->job_type(), ALTERNATIVE);
|
| + DCHECK_NE(OK, net_error);
|
| + DCHECK(alternative_job_->alternative_proxy_server().is_valid());
|
| +
|
| + // Need to mark alt proxy as broken regardless whether the job is bound.
|
| + ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
|
| + if (proxy_delegate) {
|
| + proxy_delegate->OnAlternativeProxyBroken(
|
| + alternative_job_->alternative_proxy_server());
|
| + }
|
| +}
|
| +
|
| void HttpStreamFactoryImpl::JobController::ReportBrokenAlternativeService() {
|
| - DCHECK(failed_alternative_service_.protocol != kProtoUnknown ||
|
| - failed_alternative_proxy_server_.is_valid());
|
| + DCHECK(failed_alternative_service_.protocol != kProtoUnknown);
|
| DCHECK_NE(OK, alternative_job_net_error_);
|
|
|
| - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AlternateServiceFailed",
|
| - -alternative_job_net_error_);
|
| + int error_to_report = alternative_job_net_error_;
|
| + alternative_job_net_error_ = OK;
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.AlternateServiceFailed", -error_to_report);
|
|
|
| - if (alternative_job_net_error_ == ERR_NETWORK_CHANGED ||
|
| - alternative_job_net_error_ == ERR_INTERNET_DISCONNECTED) {
|
| + if (error_to_report == ERR_NETWORK_CHANGED ||
|
| + error_to_report == ERR_INTERNET_DISCONNECTED) {
|
| // No need to mark alternative service or proxy as broken.
|
| return;
|
| }
|
|
|
| - if (failed_alternative_proxy_server_.is_valid()) {
|
| - ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
|
| - if (proxy_delegate) {
|
| - proxy_delegate->OnAlternativeProxyBroken(
|
| - failed_alternative_proxy_server_);
|
| - }
|
| - } else {
|
| - HistogramBrokenAlternateProtocolLocation(
|
| - BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
|
| - session_->http_server_properties()->MarkAlternativeServiceBroken(
|
| - failed_alternative_service_);
|
| - }
|
| + HistogramBrokenAlternateProtocolLocation(
|
| + BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
|
| + session_->http_server_properties()->MarkAlternativeServiceBroken(
|
| + failed_alternative_service_);
|
| }
|
|
|
| void HttpStreamFactoryImpl::JobController::MaybeNotifyFactoryOfCompletion() {
|
| @@ -889,6 +985,12 @@ void HttpStreamFactoryImpl::JobController::MaybeNotifyFactoryOfCompletion() {
|
| }
|
| }
|
|
|
| +void HttpStreamFactoryImpl::JobController::NotifyRequestFailed(int rv) {
|
| + if (!request_)
|
| + return;
|
| + request_->OnStreamFailed(rv, server_ssl_config_);
|
| +}
|
| +
|
| GURL HttpStreamFactoryImpl::JobController::ApplyHostMappingRules(
|
| const GURL& url,
|
| HostPortPair* endpoint) {
|
| @@ -1032,7 +1134,6 @@ HttpStreamFactoryImpl::JobController::GetAlternativeServiceForInternal(
|
|
|
| bool HttpStreamFactoryImpl::JobController::
|
| ShouldCreateAlternativeProxyServerJob(
|
| - Job* job,
|
| const ProxyInfo& proxy_info,
|
| const GURL& url,
|
| ProxyServer* alternative_proxy_server) const {
|
| @@ -1047,18 +1148,6 @@ bool HttpStreamFactoryImpl::JobController::
|
| return false;
|
| }
|
|
|
| - if (job->job_type() == ALTERNATIVE) {
|
| - // If |job| is using alternative service, then alternative proxy server
|
| - // should not be used.
|
| - return false;
|
| - }
|
| -
|
| - if (is_preconnect_ || 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.
|
| @@ -1075,7 +1164,6 @@ bool HttpStreamFactoryImpl::JobController::
|
| ProxyDelegate* proxy_delegate = session_->params().proxy_delegate;
|
| if (!proxy_delegate)
|
| return false;
|
| -
|
| proxy_delegate->GetAlternativeProxy(url, proxy_info.proxy_server(),
|
| alternative_proxy_server);
|
|
|
| @@ -1123,15 +1211,56 @@ void HttpStreamFactoryImpl::JobController::ReportAlternateProtocolUsage(
|
| proxy_server_used);
|
| }
|
|
|
| -void HttpStreamFactoryImpl::JobController::StartAlternativeProxyServerJob() {
|
| - if (!alternative_job_ || !request_)
|
| - return;
|
| - DCHECK(alternative_job_->alternative_proxy_server().is_valid());
|
| - alternative_job_->Start(request_->stream_type());
|
| -}
|
| -
|
| bool HttpStreamFactoryImpl::JobController::IsJobOrphaned(Job* job) const {
|
| return !request_ || (job_bound_ && bound_job_ != job);
|
| }
|
|
|
| +int HttpStreamFactoryImpl::JobController::ReconsiderProxyAfterError(Job* job,
|
| + int error) {
|
| + // ReconsiderProxyAfterError() should only be called when the last job fails.
|
| + DCHECK(!(alternative_job_ && main_job_));
|
| + DCHECK(!pac_request_);
|
| + DCHECK(session_);
|
| +
|
| + if (!job->should_reconsider_proxy())
|
| + return error;
|
| +
|
| + DCHECK(!job->alternative_proxy_server().is_valid());
|
| +
|
| + // Do not bypass non-QUIC proxy on ERR_MSG_TOO_BIG.
|
| + if (!proxy_info_.is_quic() && error == ERR_MSG_TOO_BIG)
|
| + return error;
|
| +
|
| + if (request_info_.load_flags & LOAD_BYPASS_PROXY)
|
| + return error;
|
| +
|
| + if (proxy_info_.is_https() && proxy_ssl_config_.send_client_cert) {
|
| + session_->ssl_client_auth_cache()->Remove(
|
| + proxy_info_.proxy_server().host_port_pair());
|
| + }
|
| +
|
| + HostPortPair destination(HostPortPair::FromURL(request_info_.url));
|
| + GURL origin_url = ApplyHostMappingRules(request_info_.url, &destination);
|
| +
|
| + int rv = session_->proxy_service()->ReconsiderProxyAfterError(
|
| + origin_url, request_info_.method, error, &proxy_info_, io_callback_,
|
| + &pac_request_, session_->params().proxy_delegate, net_log_);
|
| + if (rv == OK || rv == ERR_IO_PENDING) {
|
| + RemoveRequestFromSpdySessionRequestMap();
|
| + // Abandon all Jobs and start over.
|
| + job_bound_ = false;
|
| + bound_job_ = nullptr;
|
| + alternative_job_.reset();
|
| + main_job_.reset();
|
| + next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
|
| + } else {
|
| + // If ReconsiderProxyAfterError() failed synchronously, it means
|
| + // there was nothing left to fall-back to, so fail the transaction
|
| + // with the last connection error we got.
|
| + // TODO(eroman): This is a confusing contract, make it more obvious.
|
| + rv = error;
|
| + }
|
| + return rv;
|
| +}
|
| +
|
| } // namespace net
|
|
|