Index: net/base/host_resolver_proc.cc |
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc |
index fd350dffa998baa4c0c21197e2f7667c311c0cf2..86304dcec2e65d34356d463b983e2ee17dc7d95e 100644 |
--- a/net/base/host_resolver_proc.cc |
+++ b/net/base/host_resolver_proc.cc |
@@ -18,6 +18,42 @@ |
namespace net { |
+namespace { |
+ |
+bool IsAllLocalhostOfOneFamily(const struct addrinfo* ai) { |
+ bool saw_v4_localhost = false; |
+ bool saw_v6_localhost = false; |
+ for (; ai != NULL; ai = ai->ai_next) { |
+ switch (ai->ai_family) { |
+ case AF_INET: { |
+ const struct sockaddr_in* addr_in = |
+ reinterpret_cast<struct sockaddr_in*>(ai->ai_addr); |
+ if ((ntohl(addr_in->sin_addr.s_addr) & 0xff000000) == 0x7f000000) |
+ saw_v4_localhost = true; |
+ else |
+ return false; |
+ break; |
+ } |
+ case AF_INET6: { |
+ const struct sockaddr_in6* addr_in6 = |
+ reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr); |
+ if (IN6_IS_ADDR_LOOPBACK(&addr_in6->sin6_addr)) |
+ saw_v6_localhost = true; |
+ else |
+ return false; |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+ } |
+ |
+ return saw_v4_localhost != saw_v6_localhost; |
+} |
+ |
+} // namespace |
+ |
HostResolverProc* HostResolverProc::default_proc_ = NULL; |
HostResolverProc::HostResolverProc(HostResolverProc* previous) { |
@@ -161,15 +197,36 @@ int SystemHostResolverProc(const std::string& host, |
hints.ai_socktype = SOCK_STREAM; |
int err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |
+ bool should_retry = false; |
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) |
// If we fail, re-initialise the resolver just in case there have been any |
// changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. |
if (err && DnsReloadTimerHasExpired()) { |
res_nclose(&_res); |
if (!res_ninit(&_res)) |
- err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |
+ should_retry = true; |
} |
#endif |
+ // If the lookup was restricted (either by address family, or address |
+ // detection), and the results where all localhost of a single family, |
+ // maybe we should retry. There were several bugs related to these |
+ // issues, for example http://crbug.com/42058 and http://crbug.com/49024 |
+ if ((hints.ai_family != AF_UNSPEC || hints.ai_flags & AI_ADDRCONFIG) && |
+ err == 0 && IsAllLocalhostOfOneFamily(ai)) { |
willchan no longer on Chromium
2010/09/03 19:36:50
I personally think "err == OK" is more readable, b
vandebo (ex-Chrome)
2010/09/03 19:42:18
err is the result of getaddrinfo, not a chrome net
willchan no longer on Chromium
2010/09/03 20:23:07
Oops, sorry, I thought this was a net::Error. I c
|
+ if (host_resolver_flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) { |
+ hints.ai_family = AF_UNSPEC; |
+ should_retry = true; |
+ } |
+ if (hints.ai_flags & AI_ADDRCONFIG) { |
+ hints.ai_flags &= ~AI_ADDRCONFIG; |
+ should_retry = true; |
+ } |
+ } |
+ if (should_retry) { |
+ freeaddrinfo(ai); |
willchan no longer on Chromium
2010/09/03 19:36:50
don't you need a NULL check here? In the line 207
vandebo (ex-Chrome)
2010/09/03 19:42:18
From man 3 free: 'If ptr is NULL, no operation is
willchan no longer on Chromium
2010/09/03 20:23:07
Clearly I haven't done C programming in forever.
|
+ ai = NULL; |
+ err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |
+ } |
if (err) { |
if (os_error) { |