// 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 #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