| Index: net/dns/host_cache.cc
|
| diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
|
| index 0026c02176c03c8c5dc28ba463000d4d8699d890..c1dbbda9b0afb67f356c1be16b14f83463af71d9 100644
|
| --- a/net/dns/host_cache.cc
|
| +++ b/net/dns/host_cache.cc
|
| @@ -4,15 +4,19 @@
|
|
|
| #include "net/dns/host_cache.h"
|
|
|
| +#include <utility>
|
| +
|
| #include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/metrics/field_trial.h"
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/trace_event/trace_event.h"
|
| +#include "base/values.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/base/trace_constants.h"
|
| #include "net/dns/dns_util.h"
|
| +#include "net/log/net_log.h"
|
|
|
| namespace net {
|
|
|
| @@ -27,6 +31,31 @@ namespace {
|
| #define CACHE_HISTOGRAM_ENUM(name, value, max) \
|
| UMA_HISTOGRAM_ENUMERATION("DNS.HostCache." name, value, max)
|
|
|
| +// String constants for dictionary keys.
|
| +const char kHostnameKey[] = "hostname";
|
| +const char kAddressFamilyKey[] = "address_family";
|
| +const char kFlagsKey[] = "flags";
|
| +const char kExpirationKey[] = "expiration";
|
| +const char kTtlKey[] = "ttl";
|
| +const char kNetworkChangesKey[] = "network_changes";
|
| +const char kErrorKey[] = "error";
|
| +const char kAddressesKey[] = "addresses";
|
| +
|
| +bool AddressListFromListValue(base::ListValue* value, AddressList* list) {
|
| + list->clear();
|
| + for (base::ListValue::const_iterator it = value->begin(); it != value->end();
|
| + it++) {
|
| + IPAddress address;
|
| + std::string addr_string;
|
| + if (!it->GetAsString(&addr_string) ||
|
| + !address.AssignFromIPLiteral(addr_string)) {
|
| + return false;
|
| + }
|
| + list->push_back(IPEndPoint(address, 0));
|
| + }
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // Used in histograms; do not modify existing values.
|
| @@ -80,6 +109,18 @@ HostCache::Entry::Entry(const HostCache::Entry& entry,
|
| total_hits_(0),
|
| stale_hits_(0) {}
|
|
|
| +HostCache::Entry::Entry(int error,
|
| + const AddressList& addresses,
|
| + base::TimeTicks expires,
|
| + int network_changes)
|
| + : error_(error),
|
| + addresses_(addresses),
|
| + ttl_(base::TimeDelta::FromSeconds(-1)),
|
| + expires_(expires),
|
| + network_changes_(network_changes),
|
| + total_hits_(0),
|
| + stale_hits_(0) {}
|
| +
|
| bool HostCache::Entry::IsStale(base::TimeTicks now, int network_changes) const {
|
| EntryStaleness stale;
|
| stale.expired_by = now - expires_;
|
| @@ -182,10 +223,13 @@ void HostCache::Set(const Key& key,
|
| RecordSet(SET_INSERT, now, nullptr, entry);
|
| }
|
|
|
| + AddEntry(Key(key), Entry(entry, now, ttl, network_changes_));
|
| +}
|
| +
|
| +void HostCache::AddEntry(const Key& key, const Entry& entry) {
|
| DCHECK_GT(max_entries_, size());
|
| DCHECK_EQ(0u, entries_.count(key));
|
| - entries_.insert(
|
| - std::make_pair(Key(key), Entry(entry, now, ttl, network_changes_)));
|
| + entries_.insert(std::make_pair(key, entry));
|
| DCHECK_GE(max_entries_, size());
|
| }
|
|
|
| @@ -221,6 +265,110 @@ void HostCache::ClearForHosts(
|
| }
|
| }
|
|
|
| +std::unique_ptr<base::ListValue> HostCache::GetAsListValue(
|
| + bool include_staleness) const {
|
| + std::unique_ptr<base::ListValue> entry_list(new base::ListValue());
|
| +
|
| + for (const auto& pair : entries_) {
|
| + const Key& key = pair.first;
|
| + const Entry& entry = pair.second;
|
| +
|
| + std::unique_ptr<base::DictionaryValue> entry_dict(
|
| + new base::DictionaryValue());
|
| +
|
| + entry_dict->SetString(kHostnameKey, key.hostname);
|
| + entry_dict->SetInteger(kAddressFamilyKey,
|
| + static_cast<int>(key.address_family));
|
| + entry_dict->SetInteger(kFlagsKey, key.host_resolver_flags);
|
| +
|
| + if (include_staleness) {
|
| + entry_dict->SetString(kExpirationKey,
|
| + NetLog::TickCountToString(entry.expires()));
|
| + entry_dict->SetInteger(kTtlKey, entry.ttl().InMilliseconds());
|
| + entry_dict->SetInteger(kNetworkChangesKey, entry.network_changes());
|
| + } else {
|
| + // Convert expiration time in TimeTicks to Time for serialization, using a
|
| + // string because base::Value doesn't handle 64-bit integers.
|
| + base::Time expiration_time =
|
| + base::Time::Now() - (base::TimeTicks::Now() - entry.expires());
|
| + entry_dict->SetString(
|
| + kExpirationKey,
|
| + base::Int64ToString(expiration_time.ToInternalValue()));
|
| + }
|
| +
|
| + if (entry.error() != OK) {
|
| + entry_dict->SetInteger(kErrorKey, entry.error());
|
| + } else {
|
| + const AddressList& addresses = entry.addresses();
|
| + // Append all of the resolved addresses.
|
| + auto addresses_value = base::MakeUnique<base::ListValue>();
|
| + for (size_t i = 0; i < addresses.size(); ++i)
|
| + addresses_value->AppendString(addresses[i].ToStringWithoutPort());
|
| + entry_dict->SetList(kAddressesKey, std::move(addresses_value));
|
| + }
|
| +
|
| + entry_list->Append(std::move(entry_dict));
|
| + }
|
| +
|
| + return entry_list;
|
| +}
|
| +
|
| +// TODO(mgersh): Add histograms to track failures.
|
| +bool HostCache::RestoreFromListValue(base::ListValue& old_cache) {
|
| + for (base::ListValue::iterator it = old_cache.begin(); it != old_cache.end();
|
| + it++) {
|
| + base::DictionaryValue* entry_dict;
|
| + if (!it->GetAsDictionary(&entry_dict))
|
| + return false;
|
| +
|
| + std::string hostname;
|
| + int address_family;
|
| + HostResolverFlags flags;
|
| + int error = OK;
|
| + std::string expiration;
|
| + base::ListValue empty_list;
|
| + base::ListValue* addresses_value = &empty_list;
|
| + AddressList address_list;
|
| +
|
| + if (!entry_dict->GetString(kHostnameKey, &hostname) ||
|
| + !entry_dict->GetInteger(kFlagsKey, &flags) ||
|
| + !entry_dict->GetInteger(kAddressFamilyKey, &address_family) ||
|
| + !entry_dict->GetString(kExpirationKey, &expiration)) {
|
| + return false;
|
| + }
|
| +
|
| + // Only one of these fields should be in the dictionary.
|
| + if (!entry_dict->GetInteger(kErrorKey, &error) &&
|
| + !entry_dict->GetList(kAddressesKey, &addresses_value)) {
|
| + return false;
|
| + }
|
| +
|
| + int64_t time_internal;
|
| + if (!base::StringToInt64(expiration, &time_internal))
|
| + return false;
|
| +
|
| + base::TimeTicks expiration_time =
|
| + base::TimeTicks::Now() -
|
| + (base::Time::Now() - base::Time::FromInternalValue(time_internal));
|
| +
|
| + Key key(hostname, static_cast<AddressFamily>(address_family), flags);
|
| + if (error == OK &&
|
| + !AddressListFromListValue(addresses_value, &address_list)) {
|
| + return false;
|
| + }
|
| +
|
| + // If the key is already in the cache, assume it's more recent and don't
|
| + // replace the entry. If the cache is already full, don't bother
|
| + // prioritizing what to evict, just stop restoring.
|
| + auto found = entries_.find(key);
|
| + if (found == entries_.end() && size() < max_entries_) {
|
| + AddEntry(key, Entry(error, address_list, expiration_time,
|
| + network_changes_ - 1));
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| size_t HostCache::size() const {
|
| DCHECK(CalledOnValidThread());
|
| return entries_.size();
|
|
|