Skip to content

Commit

Permalink
Generalize for non-address results in HostResolverImpl
Browse files Browse the repository at this point in the history
Now extensively using HostCache::Entry internally (but only internally
to preserve flexibility of HostCache) as a generalized results
container within HostResolverImpl. Added some needed setter/merge
functionality to Entry for that purpose.  Many methods within the
resolver changed to use Entry for consistency even if they only ever
deal with address results, eg ResolveAsIP().

Slightly modified results port-setting functionality to only set port
to an input port (from |host.port()|) if the port in the results is 0
(where before it would set it whenever it wasn't equal to the input
port).  This will be necessary eg for SRV support where DNS provides a
specific port that needs to be maintained in the results. Also cleaned
up the port setting to consistently only ever happen just before
setting results on the RequestImpl and having 0 or a DNS-provided port
until then.

Bug: 846423
Change-Id: I679c0ac915e0f81b49adb5ee769f250be49c9c90
Reviewed-on: https://chromium-review.googlesource.com/c/1340835
Reviewed-by: Matt Menke <mmenke@chromium.org>
Commit-Queue: Eric Orth <ericorth@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611963}
  • Loading branch information
Eric Orth authored and Commit Bot committed Nov 29, 2018
1 parent fc06c16 commit 07ee5f0
Show file tree
Hide file tree
Showing 11 changed files with 924 additions and 516 deletions.
203 changes: 146 additions & 57 deletions net/dns/host_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@

#include <algorithm>

#include "base/bind.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/default_tick_clock.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/dns/host_resolver.h"
#include "net/log/net_log.h"

Expand Down Expand Up @@ -67,6 +66,16 @@ bool AddressListFromListValue(const base::ListValue* value,
return true;
}

template <typename T>
void MergeLists(base::Optional<T>* target, const base::Optional<T>& source) {
if (target->has_value() && source) {
target->value().insert(target->value().end(), source.value().begin(),
source.value().end());
} else if (source) {
*target = source;
}
}

} // namespace

