File: host_resolver_cache.h

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (251 lines) | stat: -rw-r--r-- 9,534 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_DNS_HOST_RESOLVER_CACHE_H_
#define NET_DNS_HOST_RESOLVER_CACHE_H_

#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "base/memory/raw_ref.h"
#include "base/strings/string_piece.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/net_export.h"
#include "net/base/network_anonymization_key.h"
#include "net/dns/public/dns_query_type.h"
#include "net/dns/public/host_resolver_source.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace net {

class HostResolverInternalResult;

// Cache used by HostResolverManager to save previously resolved information.
class NET_EXPORT HostResolverCache final {
 public:
  struct StaleLookupResult {
    StaleLookupResult(const HostResolverInternalResult& result,
                      absl::optional<base::TimeDelta> expired_by,
                      bool stale_by_generation);
    ~StaleLookupResult() = default;

    const raw_ref<const HostResolverInternalResult> result;

    // Time since the result's TTL has expired. nullopt if not expired.
    const absl::optional<base::TimeDelta> expired_by;

    // True if result is stale due to a call to
    // HostResolverCache::MakeAllResultsStale().
    const bool stale_by_generation;

    bool IsStale() const {
      return stale_by_generation || expired_by.has_value();
    }
  };

  explicit HostResolverCache(
      size_t max_results,
      const base::Clock& clock = *base::DefaultClock::GetInstance(),
      const base::TickClock& tick_clock =
          *base::DefaultTickClock::GetInstance());
  ~HostResolverCache();

  // Move-only.
  HostResolverCache(HostResolverCache&&);
  HostResolverCache& operator=(HostResolverCache&&);

  // Lookup an active (non-stale) cached result matching the given criteria. If
  // `query_type` is `DnsQueryType::UNSPECIFIED`, `source` is
  // `HostResolverSource::ANY`, or `secure` is `absl::nullopt`, it is a wildcard
  // that can match for any cached parameter of that type. In cases where a
  // wildcard lookup leads to multiple matching results, only one result will be
  // returned, preferring first the most secure result and then the most
  // recently set one. Additionally, if a cached result has
  // `DnsQueryType::UNSPECIFIED`, it will match for any argument of
  // `query_type`.
  //
  // Returns nullptr on cache miss (no active result matches the given
  // criteria).
  const HostResolverInternalResult* Lookup(
      base::StringPiece domain_name,
      const NetworkAnonymizationKey& network_anonymization_key,
      DnsQueryType query_type = DnsQueryType::UNSPECIFIED,
      HostResolverSource source = HostResolverSource::ANY,
      absl::optional<bool> secure = absl::nullopt) const;

  // Lookup a cached result matching the given criteria. Unlike Lookup(), may
  // return stale results. In cases where a wildcard lookup leads to multiple
  // matching results, only one result will be returned, preferring active
  // (non-stale) results, then the least stale by generation, then the least
  // stale by time expiration, then the most secure, then the most recently set.
  //
  // Used to implement
  // `HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED` behavior,
  // which is itself primarily for usage by cronet::StaleHostResolver, but no
  // assumptions are made here that this is Cronet-only behavior.
  //
  // Returns nullopt on cache miss (no active or stale result matches the given
  // criteria).
  absl::optional<StaleLookupResult> LookupStale(
      base::StringPiece domain_name,
      const NetworkAnonymizationKey& network_anonymization_key,
      DnsQueryType query_type = DnsQueryType::UNSPECIFIED,
      HostResolverSource source = HostResolverSource::ANY,
      absl::optional<bool> secure = absl::nullopt) const;

  // Sets the result into the cache, replacing any previous result entries that
  // would match the same criteria, even if a previous entry would have matched
  // more criteria than the new one, e.g. if the previous entry used a wildcard
  // `DnsQueryType::UNSPECIFIED`.
  void Set(std::unique_ptr<HostResolverInternalResult> result,
           const NetworkAnonymizationKey& network_anonymization_key,
           HostResolverSource source,
           bool secure);

  // Makes all cached results considered stale. Typically used for network
  // change to ensure cached results are only considered active for the current
  // network.
  void MakeAllResultsStale();

  // Serialization to later be deserialized. Only serializes the results likely
  // to still be of value after serialization and deserialization, that is that
  // results with a transient anonymization key are not included.
  //
  // Used to implement cronet::HostCachePersistenceManager, but no assumptions
  // are made here that this is Cronet-only functionality.
  base::Value Serialize() const;

