0

Add support for StaleHostResolver in Android

This CL adds the required steps needed to add support for
StaleHostResolver in WebView, It pipes the data though the
network_context to the UrlRequestContext.

It's not disabled by default and a followup
CL will add the required steps for the AndroidX API.

The CL changes the default StaleOptions based on the experiment we did
and it doesn't give the ability from outside //net to change them at the
moment.

Bug: 345757312
Change-Id: Ib042cb6863aacd73e2a4f1ba983f369f05b304b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6286686
Reviewed-by: Camille Lamy <clamy@chromium.org>
Commit-Queue: Sayed Elabady <elabadysayed@chromium.org>
Reviewed-by: Stefano Duo <stefanoduo@google.com>
Reviewed-by: Richard (Torne) Coles <torne@chromium.org>
Reviewed-by: Eric Orth <ericorth@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1430933}
This commit is contained in:
elabadysayed
2025-03-11 09:40:45 -07:00
committed by Chromium LUCI CQ
parent faca54360c
commit 0117ca0b16
16 changed files with 162 additions and 52 deletions

@ -585,6 +585,7 @@ void AwBrowserContext::ConfigureNetworkContextParams(
context_params->enable_brotli = true;
context_params->enable_zstd = true;
context_params->stale_dns_enabled = enable_stale_dns_;
context_params->check_clear_text_permitted =
AwContentBrowserClient::get_check_cleartext_permitted();

@ -251,6 +251,11 @@ class AwBrowserContext : public content::BrowserContext,
// triggered by AwContents::StartPrerendering().
int allowed_prerendering_count_ = 2;
// Enables usage of net::StaleHostResolver. This will not be applied to any
// in-flight requests, only applied to the requests made afterwards. It should
// be enabled before making any requests.
bool enable_stale_dns_ = false;
base::WeakPtrFactory<AwBrowserContext> weak_method_factory_{this};
};

