| // 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/mac/mac_system_proxy_resolution_request.h" |
| |
| #include <utility> |
| |
| #include "base/check_is_test.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/network_anonymization_key.h" |
| #include "net/proxy_resolution/mac/mac_system_proxy_resolution_service.h" |
| #include "net/proxy_resolution/proxy_info.h" |
| #include "net/proxy_resolution/proxy_list.h" |
| #include "net/traffic_annotation/network_traffic_annotation.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| constexpr net::NetworkTrafficAnnotationTag kMacResolverTrafficAnnotation = |
| net::DefineNetworkTrafficAnnotation("proxy_config_mac_resolver", R"( |
| semantics { |
| sender: "Proxy Config for macOS System Resolver" |
| description: |
| "Establishing a connection through a proxy server using system proxy " |
| "settings and macOS system proxy resolution code." |
| trigger: |
| "Whenever a network request is made when the system proxy settings " |
| "are used, the macOS system proxy resolver is enabled, and the " |
| "result indicates usage of a proxy server." |
| data: |
| "Proxy configuration." |
| destination: OTHER |
| destination_other: |
| "The proxy server specified in the configuration." |
| } |
| policy { |
| cookies_allowed: NO |
| setting: |
| "User cannot override system proxy settings, but can change them " |
| "through 'System Settings > Network > Proxies'." |
| policy_exception_justification: |
| "Using either of 'ProxyMode', 'ProxyServer', or 'ProxyPacUrl' " |
| "policies can set Chrome to use a specific proxy settings and avoid " |
| "system proxy." |
| })"); |
| |
| } // namespace |
| |
| MacSystemProxyResolutionRequest::MacSystemProxyResolutionRequest( |
| MacSystemProxyResolutionService* service, |
| GURL url, |
| std::string method, |
| NetworkAnonymizationKey network_anonymization_key, |
| ProxyInfo* results, |
| CompletionOnceCallback user_callback, |
| const NetLogWithSource& net_log, |
| MacSystemProxyResolver& mac_system_proxy_resolver) |
| : SystemProxyResolutionRequest(service, |
| std::move(url), |
| std::move(method), |
| std::move(network_anonymization_key), |
| results, |
| std::move(user_callback), |
| net_log), |
| mac_service_(static_cast<MacSystemProxyResolutionService*>(service)) { |
| proxy_resolution_request_ = |
| mac_system_proxy_resolver.GetProxyForUrl(url_, this); |
| } |
| |
| MacSystemProxyResolutionRequest::~MacSystemProxyResolutionRequest() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| // Cancel the platform-specific resolver request before the base destructor |
| // runs (which handles removing from pending requests and net log events). |
| // C++ destructor ordering guarantees this runs before |
| // ~SystemProxyResolutionRequest. |
| // Safe to call even after completion — proxy_resolution_request_.reset() is |
| // a no-op when already null. |
| CancelResolveRequest(); |
| } |
| |
| void MacSystemProxyResolutionRequest::CancelResolveRequest() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| proxy_resolution_request_.reset(); |
| } |
| |
| void MacSystemProxyResolutionRequest::ProxyResolutionComplete( |
| const ProxyList& proxy_list, |
| MacProxyResolutionStatus mac_status, |
| int os_error) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| CHECK(!was_completed()); |
| |
| // Skip histogram recording for aborted requests (e.g., service destruction |
| // during shutdown). Only record metrics for genuine resolution outcomes. |
| if (mac_status != MacProxyResolutionStatus::kAborted) { |
| // Record status for every resolution request. Volume is bounded by the |
| // number of URL loads when the system proxy resolver is active. |
| base::UmaHistogramEnumeration("Net.HttpProxy.MacSystemResolver.Status", |
| mac_status); |
| } |
| |
| if (os_error != 0) { |
| base::UmaHistogramSparse("Net.HttpProxy.MacSystemResolver.OsError", |
| os_error); |
| } |
| |
| proxy_resolution_request_.reset(); |
| results_->UseProxyList(proxy_list); |
| |
| // Note that DidFinishResolvingProxy might modify `results_`. |
| int net_error = mac_service_->DidFinishResolvingProxy( |
| url_, method_, network_anonymization_key_, results_, mac_status, os_error, |
| 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()); |
| results_->set_traffic_annotation( |
| MutableNetworkTrafficAnnotationTag(kMacResolverTrafficAnnotation)); |
| |
| // Move the callback out before MarkCompleted() because MarkCompleted() |
| // clears service_, and the callback invocation may destroy `this`. |
| CompletionOnceCallback callback = std::move(user_callback_); |
| |
| // Clear mac_service_ alongside MarkCompleted() which clears the base |
| // service_. Without this, mac_service_ would dangle after the service is |
| // destroyed with in-flight requests (the request outlives the service until |
| // the caller destroys the returned unique_ptr). |
| mac_service_ = nullptr; |
| MarkCompleted(); |
| std::move(callback).Run(net_error); |
| } |
| |
| MacSystemProxyResolver::Request* |
| MacSystemProxyResolutionRequest::GetProxyResolutionRequestForTesting() { |
| CHECK_IS_TEST(); |
| return proxy_resolution_request_.get(); |
| } |
| |
| void MacSystemProxyResolutionRequest::ResetProxyResolutionRequestForTesting() { |
| CHECK_IS_TEST(); |
| proxy_resolution_request_.reset(); |
| } |
| |
| } // namespace net |