xref: /aosp_15_r20/external/cronet/components/cronet/stale_host_resolver.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/cronet/stale_host_resolver.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/check_op.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/notreached.h"
18 #include "base/timer/timer.h"
19 #include "base/values.h"
20 #include "net/base/host_port_pair.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/network_anonymization_key.h"
23 #include "net/dns/context_host_resolver.h"
24 #include "net/dns/dns_util.h"
25 #include "net/dns/host_resolver.h"
26 #include "net/dns/public/host_resolver_results.h"
27 #include "net/dns/public/host_resolver_source.h"
28 #include "net/dns/public/resolve_error_info.h"
29 #include "net/log/net_log_with_source.h"
30 #include "url/scheme_host_port.h"
31 
32 namespace cronet {
33 
34 // A request made by the StaleHostResolver. May return fresh cached data,
35 // network data, or stale cached data.
36 class StaleHostResolver::RequestImpl
37     : public net::HostResolver::ResolveHostRequest {
38  public:
39   // StaleOptions will be read directly from |resolver|.
40   RequestImpl(base::WeakPtr<StaleHostResolver> resolver,
41               const net::HostPortPair& host,
42               const net::NetworkAnonymizationKey& network_anonymization_key,
43               const net::NetLogWithSource& net_log,
44               const ResolveHostParameters& input_parameters,
45               const base::TickClock* tick_clock);
46   ~RequestImpl() override = default;
47 
48   // net::HostResolver::ResolveHostRequest implementation:
49   int Start(net::CompletionOnceCallback result_callback) override;
50   const net::AddressList* GetAddressResults() const override;
51   const net::HostResolverEndpointResults* GetEndpointResults() const override;
52   const std::vector<std::string>* GetTextResults() const override;
53   const std::vector<net::HostPortPair>* GetHostnameResults() const override;
54   const std::set<std::string>* GetDnsAliasResults() const override;
55   net::ResolveErrorInfo GetResolveErrorInfo() const override;
56   const std::optional<net::HostCache::EntryStaleness>& GetStaleInfo()
57       const override;
58   void ChangeRequestPriority(net::RequestPriority priority) override;
59 
60   // Called on completion of an asynchronous (network) inner request. Expected
61   // to be called by StaleHostResolver::OnNetworkRequestComplete().
62   void OnNetworkRequestComplete(int error);
63 
64  private:
have_network_request() const65   bool have_network_request() const { return network_request_ != nullptr; }
have_cache_data() const66   bool have_cache_data() const {
67     return cache_error_ != net::ERR_DNS_CACHE_MISS;
68   }
have_returned() const69   bool have_returned() const { return result_callback_.is_null(); }
70 
71   // Determines if |cache_error_| and |cache_request_| represents a usable entry
72   // per the requirements of |resolver_->options_|.
73   bool CacheDataIsUsable() const;
74 
75   // Callback for |stale_timer_| that returns stale results.
76   void OnStaleDelayElapsed();
77 
78   base::WeakPtr<StaleHostResolver> resolver_;
79 
80   const net::HostPortPair host_;
81   const net::NetworkAnonymizationKey network_anonymization_key_;
82   const net::NetLogWithSource net_log_;
83   const ResolveHostParameters input_parameters_;
84 
85   // The callback passed into |Start()| to be called when the request returns.
86   net::CompletionOnceCallback result_callback_;
87 
88   // The error from the stale cache entry, if there was one.
89   // If not, net::ERR_DNS_CACHE_MISS.
90   int cache_error_;
91   // Inner local-only/stale-allowed request.
92   std::unique_ptr<ResolveHostRequest> cache_request_;
93   // A timer that fires when the |Request| should return stale results, if the
94   // underlying network request has not finished yet.
95   base::OneShotTimer stale_timer_;
96 
97   // An inner request for network results. Only set if |cache_request_| gave a
98   // stale or unusable result, and unset if the stale result is to be used as
99   // the overall result.
100   std::unique_ptr<ResolveHostRequest> network_request_;
101 
102   base::WeakPtrFactory<RequestImpl> weak_ptr_factory_{this};
103 };
104 
RequestImpl(base::WeakPtr<StaleHostResolver> resolver,const net::HostPortPair & host,const net::NetworkAnonymizationKey & network_anonymization_key,const net::NetLogWithSource & net_log,const ResolveHostParameters & input_parameters,const base::TickClock * tick_clock)105 StaleHostResolver::RequestImpl::RequestImpl(
106     base::WeakPtr<StaleHostResolver> resolver,
107     const net::HostPortPair& host,
108     const net::NetworkAnonymizationKey& network_anonymization_key,
109     const net::NetLogWithSource& net_log,
110     const ResolveHostParameters& input_parameters,
111     const base::TickClock* tick_clock)
112     : resolver_(std::move(resolver)),
113       host_(host),
114       network_anonymization_key_(network_anonymization_key),
115       net_log_(net_log),
116       input_parameters_(input_parameters),
117       cache_error_(net::ERR_DNS_CACHE_MISS),
118       stale_timer_(tick_clock) {
119   DCHECK(resolver_);
120 }
121 
Start(net::CompletionOnceCallback result_callback)122 int StaleHostResolver::RequestImpl::Start(
123     net::CompletionOnceCallback result_callback) {
124   DCHECK(resolver_);
125   DCHECK(!result_callback.is_null());
126 
127   net::HostResolver::ResolveHostParameters cache_parameters = input_parameters_;
128   cache_parameters.cache_usage =
129       net::HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
130   cache_parameters.source = net::HostResolverSource::LOCAL_ONLY;
131   cache_request_ = resolver_->inner_resolver_->CreateRequest(
132       host_, network_anonymization_key_, net_log_, cache_parameters);
133   int error =
134       cache_request_->Start(base::BindOnce([](int error) { NOTREACHED(); }));
135   DCHECK_NE(net::ERR_IO_PENDING, error);
136   cache_error_ = cache_request_->GetResolveErrorInfo().error;
137   DCHECK_NE(net::ERR_IO_PENDING, cache_error_);
138   // If it's a fresh cache hit (or literal), return it synchronously.
139   if (cache_error_ != net::ERR_DNS_CACHE_MISS &&
140       (!cache_request_->GetStaleInfo() ||
141        !cache_request_->GetStaleInfo().value().is_stale())) {
142     return cache_error_;
143   }
144 
145   if (cache_error_ != net::ERR_DNS_CACHE_MISS &&
146       input_parameters_.cache_usage ==
147           net::HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED) {
148     return cache_error_;
149   }
150 
151   result_callback_ = std::move(result_callback);
152 
153   if (CacheDataIsUsable()) {
154     // |stale_timer_| is deleted when the Request is deleted, so it's safe to
155     // use Unretained here.
156     stale_timer_.Start(
157         FROM_HERE, resolver_->options_.delay,
158         base::BindOnce(&StaleHostResolver::RequestImpl::OnStaleDelayElapsed,
159                        base::Unretained(this)));
160   } else {
161     cache_error_ = net::ERR_DNS_CACHE_MISS;
162     cache_request_.reset();
163   }
164 
165   // Don't check the cache again.
166   net::HostResolver::ResolveHostParameters no_cache_parameters =
167       input_parameters_;
168   no_cache_parameters.cache_usage =
169       net::HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
170   network_request_ = resolver_->inner_resolver_->CreateRequest(
171       host_, network_anonymization_key_, net_log_, no_cache_parameters);
172   int network_rv = network_request_->Start(
173       base::BindOnce(&StaleHostResolver::OnNetworkRequestComplete, resolver_,
174                      network_request_.get(), weak_ptr_factory_.GetWeakPtr()));
175 
176   // Network resolver has returned synchronously (for example by resolving from
177   // /etc/hosts).
178   if (network_rv != net::ERR_IO_PENDING) {
179     stale_timer_.Stop();
180   }
181   return network_rv;
182 }
183 
GetAddressResults() const184 const net::AddressList* StaleHostResolver::RequestImpl::GetAddressResults()
185     const {
186   if (network_request_)
187     return network_request_->GetAddressResults();
188 
189   DCHECK(cache_request_);
190   return cache_request_->GetAddressResults();
191 }
192 
193 const net::HostResolverEndpointResults*
GetEndpointResults() const194 StaleHostResolver::RequestImpl::GetEndpointResults() const {
195   if (network_request_)
196     return network_request_->GetEndpointResults();
197 
198   DCHECK(cache_request_);
199   return cache_request_->GetEndpointResults();
200 }
201 
GetTextResults() const202 const std::vector<std::string>* StaleHostResolver::RequestImpl::GetTextResults()
203     const {
204   if (network_request_)
205     return network_request_->GetTextResults();
206 
207   DCHECK(cache_request_);
208   return cache_request_->GetTextResults();
209 }
210 
211 const std::vector<net::HostPortPair>*
GetHostnameResults() const212 StaleHostResolver::RequestImpl::GetHostnameResults() const {
213   if (network_request_)
214     return network_request_->GetHostnameResults();
215 
216   DCHECK(cache_request_);
217   return cache_request_->GetHostnameResults();
218 }
219 
220 const std::set<std::string>*
GetDnsAliasResults() const221 StaleHostResolver::RequestImpl::GetDnsAliasResults() const {
222   if (network_request_)
223     return network_request_->GetDnsAliasResults();
224 
225   DCHECK(cache_request_);
226   return cache_request_->GetDnsAliasResults();
227 }
228 
GetResolveErrorInfo() const229 net::ResolveErrorInfo StaleHostResolver::RequestImpl::GetResolveErrorInfo()
230     const {
231   if (network_request_)
232     return network_request_->GetResolveErrorInfo();
233   DCHECK(cache_request_);
234   return cache_request_->GetResolveErrorInfo();
235 }
236 
237 const std::optional<net::HostCache::EntryStaleness>&
GetStaleInfo() const238 StaleHostResolver::RequestImpl::GetStaleInfo() const {
239   if (network_request_)
240     return network_request_->GetStaleInfo();
241 
242   DCHECK(cache_request_);
243   return cache_request_->GetStaleInfo();
244 }
245 
ChangeRequestPriority(net::RequestPriority priority)246 void StaleHostResolver::RequestImpl::ChangeRequestPriority(
247     net::RequestPriority priority) {
248   if (network_request_) {
249     network_request_->ChangeRequestPriority(priority);
250   } else {
251     DCHECK(cache_request_);
252     cache_request_->ChangeRequestPriority(priority);
253   }
254 }
255 
OnNetworkRequestComplete(int error)256 void StaleHostResolver::RequestImpl::OnNetworkRequestComplete(int error) {
257   DCHECK(resolver_);
258   DCHECK(have_network_request());
259   DCHECK(!have_returned());
260 
261   bool return_stale_data_instead_of_network_name_not_resolved =
262       resolver_->options_.use_stale_on_name_not_resolved &&
263       error == net::ERR_NAME_NOT_RESOLVED && have_cache_data();
264 
265   stale_timer_.Stop();
266 
267   if (return_stale_data_instead_of_network_name_not_resolved) {
268     network_request_.reset();
269     std::move(result_callback_).Run(cache_error_);
270   } else {
271     cache_request_.reset();
272     std::move(result_callback_).Run(error);
273   }
274 }
275 
CacheDataIsUsable() const276 bool StaleHostResolver::RequestImpl::CacheDataIsUsable() const {
277   DCHECK(resolver_);
278   DCHECK(cache_request_);
279 
280   if (cache_error_ != net::OK)
281     return false;
282 
283   DCHECK(cache_request_->GetStaleInfo());
284   const net::HostCache::EntryStaleness& staleness =
285       cache_request_->GetStaleInfo().value();
286 
287   if (resolver_->options_.max_expired_time != base::TimeDelta() &&
288       staleness.expired_by > resolver_->options_.max_expired_time) {
289     return false;
290   }
291   if (resolver_->options_.max_stale_uses > 0 &&
292       staleness.stale_hits > resolver_->options_.max_stale_uses) {
293     return false;
294   }
295   if (!resolver_->options_.allow_other_network &&
296       staleness.network_changes > 0) {
297     return false;
298   }
299   return true;
300 }
301 
OnStaleDelayElapsed()302 void StaleHostResolver::RequestImpl::OnStaleDelayElapsed() {
303   DCHECK(!have_returned());
304   DCHECK(have_cache_data());
305   DCHECK(have_network_request());
306 
307   // If resolver is destroyed after starting a request, the request is
308   // considered cancelled and callbacks must not be invoked. Logging the
309   // cancellation will happen on destruction of |this|.
310   if (!resolver_) {
311     network_request_.reset();
312     return;
313   }
314   DCHECK(CacheDataIsUsable());
315 
316   // Detach |network_request_| to allow it to complete and backfill the cache
317   // even if |this| is destroyed.
318   resolver_->DetachRequest(std::move(network_request_));
319 
320   std::move(result_callback_).Run(cache_error_);
321 }
322 
StaleOptions()323 StaleHostResolver::StaleOptions::StaleOptions()
324     : allow_other_network(false),
325       max_stale_uses(0),
326       use_stale_on_name_not_resolved(false) {}
327 
StaleHostResolver(std::unique_ptr<net::ContextHostResolver> inner_resolver,const StaleOptions & stale_options)328 StaleHostResolver::StaleHostResolver(
329     std::unique_ptr<net::ContextHostResolver> inner_resolver,
330     const StaleOptions& stale_options)
331     : inner_resolver_(std::move(inner_resolver)), options_(stale_options) {
332   DCHECK_LE(0, stale_options.max_expired_time.InMicroseconds());
333   DCHECK_LE(0, stale_options.max_stale_uses);
334 }
335 
~StaleHostResolver()336 StaleHostResolver::~StaleHostResolver() {}
337 
OnShutdown()338 void StaleHostResolver::OnShutdown() {
339   inner_resolver_->OnShutdown();
340 }
341 
342 std::unique_ptr<net::HostResolver::ResolveHostRequest>
CreateRequest(url::SchemeHostPort host,net::NetworkAnonymizationKey network_anonymization_key,net::NetLogWithSource net_log,std::optional<ResolveHostParameters> optional_parameters)343 StaleHostResolver::CreateRequest(
344     url::SchemeHostPort host,
345     net::NetworkAnonymizationKey network_anonymization_key,
346     net::NetLogWithSource net_log,
347     std::optional<ResolveHostParameters> optional_parameters) {
348   // TODO(crbug.com/40181080): Propagate scheme.
349   return CreateRequest(net::HostPortPair::FromSchemeHostPort(host),
350                        network_anonymization_key, net_log, optional_parameters);
351 }
352 
353 std::unique_ptr<net::HostResolver::ResolveHostRequest>
CreateRequest(const net::HostPortPair & host,const net::NetworkAnonymizationKey & network_anonymization_key,const net::NetLogWithSource & net_log,const std::optional<ResolveHostParameters> & optional_parameters)354 StaleHostResolver::CreateRequest(
355     const net::HostPortPair& host,
356     const net::NetworkAnonymizationKey& network_anonymization_key,
357     const net::NetLogWithSource& net_log,
358     const std::optional<ResolveHostParameters>& optional_parameters) {
359   DCHECK(tick_clock_);
360   return std::make_unique<RequestImpl>(
361       weak_ptr_factory_.GetWeakPtr(), host, network_anonymization_key, net_log,
362       optional_parameters.value_or(ResolveHostParameters()), tick_clock_);
363 }
364 
365 std::unique_ptr<net::HostResolver::ServiceEndpointRequest>
CreateServiceEndpointRequest(Host host,net::NetworkAnonymizationKey network_anonymization_key,net::NetLogWithSource net_log,ResolveHostParameters parameters)366 StaleHostResolver::CreateServiceEndpointRequest(
367     Host host,
368     net::NetworkAnonymizationKey network_anonymization_key,
369     net::NetLogWithSource net_log,
370     ResolveHostParameters parameters) {
371   // TODO(crbug.com/335119455): Figure out a plan to support the
372   // ServiceEndpointRequest API.
373   NOTIMPLEMENTED();
374   return nullptr;
375 }
376 
GetHostCache()377 net::HostCache* StaleHostResolver::GetHostCache() {
378   return inner_resolver_->GetHostCache();
379 }
380 
GetDnsConfigAsValue() const381 base::Value::Dict StaleHostResolver::GetDnsConfigAsValue() const {
382   return inner_resolver_->GetDnsConfigAsValue();
383 }
384 
SetRequestContext(net::URLRequestContext * request_context)385 void StaleHostResolver::SetRequestContext(
386     net::URLRequestContext* request_context) {
387   inner_resolver_->SetRequestContext(request_context);
388 }
389 
OnNetworkRequestComplete(ResolveHostRequest * network_request,base::WeakPtr<RequestImpl> stale_request,int error)390 void StaleHostResolver::OnNetworkRequestComplete(
391     ResolveHostRequest* network_request,
392     base::WeakPtr<RequestImpl> stale_request,
393     int error) {
394   if (detached_requests_.erase(network_request))
395     return;
396 
397   // If not a detached request, there should still be an owning RequestImpl.
398   // Otherwise the request should have been cancelled and this method never
399   // called.
400   DCHECK(stale_request);
401 
402   stale_request->OnNetworkRequestComplete(error);
403 }
404 
DetachRequest(std::unique_ptr<ResolveHostRequest> request)405 void StaleHostResolver::DetachRequest(
406     std::unique_ptr<ResolveHostRequest> request) {
407   DCHECK_EQ(0u, detached_requests_.count(request.get()));
408   detached_requests_[request.get()] = std::move(request);
409 }
410 
SetTickClockForTesting(const base::TickClock * tick_clock)411 void StaleHostResolver::SetTickClockForTesting(
412     const base::TickClock* tick_clock) {
413   tick_clock_ = tick_clock;
414   inner_resolver_->SetTickClockForTesting(tick_clock);
415 }
416 
417 }  // namespace cronet
418