@ -389,6 +389,13 @@ void URLRequestContextConfig::SetContextBuilderExperimentalOptions(
std::optional<net::HostResolver::HttpsSvcbOptions> https_svcb_options;
net::StaleHostResolver::StaleOptions stale_dns_options;
// TODO(crbug.com/399372859): Run an experiment to use the default
// StaleOptions() values.
stale_dns_options.allow_other_network = false;
stale_dns_options.max_stale_uses = 0;
stale_dns_options.use_stale_on_name_not_resolved = false;
stale_dns_options.max_expired_time = base::Milliseconds(0);
const std::string* host_resolver_rules_string;
for (auto iter = experimental_options.begin();

@ -19,6 +19,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/time/time_delta_from_string.h"
#include "base/values.h"
#include "mapped_host_resolver.h"
#include "net/base/address_list.h"
#include "net/base/features.h"
#include "net/base/host_port_pair.h"
@ -32,6 +33,8 @@
#include "net/dns/mapped_host_resolver.h"
#include "net/dns/public/host_resolver_results.h"
#include "net/dns/resolve_context.h"
#include "net/dns/stale_host_resolver.h"
#include "stale_host_resolver.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "url/scheme_host_port.h"
@ -312,18 +315,20 @@ HostResolver::ResolveHostRequest::GetExperimentalResultsForTesting() const {
std::unique_ptr<HostResolver> HostResolver::Factory::CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) {
bool enable_caching,
bool enable_stale) {
return HostResolver::CreateResolver(manager, host_mapping_rules,
enable_caching);
enable_caching, enable_stale);
}
std::unique_ptr<HostResolver> HostResolver::Factory::CreateStandaloneResolver(
NetLog* net_log,
const ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) {
bool enable_caching,
bool enable_stale) {
return HostResolver::CreateStandaloneResolver(
net_log, options, host_mapping_rules, enable_caching);
net_log, options, host_mapping_rules, enable_caching, enable_stale);
}
HostResolver::ResolveHostParameters::ResolveHostParameters() = default;
@ -386,21 +391,36 @@ handles::NetworkHandle HostResolver::GetTargetNetworkForTesting() const {
std::unique_ptr<HostResolver> HostResolver::CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) {
bool enable_caching,
bool enable_stale) {
DCHECK(manager);
auto resolve_context = std::make_unique<ResolveContext>(
nullptr /* url_request_context */, enable_caching);
auto resolver = std::make_unique<ContextHostResolver>(
manager, std::move(resolve_context));
std::unique_ptr<ContextHostResolver> context_resolver =
std::make_unique<ContextHostResolver>(manager,
std::move(resolve_context));
if (host_mapping_rules.empty())
return resolver;
auto remapped_resolver =
std::make_unique<MappedHostResolver>(std::move(resolver));
remapped_resolver->SetRulesFromString(host_mapping_rules);
return remapped_resolver;
std::unique_ptr<HostResolver> resolver;
// Wrap in StaleHostResolver if needed.
if (enable_stale) {
resolver = std::make_unique<StaleHostResolver>(
std::move(context_resolver), StaleHostResolver::StaleOptions());
} else {
resolver = std::move(context_resolver);
}
// Wrap in MappedHostResolver if needed.
if (!host_mapping_rules.empty()) {
auto remapped_resolver =
std::make_unique<MappedHostResolver>(std::move(resolver));
remapped_resolver->SetRulesFromString(host_mapping_rules);
resolver = std::move(remapped_resolver);
}
return resolver;
}
// static
@ -408,17 +428,31 @@ std::unique_ptr<HostResolver> HostResolver::CreateStandaloneResolver(
NetLog* net_log,
std::optional<ManagerOptions> options,
std::string_view host_mapping_rules,
bool enable_caching) {
std::unique_ptr<ContextHostResolver> resolver =
bool enable_caching,
bool enable_stale) {
std::unique_ptr<ContextHostResolver> context_resolver =
CreateStandaloneContextResolver(net_log, std::move(options),
enable_caching);
if (host_mapping_rules.empty())
return resolver;
auto remapped_resolver =
std::make_unique<MappedHostResolver>(std::move(resolver));
remapped_resolver->SetRulesFromString(host_mapping_rules);
return remapped_resolver;
std::unique_ptr<HostResolver> resolver;
// Wrap in StaleHostResolver if needed.
if (enable_stale) {
resolver = std::make_unique<StaleHostResolver>(
std::move(context_resolver), StaleHostResolver::StaleOptions());
} else {
resolver = std::move(context_resolver);
}
// Wrap in MappedHostResolver if needed.
if (!host_mapping_rules.empty()) {
auto remapped_resolver =
std::make_unique<MappedHostResolver>(std::move(resolver));
remapped_resolver->SetRulesFromString(host_mapping_rules);
resolver = std::move(remapped_resolver);
}
return resolver;
}
// static