// Used in histograms; do not modify existing values.
Expand Down Expand Up @@ -114,9 +123,78 @@ HostCache::Key::Key(const std::string& hostname,
HostCache::Key::Key()
: Key("", DnsQueryType::UNSPECIFIED, 0, HostResolverSource::ANY) {}

HostCache::Entry::Entry(int error, Source source, base::TimeDelta ttl)
: error_(error), source_(source), ttl_(ttl) {
DCHECK_GE(ttl_, base::TimeDelta());
DCHECK_NE(OK, error_);
}

HostCache::Entry::Entry(int error, Source source)
: error_(error), source_(source), ttl_(base::TimeDelta::FromSeconds(-1)) {
DCHECK_NE(OK, error_);
}

HostCache::Entry::Entry(const Entry& entry) = default;

HostCache::Entry::Entry(Entry&& entry) = default;

HostCache::Entry::~Entry() = default;

HostCache::Entry::Entry(HostCache::Entry&& entry) = default;
base::Optional<base::TimeDelta> HostCache::Entry::GetOptionalTtl() const {
if (has_ttl())
return ttl();
else
return base::nullopt;
}

// static
HostCache::Entry HostCache::Entry::MergeEntries(Entry front, Entry back) {
// Only expected to merge OK or ERR_NAME_NOT_RESOLVED results.
DCHECK(front.error() == OK || front.error() == ERR_NAME_NOT_RESOLVED);
DCHECK(back.error() == OK || back.error() == ERR_NAME_NOT_RESOLVED);

// Build results in |front| to preserve unmerged fields.

front.error_ =
front.error() == OK || back.error() == OK ? OK : ERR_NAME_NOT_RESOLVED;

MergeLists(&front.addresses_, back.addresses());
MergeLists(&front.text_records_, back.text_records());
MergeLists(&front.hostnames_, back.hostnames());

// Use canonical name from |back| iff empty in |front|.
if (front.addresses() && front.addresses().value().canonical_name().empty() &&
back.addresses()) {
front.addresses_.value().set_canonical_name(
back.addresses().value().canonical_name());
}

// Only expected to merge entries from same source.
DCHECK_EQ(front.source(), back.source());

if (front.has_ttl() && back.has_ttl()) {
front.ttl_ = std::min(front.ttl(), back.ttl());
} else if (back.has_ttl()) {
front.ttl_ = back.ttl();
}

front.expires_ = std::min(front.expires(), back.expires());
front.network_changes_ =
std::max(front.network_changes(), back.network_changes());
front.total_hits_ = front.total_hits() + back.total_hits();
front.stale_hits_ = front.stale_hits() + back.stale_hits();

return front;
}

NetLogParametersCallback HostCache::Entry::CreateNetLogCallback() const {
return base::BindRepeating(&HostCache::Entry::NetLogCallback,
base::Unretained(this));
}

HostCache::Entry& HostCache::Entry::operator=(const Entry& entry) = default;

HostCache::Entry& HostCache::Entry::operator=(Entry&& entry) = default;

HostCache::Entry::Entry(const HostCache::Entry& entry,
base::TimeTicks now,
Expand Down Expand Up @@ -174,6 +252,69 @@ void HostCache::Entry::GetStaleness(base::TimeTicks now,
out->stale_hits = stale_hits_;
}

std::unique_ptr<base::Value> HostCache::Entry::NetLogCallback(
NetLogCaptureMode capture_mode) const {
return std::make_unique<base::Value>(
GetAsValue(false /* include_staleness */));
}

base::DictionaryValue HostCache::Entry::GetAsValue(
bool include_staleness) const {
base::DictionaryValue entry_dict;

if (include_staleness) {
// The kExpirationKey value is using TimeTicks instead of Time used if
// |include_staleness| is false, so it cannot be used to deserialize.
// This is ok as it is used only for netlog.
entry_dict.SetString(kExpirationKey, NetLog::TickCountToString(expires()));
entry_dict.SetInteger(kTtlKey, ttl().InMilliseconds());
entry_dict.SetInteger(kNetworkChangesKey, 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() - expires());
entry_dict.SetString(
kExpirationKey, base::Int64ToString(expiration_time.ToInternalValue()));
}

if (error() != OK) {
entry_dict.SetInteger(kErrorKey, error());
} else {
if (addresses()) {
// Append all of the resolved addresses.
base::ListValue addresses_value;
for (const IPEndPoint& address : addresses().value()) {
addresses_value.GetList().emplace_back(address.ToStringWithoutPort());
}
entry_dict.SetKey(kAddressesKey, std::move(addresses_value));
}

if (text_records()) {
// Append all resolved text records.
base::ListValue text_list_value;
for (const std::string& text_record : text_records().value()) {
text_list_value.GetList().emplace_back(text_record);
}
entry_dict.SetKey(kTextRecordsKey, std::move(text_list_value));
}

if (hostnames()) {
// Append all the resolved hostnames.
base::ListValue hostnames_value;
base::ListValue host_ports_value;
for (const HostPortPair& hostname : 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));
}
}

return entry_dict;
}

HostCache::HostCache(size_t max_entries)
: max_entries_(max_entries),
network_changes_(0),
Expand Down Expand Up @@ -368,8 +509,8 @@ void HostCache::GetAsListValue(base::ListValue* entry_list,
const Key& key = pair.first;
const Entry& entry = pair.second;

std::unique_ptr<base::DictionaryValue> entry_dict(
new base::DictionaryValue());
auto entry_dict = std::make_unique<base::DictionaryValue>(
entry.GetAsValue(include_staleness));

entry_dict->SetString(kHostnameKey, key.hostname);
entry_dict->SetInteger(kDnsQueryTypeKey,
Expand All @@ -378,58 +519,6 @@ void HostCache::GetAsListValue(base::ListValue* entry_list,
entry_dict->SetInteger(kHostResolverSourceKey,
static_cast<int>(key.host_resolver_source));

if (include_staleness) {
// The kExpirationKey value is using TimeTicks instead of Time used if
// |include_staleness| is false, so it cannot be used to deserialize.
// This is ok as it is used only for netlog.
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() - (tick_clock_->NowTicks() - entry.expires());
entry_dict->SetString(
kExpirationKey,
base::Int64ToString(expiration_time.ToInternalValue()));
}

if (entry.error() != OK) {
entry_dict->SetInteger(kErrorKey, entry.error());
} else {
if (entry.addresses()) {
// Append all of the resolved addresses.
base::ListValue addresses_value;
for (const IPEndPoint& address : entry.addresses().value()) {
addresses_value.GetList().emplace_back(address.ToStringWithoutPort());
}
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));
}
}
Expand Down
39 changes: 39 additions & 0 deletions net/dns/host_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/address_family.h"
#include "net/base/address_list.h"
#include "net/base/expiring_cache.h"
Expand All @@ -29,6 +30,8 @@
#include "net/dns/dns_util.h"
#include "net/dns/host_resolver_source.h"
#include "net/dns/public/dns_query_type.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_parameters_callback.h"

namespace base {
class ListValue;
Expand Down Expand Up @@ -110,26 +113,58 @@ class NET_EXPORT HostCache {
SetResult(std::forward<T>(results));
}

// For errors with no |results|.
Entry(int error, Source source, base::TimeDelta ttl);
Entry(int error, Source source);

Entry(const Entry& entry);
Entry(Entry&& entry);
~Entry();

Entry& operator=(const Entry& entry);
Entry& operator=(Entry&& entry);

int error() const { return error_; }
void set_error(int error) { error_ = error; }
const base::Optional<AddressList>& addresses() const { return addresses_; }
void set_addresses(const base::Optional<AddressList>& addresses) {
addresses_ = addresses;
}
const base::Optional<std::vector<std::string>>& text_records() const {
return text_records_;
}
void set_text_records(
base::Optional<std::vector<std::string>> text_records) {
text_records_ = std::move(text_records);
}
const base::Optional<std::vector<HostPortPair>>& hostnames() const {
return hostnames_;
}
void set_hostnames(base::Optional<std::vector<HostPortPair>> hostnames) {
hostnames_ = std::move(hostnames);
}
Source source() const { return source_; }
bool has_ttl() const { return ttl_ >= base::TimeDelta(); }
base::TimeDelta ttl() const { return ttl_; }
base::Optional<base::TimeDelta> GetOptionalTtl() const;
void set_ttl(base::TimeDelta ttl) { ttl_ = ttl; }

base::TimeTicks expires() const { return expires_; }

// Public for the net-internals UI.
int network_changes() const { return network_changes_; }

// Merge |front| and |back|, representing results from multiple
// transactions for the same overal host resolution query. On merging result
// lists, result elements from |front| will be merged in front of elements
// from |back|. Fields that cannot be merged take precedence from |front|.
static Entry MergeEntries(Entry front, Entry back);

// Creates a callback for use with the NetLog that returns a Value
// representation of the entry. The callback must be destroyed before
// |this| is.
NetLogParametersCallback CreateNetLogCallback() const;

private:
friend class HostCache;

Expand Down Expand Up @@ -163,6 +198,10 @@ class NET_EXPORT HostCache {
int network_changes,
EntryStaleness* out) const;

std::unique_ptr<base::Value> NetLogCallback(
NetLogCaptureMode capture_mode) const;
base::DictionaryValue GetAsValue(bool include_staleness) const;

// The resolve results for this entry.
int error_;
base::Optional<AddressList> addresses_;
Expand Down
Loading

0 comments on commit 07ee5f0

Please sign in to comment.