summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/dns_global.cc5
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h2
-rw-r--r--chrome/test/unit/chrome_test_suite.h6
-rw-r--r--net/base/address_family.h19
-rw-r--r--net/base/address_list_unittest.cc4
-rw-r--r--net/base/host_cache.cc8
-rw-r--r--net/base/host_cache.h32
-rw-r--r--net/base/host_cache_unittest.cc175
-rw-r--r--net/base/host_resolver.h13
-rw-r--r--net/base/host_resolver_impl.cc59
-rw-r--r--net/base/host_resolver_impl.h18
-rw-r--r--net/base/host_resolver_impl_unittest.cc6
-rw-r--r--net/base/host_resolver_proc.cc18
-rw-r--r--net/base/host_resolver_proc.h19
-rw-r--r--net/base/mock_host_resolver.cc7
-rw-r--r--net/base/mock_host_resolver.h10
-rw-r--r--net/net.gyp1
-rw-r--r--net/url_request/url_request_view_net_internals_job.cc26
19 files changed, 302 insertions, 129 deletions
diff --git a/chrome/browser/net/dns_global.cc b/chrome/browser/net/dns_global.cc
index 434208b..c2a89c0 100644
--- a/chrome/browser/net/dns_global.cc
+++ b/chrome/browser/net/dns_global.cc
@@ -22,7 +22,9 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
+#include "chrome/common/chrome_switches.h"
#include "net/base/host_resolver.h"
+#include "net/base/host_resolver_impl.h"
using base::Time;
using base::TimeDelta;
@@ -477,6 +479,9 @@ net::HostResolver* GetGlobalHostResolver() {
// Called from UI thread.
if (!global_host_resolver) {
global_host_resolver = net::CreateSystemHostResolver();
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIPv6))
+ global_host_resolver->DisableIPv6(true);
}
return global_host_resolver;
}
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index f9413b4..4b47a59 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -237,6 +237,9 @@ const char kShowIcons[] = "show-icons";
// Make Chrome default browser
const char kMakeDefaultBrowser[] = "make-default-browser";
+// Don't resolve hostnames to IPv6 addresses.
+const char kDisableIPv6[] = "disable-ipv6";
+
// Use a specified proxy server, overrides system settings. This switch only
// affects HTTP and HTTPS requests.
const char kProxyServer[] = "proxy-server";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 9920df2..ded4e54 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -81,6 +81,8 @@ extern const char kHideIcons[];
extern const char kShowIcons[];
extern const char kMakeDefaultBrowser[];
+extern const char kDisableIPv6[];
+
extern const char kProxyServer[];
extern const char kNoProxyServer[];
extern const char kProxyBypassList[];
diff --git a/chrome/test/unit/chrome_test_suite.h b/chrome/test/unit/chrome_test_suite.h
index 52dcc2c..43c7de0 100644
--- a/chrome/test/unit/chrome_test_suite.h
+++ b/chrome/test/unit/chrome_test_suite.h
@@ -36,7 +36,9 @@ class WarningHostResolverProc : public net::HostResolverProc {
public:
WarningHostResolverProc() : HostResolverProc(NULL) {}
- virtual int Resolve(const std::string& host, net::AddressList* addrlist) {
+ virtual int Resolve(const std::string& host,
+ net::AddressFamily address_family,
+ net::AddressList* addrlist) {
const char* kLocalHostNames[] = {"localhost", "127.0.0.1"};
bool local = false;
@@ -55,7 +57,7 @@ class WarningHostResolverProc : public net::HostResolverProc {
// net::RuleBasedHostResolverProc and its AllowDirectLookup method.
EXPECT_TRUE(local) << "Making external DNS lookup of " << host;
- return ResolveUsingPrevious(host, addrlist);
+ return ResolveUsingPrevious(host, address_family, addrlist);
}
};
diff --git a/net/base/address_family.h b/net/base/address_family.h
new file mode 100644
index 0000000..faa9193
--- /dev/null
+++ b/net/base/address_family.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_ADDRESS_FAMILY_H_
+#define NET_BASE_ADDRESS_FAMILY_H_
+
+namespace net {
+
+// Enum wrapper around the address family types supported by host resolver
+// procedures. These correspond with AF_UNSPEC and AF_INET.
+enum AddressFamily {
+ ADDRESS_FAMILY_UNSPECIFIED,
+ ADDRESS_FAMILY_IPV4_ONLY,
+};
+
+} // namesapce net
+
+#endif // NET_BASE_ADDRESS_FAMILY_H_
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index d8ab3c1..d440c15 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -19,7 +19,9 @@ void CreateAddressList(net::AddressList* addrlist, int port) {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
- int rv = SystemHostResolverProc("192.168.1.1", addrlist);
+ int rv = SystemHostResolverProc("192.168.1.1",
+ net::ADDRESS_FAMILY_UNSPECIFIED,
+ addrlist);
EXPECT_EQ(0, rv);
addrlist->SetPort(port);
}
diff --git a/net/base/host_cache.cc b/net/base/host_cache.cc
index 53af5b4..fbe2a7e 100644
--- a/net/base/host_cache.cc
+++ b/net/base/host_cache.cc
@@ -29,12 +29,12 @@ HostCache::HostCache(size_t max_entries, size_t cache_duration_ms)
HostCache::~HostCache() {
}
-const HostCache::Entry* HostCache::Lookup(const std::string& hostname,
+const HostCache::Entry* HostCache::Lookup(const Key& key,
base::TimeTicks now) const {
if (caching_is_disabled())
return NULL;
- EntryMap::const_iterator it = entries_.find(hostname);
+ EntryMap::const_iterator it = entries_.find(key);
if (it == entries_.end())
return NULL; // Not found.
@@ -45,7 +45,7 @@ const HostCache::Entry* HostCache::Lookup(const std::string& hostname,
return NULL;
}
-HostCache::Entry* HostCache::Set(const std::string& hostname,
+HostCache::Entry* HostCache::Set(const Key& key,
int error,
const AddressList addrlist,
base::TimeTicks now) {
@@ -55,7 +55,7 @@ HostCache::Entry* HostCache::Set(const std::string& hostname,
base::TimeTicks expiration = now +
base::TimeDelta::FromMilliseconds(cache_duration_ms_);
- scoped_refptr<Entry>& entry = entries_[hostname];
+ scoped_refptr<Entry>& entry = entries_[key];
if (!entry) {
// Entry didn't exist, creating one now.
Entry* ptr = new Entry(error, addrlist, expiration);
diff --git a/net/base/host_cache.h b/net/base/host_cache.h
index ab01c86..538f7ef 100644
--- a/net/base/host_cache.h
+++ b/net/base/host_cache.h
@@ -5,11 +5,12 @@
#ifndef NET_BASE_HOST_CACHE_H_
#define NET_BASE_HOST_CACHE_H_
+#include <map>
#include <string>
-#include "base/hash_tables.h"
#include "base/ref_counted.h"
#include "base/time.h"
+#include "net/base/address_family.h"
#include "net/base/address_list.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
@@ -31,7 +32,26 @@ class HostCache {
base::TimeTicks expiration;
};
- typedef base::hash_map<std::string, scoped_refptr<Entry> > EntryMap;
+ struct Key {
+ Key(const std::string& hostname, AddressFamily address_family)
+ : hostname(hostname), address_family(address_family) {}
+
+ bool operator==(const Key& other) const {
+ return other.hostname == hostname &&
+ other.address_family == address_family;
+ }
+
+ bool operator<(const Key& other) const {
+ if (address_family < other.address_family)
+ return true;
+ return hostname < other.hostname;
+ }
+
+ std::string hostname;
+ AddressFamily address_family;
+ };
+
+ typedef std::map<Key, scoped_refptr<Entry> > EntryMap;
// Constructs a HostCache whose entries are valid for |cache_duration_ms|
// milliseconds. The cache will store up to |max_entries|.
@@ -39,15 +59,15 @@ class HostCache {
~HostCache();
- // Returns a pointer to the entry for |hostname|, which is valid at time
+ // Returns a pointer to the entry for |key|, which is valid at time
// |now|. If there is no such entry, returns NULL.
- const Entry* Lookup(const std::string& hostname, base::TimeTicks now) const;
+ const Entry* Lookup(const Key& key, base::TimeTicks now) const;
- // Overwrites or creates an entry for |hostname|. Returns the pointer to the
+ // Overwrites or creates an entry for |key|. Returns the pointer to the
// entry, or NULL on failure (fails if caching is disabled).
// (|error|, |addrlist|) is the value to set, and |now| is the current
// timestamp.
- Entry* Set(const std::string& hostname,
+ Entry* Set(const Key& key,
int error,
const AddressList addrlist,
base::TimeTicks now);
diff --git a/net/base/host_cache_unittest.cc b/net/base/host_cache_unittest.cc
index 2259185..55742ba 100644
--- a/net/base/host_cache_unittest.cc
+++ b/net/base/host_cache_unittest.cc
@@ -12,10 +12,16 @@
namespace net {
namespace {
-static const int kMaxCacheEntries = 10;
-static const int kCacheDurationMs = 10000; // 10 seconds.
+const int kMaxCacheEntries = 10;
+const int kCacheDurationMs = 10000; // 10 seconds.
+
+// Builds a key for |hostname|, defaulting the address family to unspecified.
+HostCache::Key Key(const std::string& hostname) {
+ return HostCache::Key(hostname, ADDRESS_FAMILY_UNSPECIFIED);
}
+} // namespace
+
TEST(HostCacheTest, Basic) {
HostCache cache(kMaxCacheEntries, kCacheDurationMs);
@@ -28,9 +34,9 @@ TEST(HostCacheTest, Basic) {
EXPECT_EQ(0U, cache.size());
// Add an entry for "foobar.com" at t=0.
- EXPECT_TRUE(cache.Lookup("foobar.com", base::TimeTicks()) == NULL);
- cache.Set("foobar.com", OK, AddressList(), now);
- entry1 = cache.Lookup("foobar.com", base::TimeTicks());
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
+ cache.Set(Key("foobar.com"), OK, AddressList(), now);
+ entry1 = cache.Lookup(Key("foobar.com"), base::TimeTicks());
EXPECT_FALSE(entry1 == NULL);
EXPECT_EQ(1U, cache.size());
@@ -38,9 +44,9 @@ TEST(HostCacheTest, Basic) {
now += base::TimeDelta::FromSeconds(5);
// Add an entry for "foobar2.com" at t=5.
- EXPECT_TRUE(cache.Lookup("foobar2.com", base::TimeTicks()) == NULL);
- cache.Set("foobar2.com", OK, AddressList(), now);
- entry2 = cache.Lookup("foobar2.com", base::TimeTicks());
+ EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), base::TimeTicks()) == NULL);
+ cache.Set(Key("foobar2.com"), OK, AddressList(), now);
+ entry2 = cache.Lookup(Key("foobar2.com"), base::TimeTicks());
EXPECT_FALSE(NULL == entry1);
EXPECT_EQ(2U, cache.size());
@@ -48,30 +54,30 @@ TEST(HostCacheTest, Basic) {
now += base::TimeDelta::FromSeconds(4);
// Verify that the entries we added are still retrievable, and usable.
- EXPECT_EQ(entry1, cache.Lookup("foobar.com", now));
- EXPECT_EQ(entry2, cache.Lookup("foobar2.com", now));
+ EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
+ EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
// Advance to t=10; entry1 is now expired.
now += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(cache.Lookup("foobar.com", now) == NULL);
- EXPECT_EQ(entry2, cache.Lookup("foobar2.com", now));
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
+ EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
// Update entry1, so it is no longer expired.
- cache.Set("foobar.com", OK, AddressList(), now);
+ cache.Set(Key("foobar.com"), OK, AddressList(), now);
// Re-uses existing entry storage.
- EXPECT_EQ(entry1, cache.Lookup("foobar.com", now));
+ EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
EXPECT_EQ(2U, cache.size());
// Both entries should still be retrievable and usable.
- EXPECT_EQ(entry1, cache.Lookup("foobar.com", now));
- EXPECT_EQ(entry2, cache.Lookup("foobar2.com", now));
+ EXPECT_EQ(entry1, cache.Lookup(Key("foobar.com"), now));
+ EXPECT_EQ(entry2, cache.Lookup(Key("foobar2.com"), now));
// Advance to t=20; both entries are now expired.
now += base::TimeDelta::FromSeconds(10);
- EXPECT_TRUE(cache.Lookup("foobar.com", now) == NULL);
- EXPECT_TRUE(cache.Lookup("foobar2.com", now) == NULL);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
+ EXPECT_TRUE(cache.Lookup(Key("foobar2.com"), now) == NULL);
}
// Try caching entries for a failed resolve attempt.
@@ -81,24 +87,24 @@ TEST(HostCacheTest, NegativeEntry) {
// Set t=0.
base::TimeTicks now;
- EXPECT_TRUE(cache.Lookup("foobar.com", base::TimeTicks()) == NULL);
- cache.Set("foobar.com", ERR_NAME_NOT_RESOLVED, AddressList(), now);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
+ cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
EXPECT_EQ(1U, cache.size());
// We disallow use of negative entries.
- EXPECT_TRUE(cache.Lookup("foobar.com", now) == NULL);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
// Now overwrite with a valid entry, and then overwrite with negative entry
// again -- the valid entry should be kicked out.
- cache.Set("foobar.com", OK, AddressList(), now);
- EXPECT_FALSE(cache.Lookup("foobar.com", now) == NULL);
- cache.Set("foobar.com", ERR_NAME_NOT_RESOLVED, AddressList(), now);
- EXPECT_TRUE(cache.Lookup("foobar.com", now) == NULL);
+ cache.Set(Key("foobar.com"), OK, AddressList(), now);
+ EXPECT_FALSE(cache.Lookup(Key("foobar.com"), now) == NULL);
+ cache.Set(Key("foobar.com"), ERR_NAME_NOT_RESOLVED, AddressList(), now);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), now) == NULL);
}
TEST(HostCacheTest, Compact) {
// Initial entries limit is big enough to accomadate everything we add.
- net::HostCache cache(kMaxCacheEntries, kCacheDurationMs);
+ HostCache cache(kMaxCacheEntries, kCacheDurationMs);
EXPECT_EQ(0U, cache.size());
@@ -108,7 +114,7 @@ TEST(HostCacheTest, Compact) {
// Add five valid entries at t=10.
for (int i = 0; i < 5; ++i) {
std::string hostname = StringPrintf("valid%d", i);
- cache.Set(hostname, OK, AddressList(), now);
+ cache.Set(Key(hostname), OK, AddressList(), now);
}
EXPECT_EQ(5U, cache.size());
@@ -116,27 +122,27 @@ TEST(HostCacheTest, Compact) {
for (int i = 0; i < 3; ++i) {
std::string hostname = StringPrintf("expired%d", i);
base::TimeTicks t = now - base::TimeDelta::FromSeconds(10);
- cache.Set(hostname, OK, AddressList(), t);
+ cache.Set(Key(hostname), OK, AddressList(), t);
}
EXPECT_EQ(8U, cache.size());
// Add 2 negative entries at t=10
for (int i = 0; i < 2; ++i) {
std::string hostname = StringPrintf("negative%d", i);
- cache.Set(hostname, ERR_NAME_NOT_RESOLVED, AddressList(), now);
+ cache.Set(Key(hostname), ERR_NAME_NOT_RESOLVED, AddressList(), now);
}
EXPECT_EQ(10U, cache.size());
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid3"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid4"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "expired2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "negative0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "negative1"));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid0")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid1")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid2")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid3")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid4")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired0")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired1")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("expired2")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("negative0")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("negative1")));
// Shrink the max constraints bound and compact. We expect the "negative"
// and "expired" entries to have been dropped.
@@ -144,16 +150,16 @@ TEST(HostCacheTest, Compact) {
cache.Compact(now, NULL);
EXPECT_EQ(5U, cache.entries_.size());
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid0"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid1"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid2"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid3"));
- EXPECT_TRUE(ContainsKey(cache.entries_, "valid4"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired0"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired1"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "expired2"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "negative0"));
- EXPECT_FALSE(ContainsKey(cache.entries_, "negative1"));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid0")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid1")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid2")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid3")));
+ EXPECT_TRUE(ContainsKey(cache.entries_, Key("valid4")));
+ EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired0")));
+ EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired1")));
+ EXPECT_FALSE(ContainsKey(cache.entries_, Key("expired2")));
+ EXPECT_FALSE(ContainsKey(cache.entries_, Key("negative0")));
+ EXPECT_FALSE(ContainsKey(cache.entries_, Key("negative1")));
// Shrink further -- this time the compact will start dropping valid entries
// to make space.
@@ -164,39 +170,74 @@ TEST(HostCacheTest, Compact) {
// Add entries while the cache is at capacity, causing evictions.
TEST(HostCacheTest, SetWithCompact) {
- net::HostCache cache(3, kCacheDurationMs);
+ HostCache cache(3, kCacheDurationMs);
// t=10
base::TimeTicks now =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(kCacheDurationMs);
- cache.Set("host1", OK, AddressList(), now);
- cache.Set("host2", OK, AddressList(), now);
- cache.Set("expired", OK, AddressList(),
+ cache.Set(Key("host1"), OK, AddressList(), now);
+ cache.Set(Key("host2"), OK, AddressList(), now);
+ cache.Set(Key("expired"), OK, AddressList(),
now - base::TimeDelta::FromMilliseconds(kCacheDurationMs));
EXPECT_EQ(3U, cache.size());
// Should all be retrievable except "expired".
- EXPECT_FALSE(NULL == cache.Lookup("host1", now));
- EXPECT_FALSE(NULL == cache.Lookup("host2", now));
- EXPECT_TRUE(NULL == cache.Lookup("expired", now));
+ EXPECT_FALSE(NULL == cache.Lookup(Key("host1"), now));
+ EXPECT_FALSE(NULL == cache.Lookup(Key("host2"), now));
+ EXPECT_TRUE(NULL == cache.Lookup(Key("expired"), now));
// Adding the fourth entry will cause "expired" to be evicted.
- cache.Set("host3", OK, AddressList(), now);
+ cache.Set(Key("host3"), OK, AddressList(), now);
EXPECT_EQ(3U, cache.size());
- EXPECT_TRUE(cache.Lookup("expired", now) == NULL);
- EXPECT_FALSE(cache.Lookup("host1", now) == NULL);
- EXPECT_FALSE(cache.Lookup("host2", now) == NULL);
- EXPECT_FALSE(cache.Lookup("host3", now) == NULL);
+ EXPECT_TRUE(cache.Lookup(Key("expired"), now) == NULL);
+ EXPECT_FALSE(cache.Lookup(Key("host1"), now) == NULL);
+ EXPECT_FALSE(cache.Lookup(Key("host2"), now) == NULL);
+ EXPECT_FALSE(cache.Lookup(Key("host3"), now) == NULL);
// Add two more entries. Something should be evicted, however "host5"
// should definitely be in there (since it was last inserted).
- cache.Set("host4", OK, AddressList(), now);
+ cache.Set(Key("host4"), OK, AddressList(), now);
EXPECT_EQ(3U, cache.size());
- cache.Set("host5", OK, AddressList(), now);
+ cache.Set(Key("host5"), OK, AddressList(), now);
EXPECT_EQ(3U, cache.size());
- EXPECT_FALSE(cache.Lookup("host5", now) == NULL);
+ EXPECT_FALSE(cache.Lookup(Key("host5"), now) == NULL);
+}
+
+// Tests that the same hostname can be duplicated in the cache, so long as
+// the address family differs.
+TEST(HostCacheTest, AddressFamilyIsPartOfKey) {
+ HostCache cache(kMaxCacheEntries, kCacheDurationMs);
+
+ // t=0.
+ base::TimeTicks now;
+
+ HostCache::Key key1("foobar.com", ADDRESS_FAMILY_UNSPECIFIED);
+ HostCache::Key key2("foobar.com", ADDRESS_FAMILY_IPV4_ONLY);
+
+ const HostCache::Entry* entry1 = NULL; // Entry for key1
+ const HostCache::Entry* entry2 = NULL; // Entry for key2
+
+ EXPECT_EQ(0U, cache.size());
+
+ // Add an entry for ("foobar.com", UNSPECIFIED) at t=0.
+ EXPECT_TRUE(cache.Lookup(key1, base::TimeTicks()) == NULL);
+ cache.Set(key1, OK, AddressList(), now);
+ entry1 = cache.Lookup(key1, base::TimeTicks());
+ EXPECT_FALSE(entry1 == NULL);
+ EXPECT_EQ(1U, cache.size());
+
+ // Add an entry for ("foobar.com", IPV4_ONLY) at t=0.
+ EXPECT_TRUE(cache.Lookup(key2, base::TimeTicks()) == NULL);
+ cache.Set(key2, OK, AddressList(), now);
+ entry2 = cache.Lookup(key2, base::TimeTicks());
+ EXPECT_FALSE(entry2 == NULL);
+ EXPECT_EQ(2U, cache.size());
+
+ // Even though the hostnames were the same, we should have two unique
+ // entries (because the address families differ).
+ EXPECT_NE(entry1, entry2);
}
TEST(HostCacheTest, NoCache) {
@@ -208,9 +249,9 @@ TEST(HostCacheTest, NoCache) {
base::TimeTicks now;
// Lookup and Set should have no effect.
- EXPECT_TRUE(cache.Lookup("foobar.com", base::TimeTicks()) == NULL);
- cache.Set("foobar.com", OK, AddressList(), now);
- EXPECT_TRUE(cache.Lookup("foobar.com", base::TimeTicks()) == NULL);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
+ cache.Set(Key("foobar.com"), OK, AddressList(), now);
+ EXPECT_TRUE(cache.Lookup(Key("foobar.com"), base::TimeTicks()) == NULL);
EXPECT_EQ(0U, cache.size());
}
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index fe91b4d..4829c1c 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -9,6 +9,7 @@
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
+#include "net/base/address_family.h"
#include "net/base/completion_callback.h"
class MessageLoop;
@@ -36,6 +37,7 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> {
public:
RequestInfo(const std::string& hostname, int port)
: hostname_(hostname),
+ address_family_(ADDRESS_FAMILY_UNSPECIFIED),
port_(port),
allow_cached_response_(true),
is_speculative_(false) {}
@@ -43,6 +45,11 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> {
const int port() const { return port_; }
const std::string& hostname() const { return hostname_; }
+ AddressFamily address_family() const { return address_family_; }
+ void set_address_family(AddressFamily address_family) {
+ address_family_ = address_family;
+ }
+
bool allow_cached_response() const { return allow_cached_response_; }
void set_allow_cached_response(bool b) { allow_cached_response_ = b; }
@@ -56,6 +63,9 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> {
// The hostname to resolve.
std::string hostname_;
+ // The address family to restrict results to.
+ AddressFamily address_family_;
+
// The port number to set in the result's sockaddrs.
int port_;
@@ -138,6 +148,9 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> {
// TODO(eroman): temp hack for http://crbug.com/18373
virtual void Shutdown() = 0;
+ // Disables or enables support for IPv6 results.
+ virtual void DisableIPv6(bool disable_ipv6) {}
+
protected:
HostResolver() { }
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index c93c8eb..e3cfcd3 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -41,13 +41,15 @@ HostResolver* CreateSystemHostResolver() {
}
static int ResolveAddrInfo(HostResolverProc* resolver_proc,
- const std::string& host, AddressList* out) {
+ const std::string& host,
+ AddressFamily address_family,
+ AddressList* out) {
if (resolver_proc) {
// Use the custom procedure.
- return resolver_proc->Resolve(host, out);
+ return resolver_proc->Resolve(host, address_family, out);
} else {
// Use the system procedure (getaddrinfo).
- return SystemHostResolverProc(host, out);
+ return SystemHostResolverProc(host, address_family, out);
}
}
@@ -142,8 +144,8 @@ class HostResolverImpl::Request {
class HostResolverImpl::Job
: public base::RefCountedThreadSafe<HostResolverImpl::Job> {
public:
- Job(HostResolverImpl* resolver, const std::string& host)
- : host_(host),
+ Job(HostResolverImpl* resolver, const Key& key)
+ : key_(key),
resolver_(resolver),
origin_loop_(MessageLoop::current()),
resolver_proc_(resolver->effective_resolver_proc()),
@@ -206,8 +208,8 @@ class HostResolverImpl::Job
}
// Called from origin thread.
- const std::string& host() const {
- return host_;
+ const Key& key() const {
+ return key_;
}
// Called from origin thread.
@@ -218,7 +220,10 @@ class HostResolverImpl::Job
private:
void DoLookup() {
// Running on the worker thread
- error_ = ResolveAddrInfo(resolver_proc_, host_, &results_);
+ error_ = ResolveAddrInfo(resolver_proc_,
+ key_.hostname,
+ key_.address_family,
+ &results_);
Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete);
@@ -257,7 +262,7 @@ class HostResolverImpl::Job
}
// Set on the origin thread, read on the worker thread.
- std::string host_;
+ Key key_;
// Only used on the origin thread (where Resolve was called).
HostResolverImpl* resolver_;
@@ -285,8 +290,11 @@ class HostResolverImpl::Job
HostResolverImpl::HostResolverImpl(HostResolverProc* resolver_proc,
int max_cache_entries,
int cache_duration_ms)
- : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0),
- resolver_proc_(resolver_proc), shutdown_(false) {
+ : cache_(max_cache_entries, cache_duration_ms),
+ next_request_id_(0),
+ resolver_proc_(resolver_proc),
+ disable_ipv6_(false),
+ shutdown_(false) {
#if defined(OS_WIN)
EnsureWinsockInit();
#endif
@@ -319,10 +327,16 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
// Update the load log and notify registered observers.
OnStartRequest(load_log, request_id, info);
+ // Build a key that identifies the request in the cache and in the
+ // outstanding jobs map.
+ Key key(info.hostname(), info.address_family());
+ if (disable_ipv6_)
+ key.address_family = ADDRESS_FAMILY_IPV4_ONLY;
+
// If we have an unexpired cache entry, use it.
if (info.allow_cached_response()) {
const HostCache::Entry* cache_entry = cache_.Lookup(
- info.hostname(), base::TimeTicks::Now());
+ key, base::TimeTicks::Now());
if (cache_entry) {
addresses->SetFrom(cache_entry->addrlist, info.port());
int error = cache_entry->error;
@@ -338,14 +352,14 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
if (!callback) {
AddressList addrlist;
int error = ResolveAddrInfo(
- effective_resolver_proc(), info.hostname(), &addrlist);
+ effective_resolver_proc(), key.hostname, key.address_family, &addrlist);
if (error == OK) {
addrlist.SetPort(info.port());
*addresses = addrlist;
}
// Write to cache.
- cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now());
+ cache_.Set(key, error, addrlist, base::TimeTicks::Now());
// Update the load log and notify registered observers.
OnFinishRequest(load_log, request_id, info, error);
@@ -363,14 +377,14 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
// calling "getaddrinfo(hostname)" on a worker thread.
scoped_refptr<Job> job;
- // If there is already an outstanding job to resolve |info.hostname()|, use
+ // If there is already an outstanding job to resolve |key|, use
// it. This prevents starting concurrent resolves for the same hostname.
- job = FindOutstandingJob(info.hostname());
+ job = FindOutstandingJob(key);
if (job) {
job->AddRequest(req);
} else {
// Create a new job for this request.
- job = new Job(this, info.hostname());
+ job = new Job(this, key);
job->AddRequest(req);
AddOutstandingJob(job);
// TODO(eroman): Bound the total number of concurrent jobs.
@@ -431,21 +445,20 @@ void HostResolverImpl::Shutdown() {
}
void HostResolverImpl::AddOutstandingJob(Job* job) {
- scoped_refptr<Job>& found_job = jobs_[job->host()];
+ scoped_refptr<Job>& found_job = jobs_[job->key()];
DCHECK(!found_job);
found_job = job;
}
-HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(
- const std::string& hostname) {
- JobMap::iterator it = jobs_.find(hostname);
+HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
+ JobMap::iterator it = jobs_.find(key);
if (it != jobs_.end())
return it->second;
return NULL;
}
void HostResolverImpl::RemoveOutstandingJob(Job* job) {
- JobMap::iterator it = jobs_.find(job->host());
+ JobMap::iterator it = jobs_.find(job->key());
DCHECK(it != jobs_.end());
DCHECK_EQ(it->second.get(), job);
jobs_.erase(it);
@@ -457,7 +470,7 @@ void HostResolverImpl::OnJobComplete(Job* job,
RemoveOutstandingJob(job);
// Write result to the cache.
- cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now());
+ cache_.Set(job->key(), error, addrlist, base::TimeTicks::Now());
// Make a note that we are executing within OnJobComplete() in case the
// HostResolver is deleted by a callback invocation.
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index 74dea08..b641b0b 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -27,7 +27,7 @@ namespace net {
// +----------- HostResolverImpl -------------+
// | | |
// Job Job Job
-// (for host1) (for host2) (for hostX)
+// (for host1, fam1) (for host2, fam2) (for hostx, famx)
// / | | / | | / | |
// Request ... Request Request ... Request Request ... Request
// (port1) (port2) (port3) (port4) (port5) (portX)
@@ -70,11 +70,18 @@ class HostResolverImpl : public HostResolver {
// TODO(eroman): temp hack for http://crbug.com/15513
virtual void Shutdown();
+ // Prevents returning IPv6 addresses from Resolve().
+ // The default is to allow IPv6 results.
+ virtual void DisableIPv6(bool disable_ipv6) {
+ disable_ipv6_ = disable_ipv6;
+ }
+
private:
class Job;
class Request;
typedef std::vector<Request*> RequestsList;
- typedef base::hash_map<std::string, scoped_refptr<Job> > JobMap;
+ typedef HostCache::Key Key;
+ typedef std::map<Key, scoped_refptr<Job> > JobMap;
typedef std::vector<Observer*> ObserversList;
// Returns the HostResolverProc to use for this instance.
@@ -86,8 +93,8 @@ class HostResolverImpl : public HostResolver {
// Adds a job to outstanding jobs list.
void AddOutstandingJob(Job* job);
- // Returns the outstanding job for |hostname|, or NULL if there is none.
- Job* FindOutstandingJob(const std::string& hostname);
+ // Returns the outstanding job for |key|, or NULL if there is none.
+ Job* FindOutstandingJob(const Key& key);
// Removes |job| from the outstanding jobs list.
void RemoveOutstandingJob(Job* job);
@@ -132,6 +139,9 @@ class HostResolverImpl : public HostResolver {
// in the case of unit-tests which inject custom host resolving behaviors.
scoped_refptr<HostResolverProc> resolver_proc_;
+ // Set to true if only IPv4 address are to be returned by Resolve().
+ bool disable_ipv6_;
+
// TODO(eroman): temp hack for http://crbug.com/15513
bool shutdown_;
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index fd35d88..eee6fd1 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -46,13 +46,15 @@ class CapturingHostResolverProc : public HostResolverProc {
event_.Signal();
}
- virtual int Resolve(const std::string& host, AddressList* addrlist) {
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist) {
event_.Wait();
{
AutoLock l(lock_);
capture_list_.push_back(host);
}
- return ResolveUsingPrevious(host, addrlist);
+ return ResolveUsingPrevious(host, address_family, addrlist);
}
std::vector<std::string> GetCaptureList() const {
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc
index 8951646..af92087 100644
--- a/net/base/host_resolver_proc.cc
+++ b/net/base/host_resolver_proc.cc
@@ -52,12 +52,13 @@ HostResolverProc* HostResolverProc::GetDefault() {
}
int HostResolverProc::ResolveUsingPrevious(const std::string& host,
+ AddressFamily address_family,
AddressList* addrlist) {
if (previous_proc_)
- return previous_proc_->Resolve(host, addrlist);
+ return previous_proc_->Resolve(host, address_family, addrlist);
// Final fallback is the system resolver.
- return SystemHostResolverProc(host, addrlist);
+ return SystemHostResolverProc(host, address_family, addrlist);
}
#if defined(OS_LINUX)
@@ -124,7 +125,9 @@ ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
#endif // defined(OS_LINUX)
-int SystemHostResolverProc(const std::string& host, AddressList* addrlist) {
+int SystemHostResolverProc(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist) {
// The result of |getaddrinfo| for empty hosts is inconsistent across systems.
// On Windows it gives the default interface's address, whereas on Linux it
// gives an error. We will make it fail on all platforms for consistency.
@@ -133,7 +136,14 @@ int SystemHostResolverProc(const std::string& host, AddressList* addrlist) {
struct addrinfo* ai = NULL;
struct addrinfo hints = {0};
- hints.ai_family = AF_UNSPEC;
+
+ switch (address_family) {
+ case ADDRESS_FAMILY_IPV4_ONLY:
+ hints.ai_family = AF_INET;
+ break;
+ default:
+ hints.ai_family = AF_UNSPEC;
+ }
#if defined(OS_WIN)
// DO NOT USE AI_ADDRCONFIG ON WINDOWS.
diff --git a/net/base/host_resolver_proc.h b/net/base/host_resolver_proc.h
index 66978f7..8507e03 100644
--- a/net/base/host_resolver_proc.h
+++ b/net/base/host_resolver_proc.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/ref_counted.h"
+#include "net/base/address_family.h"
namespace net {
@@ -25,14 +26,18 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
explicit HostResolverProc(HostResolverProc* previous);
virtual ~HostResolverProc() {}
- // Resolves |host| to an address list. If successful returns OK and fills
- // |addrlist| with a list of socket addresses. Otherwise returns a
- // network error code.
- virtual int Resolve(const std::string& host, AddressList* addrlist) = 0;
+ // Resolves |host| to an address list, restricting the results to addresses
+ // in |address_family|. If successful returns OK and fills |addrlist| with
+ // a list of socket addresses. Otherwise returns a network error code.
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist) = 0;
protected:
// Asks the fallback procedure (if set) to do the resolve.
- int ResolveUsingPrevious(const std::string& host, AddressList* addrlist);
+ int ResolveUsingPrevious(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist);
private:
friend class HostResolverImpl;
@@ -62,7 +67,9 @@ class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
// (i.e. this calls out to getaddrinfo()). If successful returns OK and fills
// |addrlist| with a list of socket addresses. Otherwise returns a
// network error code.
-int SystemHostResolverProc(const std::string& host, AddressList* addrlist);
+int SystemHostResolverProc(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist);
} // namespace net
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index addccd0f..c6d31e9 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -165,6 +165,7 @@ void RuleBasedHostResolverProc::AddSimulatedFailure(
}
int RuleBasedHostResolverProc::Resolve(const std::string& host,
+ AddressFamily address_family,
AddressList* addrlist) {
RuleList::iterator r;
for (r = rules_.begin(); r != rules_.end(); ++r) {
@@ -181,7 +182,9 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
case Rule::kResolverTypeFail:
return ERR_NAME_NOT_RESOLVED;
case Rule::kResolverTypeSystem:
- return SystemHostResolverProc(effective_host, addrlist);
+ return SystemHostResolverProc(effective_host,
+ address_family,
+ addrlist);
case Rule::kResolverTypeIPV6Literal:
return ResolveIPV6LiteralUsingGURL(effective_host, addrlist);
default:
@@ -190,7 +193,7 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
}
}
}
- return ResolveUsingPrevious(host, addrlist);
+ return ResolveUsingPrevious(host, address_family, addrlist);
}
//-----------------------------------------------------------------------------
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
index 01a2eab..de91576 100644
--- a/net/base/mock_host_resolver.h
+++ b/net/base/mock_host_resolver.h
@@ -121,7 +121,9 @@ class RuleBasedHostResolverProc : public HostResolverProc {
void AddSimulatedFailure(const std::string& host);
// HostResolverProc methods:
- virtual int Resolve(const std::string& host, AddressList* addrlist);
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist);
private:
struct Rule;
@@ -141,9 +143,11 @@ class WaitingHostResolverProc : public HostResolverProc {
}
// HostResolverProc methods:
- virtual int Resolve(const std::string& host, AddressList* addrlist) {
+ virtual int Resolve(const std::string& host,
+ AddressFamily address_family,
+ AddressList* addrlist) {
event_.Wait();
- return ResolveUsingPrevious(host, addrlist);
+ return ResolveUsingPrevious(host, address_family, addrlist);
}
base::WaitableEvent event_;
diff --git a/net/net.gyp b/net/net.gyp
index f672009..298d0a7 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -24,6 +24,7 @@
],
'msvs_guid': '326E9795-E760-410A-B69A-3F79DB3F5243',
'sources': [
+ 'base/address_family.h',
'base/address_list.cc',
'base/address_list.h',
'base/auth.h',
diff --git a/net/url_request/url_request_view_net_internals_job.cc b/net/url_request/url_request_view_net_internals_job.cc
index 56aa8a8..5cadc075 100644
--- a/net/url_request/url_request_view_net_internals_job.cc
+++ b/net/url_request/url_request_view_net_internals_job.cc
@@ -225,6 +225,7 @@ class HostResolverCacheSubSection : public SubSection {
out->append("<table border=1>"
"<tr>"
"<th>Host</th>"
+ "<th>Address family</th>"
"<th>Address list</th>"
"<th>Time to live (ms)</th>"
"</tr>");
@@ -233,9 +234,12 @@ class HostResolverCacheSubSection : public SubSection {
host_cache->entries().begin();
it != host_cache->entries().end();
++it) {
- const std::string& host = it->first;
+ const net::HostCache::Key& key = it->first;
const net::HostCache::Entry* entry = it->second.get();
+ std::string address_family_str =
+ AddressFamilyToString(key.address_family);
+
if (entry->error == net::OK) {
// Note that ttl_ms may be negative, for the cases where entries have
// expired but not been garbage collected yet.
@@ -261,23 +265,35 @@ class HostResolverCacheSubSection : public SubSection {
current_address = current_address->ai_next;
}
- out->append(StringPrintf("<td>%s</td><td>%s</td><td>%d</td></tr>",
- EscapeForHTML(host).c_str(),
+ out->append(StringPrintf("<td>%s</td><td>%s</td><td>%s</td>"
+ "<td>%d</td></tr>",
+ EscapeForHTML(key.hostname).c_str(),
+ EscapeForHTML(address_family_str).c_str(),
address_list_html.c_str(),
ttl_ms));
} else {
// This was an entry that failed to be resolved.
// Color negative entries red.
out->append(StringPrintf(
- "<tr style='color:red'><td>%s</td>"
+ "<tr style='color:red'><td>%s</td><td>%s</td>"
"<td colspan=2>%s</td></tr>",
- EscapeForHTML(host).c_str(),
+ EscapeForHTML(key.hostname).c_str(),
+ EscapeForHTML(address_family_str).c_str(),
EscapeForHTML(net::ErrorToString(entry->error)).c_str()));
}
}
out->append("</table>");
}
+
+ static std::string AddressFamilyToString(net::AddressFamily address_family) {
+ switch (address_family) {
+ case net::ADDRESS_FAMILY_IPV4_ONLY:
+ return "IPV4_ONLY";
+ default:
+ return "UNSPECIFIED";
+ }
+ }
};
class HostResolverSubSection : public SubSection {