blob: 0b7c956e028b6040b823f5f55d7bc8f6bfb4eacd [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/proxy_resolution/proxy_resolution_request_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_event_type.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/proxy_resolution/proxy_info.h"
namespace net {
ProxyResolutionRequestImpl::ProxyResolutionRequestImpl(
ConfiguredProxyResolutionService* service,
const GURL& url,
const std::string& method,
const NetworkIsolationKey& network_isolation_key,
ProxyInfo* results,
CompletionOnceCallback user_callback,
const NetLogWithSource& net_log)
: service_(service),
user_callback_(std::move(user_callback)),
results_(results),
url_(url),
method_(method),
network_isolation_key_(network_isolation_key),
resolve_job_(nullptr),
net_log_(net_log),
creation_time_(base::TimeTicks::Now()) {
DCHECK(!user_callback_.is_null());
}
ProxyResolutionRequestImpl::~ProxyResolutionRequestImpl() {
if (service_) {
service_->RemovePendingRequest(this);
net_log_.AddEvent(NetLogEventType::CANCELLED);
if (is_started())
CancelResolveJob();
// This should be emitted last, after any message |CancelResolveJob()| may
// trigger.
net_log_.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
}
}
// Starts the resolve proxy request.
int ProxyResolutionRequestImpl::Start() {
DCHECK(!was_completed());
DCHECK(!is_started());
DCHECK(service_->config_);
traffic_annotation_ = MutableNetworkTrafficAnnotationTag(
service_->config_->traffic_annotation());
if (service_->ApplyPacBypassRules(url_, results_))
return OK;
return service_->GetProxyResolver()->GetProxyForURL(
url_, network_isolation_key_, results_,
base::BindOnce(&ProxyResolutionRequestImpl::QueryComplete,
base::Unretained(this)),
&resolve_job_, net_log_);
}
void ProxyResolutionRequestImpl::StartAndCompleteCheckingForSynchronous() {
int rv = service_->TryToCompleteSynchronously(url_, results_);
if (rv == ERR_IO_PENDING)
rv = Start();
if (rv != ERR_IO_PENDING)
QueryComplete(rv);
}
void ProxyResolutionRequestImpl::CancelResolveJob() {
DCHECK(is_started());
// The request may already be running in the resolver.
resolve_job_.reset();
DCHECK(!is_started());
}
int ProxyResolutionRequestImpl::QueryDidComplete(int result_code) {
DCHECK(!was_completed());
// Clear |resolve_job_| so is_started() returns false while
// DidFinishResolvingProxy() runs.
resolve_job_.reset();
// Note that DidFinishResolvingProxy might modify |results_|.
int rv = service_->DidFinishResolvingProxy(url_, method_, results_,
result_code, net_log_);
// Make a note in the results which configuration was in use at the
// time of the resolve.
results_->did_use_pac_script_ = true;
results_->proxy_resolve_start_time_ = creation_time_;
results_->proxy_resolve_end_time_ = base::TimeTicks::Now();
// If annotation is not already set, e.g. through TryToCompleteSynchronously
// function, use in-progress-resolve annotation.
if (!results_->traffic_annotation_.is_valid())
results_->set_traffic_annotation(traffic_annotation_);
// If proxy is set without error, ensure that an annotation is provided.
if (result_code != ERR_ABORTED && !rv)
DCHECK(results_->traffic_annotation_.is_valid());
// Reset the state associated with in-progress-resolve.
traffic_annotation_.reset();
return rv;
}
int ProxyResolutionRequestImpl::QueryDidCompleteSynchronously(int result_code) {
int rv = QueryDidComplete(result_code);
service_ = nullptr;
return rv;
}
LoadState ProxyResolutionRequestImpl::GetLoadState() const {
LoadState load_state = LOAD_STATE_IDLE;
if (service_ && service_->GetLoadStateIfAvailable(&load_state))
return load_state;
if (is_started())
return resolve_job_->GetLoadState();
return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
}
// Callback for when the ProxyResolver request has completed.
void ProxyResolutionRequestImpl::QueryComplete(int result_code) {
result_code = QueryDidComplete(result_code);
CompletionOnceCallback callback = std::move(user_callback_);
service_->RemovePendingRequest(this);
service_ = nullptr;
user_callback_.Reset();
std::move(callback).Run(result_code);
}
} // namespace net