blob: d577cdb1b9b1a7941e9ae1820a48b249d1c7a6f1 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/proxy_resolution/configured_proxy_resolution_request.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback_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 {
ConfiguredProxyResolutionRequest::ConfiguredProxyResolutionRequest(
ConfiguredProxyResolutionService* service,
const GURL& url,
const std::string& method,
const NetworkAnonymizationKey& network_anonymization_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_anonymization_key_(network_anonymization_key),
net_log_(net_log),
creation_time_(base::TimeTicks::Now()) {
DCHECK(!user_callback_.is_null());
}
ConfiguredProxyResolutionRequest::~ConfiguredProxyResolutionRequest() {
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 ConfiguredProxyResolutionRequest::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_anonymization_key_, results_,
base::BindOnce(&ConfiguredProxyResolutionRequest::QueryComplete,
base::Unretained(this)),
&resolve_job_, net_log_);
}
void ConfiguredProxyResolutionRequest::
StartAndCompleteCheckingForSynchronous() {
int rv = service_->TryToCompleteSynchronously(url_, results_);
if (rv == ERR_IO_PENDING)
rv = Start();
if (rv != ERR_IO_PENDING)
QueryComplete(rv);
}
void ConfiguredProxyResolutionRequest::CancelResolveJob() {
DCHECK(is_started());
// The request may already be running in the resolver.
resolve_job_.reset();
DCHECK(!is_started());
}
int ConfiguredProxyResolutionRequest::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_, network_anonymization_key_,
method_, results_, result_code,
net_log_);
// Make a note in the results which configuration was in use at the
// time of the resolve.
results_->set_proxy_resolve_start_time(creation_time_);
results_->set_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 ConfiguredProxyResolutionRequest::QueryDidCompleteSynchronously(
int result_code) {
int rv = QueryDidComplete(result_code);
service_ = nullptr;
return rv;
}
LoadState ConfiguredProxyResolutionRequest::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 ConfiguredProxyResolutionRequest::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