blob: f6f5b81afa7860f1da93fba6da7f6cc4f5c29afc [file] [log] [blame] [edit]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/cronet/cronet_proxy_delegate.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/trace_event/trace_event.h"
#include "base/types/expected.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_errors.h"
#include "net/proxy_resolution/proxy_info.h"
namespace cronet {
CronetProxyDelegate::CronetProxyDelegate(
cronet::proto::ProxyOptions proxy_options,
CronetContext::NetworkTasks* network_tasks)
: proxy_options_(std::move(proxy_options)), network_tasks_(network_tasks) {
CHECK(network_tasks);
}
CronetProxyDelegate::~CronetProxyDelegate() = default;
void CronetProxyDelegate::OnResolveProxy(
const GURL& url,
const net::NetworkAnonymizationKey& network_anonymization_key,
const std::string& method,
const net::ProxyRetryInfoMap& proxy_retry_info,
net::ProxyInfo* result) {
TRACE_EVENT_BEGIN("cronet", "CronetProxyDelegate::OnResolveProxy", "url", url,
"method", method, "initial_proxy_info",
result->ToDebugString());
// Using a self-calling lambda to make sure we always call TRACE_EVENT_END
// regardless of early returns.
[&] {
net::ProxyList proxy_list;
for (int i = 0; i < proxy_options_.proxies_size(); ++i) {
const auto& proxy_server = proxy_options_.proxies(i);
if (proxy_server.scheme() == cronet::proto::ProxyScheme::DIRECT) {
auto chain =
net::ProxyChain::WithOpaqueData(std::vector<net::ProxyServer>(),
/*opaque_data=*/i);
CHECK(chain.IsValid());
proxy_list.AddProxyChain(std::move(chain));
} else {
net::ProxyServer::Scheme scheme =
net::ProxyServer::Scheme::SCHEME_INVALID;
switch (proxy_server.scheme()) {
case cronet::proto::ProxyScheme::HTTP:
scheme = net::ProxyServer::Scheme::SCHEME_HTTP;
break;
case cronet::proto::ProxyScheme::HTTPS:
scheme = net::ProxyServer::Scheme::SCHEME_HTTPS;
break;
default:
NOTREACHED();
}
auto chain = net::ProxyChain::WithOpaqueData(
std::vector<net::ProxyServer>{net::ProxyServer(
scheme,
net::HostPortPair(proxy_server.host(), proxy_server.port()))},
/*opaque_data=*/i);
CHECK(chain.IsValid());
proxy_list.AddProxyChain(std::move(chain));
}
}
result->UseProxyList(proxy_list);
}();
TRACE_EVENT_END("cronet", "resulting_proxy_info", result->ToDebugString());
}
void CronetProxyDelegate::OnSuccessfulRequestAfterFailures(
const net::ProxyRetryInfoMap& proxy_retry_info) {
TRACE_EVENT_INSTANT("cronet",
"CronetProxyDelegate::OnSuccessfulRequestAfterFailures");
}
void CronetProxyDelegate::OnFallback(const net::ProxyChain& bad_chain,
int net_error) {
TRACE_EVENT_INSTANT("cronet", "CronetProxyDelegate::OnFallback", "bad_chain",
bad_chain.ToDebugString(), "net_error", net_error);
}
base::expected<net::HttpRequestHeaders, net::Error>
CronetProxyDelegate::OnBeforeTunnelRequest(
const net::ProxyChain& proxy_chain,
size_t proxy_index,
OnBeforeTunnelRequestCallback callback) {
TRACE_EVENT_BEGIN("cronet", "CronetProxyDelegate::OnBeforeTunnelRequest",
"proxy_chain", proxy_chain.ToDebugString(), "proxy_index",
proxy_index);
CHECK(proxy_chain.opaque_data().has_value());
// org.chromium.net.Proxy.Callback#onBeforeTunnelRequest always continues
// asynchronously. So, from //net's perspective, this always ends up in
// `net::ERR_IO_PENDING`.
network_tasks_->OnBeforeTunnelRequest(*proxy_chain.opaque_data(),
std::move(callback));
const auto result = net::ERR_IO_PENDING;
TRACE_EVENT_END("cronet", "result", result);
return base::unexpected(result);
}
net::Error CronetProxyDelegate::OnTunnelHeadersReceived(
const net::ProxyChain& proxy_chain,
size_t proxy_index,
const net::HttpResponseHeaders& response_headers,
net::CompletionOnceCallback callback) {
TRACE_EVENT_BEGIN("cronet", "CronetProxyDelegate::OnTunnelHeadersReceived",
"proxy_chain", proxy_chain.ToDebugString(), "proxy_index",
proxy_index);
CHECK(proxy_chain.opaque_data().has_value());
// org.chromium.net.Proxy.Callback#onTunnelHeadersReceived always continues
// asynchronously. So, from //net's perspective, this always ends up in
// `net::ERR_IO_PENDING`.
network_tasks_->OnTunnelHeadersReceived(
*proxy_chain.opaque_data(), response_headers, std::move(callback));
const auto result = net::ERR_IO_PENDING;
TRACE_EVENT_END("cronet", "result", result);
return result;
}
void CronetProxyDelegate::SetProxyResolutionService(
net::ProxyResolutionService* proxy_resolution_service) {
TRACE_EVENT_INSTANT("cronet",
"CronetProxyDelegate::SetProxyResolutionService");
}
bool CronetProxyDelegate::AliasRequiresProxyOverride(
const std::string scheme,
const std::vector<std::string>& dns_aliases,
const net::NetworkAnonymizationKey& network_anonymization_key) {
TRACE_EVENT_INSTANT("cronet",
"CronetProxyDelegate::AliasRequiresProxyOverride");
return false;
}
} // namespace cronet