• 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 #ifndef COMPONENTS_CRONET_STALE_HOST_RESOLVER_H_
6 #define COMPONENTS_CRONET_STALE_HOST_RESOLVER_H_
7 
8 #include <memory>
9 #include <unordered_map>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/time/default_tick_clock.h"
14 #include "base/values.h"
15 #include "net/base/completion_once_callback.h"
16 #include "net/base/network_anonymization_key.h"
17 #include "net/dns/host_resolver.h"
18 #include "net/log/net_log_with_source.h"
19 #include "third_party/abseil-cpp/absl/types/optional.h"
20 #include "url/scheme_host_port.h"
21 
22 namespace base {
23 class TickClock;
24 }  // namespace base
25 
26 namespace net {
27 class ContextHostResolver;
28 }  // namespace net
29 
30 namespace cronet {
31 namespace {
32 class StaleHostResolverTest;
33 }  // namespace
34 
35 // A HostResolver that wraps a ContextHostResolver and uses it to make requests,
36 // but "impatiently" returns stale data (if available and usable) after a delay,
37 // to reduce DNS latency at the expense of accuracy.
38 class StaleHostResolver : public net::HostResolver {
39  public:
40   struct StaleOptions {
41     StaleOptions();
42 
43     // How long to wait before returning stale data, if available.
44     base::TimeDelta delay;
45 
46     // If positive, how long stale data can be past the expiration time before
47     // it's considered unusable. If zero or negative, stale data can be used
48     // indefinitely.
49     base::TimeDelta max_expired_time;
50 
51     // If set, stale data from previous networks is usable; if clear, it's not.
52     //
53     // If the other network had a working, correct DNS setup, this can increase
54     // the availability of useful stale results.
55     //
56     // If the other network had a broken (e.g. hijacked for captive portal) DNS
57     // setup, this will instead end up returning useless results.
58     bool allow_other_network;
59 
60     // If positive, the maximum number of times a stale entry can be used. If
61     // zero, there is no limit.
62     int max_stale_uses;
63 
64     // If network resolution returns ERR_NAME_NOT_RESOLVED, use stale result if
65     // available.
66     bool use_stale_on_name_not_resolved;
67   };
68 
69   // Creates a StaleHostResolver that uses |inner_resolver| for actual
70   // resolution, but potentially returns stale data according to
71   // |stale_options|.
72   StaleHostResolver(std::unique_ptr<net::ContextHostResolver> inner_resolver,
73                     const StaleOptions& stale_options);
74 
75   StaleHostResolver(const StaleHostResolver&) = delete;
76   StaleHostResolver& operator=(const StaleHostResolver&) = delete;
77 
78   ~StaleHostResolver() override;
79 
80   // HostResolver implementation:
81 
82   void OnShutdown() override;
83 
84   // Resolves as a regular HostResolver, but if stale data is available and
85   // usable (according to the options passed to the constructor), and fresh data
86   // is not returned before the specified delay, returns the stale data instead.
87   //
88   // If stale data is returned, the StaleHostResolver allows the underlying
89   // request to continue in order to repopulate the cache.
90   std::unique_ptr<ResolveHostRequest> CreateRequest(
91       url::SchemeHostPort host,
92       net::NetworkAnonymizationKey network_anonymization_key,
93       net::NetLogWithSource net_log,
94       absl::optional<ResolveHostParameters> optional_parameters) override;
95   std::unique_ptr<ResolveHostRequest> CreateRequest(
96       const net::HostPortPair& host,
97       const net::NetworkAnonymizationKey& network_anonymization_key,
98       const net::NetLogWithSource& net_log,
99       const absl::optional<ResolveHostParameters>& optional_parameters)
100       override;
101 
102   // The remaining public methods pass through to the inner resolver:
103 
104   net::HostCache* GetHostCache() override;
105   base::Value::Dict GetDnsConfigAsValue() const override;
106   void SetRequestContext(net::URLRequestContext* request_context) override;
107 
108  private:
109   class RequestImpl;
110   friend class StaleHostResolverTest;
111 
112   // Called on completion of |network_request| when completed asynchronously (a
113   // "network" request). Determines if the request is owned by a RequestImpl or
114   // if it is a detached request and handles appropriately.
115   void OnNetworkRequestComplete(ResolveHostRequest* network_request,
116                                 base::WeakPtr<RequestImpl> stale_request,
117                                 int error);
118 
119   // Detach an inner request from a RequestImpl, letting it finish (and populate
120   // the host cache) as long as |this| is not destroyed.
121   void DetachRequest(std::unique_ptr<ResolveHostRequest> request);
122 
123   // Set |tick_clock_| for testing. Must be set before issuing any requests.
124   void SetTickClockForTesting(const base::TickClock* tick_clock);
125 
126   // The underlying ContextHostResolver that will be used to make cache and
127   // network requests.
128   std::unique_ptr<net::ContextHostResolver> inner_resolver_;
129 
130   // Shared instance of tick clock, overridden for testing.
131   raw_ptr<const base::TickClock> tick_clock_ =
132       base::DefaultTickClock::GetInstance();
133 
134   // Options that govern when a stale response can or can't be returned.
135   const StaleOptions options_;
136 
137   // Requests not used for returned results but allowed to continue (unless
138   // |this| is destroyed) to backfill the cache.
139   std::unordered_map<ResolveHostRequest*, std::unique_ptr<ResolveHostRequest>>
140       detached_requests_;
141 
142   base::WeakPtrFactory<StaleHostResolver> weak_ptr_factory_{this};
143 };
144 
145 }  // namespace cronet
146 
147 #endif  // COMPONENTS_CRONET_STALE_HOST_RESOLVER_H_
148