@ -371,14 +371,16 @@ class NET_EXPORT HostResolver {
virtual std::unique_ptr<HostResolver> CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching);
bool enable_caching,
bool enable_stale);
// See HostResolver::CreateStandaloneResolver.
virtual std::unique_ptr<HostResolver> CreateStandaloneResolver(
NetLog* net_log,
const ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching);
bool enable_caching,
bool enable_stale);
};
// Parameter-grouping struct for additional optional parameters for
@ -569,25 +571,33 @@ class NET_EXPORT HostResolver {
virtual const URLRequestContext* GetContextForTesting() const;
virtual handles::NetworkHandle GetTargetNetworkForTesting() const;
// Creates a new HostResolver. |manager| must outlive the returned resolver.
// Creates a new HostResolver. `manager` must outlive the returned resolver.
//
// If |mapping_rules| is non-empty, the mapping rules will be applied to
// If `mapping_rules` is non-empty, the mapping rules will be applied to
// requests. See MappedHostResolver for details.
// if `enable_stale` is true, Stale DNS records will be used based on the
// default configurations in `StaleHostResolver::StaleOptions`, see
// `StaleHostResolver` for details.
static std::unique_ptr<HostResolver> CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules = "",
bool enable_caching = true);
bool enable_caching = true,
bool enable_stale = false);
// Creates a HostResolver independent of any global HostResolverManager. Only
// for tests and standalone tools not part of the browser.
//
// If |mapping_rules| is non-empty, the mapping rules will be applied to
// If `mapping_rules` is non-empty, the mapping rules will be applied to
// requests. See MappedHostResolver for details.
// if `enable_stale` is true, Stale DNS records will be used based on the
// default configurations in `StaleHostResolver::StaleOptions`, see
// `StaleHostResolver` for details.
static std::unique_ptr<HostResolver> CreateStandaloneResolver(
NetLog* net_log,
std::optional<ManagerOptions> options = std::nullopt,
std::string_view host_mapping_rules = "",
bool enable_caching = true);
bool enable_caching = true,
bool enable_stale = false);
// Same, but explicitly returns the implementing ContextHostResolver. Only
// used by tests and by StaleHostResolver in Cronet. No mapping rules can be
// applied because doing so requires wrapping the ContextHostResolver.
@ -653,7 +663,6 @@ class NET_EXPORT HostResolver {
static bool MayUseNAT64ForIPv4Literal(HostResolverFlags flags,
HostResolverSource source,
const IPAddress& ip_address);
protected:
HostResolver();

@ -1270,7 +1270,8 @@ MockHostResolverFactory::~MockHostResolverFactory() = default;
std::unique_ptr<HostResolver> MockHostResolverFactory::CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) {
bool enable_caching,
bool enable_stale) {
DCHECK(host_mapping_rules.empty());
// Explicit new to access private constructor.
@ -1283,8 +1284,10 @@ std::unique_ptr<HostResolver> MockHostResolverFactory::CreateStandaloneResolver(
NetLog* net_log,
const HostResolver::ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) {
return CreateResolver(nullptr, host_mapping_rules, enable_caching);
bool enable_caching,
bool enable_stale) {
return CreateResolver(nullptr, host_mapping_rules, enable_caching,
enable_stale);
}
//-----------------------------------------------------------------------------

@ -513,12 +513,14 @@ class MockHostResolverFactory : public HostResolver::Factory {
std::unique_ptr<HostResolver> CreateResolver(
HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) override;
bool enable_caching,
bool enable_stale) override;
std::unique_ptr<HostResolver> CreateStandaloneResolver(
NetLog* net_log,
const HostResolver::ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) override;
bool enable_caching,
bool enable_stale) override;
private:
const MockHostResolverBase::RuleResolver rules_;

