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_;
......
This diff is collapsed.
...@@ -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,12 +276,12 @@ class NET_EXPORT HostCache { ...@@ -243,12 +276,12 @@ 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,
......
...@@ -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