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