  // Deserialize value received from Serialize(). Results already contained in
  // the cache are preferred, thus deserialized results are ignored if any
  // previous result entries would match the same criteria, and deserialization
  // stops on reaching max size, rather than evicting anything. Deserialized
  // results are also always considered stale by generation.
  //
  // Returns false if `value` is malformed to be deserialized.
  //
  // Used to implement cronet::HostCachePersistenceManager, but no assumptions
  // are made here that this is Cronet-only functionality.
  bool RestoreFromValue(const base::Value& value);

  // Serialize for output to debug logs, e.g. netlog. Serializes all results,
  // including those with transient anonymization keys, and also serializes
  // cache-wide data. Incompatible with base::Values returned from Serialize(),
  // and cannot be used in RestoreFromValue().
  base::Value SerializeForLogging() const;

  bool AtMaxSizeForTesting() const { return entries_.size() >= max_entries_; }

 private:
  struct Key {
    ~Key();

    std::string domain_name;
    NetworkAnonymizationKey network_anonymization_key;
  };

  struct KeyRef {
    ~KeyRef() = default;

    base::StringPiece domain_name;
    const raw_ref<const NetworkAnonymizationKey> network_anonymization_key;
  };

  // Allow comparing Key to KeyRef to allow refs for entry lookup.
  struct KeyComparator {
    using is_transparent = void;

    ~KeyComparator() = default;

    bool operator()(const Key& lhs, const Key& rhs) const {
      return std::tie(lhs.domain_name, lhs.network_anonymization_key) <
             std::tie(rhs.domain_name, rhs.network_anonymization_key);
    }

    bool operator()(const Key& lhs, const KeyRef& rhs) const {
      return std::tie(lhs.domain_name, lhs.network_anonymization_key) <
             std::tie(rhs.domain_name, *rhs.network_anonymization_key);
    }

    bool operator()(const KeyRef& lhs, const Key& rhs) const {
      return std::tie(lhs.domain_name, *lhs.network_anonymization_key) <
             std::tie(rhs.domain_name, rhs.network_anonymization_key);
    }
  };

  struct Entry {
    Entry(std::unique_ptr<HostResolverInternalResult> result,
          HostResolverSource source,
          bool secure,
          int staleness_generation);
    ~Entry();

    Entry(Entry&&);
    Entry& operator=(Entry&&);

    bool IsStale(base::Time now,
                 base::TimeTicks now_ticks,
                 int current_staleness_generation) const;
    base::TimeDelta TimeUntilExpiration(base::Time now,
                                        base::TimeTicks now_ticks) const;

    std::unique_ptr<HostResolverInternalResult> result;
    HostResolverSource source;
    bool secure;

    // The `HostResolverCache::staleness_generation_` value at the time this
    // entry was created. Entry is stale if this does not match the current
    // value.
    int staleness_generation;
  };

  using EntryMap = std::multimap<Key, Entry, KeyComparator>;

  // Get all matching results, from most to least recently added.
  std::vector<EntryMap::const_iterator> LookupInternal(
      base::StringPiece domain_name,
      const NetworkAnonymizationKey& network_anonymization_key,
      DnsQueryType query_type,
      HostResolverSource source,
      absl::optional<bool> secure) const;

  void Set(std::unique_ptr<HostResolverInternalResult> result,
           const NetworkAnonymizationKey& network_anonymization_key,
           HostResolverSource source,
           bool secure,
           bool replace_existing,
           int staleness_generation);

  void EvictEntries();

  // If `require_persistable_anonymization_key` is true, will not serialize
  // any entries that do not have an anonymization key that supports
  // serialization and restoration. If false, will serialize all entries, but
  // the result may contain anonymization keys that are malformed for
  // restoration.
  base::Value SerializeEntries(
      bool serialize_staleness_generation,
      bool require_persistable_anonymization_key) const;

  EntryMap entries_;
  size_t max_entries_;

  // Number of times MakeAllEntriesStale() has been called.
  int staleness_generation_ = 0;

  raw_ref<const base::Clock> clock_;
  raw_ref<const base::TickClock> tick_clock_;
};

}  // namespace net

#endif  // NET_DNS_HOST_RESOLVER_CACHE_H_