blob: 94b2075ab015f1703517cb45e53a4169d03b9645 [file]
// Copyright 2026 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/linux/linux_system_proxy_resolution_service.h"
#include <utility>
#include "base/check.h"
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_delegate.h"
#include "net/log/net_log_event_type.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/linux/linux_system_proxy_resolution_request.h"
#include "net/proxy_resolution/linux/linux_system_proxy_resolver.h"
#include "net/proxy_resolution/proxy_info.h"
#include "net/proxy_resolution/proxy_list.h"
#include "net/proxy_resolution/proxy_resolution_url_sanitizer.h"
#include "url/gurl.h"
namespace net {
// static
std::unique_ptr<LinuxSystemProxyResolutionService>
LinuxSystemProxyResolutionService::Create(
std::unique_ptr<LinuxSystemProxyResolver> linux_system_proxy_resolver) {
if (!linux_system_proxy_resolver) {
return nullptr;
}
return base::WrapUnique(new LinuxSystemProxyResolutionService(
std::move(linux_system_proxy_resolver)));
}
LinuxSystemProxyResolutionService::LinuxSystemProxyResolutionService(
std::unique_ptr<LinuxSystemProxyResolver> linux_system_proxy_resolver)
: linux_system_proxy_resolver_(std::move(linux_system_proxy_resolver)) {}
LinuxSystemProxyResolutionService::~LinuxSystemProxyResolutionService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Cancel any in-progress requests. This cancels the internal requests, but
// leaves the responsibility of canceling the high-level
// ProxyResolutionRequest (by deleting it) to the client. Since the pending
// sets might be modified in one of the requests' callbacks (if it deletes
// another request), iterating through the set in a for-loop will not work.
while (!linux_pending_requests_.empty()) {
const size_t size_before = linux_pending_requests_.size();
LinuxSystemProxyResolutionRequest* req =
linux_pending_requests_.begin()->get();
// ProxyResolutionComplete() removes `req` from both pending sets and
// clears the request's service pointers, so the request's destructor will
// not attempt to touch this service again.
req->ProxyResolutionComplete(ProxyList(),
LinuxProxyResolutionStatus::kAborted);
CHECK_LT(linux_pending_requests_.size(), size_before);
}
DCHECK(pending_requests_.empty());
}
int LinuxSystemProxyResolutionService::ResolveProxy(
const GURL& url,
const std::string& method,
const NetworkAnonymizationKey& network_anonymization_key,
handles::NetworkHandle target_network,
ProxyInfo* results,
CompletionOnceCallback callback,
std::unique_ptr<ProxyResolutionRequest>* request,
const NetLogWithSource& net_log,
RequestPriority priority) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!callback.is_null());
DCHECK(request);
if (is_shutting_down()) {
return ERR_CONTEXT_SHUT_DOWN;
}
net_log.BeginEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
// Once it's created, the LinuxSystemProxyResolutionRequest immediately kicks
// off proxy resolution in the browser process.
auto req = std::make_unique<LinuxSystemProxyResolutionRequest>(
this, SanitizeUrlForProxyResolution(url), method,
network_anonymization_key, results, std::move(callback), net_log,
*linux_system_proxy_resolver_);
DCHECK(!ContainsPendingRequest(req.get()));
pending_requests_.insert(req.get());
linux_pending_requests_.insert(req.get());
// Completion will be notified through `callback`, unless the caller cancels
// the request using `request`.
*request = std::move(req);
return ERR_IO_PENDING;
}
base::DictValue LinuxSystemProxyResolutionService::GetProxySettingsForNetLog() {
base::DictValue dict;
dict.Set("source", "system");
dict.Set("description",
"Linux system proxy configuration via "
"org.freedesktop.portal.ProxyResolver");
return dict;
}
int LinuxSystemProxyResolutionService::DidFinishResolvingProxy(
const GURL& url,
const std::string& method,
const NetworkAnonymizationKey& network_anonymization_key,
ProxyInfo* result,
LinuxProxyResolutionStatus linux_status,
const NetLogWithSource& net_log) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
net_log.AddEvent(
NetLogEventType::PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST, [&] {
base::DictValue resolution_dict;
resolution_dict.Set("linux_status", static_cast<int>(linux_status));
if (linux_status == LinuxProxyResolutionStatus::kOk) {
resolution_dict.Set("proxy_info", result->ToDebugString());
}
return resolution_dict;
});
if (linux_status == LinuxProxyResolutionStatus::kOk) {
if (proxy_delegate_) {
proxy_delegate_->OnResolveProxy(url, network_anonymization_key, method,
proxy_retry_info_, result);
}
DeprioritizeBadProxyChains(proxy_retry_info_, result, net_log);
} else {
result->UseDirect();
}
net_log.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
return OK;
}
void LinuxSystemProxyResolutionService::RemoveLinuxPendingRequest(
LinuxSystemProxyResolutionRequest* req) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(linux_pending_requests_.contains(req));
linux_pending_requests_.erase(req);
}
} // namespace net