@ -321,10 +321,13 @@ void StaleHostResolver::RequestImpl::OnStaleDelayElapsed() {
std::move(result_callback_).Run(cache_error_);
}
// NOTE: Don't change these values without checking with all browsers using it.
// Currently this is being used but android_webview and Cronet.
StaleHostResolver::StaleOptions::StaleOptions()
: allow_other_network(false),
max_stale_uses(0),
use_stale_on_name_not_resolved(false) {}
: max_expired_time(base::Hours(6)),
allow_other_network(true),
max_stale_uses(1),
use_stale_on_name_not_resolved(true) {}
StaleHostResolver::StaleHostResolver(
std::unique_ptr<ContextHostResolver> inner_resolver,
@ -383,6 +386,11 @@ base::Value::Dict StaleHostResolver::GetDnsConfigAsValue() const {
return inner_resolver_->GetDnsConfigAsValue();
}
std::unique_ptr<HostResolver::ProbeRequest>
StaleHostResolver::CreateDohProbeRequest() {
return inner_resolver_->CreateDohProbeRequest();
}
void StaleHostResolver::SetRequestContext(URLRequestContext* request_context) {
inner_resolver_->SetRequestContext(request_context);
}

@ -109,6 +109,7 @@ class StaleHostResolver : public HostResolver {
base::Value::Dict GetDnsConfigAsValue() const override;
void SetRequestContext(URLRequestContext* request_context) override;
bool IsHappyEyeballsV3Enabled() const override;
std::unique_ptr<HostResolver::ProbeRequest> CreateDohProbeRequest() override;
// Set `tick_clock_` for testing. Must be set before issuing any requests.
NET_EXPORT void SetTickClockForTesting(const base::TickClock* tick_clock);

@ -46,6 +46,7 @@
#include "net/proxy_resolution/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_builder.h"
#include "stale_host_resolver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@ -150,10 +151,10 @@ class StaleHostResolverTest : public testing::Test {
options_.delay = base::Seconds(stale_delay_sec);
}
void SetUseStaleOnNameNotResolved() {
void SetUseStaleOnNameNotResolved(bool enabled = true) {
DCHECK(!resolver_);
options_.use_stale_on_name_not_resolved = true;
options_.use_stale_on_name_not_resolved = enabled;
}
void SetStaleUsability(int max_expired_time_sec,
@ -417,6 +418,17 @@ TEST_F(StaleHostResolverTest, FreshCache) {
WaitForIdle();
}
// Make sure that the default options are not changed unintentionally.
// Check with usages owners if this test failed due to your change.
TEST_F(StaleHostResolverTest, DefaultOptions) {
StaleHostResolver::StaleOptions stale_options;
EXPECT_TRUE(stale_options.allow_other_network);
EXPECT_TRUE(stale_options.use_stale_on_name_not_resolved);
EXPECT_EQ(base::Hours(6), stale_options.max_expired_time);
EXPECT_EQ(1, stale_options.max_stale_uses);
}
// Flaky on Linux ASan, crbug.com/838524.
#if defined(ADDRESS_SANITIZER)
#define MAYBE_StaleCache DISABLED_StaleCache
@ -474,6 +486,7 @@ TEST_F(StaleHostResolverTest, StaleCacheNameNotResolvedEnabled) {
TEST_F(StaleHostResolverTest, StaleCacheNameNotResolvedDisabled) {
SetStaleDelay(kLongStaleDelaySec);
SetNetResult(ERR_NAME_NOT_RESOLVED);
SetUseStaleOnNameNotResolved(false);
CreateResolver();
CreateCacheEntry(kAgeExpiredSec, OK);

@ -31,6 +31,7 @@
#include "net/dns/context_host_resolver.h"
#include "net/dns/host_resolver.h"
#include "net/dns/host_resolver_manager.h"
#include "net/dns/stale_host_resolver.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
@ -354,21 +355,21 @@ std::unique_ptr<URLRequestContext> URLRequestContextBuilder::Build() {
if (host_resolver_factory_) {
host_resolver_ = host_resolver_factory_->CreateResolver(
host_resolver_manager_, host_mapping_rules_,
true /* enable_caching */);
true /* enable_caching */, stale_dns_enabled_);
} else {
host_resolver_ = HostResolver::CreateResolver(host_resolver_manager_,
host_mapping_rules_,
true /* enable_caching */);
host_resolver_ = HostResolver::CreateResolver(
host_resolver_manager_, host_mapping_rules_,
true /* enable_caching */, stale_dns_enabled_);
}
} else {
if (host_resolver_factory_) {
host_resolver_ = host_resolver_factory_->CreateStandaloneResolver(
context->net_log(), HostResolver::ManagerOptions(),
host_mapping_rules_, true /* enable_caching */);
host_mapping_rules_, true /* enable_caching */, stale_dns_enabled_);
} else {
host_resolver_ = HostResolver::CreateStandaloneResolver(
context->net_log(), HostResolver::ManagerOptions(),
host_mapping_rules_, true /* enable_caching */);
host_mapping_rules_, true /* enable_caching */, stale_dns_enabled_);
}
}
host_resolver_->SetRequestContext(context.get());

@ -37,6 +37,7 @@
#include "net/base/proxy_delegate.h"
#include "net/disk_cache/disk_cache.h"
#include "net/dns/host_resolver.h"
#include "net/dns/stale_host_resolver.h"
#include "net/http/http_network_session.h"
#include "net/net_buildflags.h"
#include "net/network_error_logging/network_error_logging_service.h"
@ -149,6 +150,13 @@ class NET_EXPORT URLRequestContextBuilder {
// Sets whether Zstd compression is enabled. Disabled by default.
void set_enable_zstd(bool enable_zstd) { enable_zstd_ = enable_zstd; }
#if BUILDFLAG(IS_ANDROID)
// Sets whether StaleHostResolver is enabled. Disabled by default.
void enable_stale_dns_resolver(bool stale_dns_enabled) {
stale_dns_enabled_ = stale_dns_enabled;
}
#endif
// Sets whether Compression Dictionary is enabled. Disabled by default.
void set_enable_shared_dictionary(bool enable_shared_dictionary) {
enable_shared_dictionary_ = enable_shared_dictionary;
@ -457,6 +465,7 @@ class NET_EXPORT URLRequestContextBuilder {
bool http_cache_enabled_ = true;
bool cookie_store_set_by_client_ = false;
bool suppress_setting_socket_performance_watcher_factory_for_testing_ = false;
bool stale_dns_enabled_ = false;
handles::NetworkHandle bound_network_ = handles::kInvalidNetworkHandle;
// Used only if the context is bound to a network to customize the

@ -2034,7 +2034,8 @@ void NetworkContext::CreateHostResolver(
private_internal_resolver =
network_service_->host_resolver_factory()->CreateStandaloneResolver(
url_request_context_->net_log(), std::move(options),
"" /* host_mapping_rules */, false /* enable_caching */);
/* host_mapping_rules */ "", /* enable_caching */ false,
/* enable_stale */ false);
private_internal_resolver->SetRequestContext(url_request_context_);
internal_resolver = private_internal_resolver.get();
}
@ -2988,6 +2989,10 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
}
}
#if BUILDFLAG(IS_ANDROID)
builder.enable_stale_dns_resolver(params_->stale_dns_enabled);
#endif // BUILDFLAG(IS_ANDROID)
if (on_url_request_context_builder_configured) {
std::move(on_url_request_context_builder_configured).Run(&builder);
}

@ -505,7 +505,8 @@ class HostResolverFactory final : public net::HostResolver::Factory {
std::unique_ptr<net::HostResolver> CreateResolver(
net::HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
DCHECK(resolver_);
return std::move(resolver_);
}
@ -515,7 +516,8 @@ class HostResolverFactory final : public net::HostResolver::Factory {
net::NetLog* net_log,
const net::HostResolver::ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
NOTREACHED();
}
@ -4809,7 +4811,8 @@ class TestResolverFactory : public net::HostResolver::Factory {
std::unique_ptr<net::HostResolver> CreateResolver(
net::HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
DCHECK(host_mapping_rules.empty());
auto resolve_context = std::make_unique<net::ResolveContext>(
/*url_request_context=*/nullptr, /*enable_caching=*/false);
@ -4823,7 +4826,8 @@ class TestResolverFactory : public net::HostResolver::Factory {
net::NetLog* net_log,
const net::HostResolver::ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
DCHECK(host_mapping_rules.empty());
std::unique_ptr<net::ContextHostResolver> resolver =
net::HostResolver::CreateStandaloneContextResolver(net_log, options,

@ -618,6 +618,12 @@ struct NetworkContextParams {
// Stores mapping of endpoint name to endpoint url from initial reporting
// endpoints set by the ReportingEndpoints enterprise policy.
map<string, url.mojom.Url>? enterprise_reporting_endpoints;
// Enables usage of net::dns::StaleHostResolver. This is only available
// as opt-in in Android. This will be used during constructing
// the URLRequestContextOwner object in the NetworkContext.
[EnableIf=is_android]
bool stale_dns_enabled = false;
};
struct NetworkConditions {

@ -46,7 +46,8 @@ class HostResolverFactory final : public net::HostResolver::Factory {
std::unique_ptr<net::HostResolver> CreateResolver(
net::HostResolverManager* manager,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
DCHECK(resolver_);
return std::move(resolver_);
}
@ -56,7 +57,8 @@ class HostResolverFactory final : public net::HostResolver::Factory {
net::NetLog* net_log,
const net::HostResolver::ManagerOptions& options,
std::string_view host_mapping_rules,
bool enable_caching) override {
bool enable_caching,
bool enable_stale) override {
NOTREACHED();
}