Commit 84dbdda3 authored by Eric Orth's avatar Eric Orth Committed by Commit Bot

Allow non-address results in HostCache::Entry

Changed addresses_ to an Optional and added additional optional fields
for text results (eg for TXT records) and hostname results (eg for SRV
or PTR records). Deliberately avoided assumptions that only one result
field could be non-nullopt at at time (but no constructor currently
allows creating it) because there's nothing wrong with some query
having results of multiple types. Eg, we may in the future choose to
pull cannonname out of AddressList and set it as a hostname result.

A subsequent CL will alter HostResolverImpl to allow querying, caching,
and returning non-address types, and it will also use HostCache::Entry
internally (and only internally) as a results container. For now, in
this CL, most of the code dealing with HostCache results will just
assume Entry::addresses() always has a value.

Bug: 846423
Change-Id: I62e177452bf89e5931f75a74448f9de70b7f2357
Reviewed-on: https://chromium-review.googlesource.com/c/1331143
Commit-Queue: Eric Orth <ericorth@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609373}
parent 448a2490
...@@ -40,6 +40,8 @@ class NET_EXPORT HostPortPair { ...@@ -40,6 +40,8 @@ class NET_EXPORT HostPortPair {
return std::tie(port_, host_) < std::tie(other.port_, other.host_); return std::tie(port_, host_) < std::tie(other.port_, other.host_);
} }
bool operator==(const HostPortPair& other) const { return Equals(other); }
// Equality test of contents. (Probably another violation of style guide). // Equality test of contents. (Probably another violation of style guide).
bool Equals(const HostPortPair& other) const { bool Equals(const HostPortPair& other) const {
return host_ == other.host_ && port_ == other.port_; return host_ == other.host_ && port_ == other.port_;
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
#include "net/dns/host_cache.h" #include "net/dns/host_cache.h"
#include <utility> #include <algorithm>
#include "base/logging.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/time/default_tick_clock.h" #include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
...@@ -43,9 +43,18 @@ const char kTtlKey[] = "ttl"; ...@@ -43,9 +43,18 @@ const char kTtlKey[] = "ttl";
const char kNetworkChangesKey[] = "network_changes"; const char kNetworkChangesKey[] = "network_changes";
const char kErrorKey[] = "error"; const char kErrorKey[] = "error";
const char kAddressesKey[] = "addresses"; const char kAddressesKey[] = "addresses";
const char kTextRecordsKey[] = "text_records";
const char kHostnameResultsKey[] = "hostname_results";
const char kHostPortsKey[] = "host_ports";
bool AddressListFromListValue(const base::ListValue* value,
base::Optional<AddressList>* out_list) {
if (!value) {
out_list->reset();
return true;
}
bool AddressListFromListValue(const base::ListValue* value, AddressList* list) { out_list->emplace();
list->clear();
for (auto it = value->begin(); it != value->end(); it++) { for (auto it = value->begin(); it != value->end(); it++) {
IPAddress address; IPAddress address;
std::string addr_string; std::string addr_string;
...@@ -53,7 +62,7 @@ bool AddressListFromListValue(const base::ListValue* value, AddressList* list) { ...@@ -53,7 +62,7 @@ bool AddressListFromListValue(const base::ListValue* value, AddressList* list) {
!address.AssignFromIPLiteral(addr_string)) { !address.AssignFromIPLiteral(addr_string)) {
return false; return false;
} }
list->push_back(IPEndPoint(address, 0)); out_list->value().push_back(IPEndPoint(address, 0));
} }
return true; return true;
} }
...@@ -105,20 +114,6 @@ HostCache::Key::Key(const std::string& hostname, ...@@ -105,20 +114,6 @@ HostCache::Key::Key(const std::string& hostname,
HostCache::Key::Key() HostCache::Key::Key()
: Key("", DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY) {} : Key("", DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY) {}
HostCache::Entry::Entry(int error,
const AddressList& addresses,
Source source,
base::TimeDelta ttl)
: error_(error), addresses_(addresses), source_(source), ttl_(ttl) {
DCHECK(ttl >= base::TimeDelta());
}
HostCache::Entry::Entry(int error, const AddressList& addresses, Source source)
: error_(error),
addresses_(addresses),
source_(source),
ttl_(base::TimeDelta::FromSeconds(-1)) {}
HostCache::Entry::~Entry() = default; HostCache::Entry::~Entry() = default;
HostCache::Entry::Entry(HostCache::Entry&& entry) = default; HostCache::Entry::Entry(HostCache::Entry&& entry) = default;
...@@ -129,6 +124,8 @@ HostCache::Entry::Entry(const HostCache::Entry& entry, ...@@ -129,6 +124,8 @@ HostCache::Entry::Entry(const HostCache::Entry& entry,
int network_changes) int network_changes)
: error_(entry.error()), : error_(entry.error()),
addresses_(entry.addresses()), addresses_(entry.addresses()),
text_records_(entry.text_records()),
hostnames_(entry.hostnames()),
source_(entry.source()), source_(entry.source()),
ttl_(entry.ttl()), ttl_(entry.ttl()),
expires_(now + ttl), expires_(now + ttl),
...@@ -137,12 +134,16 @@ HostCache::Entry::Entry(const HostCache::Entry& entry, ...@@ -137,12 +134,16 @@ HostCache::Entry::Entry(const HostCache::Entry& entry,
stale_hits_(0) {} stale_hits_(0) {}
HostCache::Entry::Entry(int error, HostCache::Entry::Entry(int error,
const AddressList& addresses, const base::Optional<AddressList>& addresses,
base::Optional<std::vector<std::string>>&& text_records,
base::Optional<std::vector<HostPortPair>>&& hostnames,
Source source, Source source,
base::TimeTicks expires, base::TimeTicks expires,
int network_changes) int network_changes)
: error_(error), : error_(error),
addresses_(addresses), addresses_(addresses),
text_records_(std::move(text_records)),
hostnames_(std::move(hostnames)),
source_(source), source_(source),
ttl_(base::TimeDelta::FromSeconds(-1)), ttl_(base::TimeDelta::FromSeconds(-1)),
expires_(expires), expires_(expires),
...@@ -246,21 +247,69 @@ void HostCache::Set(const Key& key, ...@@ -246,21 +247,69 @@ void HostCache::Set(const Key& key,
auto it = entries_.find(key); auto it = entries_.find(key);
if (it != entries_.end()) { if (it != entries_.end()) {
bool is_stale = it->second.IsStale(now, network_changes_); bool is_stale = it->second.IsStale(now, network_changes_);
AddressListDeltaType delta =
FindAddressListDeltaType(it->second.addresses(), entry.addresses()); base::Optional<AddressListDeltaType> addresses_delta;
RecordSet(is_stale ? SET_UPDATE_STALE : SET_UPDATE_VALID, now, &it->second, if (entry.addresses() || it->second.addresses()) {
entry, delta); if (entry.addresses() && it->second.addresses()) {
addresses_delta = FindAddressListDeltaType(
it->second.addresses().value(), entry.addresses().value());
} else {
addresses_delta = DELTA_DISJOINT;
}
} // Else no addresses in old or new, so nullopt delta.
// For non-address results, delta is only considered for whole-list
// equality. The meaning of partial list equality varies too much depending
// on the context of a DNS record.
base::Optional<AddressListDeltaType> nonaddress_delta;
if (entry.text_records() || it->second.text_records() ||
entry.hostnames() || it->second.hostnames()) {
if (entry.text_records() == it->second.text_records() &&
entry.hostnames() == it->second.hostnames()) {
nonaddress_delta = DELTA_IDENTICAL;
} else if (entry.text_records() == it->second.text_records() ||
entry.hostnames() == it->second.hostnames()) {
nonaddress_delta = DELTA_OVERLAP;
} else {
nonaddress_delta = DELTA_DISJOINT;
}
} // Else no nonaddress results in old or new, so nullopt delta.
AddressListDeltaType overall_delta;
if (!addresses_delta && !nonaddress_delta) {
// No results in old or new is IDENTICAL.
overall_delta = DELTA_IDENTICAL;
} else if (!addresses_delta) {
overall_delta = nonaddress_delta.value();
} else if (!nonaddress_delta) {
overall_delta = addresses_delta.value();
} else if (addresses_delta == DELTA_DISJOINT &&
nonaddress_delta == DELTA_DISJOINT) {
overall_delta = DELTA_DISJOINT;
} else if (addresses_delta == DELTA_DISJOINT ||
nonaddress_delta == DELTA_DISJOINT) {
// If only some result types are DISJOINT, some match and we have OVERLAP.
overall_delta = DELTA_OVERLAP;
} else {
// No DISJOINT result types, so we have at least partial match. Take the
// least matching amount (highest enum value).
overall_delta =
std::max(addresses_delta.value(), nonaddress_delta.value());
}
LogRecordSet(is_stale ? SET_UPDATE_STALE : SET_UPDATE_VALID, now,
&it->second, entry, overall_delta);
// TODO(juliatuttle): Remember some old metadata (hit count or frequency or // TODO(juliatuttle): Remember some old metadata (hit count or frequency or
// something like that) if it's useful for better eviction algorithms? // something like that) if it's useful for better eviction algorithms?
result_changed = result_changed =
entry.error() == OK && entry.error() == OK && (it->second.error() != entry.error() ||
(it->second.error() != entry.error() || delta != DELTA_IDENTICAL); overall_delta != DELTA_IDENTICAL);
entries_.erase(it); entries_.erase(it);
} else { } else {
result_changed = true; result_changed = true;
if (size() == max_entries_) if (size() == max_entries_)
EvictOneEntry(now); EvictOneEntry(now);
RecordSet(SET_INSERT, now, nullptr, entry, DELTA_DISJOINT); LogRecordSet(SET_INSERT, now, nullptr, entry, DELTA_DISJOINT);
} }
AddEntry(Key(key), Entry(entry, now, ttl, network_changes_)); AddEntry(Key(key), Entry(entry, now, ttl, network_changes_));
...@@ -367,12 +416,35 @@ void HostCache::GetAsListValue(base::ListValue* entry_list, ...@@ -367,12 +416,35 @@ void HostCache::GetAsListValue(base::ListValue* entry_list,
if (entry.error() != OK) { if (entry.error() != OK) {
entry_dict->SetInteger(kErrorKey, entry.error()); entry_dict->SetInteger(kErrorKey, entry.error());
} else { } else {
const AddressList& addresses = entry.addresses(); if (entry.addresses()) {
// Append all of the resolved addresses. // Append all of the resolved addresses.
auto addresses_value = std::make_unique<base::ListValue>(); base::ListValue addresses_value;
for (size_t i = 0; i < addresses.size(); ++i) for (const IPEndPoint& address : entry.addresses().value()) {
addresses_value->AppendString(addresses[i].ToStringWithoutPort()); addresses_value.GetList().emplace_back(address.ToStringWithoutPort());
entry_dict->SetList(kAddressesKey, std::move(addresses_value)); }
entry_dict->SetKey(kAddressesKey, std::move(addresses_value));
}
if (entry.text_records()) {
// Append all resolved text records.
base::ListValue text_list_value;
for (const std::string& text_record : entry.text_records().value()) {
text_list_value.GetList().emplace_back(text_record);
}
entry_dict->SetKey(kTextRecordsKey, std::move(text_list_value));
}
if (entry.hostnames()) {
// Append all the resolved hostnames.
base::ListValue hostnames_value;
base::ListValue host_ports_value;
for (const HostPortPair& hostname : entry.hostnames().value()) {
hostnames_value.GetList().emplace_back(hostname.host());
host_ports_value.GetList().emplace_back(hostname.port());
}
entry_dict->SetKey(kHostnameResultsKey, std::move(hostnames_value));
entry_dict->SetKey(kHostPortsKey, std::move(host_ports_value));
}
} }
entry_list->Append(std::move(entry_dict)); entry_list->Append(std::move(entry_dict));
...@@ -386,15 +458,8 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { ...@@ -386,15 +458,8 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) {
return false; return false;
std::string hostname; std::string hostname;
int dns_query_type;
HostResolverFlags flags; HostResolverFlags flags;
int host_resolver_source;
int error = OK;
std::string expiration; std::string expiration;
base::ListValue empty_list;
const base::ListValue* addresses_value = &empty_list;
AddressList address_list;
if (!entry_dict->GetString(kHostnameKey, &hostname) || if (!entry_dict->GetString(kHostnameKey, &hostname) ||
!entry_dict->GetInteger(kFlagsKey, &flags) || !entry_dict->GetInteger(kFlagsKey, &flags) ||
!entry_dict->GetString(kExpirationKey, &expiration)) { !entry_dict->GetString(kExpirationKey, &expiration)) {
...@@ -406,25 +471,39 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { ...@@ -406,25 +471,39 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) {
// TODO(crbug.com/846423): Remove kAddressFamilyKey support after a enough // TODO(crbug.com/846423): Remove kAddressFamilyKey support after a enough
// time has passed to minimize loss-of-persistence impact from backwards // time has passed to minimize loss-of-persistence impact from backwards
// incompatibility. // incompatibility.
if (!entry_dict->GetInteger(kDnsQueryTypeKey, &dns_query_type)) { int dns_query_type_val;
DnsQueryType dns_query_type;
if (entry_dict->GetInteger(kDnsQueryTypeKey, &dns_query_type_val)) {
dns_query_type = static_cast<DnsQueryType>(dns_query_type_val);
} else {
int address_family; int address_family;
if (!entry_dict->GetInteger(kAddressFamilyKey, &address_family)) { if (!entry_dict->GetInteger(kAddressFamilyKey, &address_family)) {
return false; return false;
} }
dns_query_type = static_cast<int>(AddressFamilyToDnsQueryType( dns_query_type = AddressFamilyToDnsQueryType(
static_cast<AddressFamily>(address_family))); static_cast<AddressFamily>(address_family));
} }
// HostResolverSource is optional. // HostResolverSource is optional.
int host_resolver_source;
if (!entry_dict->GetInteger(kHostResolverSourceKey, if (!entry_dict->GetInteger(kHostResolverSourceKey,
&host_resolver_source)) { &host_resolver_source)) {
host_resolver_source = static_cast<int>(HostResolverSource::ANY); host_resolver_source = static_cast<int>(HostResolverSource::ANY);
} }
// Only one of these fields should be in the dictionary. int error = OK;
if (!entry_dict->GetInteger(kErrorKey, &error) && const base::ListValue* addresses_value = nullptr;
!entry_dict->GetList(kAddressesKey, &addresses_value)) { const base::ListValue* text_records_value = nullptr;
return false; const base::ListValue* hostname_records_value = nullptr;
const base::ListValue* host_ports_value = nullptr;
if (!entry_dict->GetInteger(kErrorKey, &error)) {
entry_dict->GetList(kAddressesKey, &addresses_value);
entry_dict->GetList(kTextRecordsKey, &text_records_value);
if (entry_dict->GetList(kHostnameResultsKey, &hostname_records_value) !=
entry_dict->GetList(kHostPortsKey, &host_ports_value)) {
return false;
}
} }
int64_t time_internal; int64_t time_internal;
...@@ -435,19 +514,60 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) { ...@@ -435,19 +514,60 @@ bool HostCache::RestoreFromListValue(const base::ListValue& old_cache) {
tick_clock_->NowTicks() - tick_clock_->NowTicks() -
(base::Time::Now() - base::Time::FromInternalValue(time_internal)); (base::Time::Now() - base::Time::FromInternalValue(time_internal));
Key key(hostname, static_cast<DnsQueryType>(dns_query_type), flags, base::Optional<AddressList> address_list;
static_cast<HostResolverSource>(host_resolver_source)); if (!AddressListFromListValue(addresses_value, &address_list)) {
if (error == OK &&
!AddressListFromListValue(addresses_value, &address_list)) {
return false; return false;
} }
base::Optional<std::vector<std::string>> text_records;
if (text_records_value) {
text_records.emplace();
for (const base::Value& value : text_records_value->GetList()) {
if (!value.is_string())
return false;
text_records.value().push_back(value.GetString());
}
}
base::Optional<std::vector<HostPortPair>> hostname_records;
if (hostname_records_value) {
DCHECK(host_ports_value);
if (hostname_records_value->GetList().size() !=
host_ports_value->GetList().size()) {
return false;
}
hostname_records.emplace();
for (size_t i = 0; i < hostname_records_value->GetList().size(); ++i) {
if (!hostname_records_value->GetList()[i].is_string() ||
!host_ports_value->GetList()[i].is_int() ||
!base::IsValueInRangeForNumericType<uint16_t>(
host_ports_value->GetList()[i].GetInt())) {
return false;
}
hostname_records.value().push_back(
HostPortPair(hostname_records_value->GetList()[i].GetString(),
base::checked_cast<uint16_t>(
host_ports_value->GetList()[i].GetInt())));
}
}
// Assume an empty address list if we have an address type and no results.
if (IsAddressType(dns_query_type) && !address_list && !text_records &&
!hostname_records) {
address_list.emplace();
}
Key key(hostname, dns_query_type, flags,
static_cast<HostResolverSource>(host_resolver_source));
// If the key is already in the cache, assume it's more recent and don't // 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 // replace the entry. If the cache is already full, don't bother
// prioritizing what to evict, just stop restoring. // prioritizing what to evict, just stop restoring.
auto found = entries_.find(key); auto found = entries_.find(key);
if (found == entries_.end() && size() < max_entries_) { if (found == entries_.end() && size() < max_entries_) {
AddEntry(key, Entry(error, address_list, Entry::SOURCE_UNKNOWN, AddEntry(key, Entry(error, address_list, std::move(text_records),
std::move(hostname_records), Entry::SOURCE_UNKNOWN,
expiration_time, network_changes_ - 1)); expiration_time, network_changes_ - 1));
} }
} }
...@@ -491,11 +611,11 @@ void HostCache::EvictOneEntry(base::TimeTicks now) { ...@@ -491,11 +611,11 @@ void HostCache::EvictOneEntry(base::TimeTicks now) {
entries_.erase(oldest_it); entries_.erase(oldest_it);
} }
void HostCache::RecordSet(SetOutcome outcome, void HostCache::LogRecordSet(SetOutcome outcome,
base::TimeTicks now, base::TimeTicks now,
const Entry* old_entry, const Entry* old_entry,
const Entry& new_entry, const Entry& new_entry,
AddressListDeltaType delta) { AddressListDeltaType delta) {
CACHE_HISTOGRAM_ENUM("Set", outcome, MAX_SET_OUTCOME); CACHE_HISTOGRAM_ENUM("Set", outcome, MAX_SET_OUTCOME);
switch (outcome) { switch (outcome) {
case SET_INSERT: case SET_INSERT:
...@@ -510,7 +630,7 @@ void HostCache::RecordSet(SetOutcome outcome, ...@@ -510,7 +630,7 @@ void HostCache::RecordSet(SetOutcome outcome,
stale.network_changes); stale.network_changes);
CACHE_HISTOGRAM_COUNT("UpdateStale.StaleHits", stale.stale_hits); CACHE_HISTOGRAM_COUNT("UpdateStale.StaleHits", stale.stale_hits);
if (old_entry->error() == OK && new_entry.error() == OK) { if (old_entry->error() == OK && new_entry.error() == OK) {
RecordUpdateStale(delta, stale); LogRecordUpdateStale(delta, stale);
} }
break; break;
} }
...@@ -520,8 +640,8 @@ void HostCache::RecordSet(SetOutcome outcome, ...@@ -520,8 +640,8 @@ void HostCache::RecordSet(SetOutcome outcome,
} }
} }
void HostCache::RecordUpdateStale(AddressListDeltaType delta, void HostCache::LogRecordUpdateStale(AddressListDeltaType delta,
const EntryStaleness& stale) { const EntryStaleness& stale) {
CACHE_HISTOGRAM_ENUM("UpdateStale.AddressListDelta", delta, MAX_DELTA_TYPE); CACHE_HISTOGRAM_ENUM("UpdateStale.AddressListDelta", delta, MAX_DELTA_TYPE);
switch (delta) { switch (delta) {
case DELTA_IDENTICAL: case DELTA_IDENTICAL:
......
...@@ -12,14 +12,19 @@ ...@@ -12,14 +12,19 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <utility>
#include <vector>
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "net/base/address_family.h" #include "net/base/address_family.h"
#include "net/base/address_list.h" #include "net/base/address_list.h"
#include "net/base/expiring_cache.h" #include "net/base/expiring_cache.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_export.h" #include "net/base/net_export.h"
#include "net/dns/dns_util.h" #include "net/dns/dns_util.h"
#include "net/dns/host_resolver_source.h" #include "net/dns/host_resolver_source.h"
...@@ -89,17 +94,33 @@ class NET_EXPORT HostCache { ...@@ -89,17 +94,33 @@ class NET_EXPORT HostCache {
SOURCE_HOSTS, SOURCE_HOSTS,
}; };
Entry(int error, template <typename T>
const AddressList& addresses, Entry(int error, T&& results, Source source, base::TimeDelta ttl)
Source source, : error_(error), source_(source), ttl_(ttl) {
base::TimeDelta ttl); DCHECK(ttl >= base::TimeDelta());
SetResult(std::forward<T>(results));
}
// Use when |ttl| is unknown. // Use when |ttl| is unknown.
Entry(int error, const AddressList& addresses, Source source); template <typename T>
Entry(int error, T&& results, Source source)
: error_(error),
source_(source),
ttl_(base::TimeDelta::FromSeconds(-1)) {
SetResult(std::forward<T>(results));
}
Entry(Entry&& entry); Entry(Entry&& entry);
~Entry(); ~Entry();
int error() const { return error_; } int error() const { return error_; }
const AddressList& addresses() const { return addresses_; } const base::Optional<AddressList>& addresses() const { return addresses_; }
const base::Optional<std::vector<std::string>>& text_records() const {
return text_records_;
}
const base::Optional<std::vector<HostPortPair>>& hostnames() const {
return hostnames_;
}
Source source() const { return source_; } Source source() const { return source_; }
bool has_ttl() const { return ttl_ >= base::TimeDelta(); } bool has_ttl() const { return ttl_ >= base::TimeDelta(); }
base::TimeDelta ttl() const { return ttl_; } base::TimeDelta ttl() const { return ttl_; }
...@@ -118,11 +139,21 @@ class NET_EXPORT HostCache { ...@@ -118,11 +139,21 @@ class NET_EXPORT HostCache {
int network_changes); int network_changes);
Entry(int error, Entry(int error,
const AddressList& addresses, const base::Optional<AddressList>& addresses,
base::Optional<std::vector<std::string>>&& text_results,
base::Optional<std::vector<HostPortPair>>&& hostnames,
Source source, Source source,
base::TimeTicks expires, base::TimeTicks expires,
int network_changes); int network_changes);
void SetResult(AddressList addresses) { addresses_ = std::move(addresses); }
void SetResult(std::vector<std::string> text_records) {
text_records_ = std::move(text_records);
}
void SetResult(std::vector<HostPortPair> hostnames) {
hostnames_ = std::move(hostnames);
}
int total_hits() const { return total_hits_; } int total_hits() const { return total_hits_; }
int stale_hits() const { return stale_hits_; } int stale_hits() const { return stale_hits_; }
...@@ -134,8 +165,10 @@ class NET_EXPORT HostCache { ...@@ -134,8 +165,10 @@ class NET_EXPORT HostCache {
// The resolve results for this entry. // The resolve results for this entry.
int error_; int error_;
AddressList addresses_; base::Optional<AddressList> addresses_;
// Where addresses_ were obtained (e.g. DNS lookup, hosts file, etc). base::Optional<std::vector<std::string>> text_records_;
base::Optional<std::vector<HostPortPair>> hostnames_;
// Where results were obtained (e.g. DNS lookup, hosts file, etc).
Source source_; Source source_;
// TTL obtained from the nameserver. Negative if unknown. // TTL obtained from the nameserver. Negative if unknown.
base::TimeDelta ttl_; base::TimeDelta ttl_;
...@@ -243,13 +276,13 @@ class NET_EXPORT HostCache { ...@@ -243,13 +276,13 @@ class NET_EXPORT HostCache {
Entry* LookupInternal(const Key& key); Entry* LookupInternal(const Key& key);
void RecordSet(SetOutcome outcome, void LogRecordSet(SetOutcome outcome,
base::TimeTicks now, base::TimeTicks now,
const Entry* old_entry, const Entry* old_entry,
const Entry& new_entry, const Entry& new_entry,
AddressListDeltaType delta); AddressListDeltaType delta);
void RecordUpdateStale(AddressListDeltaType delta, void LogRecordUpdateStale(AddressListDeltaType delta,
const EntryStaleness& stale); const EntryStaleness& stale);
void RecordLookup(LookupOutcome outcome, void RecordLookup(LookupOutcome outcome,
base::TimeTicks now, base::TimeTicks now,
const Entry* entry); const Entry* entry);
......
...@@ -694,8 +694,11 @@ TEST(HostCacheTest, SerializeAndDeserialize) { ...@@ -694,8 +694,11 @@ TEST(HostCacheTest, SerializeAndDeserialize) {
const HostCache::Entry* result1 = const HostCache::Entry* result1 =
restored_cache.LookupStale(key1, now, &stale); restored_cache.LookupStale(key1, now, &stale);
EXPECT_TRUE(result1); EXPECT_TRUE(result1);
EXPECT_EQ(1u, result1->addresses().size()); ASSERT_TRUE(result1->addresses());
EXPECT_EQ(address_ipv4, result1->addresses().front().address()); EXPECT_FALSE(result1->text_records());
EXPECT_FALSE(result1->hostnames());
EXPECT_EQ(1u, result1->addresses().value().size());
EXPECT_EQ(address_ipv4, result1->addresses().value().front().address());
EXPECT_EQ(1, stale.network_changes); EXPECT_EQ(1, stale.network_changes);
// Time to TimeTicks conversion is fuzzy, so just check that expected and // Time to TimeTicks conversion is fuzzy, so just check that expected and
// actual expiration times are close. // actual expiration times are close.
...@@ -707,9 +710,10 @@ TEST(HostCacheTest, SerializeAndDeserialize) { ...@@ -707,9 +710,10 @@ TEST(HostCacheTest, SerializeAndDeserialize) {
const HostCache::Entry* result2 = const HostCache::Entry* result2 =
restored_cache.LookupStale(key2, now, &stale); restored_cache.LookupStale(key2, now, &stale);
EXPECT_TRUE(result2); EXPECT_TRUE(result2);
EXPECT_EQ(2u, result2->addresses().size()); ASSERT_TRUE(result2->addresses());
EXPECT_EQ(address_ipv6, result2->addresses().front().address()); EXPECT_EQ(2u, result2->addresses().value().size());
EXPECT_EQ(address_ipv4, result2->addresses().back().address()); EXPECT_EQ(address_ipv6, result2->addresses().value().front().address());
EXPECT_EQ(address_ipv4, result2->addresses().value().back().address());
EXPECT_EQ(1, stale.network_changes); EXPECT_EQ(1, stale.network_changes);
EXPECT_GT(base::TimeDelta::FromMilliseconds(100), EXPECT_GT(base::TimeDelta::FromMilliseconds(100),
(base::TimeDelta::FromSeconds(-3) - stale.expired_by).magnitude()); (base::TimeDelta::FromSeconds(-3) - stale.expired_by).magnitude());
...@@ -717,18 +721,77 @@ TEST(HostCacheTest, SerializeAndDeserialize) { ...@@ -717,18 +721,77 @@ TEST(HostCacheTest, SerializeAndDeserialize) {
// The "foobar3.com" entry is the new one, not the restored one. // The "foobar3.com" entry is the new one, not the restored one.
const HostCache::Entry* result3 = restored_cache.Lookup(key3, now); const HostCache::Entry* result3 = restored_cache.Lookup(key3, now);
EXPECT_TRUE(result3); EXPECT_TRUE(result3);
EXPECT_EQ(1u, result3->addresses().size()); ASSERT_TRUE(result3->addresses());
EXPECT_EQ(address_ipv4, result3->addresses().front().address()); EXPECT_EQ(1u, result3->addresses().value().size());
EXPECT_EQ(address_ipv4, result3->addresses().value().front().address());
// The "foobar4.com" entry is still present and usable. // The "foobar4.com" entry is still present and usable.
const HostCache::Entry* result4 = restored_cache.Lookup(key4, now); const HostCache::Entry* result4 = restored_cache.Lookup(key4, now);
EXPECT_TRUE(result4); EXPECT_TRUE(result4);
EXPECT_EQ(1u, result4->addresses().size()); ASSERT_TRUE(result4->addresses());
EXPECT_EQ(address_ipv4, result4->addresses().front().address()); EXPECT_EQ(1u, result4->addresses().value().size());
EXPECT_EQ(address_ipv4, result4->addresses().value().front().address());
EXPECT_EQ(3u, restored_cache.last_restore_size()); EXPECT_EQ(3u, restored_cache.last_restore_size());
} }
TEST(HostCacheTest, SerializeAndDeserialize_Text) {
base::TimeTicks now;
base::TimeDelta ttl = base::TimeDelta::FromSeconds(99);
std::vector<std::string> text_records({"foo", "bar"});
HostCache::Key key("example.com", DnsQueryType::A, 0,
HostResolverSource::DNS);
HostCache::Entry entry(OK, text_records, HostCache::Entry::SOURCE_DNS, ttl);
EXPECT_TRUE(entry.text_records());
HostCache cache(kMaxCacheEntries);
cache.Set(key, entry, now, ttl);
EXPECT_EQ(1u, cache.size());
base::ListValue serialized_cache;
cache.GetAsListValue(&serialized_cache, false /* include_staleness */);
HostCache restored_cache(kMaxCacheEntries);
restored_cache.RestoreFromListValue(serialized_cache);
ASSERT_EQ(1u, cache.size());
const HostCache::Entry* result = cache.Lookup(key, now);
ASSERT_TRUE(result);
EXPECT_FALSE(result->addresses());
ASSERT_TRUE(result->text_records());
EXPECT_FALSE(result->hostnames());
EXPECT_EQ(text_records, result->text_records().value());
}
TEST(HostCacheTest, SerializeAndDeserialize_Hostname) {
base::TimeTicks now;
base::TimeDelta ttl = base::TimeDelta::FromSeconds(99);
std::vector<HostPortPair> hostnames(
{HostPortPair("example.com", 95), HostPortPair("chromium.org", 122)});
HostCache::Key key("example.com", DnsQueryType::A, 0,
HostResolverSource::DNS);
HostCache::Entry entry(OK, hostnames, HostCache::Entry::SOURCE_DNS, ttl);
EXPECT_TRUE(entry.hostnames());
HostCache cache(kMaxCacheEntries);
cache.Set(key, entry, now, ttl);
EXPECT_EQ(1u, cache.size());
base::ListValue serialized_cache;
cache.GetAsListValue(&serialized_cache, false /* include_staleness */);
HostCache restored_cache(kMaxCacheEntries);
restored_cache.RestoreFromListValue(serialized_cache);
ASSERT_EQ(1u, cache.size());
const HostCache::Entry* result = cache.Lookup(key, now);
ASSERT_TRUE(result);
EXPECT_FALSE(result->addresses());
EXPECT_FALSE(result->text_records());
ASSERT_TRUE(result->hostnames());
EXPECT_EQ(hostnames, result->hostnames().value());
}
TEST(HostCacheTest, PersistenceDelegate) { TEST(HostCacheTest, PersistenceDelegate) {
const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10); const base::TimeDelta kTTL = base::TimeDelta::FromSeconds(10);
HostCache cache(kMaxCacheEntries); HostCache cache(kMaxCacheEntries);
......
...@@ -1933,7 +1933,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job, ...@@ -1933,7 +1933,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
} }
if (entry.error() == OK && !req->parameters().is_speculative) { if (entry.error() == OK && !req->parameters().is_speculative) {
req->set_address_results(EnsurePortOnAddressList( req->set_address_results(EnsurePortOnAddressList(
entry.addresses(), req->request_host().port())); entry.addresses().value(), req->request_host().port()));
} }
req->OnJobCompleted(this, entry.error()); req->OnJobCompleted(this, entry.error());
...@@ -2519,7 +2519,8 @@ bool HostResolverImpl::ServeFromCache(const Key& key, ...@@ -2519,7 +2519,8 @@ bool HostResolverImpl::ServeFromCache(const Key& key,
if (*net_error == OK) { if (*net_error == OK) {
if (cache_entry->has_ttl()) if (cache_entry->has_ttl())
RecordTTL(cache_entry->ttl()); RecordTTL(cache_entry->ttl());
*addresses = EnsurePortOnAddressList(cache_entry->addresses(), host_port); *addresses =
EnsurePortOnAddressList(cache_entry->addresses().value(), host_port);
} }
return true; return true;
} }
......
...@@ -455,7 +455,8 @@ int MockHostResolverBase::ResolveFromIPLiteralOrCache( ...@@ -455,7 +455,8 @@ int MockHostResolverBase::ResolveFromIPLiteralOrCache(
if (entry) { if (entry) {
rv = entry->error(); rv = entry->error();
if (rv == OK) if (rv == OK)
*addresses = AddressList::CopyWithPort(entry->addresses(), host.port()); *addresses =
AddressList::CopyWithPort(entry->addresses().value(), host.port());
} }
} }
return rv; return rv;
......
...@@ -153,7 +153,8 @@ int HostResolverMojo::ResolveFromCacheInternal(const RequestInfo& info, ...@@ -153,7 +153,8 @@ int HostResolverMojo::ResolveFromCacheInternal(const RequestInfo& info,
if (!entry) if (!entry)
return net::ERR_DNS_CACHE_MISS; return net::ERR_DNS_CACHE_MISS;
*addresses = net::AddressList::CopyWithPort(entry->addresses(), info.port()); *addresses =
net::AddressList::CopyWithPort(entry->addresses().value(), info.port());
return entry->error(); return entry->error();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment