diff options
-rw-r--r-- | chrome/browser/net/dns_global.cc | 51 | ||||
-rw-r--r-- | chrome/browser/net/dns_master.cc | 12 | ||||
-rw-r--r-- | chrome/browser/net/dns_master_unittest.cc | 3 | ||||
-rw-r--r-- | net/base/client_socket_handle.cc | 5 | ||||
-rw-r--r-- | net/base/client_socket_handle.h | 8 | ||||
-rw-r--r-- | net/base/client_socket_pool.h | 5 | ||||
-rw-r--r-- | net/base/dns_resolution_observer.cc | 60 | ||||
-rw-r--r-- | net/base/dns_resolution_observer.h | 42 | ||||
-rw-r--r-- | net/base/host_resolver.cc | 115 | ||||
-rw-r--r-- | net/base/host_resolver.h | 80 | ||||
-rw-r--r-- | net/base/host_resolver_unittest.cc | 208 | ||||
-rw-r--r-- | net/base/ssl_client_socket_unittest.cc | 25 | ||||
-rw-r--r-- | net/base/ssl_test_util.cc | 3 | ||||
-rw-r--r-- | net/base/tcp_client_socket_pool.cc | 41 | ||||
-rw-r--r-- | net/base/tcp_client_socket_pool.h | 20 | ||||
-rw-r--r-- | net/base/tcp_client_socket_pool_unittest.cc | 51 | ||||
-rw-r--r-- | net/base/tcp_client_socket_unittest.cc | 3 | ||||
-rw-r--r-- | net/base/tcp_pinger_unittest.cc | 6 | ||||
-rw-r--r-- | net/ftp/ftp_network_transaction.cc | 14 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 21 | ||||
-rw-r--r-- | net/net.gyp | 1 | ||||
-rw-r--r-- | net/proxy/proxy_resolver_v8.cc | 13 |
22 files changed, 523 insertions, 264 deletions
diff --git a/chrome/browser/net/dns_global.cc b/chrome/browser/net/dns_global.cc index c54b14d..1d808cb 100644 --- a/chrome/browser/net/dns_global.cc +++ b/chrome/browser/net/dns_global.cc @@ -133,7 +133,7 @@ static void NavigatingTo(const std::string& host_name) { // The observer class needs to connect starts and finishes of HTTP network // resolutions. We use the following type for that map. -typedef std::map<void*, DnsHostInfo> ObservedResolutionMap; +typedef std::map<int, DnsHostInfo> ObservedResolutionMap; // There will only be one instance ever created of the following Observer // class. As a result, we get away with using static members for data local @@ -143,11 +143,13 @@ class PrefetchObserver : public net::DnsResolutionObserver { PrefetchObserver(); ~PrefetchObserver(); - virtual void OnStartResolution(const std::string& host_name, - void* context); - virtual void OnFinishResolutionWithStatus(bool was_resolved, - const GURL& referrer, - void* context); + virtual void OnStartResolution( + int request_id, + const net::HostResolver::RequestInfo& request_info); + virtual void OnFinishResolutionWithStatus( + int request_id, + bool was_resolved, + const net::HostResolver::RequestInfo& request_info); static void DnsGetFirstResolutionsHtml(std::string* output); static void SaveStartupListAsPref(PrefService* local_state); @@ -189,27 +191,37 @@ PrefetchObserver::~PrefetchObserver() { lock = NULL; } -void PrefetchObserver::OnStartResolution(const std::string& host_name, - void* context) { - DCHECK_NE(0U, host_name.length()); +void PrefetchObserver::OnStartResolution( + int request_id, + const net::HostResolver::RequestInfo& request_info) { + if (request_info.is_speculative()) + return; // One of our own requests. + DCHECK_NE(0U, request_info.hostname().length()); DnsHostInfo navigation_info; - navigation_info.SetHostname(host_name); + navigation_info.SetHostname(request_info.hostname()); navigation_info.SetStartedState(); - NavigatingTo(host_name); + NavigatingTo(request_info.hostname()); + + // TODO(eroman): If the resolve request is cancelled, then + // OnFinishResolutionWithStatus will not be called, and |resolutions| will + // grow unbounded! AutoLock auto_lock(*lock); - (*resolutions)[context] = navigation_info; + (*resolutions)[request_id] = navigation_info; } -void PrefetchObserver::OnFinishResolutionWithStatus(bool was_resolved, - const GURL& referrer, - void* context) { +void PrefetchObserver::OnFinishResolutionWithStatus( + int request_id, + bool was_resolved, + const net::HostResolver::RequestInfo& request_info) { + if (request_info.is_speculative()) + return; // One of our own requests. DnsHostInfo navigation_info; size_t startup_count; { AutoLock auto_lock(*lock); - ObservedResolutionMap::iterator it = resolutions->find(context); + ObservedResolutionMap::iterator it = resolutions->find(request_id); if (resolutions->end() == it) { DCHECK(false); return; @@ -219,7 +231,7 @@ void PrefetchObserver::OnFinishResolutionWithStatus(bool was_resolved, startup_count = first_resolutions->size(); } navigation_info.SetFinishedState(was_resolved); // Get timing info - AccruePrefetchBenefits(referrer, &navigation_info); + AccruePrefetchBenefits(request_info.referrer(), &navigation_info); if (kStartupResolutionCount <= startup_count || !was_resolved) return; // TODO(jar): Don't add host to our list if it is a non-linked lookup, and @@ -399,7 +411,10 @@ void InitDnsPrefetch(size_t max_concurrent, PrefService* user_prefs) { DLOG(INFO) << "DNS Prefetch service started"; // Start observing real HTTP stack resolutions. - net::AddDnsResolutionObserver(&dns_resolution_observer); + // TODO(eroman): really this should be called from IO thread (since that is + // where the host resolver lives). Since this occurs before requests have + // started it is not a race yet. + GetGlobalHostResolver()->AddObserver(&dns_resolution_observer); } } diff --git a/chrome/browser/net/dns_master.cc b/chrome/browser/net/dns_master.cc index 6151087..a256aa6 100644 --- a/chrome/browser/net/dns_master.cc +++ b/chrome/browser/net/dns_master.cc @@ -35,8 +35,16 @@ class DnsMaster::LookupRequest { } bool Start() { - const int result = resolver_.Resolve(hostname_, 80, &addresses_, - &net_callback_); + // Port doesn't really matter. + net::HostResolver::RequestInfo resolve_info(hostname_, 80); + + // Make a note that this is a speculative resolve request. This allows us + // to separate it from real navigations in the observer's callback, and + // lets the HostResolver know it can de-prioritize it. + resolve_info.set_is_speculative(true); + + const int result = resolver_.Resolve( + resolve_info, &addresses_, &net_callback_); return (result == net::ERR_IO_PENDING); } diff --git a/chrome/browser/net/dns_master_unittest.cc b/chrome/browser/net/dns_master_unittest.cc index be68dfb..e056555 100644 --- a/chrome/browser/net/dns_master_unittest.cc +++ b/chrome/browser/net/dns_master_unittest.cc @@ -113,7 +113,8 @@ TimeDelta BlockingDnsLookup(const std::string& hostname) { net::HostResolver resolver; net::AddressList addresses; - resolver.Resolve(hostname, 80, &addresses, NULL, NULL); + net::HostResolver::RequestInfo info(hostname, 80); + resolver.Resolve(info, &addresses, NULL, NULL); return Time::Now() - start; } diff --git a/net/base/client_socket_handle.cc b/net/base/client_socket_handle.cc index 043cefd..adedcd4 100644 --- a/net/base/client_socket_handle.cc +++ b/net/base/client_socket_handle.cc @@ -24,15 +24,14 @@ ClientSocketHandle::~ClientSocketHandle() { } int ClientSocketHandle::Init(const std::string& group_name, - const std::string& host, - int port, + const HostResolver::RequestInfo& resolve_info, int priority, CompletionCallback* callback) { ResetInternal(true); group_name_ = group_name; user_callback_ = callback; return pool_->RequestSocket( - group_name, host, port, priority, this, &callback_); + group_name, resolve_info, priority, this, &callback_); } void ClientSocketHandle::Reset() { diff --git a/net/base/client_socket_handle.h b/net/base/client_socket_handle.h index 5bac2c8..777c752 100644 --- a/net/base/client_socket_handle.h +++ b/net/base/client_socket_handle.h @@ -11,6 +11,7 @@ #include "base/scoped_ptr.h" #include "net/base/client_socket.h" #include "net/base/completion_callback.h" +#include "net/base/host_resolver.h" #include "net/base/load_states.h" namespace net { @@ -37,8 +38,8 @@ class ClientSocketHandle { // connected socket if an existing connected socket was available to reuse, // otherwise it will be set to a new connected socket. Consumers can then // call is_reused() to see if the socket was reused. If not reusing an - // existing socket, ClientSocketPool may need to establish a new - // connection to the |host| |port| pair. + // existing socket, ClientSocketPool may need to establish a new + // connection to the |resolve_info.host| |resolve_info.port| pair. // // This method returns ERR_IO_PENDING if it cannot complete synchronously, in // which case the consumer will be notified of completion via |callback|. @@ -46,8 +47,7 @@ class ClientSocketHandle { // Init may be called multiple times. // int Init(const std::string& group_name, - const std::string& host, - int port, + const HostResolver::RequestInfo& resolve_info, int priority, CompletionCallback* callback); diff --git a/net/base/client_socket_pool.h b/net/base/client_socket_pool.h index 6d200c0..86c67b8 100644 --- a/net/base/client_socket_pool.h +++ b/net/base/client_socket_pool.h @@ -11,13 +11,13 @@ #include "base/ref_counted.h" #include "net/base/completion_callback.h" +#include "net/base/host_resolver.h" #include "net/base/load_states.h" namespace net { class ClientSocket; class ClientSocketHandle; -class HostResolver; // A ClientSocketPool is used to restrict the number of sockets open at a time. // It also maintains a list of idle persistent sockets. @@ -47,8 +47,7 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool> { // client of completion. // virtual int RequestSocket(const std::string& group_name, - const std::string& host, - int port, + const HostResolver::RequestInfo& resolve_info, int priority, ClientSocketHandle* handle, CompletionCallback* callback) = 0; diff --git a/net/base/dns_resolution_observer.cc b/net/base/dns_resolution_observer.cc deleted file mode 100644 index 179a15c..0000000 --- a/net/base/dns_resolution_observer.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2006-2008 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. - -// This file supports network stack independent notification of progress -// towards resolving a hostname. - -#include "net/base/dns_resolution_observer.h" - -#include <string> - -#include "base/logging.h" - -namespace net { - -static DnsResolutionObserver* dns_resolution_observer; - -void AddDnsResolutionObserver(DnsResolutionObserver* new_observer) { - if (new_observer == dns_resolution_observer) - return; // Facilitate unit tests that init/teardown repeatedly. - DCHECK(!dns_resolution_observer); - dns_resolution_observer = new_observer; -} - -DnsResolutionObserver* RemoveDnsResolutionObserver() { - // We really need to check that the entire network subsystem is shutting down, - // and hence no additional calls can even *possibly* still be lingering in the - // notification path that includes our observer. Until we have a way to - // really assert that fact, we will outlaw the calling of this function. - // Darin suggested that the caller use a static initializer for the observer, - // so that it can safely be destroyed after process termination, and without - // inducing a memory leak. - // Bottom line: Don't call this function! You will crash for now. - CHECK(0); - DnsResolutionObserver* old_observer = dns_resolution_observer; - dns_resolution_observer = NULL; - return old_observer; -} - -// Locking access to dns_resolution_observer is not really critical... but we -// should test the value of dns_resolution_observer that we use. -// Worst case, we'll get an "out of date" value... which is no big deal for the -// DNS prefetching system (the most common (only?) observer). -void DidStartDnsResolution(const std::string& name, void* context) { - DnsResolutionObserver* current_observer = dns_resolution_observer; - if (current_observer) - current_observer->OnStartResolution(name, context); -} - -void DidFinishDnsResolutionWithStatus(bool was_resolved, - const GURL& referrer, - void* context) { - DnsResolutionObserver* current_observer = dns_resolution_observer; - if (current_observer) { - current_observer->OnFinishResolutionWithStatus(was_resolved, referrer, - context); - } -} - -} // namspace net diff --git a/net/base/dns_resolution_observer.h b/net/base/dns_resolution_observer.h index 9dd9a90..1651308 100644 --- a/net/base/dns_resolution_observer.h +++ b/net/base/dns_resolution_observer.h @@ -15,10 +15,13 @@ #include <string> +#include "net/base/host_resolver.h" + class GURL; namespace net { +// TODO(eroman): Move this interface to HostResolver::Observer. class DnsResolutionObserver { public: virtual ~DnsResolutionObserver() {} @@ -26,40 +29,17 @@ class DnsResolutionObserver { // For each OnStartResolution() notification, there should be a later // OnFinishResolutionWithStatus() indicating completion of the resolution // activity. - // Related pairs of notification will arrive with matching context values. - // A caller may use the context values to match up these asynchronous calls + // Related pairs of notification will arrive with matching id values. + // A caller may use the id values to match up these asynchronous calls // from among a larger call stream. - // Once a matching pair of notifications has been provided (i.e., a pair with - // identical context values), and the notification methods (below) have - // returned, the context values *might* be reused. - virtual void OnStartResolution(const std::string& host_name, - void* context) = 0; - virtual void OnFinishResolutionWithStatus(bool was_resolved, - const GURL& referrer, - void* context) = 0; + virtual void OnStartResolution(int id, + const HostResolver::RequestInfo& info) = 0; + virtual void OnFinishResolutionWithStatus( + int id, + bool was_resolved, + const HostResolver::RequestInfo& info) = 0; }; - -// Note that *exactly* one observer is currently supported, and any attempt to -// add a second observer via AddDnsResolutionObserver() before removing the -// first DnsResolutionObserver will induce a DCHECK() assertion. -void AddDnsResolutionObserver(DnsResolutionObserver* new_observer); - -// Note that the RemoveDnsResolutionObserver() will NOT perform any delete -// operations, and it is the responsibility of the code that called -// AddDnsResolutionObserver() to make a corresponding call to -// RemoveDnsResolutionObserver() and then delete the returned -// DnsResolutionObserver instance. -DnsResolutionObserver* RemoveDnsResolutionObserver(); - -// The following functions are expected to be called only by network stack -// implementations. This above observer class will relay the notifications -// to any registered observer. -void DidStartDnsResolution(const std::string& name, - void* context); -void DidFinishDnsResolutionWithStatus(bool was_resolved, - const GURL& url, - void* context); } // namspace net #endif // NET_BASE_DNS_RESOLUTION_OBSERVER_H_ diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc index 40ed8fd..6dcef85 100644 --- a/net/base/host_resolver.cc +++ b/net/base/host_resolver.cc @@ -22,6 +22,7 @@ #include "base/time.h" #include "base/worker_pool.h" #include "net/base/address_list.h" +#include "net/base/dns_resolution_observer.h" #include "net/base/net_errors.h" #if defined(OS_LINUX) @@ -178,8 +179,10 @@ static int ResolveAddrInfo(HostMapper* mapper, const std::string& host, class HostResolver::Request { public: - Request(CompletionCallback* callback, AddressList* addresses, int port) - : job_(NULL), callback_(callback), addresses_(addresses), port_(port) {} + Request(int id, const RequestInfo& info, CompletionCallback* callback, + AddressList* addresses) + : id_(id), info_(info), job_(NULL), callback_(callback), + addresses_(addresses) {} // Mark the request as cancelled. void Cancel() { @@ -200,19 +203,33 @@ class HostResolver::Request { void OnComplete(int error, const AddressList& addrlist) { if (error == OK) - addresses_->SetFrom(addrlist, port_); + addresses_->SetFrom(addrlist, port()); callback_->Run(error); } int port() const { - return port_; + return info_.port(); } Job* job() const { return job_; } + int id() const { + return id_; + } + + const RequestInfo& info() const { + return info_; + } + private: + // Unique ID for this request. Used by observers to identify requests. + int id_; + + // The request info that started the request. + RequestInfo info_; + // The resolve job (running in worker pool) that this request is dependent on. Job* job_; @@ -222,9 +239,6 @@ class HostResolver::Request { // The address list to save result into. AddressList* addresses_; - // The desired port number for the socket addresses. - int port_; - DISALLOW_COPY_AND_ASSIGN(Request); }; @@ -369,7 +383,7 @@ class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> { //----------------------------------------------------------------------------- HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) - : cache_(max_cache_entries, cache_duration_ms) { + : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0) { #if defined(OS_WIN) EnsureWinsockInit(); #endif @@ -388,40 +402,51 @@ HostResolver::~HostResolver() { // TODO(eroman): Don't create cache entries for hostnames which are simply IP // address literals. -int HostResolver::Resolve(const std::string& hostname, int port, +int HostResolver::Resolve(const RequestInfo& info, AddressList* addresses, CompletionCallback* callback, Request** out_req) { + // Choose a unique ID number for observers to see. + int request_id = next_request_id_++; + + // Notify registered observers. + NotifyObserversStartRequest(request_id, info); + // If we have an unexpired cache entry, use it. - const HostCache::Entry* cache_entry = cache_.Lookup( - hostname, base::TimeTicks::Now()); - if (cache_entry) { - addresses->SetFrom(cache_entry->addrlist, port); - return OK; + if (info.allow_cached_response()) { + const HostCache::Entry* cache_entry = cache_.Lookup( + info.hostname(), base::TimeTicks::Now()); + if (cache_entry) { + addresses->SetFrom(cache_entry->addrlist, info.port()); + return OK; + } } // If no callback was specified, do a synchronous resolution. if (!callback) { struct addrinfo* results; - int error = ResolveAddrInfo(host_mapper, hostname, &results); + int error = ResolveAddrInfo(host_mapper, info.hostname(), &results); // Adopt the address list. AddressList addrlist; if (error == OK) { addrlist.Adopt(results); - addrlist.SetPort(port); + addrlist.SetPort(info.port()); *addresses = addrlist; } // Write to cache. - cache_.Set(hostname, error, addrlist, base::TimeTicks::Now()); + cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); + + // Notify registered observers. + NotifyObserversFinishRequest(request_id, info, error); return error; } // Create a handle for this request, and pass it back to the user if they // asked for it (out_req != NULL). - Request* req = new Request(callback, addresses, port); + Request* req = new Request(request_id, info, callback, addresses); if (out_req) *out_req = req; @@ -429,14 +454,14 @@ int HostResolver::Resolve(const std::string& hostname, int port, // calling "getaddrinfo(hostname)" on a worker thread. scoped_refptr<Job> job; - // If there is already an outstanding job to resolve |hostname|, use it. - // This prevents starting concurrent resolves for the same hostname. - job = FindOutstandingJob(hostname); + // If there is already an outstanding job to resolve |info.hostname()|, use + // it. This prevents starting concurrent resolves for the same hostname. + job = FindOutstandingJob(info.hostname()); if (job) { job->AddRequest(req); } else { // Create a new job for this request. - job = new Job(this, hostname); + job = new Job(this, info.hostname()); job->AddRequest(req); AddOutstandingJob(job); // TODO(eroman): Bound the total number of concurrent jobs. @@ -457,6 +482,20 @@ void HostResolver::CancelRequest(Request* req) { req->Cancel(); } +void HostResolver::AddObserver(DnsResolutionObserver* observer) { + observers_.push_back(observer); +} + +void HostResolver::RemoveObserver(DnsResolutionObserver* observer) { + ObserversList::iterator it = + std::find(observers_.begin(), observers_.end(), observer); + + // Observer must exist. + DCHECK(it != observers_.end()); + + observers_.erase(it); +} + void HostResolver::AddOutstandingJob(Job* job) { scoped_refptr<Job>& found_job = jobs_[job->host()]; DCHECK(!found_job); @@ -497,6 +536,10 @@ void HostResolver::OnJobComplete(Job* job, Request* req = *it; if (!req->was_cancelled()) { DCHECK_EQ(job, req->job()); + + // Notify registered observers. + NotifyObserversFinishRequest(req->id(), req->info(), error); + req->OnComplete(error, addrlist); // Check if the job was cancelled as a result of running the callback. @@ -509,6 +552,24 @@ void HostResolver::OnJobComplete(Job* job, cur_completing_job_ = NULL; } +void HostResolver::NotifyObserversStartRequest(int request_id, + const RequestInfo& info) { + for (ObserversList::iterator it = observers_.begin(); + it != observers_.end(); ++it) { + (*it)->OnStartResolution(request_id, info); + } +} + +void HostResolver::NotifyObserversFinishRequest(int request_id, + const RequestInfo& info, + int error) { + bool was_resolved = error == OK; + for (ObserversList::iterator it = observers_.begin(); + it != observers_.end(); ++it) { + (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info); + } +} + //----------------------------------------------------------------------------- SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) @@ -526,10 +587,9 @@ SingleRequestHostResolver::~SingleRequestHostResolver() { } } -int SingleRequestHostResolver::Resolve( - const std::string& hostname, int port, - AddressList* addresses, - CompletionCallback* callback) { +int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info, + AddressList* addresses, + CompletionCallback* callback) { DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; HostResolver::Request* request = NULL; @@ -538,8 +598,7 @@ int SingleRequestHostResolver::Resolve( // we can clear out |cur_request_*|. CompletionCallback* transient_callback = callback ? &callback_ : NULL; - int rv = resolver_->Resolve( - hostname, port, addresses, transient_callback, &request); + int rv = resolver_->Resolve(info, addresses, transient_callback, &request); if (rv == ERR_IO_PENDING) { // Cleared in OnResolveCompletion(). diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index a67419a..9a7b7b9 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/lock.h" #include "base/ref_counted.h" +#include "googleurl/src/gurl.h" #include "net/base/completion_callback.h" #include "net/base/host_cache.h" @@ -19,6 +20,7 @@ class MessageLoop; namespace net { class AddressList; +class DnsResolutionObserver; class HostMapper; // This class represents the task of resolving hostnames (or IP address @@ -58,6 +60,46 @@ class HostMapper; // class HostResolver { public: + // The parameters for doing a Resolve(). |hostname| and |port| are required, + // the rest are optional (and have reasonable defaults). + class RequestInfo { + public: + RequestInfo(const std::string& hostname, int port) + : hostname_(hostname), + port_(port), + allow_cached_response_(true), + is_speculative_(false) {} + + const int port() const { return port_; } + const std::string& hostname() const { return hostname_; } + + bool allow_cached_response() const { return allow_cached_response_; } + void set_allow_cached_response(bool b) { allow_cached_response_ = b; } + + bool is_speculative() const { return is_speculative_; } + void set_is_speculative(bool b) { is_speculative_ = b; } + + const GURL& referrer() const { return referrer_; } + void set_referrer(const GURL& referrer) { referrer_ = referrer; } + + private: + // The hostname to resolve. + std::string hostname_; + + // The port number to set in the result's sockaddrs. + int port_; + + // Whether it is ok to return a result from the host cache. + bool allow_cached_response_; + + // Whether this request was started by the DNS prefetcher. + bool is_speculative_; + + // Optional data for consumption by observers. This is the URL of the + // page that lead us to the navigation, for DNS prefetcher's benefit. + GURL referrer_; + }; + // Creates a HostResolver that caches up to |max_cache_entries| for // |cache_duration_ms| milliseconds. // @@ -74,9 +116,9 @@ class HostResolver { class Request; // Resolves the given hostname (or IP address literal), filling out the - // |addresses| object upon success. The |port| parameter will be set as the - // sin(6)_port field of the sockaddr_in{6} struct. Returns OK if successful - // or an error code upon failure. + // |addresses| object upon success. The |info.port| parameter will be set as + // the sin(6)_port field of the sockaddr_in{6} struct. Returns OK if + // successful or an error code upon failure. // // When callback is null, the operation completes synchronously. // @@ -85,18 +127,26 @@ class HostResolver { // result code will be passed to the completion callback. If |req| is // non-NULL, then |*req| will be filled with a handle to the async request. // This handle is not valid after the request has completed. - int Resolve(const std::string& hostname, int port, - AddressList* addresses, CompletionCallback* callback, - Request** req); + int Resolve(const RequestInfo& info, AddressList* addresses, + CompletionCallback* callback, Request** req); // Cancels the specified request. |req| is the handle returned by Resolve(). // After a request is cancelled, its completion callback will not be called. void CancelRequest(Request* req); + // Adds an observer to this resolver. The observer will be notified of the + // start and completion of all requests (excluding cancellation). |observer| + // must remain valid for the duration of this HostResolver's lifetime. + void AddObserver(DnsResolutionObserver* observer); + + // Unregisters an observer previously added by AddObserver(). + void RemoveObserver(DnsResolutionObserver* observer); + private: class Job; typedef std::vector<Request*> RequestsList; typedef base::hash_map<std::string, scoped_refptr<Job> > JobMap; + typedef std::vector<DnsResolutionObserver*> ObserversList; // Adds a job to outstanding jobs list. void AddOutstandingJob(Job* job); @@ -110,6 +160,15 @@ class HostResolver { // Callback for when |job| has completed with |error| and |addrlist|. void OnJobComplete(Job* job, int error, const AddressList& addrlist); + // Notify all obsevers of the start of a resolve request. + void NotifyObserversStartRequest(int request_id, + const RequestInfo& info); + + // Notify all obsevers of the completion of a resolve request. + void NotifyObserversFinishRequest(int request_id, + const RequestInfo& info, + int error); + // Cache of host resolution results. HostCache cache_; @@ -120,6 +179,13 @@ class HostResolver { // HostResolver gets deleted from within the callback). scoped_refptr<Job> cur_completing_job_; + // The observers to notify when a request starts/ends. + ObserversList observers_; + + // Monotonically increasing ID number to assign to the next request. + // Observers are the only consumers of this ID number. + int next_request_id_; + DISALLOW_COPY_AND_ASSIGN(HostResolver); }; @@ -137,7 +203,7 @@ class SingleRequestHostResolver { // Resolves the given hostname (or IP address literal), filling out the // |addresses| object upon success. See HostResolver::Resolve() for details. - int Resolve(const std::string& hostname, int port, + int Resolve(const HostResolver::RequestInfo& info, AddressList* addresses, CompletionCallback* callback); private: diff --git a/net/base/host_resolver_unittest.cc b/net/base/host_resolver_unittest.cc index 090fd5c..393385af 100644 --- a/net/base/host_resolver_unittest.cc +++ b/net/base/host_resolver_unittest.cc @@ -18,6 +18,7 @@ #include "base/ref_counted.h" #include "net/base/address_list.h" #include "net/base/completion_callback.h" +#include "net/base/dns_resolution_observer.h" #include "net/base/host_resolver_unittest.h" #include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest.h" @@ -82,12 +83,22 @@ class ResolveRequest { const std::string& hostname, int port, Delegate* delegate) - : hostname_(hostname), port_(port), resolver_(resolver), - delegate_(delegate), + : info_(hostname, port), resolver_(resolver), delegate_(delegate), ALLOW_THIS_IN_INITIALIZER_LIST( callback_(this, &ResolveRequest::OnLookupFinished)) { // Start the request. - int err = resolver->Resolve(hostname, port, &addrlist_, &callback_, &req_); + int err = resolver->Resolve(info_, &addrlist_, &callback_, &req_); + EXPECT_EQ(net::ERR_IO_PENDING, err); + } + + ResolveRequest(net::HostResolver* resolver, + const net::HostResolver::RequestInfo& info, + Delegate* delegate) + : info_(info), resolver_(resolver), delegate_(delegate), + ALLOW_THIS_IN_INITIALIZER_LIST( + callback_(this, &ResolveRequest::OnLookupFinished)) { + // Start the request. + int err = resolver->Resolve(info, &addrlist_, &callback_, &req_); EXPECT_EQ(net::ERR_IO_PENDING, err); } @@ -96,11 +107,11 @@ class ResolveRequest { } const std::string& hostname() const { - return hostname_; + return info_.hostname(); } int port() const { - return port_; + return info_.port(); } int result() const { @@ -122,8 +133,7 @@ class ResolveRequest { } // The request details. - std::string hostname_; - int port_; + net::HostResolver::RequestInfo info_; net::HostResolver::Request* req_; // The result of the resolve. @@ -168,8 +178,8 @@ TEST_F(HostResolverTest, SynchronousLookup) { mapper->AddRule("just.testing", "192.168.1.42"); ScopedHostMapper scoped_mapper(mapper.get()); - int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist, NULL, - NULL); + net::HostResolver::RequestInfo info("just.testing", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, NULL, NULL); EXPECT_EQ(net::OK, err); const struct addrinfo* ainfo = adrlist.head(); @@ -191,8 +201,8 @@ TEST_F(HostResolverTest, AsynchronousLookup) { mapper->AddRule("just.testing", "192.168.1.42"); ScopedHostMapper scoped_mapper(mapper.get()); - int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist, - &callback_, NULL); + net::HostResolver::RequestInfo info("just.testing", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, &callback_, NULL); EXPECT_EQ(net::ERR_IO_PENDING, err); MessageLoop::current()->Run(); @@ -219,8 +229,8 @@ TEST_F(HostResolverTest, CanceledAsynchronousLookup) { net::AddressList adrlist; const int kPortnum = 80; - int err = host_resolver.Resolve("just.testing", kPortnum, &adrlist, - &callback_, NULL); + net::HostResolver::RequestInfo info("just.testing", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, &callback_, NULL); EXPECT_EQ(net::ERR_IO_PENDING, err); // Make sure we will exit the queue even when callback is not called. @@ -245,7 +255,8 @@ TEST_F(HostResolverTest, NumericIPv4Address) { net::HostResolver host_resolver; net::AddressList adrlist; const int kPortnum = 5555; - int err = host_resolver.Resolve("127.1.2.3", kPortnum, &adrlist, NULL, NULL); + net::HostResolver::RequestInfo info("127.1.2.3", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, NULL, NULL); EXPECT_EQ(net::OK, err); const struct addrinfo* ainfo = adrlist.head(); @@ -268,8 +279,8 @@ TEST_F(HostResolverTest, NumericIPv6Address) { net::HostResolver host_resolver; net::AddressList adrlist; const int kPortnum = 5555; - int err = host_resolver.Resolve("2001:db8::1", kPortnum, &adrlist, NULL, - NULL); + net::HostResolver::RequestInfo info("2001:db8::1", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, NULL, NULL); // On computers without IPv6 support, getaddrinfo cannot convert IPv6 // address literals to addresses (getaddrinfo returns EAI_NONAME). So this // test has to allow host_resolver.Resolve to fail. @@ -302,7 +313,8 @@ TEST_F(HostResolverTest, EmptyHost) { net::HostResolver host_resolver; net::AddressList adrlist; const int kPortnum = 5555; - int err = host_resolver.Resolve("", kPortnum, &adrlist, NULL, NULL); + net::HostResolver::RequestInfo info("", kPortnum); + int err = host_resolver.Resolve(info, &adrlist, NULL, NULL); EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, err); } @@ -457,7 +469,7 @@ class CancelWithinCallbackVerifier : public ResolveRequest::Delegate { // Start a request (so we can make sure the canceled requests don't // complete before "finalrequest" finishes. final_request_.reset(new ResolveRequest( - resolve->resolver(), "finalrequest", 70, this)); + resolve->resolver(), "finalrequest", 70, this)); } else if (83 == resolve->port()) { EXPECT_EQ("a", resolve->hostname()); @@ -618,4 +630,164 @@ TEST_F(HostResolverTest, StartWithinCallback) { MessageLoop::current()->Run(); } +// Helper class used by HostResolverTest.BypassCache. +class BypassCacheVerifier : public ResolveRequest::Delegate { + public: + BypassCacheVerifier() {} + + virtual void OnCompleted(ResolveRequest* resolve) { + EXPECT_EQ("a", resolve->hostname()); + net::HostResolver* resolver = resolve->resolver(); + + if (80 == resolve->port()) { + // On completing the first request, start another request for "a". + // Since caching is enabled, this should complete synchronously. + + // Note that |junk_callback| shouldn't be used since we are going to + // complete synchronously. We can't specify NULL though since that would + // mean synchronous mode so we give it a value of 1. + net::CompletionCallback* junk_callback = + reinterpret_cast<net::CompletionCallback*> (1); + net::AddressList addrlist; + + net::HostResolver::RequestInfo info("a", 70); + int error = resolver->Resolve(info, &addrlist, junk_callback, NULL); + EXPECT_EQ(net::OK, error); + + // Ok good. Now make sure that if we ask to bypass the cache, it can no + // longer service the request synchronously. + info = net::HostResolver::RequestInfo("a", 71); + info.set_allow_cached_response(false); + final_request_.reset(new ResolveRequest(resolver, info, this)); + } else if (71 == resolve->port()) { + // Test is done. + MessageLoop::current()->Quit(); + } else { + FAIL() << "Unexpected port number"; + } + } + + private: + scoped_ptr<ResolveRequest> final_request_; + DISALLOW_COPY_AND_ASSIGN(BypassCacheVerifier); +}; + +TEST_F(HostResolverTest, BypassCache) { + net::HostResolver host_resolver; + + // The class will receive callbacks for when each resolve completes. It + // checks that the right things happened. + BypassCacheVerifier verifier; + + // Start a request. + ResolveRequest req1(&host_resolver, "a", 80, &verifier); + + // |verifier| will send quit message once all the requests have finished. + MessageLoop::current()->Run(); +} + +bool operator==(const net::HostResolver::RequestInfo& a, + const net::HostResolver::RequestInfo& b) { + return a.hostname() == b.hostname() && + a.port() == b.port() && + a.allow_cached_response() == b.allow_cached_response() && + a.is_speculative() == b.is_speculative() && + a.referrer() == b.referrer(); +} + +// Observer that just makes note of how it was called. The test code can then +// inspect to make sure it was called with the right parameters. +class CapturingObserver : public net::DnsResolutionObserver { + public: + // DnsResolutionObserver methods: + virtual void OnStartResolution(int id, + const net::HostResolver::RequestInfo& info) { + start_log.push_back(StartEntry(id, info)); + } + + virtual void OnFinishResolutionWithStatus( + int id, + bool was_resolved, + const net::HostResolver::RequestInfo& info) { + finish_log.push_back(FinishEntry(id, was_resolved, info)); + } + + // Tuple (id, info). + struct StartEntry { + StartEntry(int id, const net::HostResolver::RequestInfo& info) + : id(id), info(info) {} + + bool operator==(const StartEntry& other) const { + return id == other.id && info == other.info; + } + + int id; + net::HostResolver::RequestInfo info; + }; + + // Tuple (id, was_resolved, info). + struct FinishEntry { + FinishEntry(int id, bool was_resolved, + const net::HostResolver::RequestInfo& info) + : id(id), was_resolved(was_resolved), info(info) {} + + bool operator==(const FinishEntry& other) const { + return id == other.id && + was_resolved == other.was_resolved && + info == other.info; + } + + int id; + bool was_resolved; + net::HostResolver::RequestInfo info; + }; + + std::vector<StartEntry> start_log; + std::vector<FinishEntry> finish_log; +}; + +// Test that registering, unregistering, and notifying of observers works. +TEST_F(HostResolverTest, Observers) { + net::HostResolver host_resolver; + + CapturingObserver observer; + + host_resolver.AddObserver(&observer); + + net::AddressList addrlist; + + // Resolve "host1". + net::HostResolver::RequestInfo info1("host1", 70); + host_resolver.Resolve(info1, &addrlist, NULL, NULL); + + EXPECT_EQ(1U, observer.start_log.size()); + EXPECT_EQ(1U, observer.finish_log.size()); + EXPECT_TRUE( + observer.start_log[0] == CapturingObserver::StartEntry(0, info1)); + EXPECT_TRUE( + observer.finish_log[0] == CapturingObserver::FinishEntry(0, true, info1)); + + // Resolve "host2", setting referrer to "http://foobar.com" + net::HostResolver::RequestInfo info2("host2", 70); + info2.set_referrer(GURL("http://foobar.com")); + host_resolver.Resolve(info2, &addrlist, NULL, NULL); + + EXPECT_EQ(2U, observer.start_log.size()); + EXPECT_EQ(2U, observer.finish_log.size()); + EXPECT_TRUE(observer.start_log[1] == CapturingObserver::StartEntry(1, info2)); + EXPECT_TRUE(observer.finish_log[1] == CapturingObserver::FinishEntry( + 1, true, info2)); + + // Unregister the observer. + host_resolver.RemoveObserver(&observer); + + // Resolve "host3" + net::HostResolver::RequestInfo info3("host3", 70); + host_resolver.Resolve(info3, &addrlist, NULL, NULL); + + // No effect this time, since observer was removed. + EXPECT_EQ(2U, observer.start_log.size()); + EXPECT_EQ(2U, observer.finish_log.size()); +} + } // namespace diff --git a/net/base/ssl_client_socket_unittest.cc b/net/base/ssl_client_socket_unittest.cc index ab29cc4..ef308a1 100644 --- a/net/base/ssl_client_socket_unittest.cc +++ b/net/base/ssl_client_socket_unittest.cc @@ -76,8 +76,8 @@ TEST_F(SSLClientSocketTest, MAYBE_Connect) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL, NULL); + net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); @@ -114,8 +114,8 @@ TEST_F(SSLClientSocketTest, MAYBE_ConnectExpired) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kBadHTTPSPort, - &addr, NULL, NULL); + net::HostResolver::RequestInfo info(server_.kHostName, server_.kBadHTTPSPort); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); @@ -151,8 +151,9 @@ TEST_F(SSLClientSocketTest, MAYBE_ConnectMismatched) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kMismatchedHostName, server_.kOKHTTPSPort, - &addr, NULL, NULL); + net::HostResolver::RequestInfo info(server_.kMismatchedHostName, + server_.kOKHTTPSPort); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); @@ -193,8 +194,8 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, &callback, NULL); + net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort); + int rv = resolver.Resolve(info, &addr, &callback, NULL); EXPECT_EQ(net::ERR_IO_PENDING, rv); rv = callback.WaitForResult(); @@ -254,8 +255,8 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL, NULL); + net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); @@ -310,8 +311,8 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_Interrupted) { net::HostResolver resolver; TestCompletionCallback callback; - int rv = resolver.Resolve(server_.kHostName, server_.kOKHTTPSPort, - &addr, NULL, NULL); + net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); diff --git a/net/base/ssl_test_util.cc b/net/base/ssl_test_util.cc index cac5d04..f470139 100644 --- a/net/base/ssl_test_util.cc +++ b/net/base/ssl_test_util.cc @@ -247,7 +247,8 @@ bool TestServerLauncher::WaitToStart(const std::string& host_name, int port) { // Otherwise tests can fail if they run faster than Python can start. net::AddressList addr; net::HostResolver resolver; - int rv = resolver.Resolve(host_name, port, &addr, NULL, NULL); + net::HostResolver::RequestInfo info(host_name, port); + int rv = resolver.Resolve(info, &addr, NULL, NULL); if (rv != net::OK) return false; diff --git a/net/base/tcp_client_socket_pool.cc b/net/base/tcp_client_socket_pool.cc index 4a52c10..c5e961e 100644 --- a/net/base/tcp_client_socket_pool.cc +++ b/net/base/tcp_client_socket_pool.cc @@ -58,11 +58,9 @@ TCPClientSocketPool::ConnectingSocket::~ConnectingSocket() { } int TCPClientSocketPool::ConnectingSocket::Connect( - const std::string& host, - int port) { + const HostResolver::RequestInfo& resolve_info) { CHECK(!canceled_); - DidStartDnsResolution(host, this); - int rv = resolver_.Resolve(host, port, &addresses_, &callback_); + int rv = resolver_.Resolve(resolve_info, &addresses_, &callback_); if (rv != ERR_IO_PENDING) rv = OnIOCompleteInternal(rv, true /* synchronous */); return rv; @@ -186,26 +184,20 @@ void TCPClientSocketPool::InsertRequestIntoQueue( pending_requests->insert(it, r); } -int TCPClientSocketPool::RequestSocket(const std::string& group_name, - const std::string& host, - int port, - int priority, - ClientSocketHandle* handle, - CompletionCallback* callback) { - DCHECK(!host.empty()); +int TCPClientSocketPool::RequestSocket( + const std::string& group_name, + const HostResolver::RequestInfo& resolve_info, + int priority, + ClientSocketHandle* handle, + CompletionCallback* callback) { + DCHECK(!resolve_info.hostname().empty()); DCHECK_GE(priority, 0); Group& group = group_map_[group_name]; // Can we make another active socket now? if (group.active_socket_count == max_sockets_per_group_) { - Request r; - r.handle = handle; CHECK(callback); - r.callback = callback; - r.priority = priority; - r.host = host; - r.port = port; - r.load_state = LOAD_STATE_IDLE; + Request r(handle, callback, priority, resolve_info, LOAD_STATE_IDLE); InsertRequestIntoQueue(r, &group.pending_requests); return ERR_IO_PENDING; } @@ -234,20 +226,15 @@ int TCPClientSocketPool::RequestSocket(const std::string& group_name, if (ContainsKey(connecting_socket_map_, handle)) connecting_socket_map_[handle]->Cancel(); - Request r; - r.handle = handle; CHECK(callback); - r.callback = callback; - r.priority = priority; - r.host = host; - r.port = port; - r.load_state = LOAD_STATE_RESOLVING_HOST; + Request r(handle, callback, priority, resolve_info, + LOAD_STATE_RESOLVING_HOST); group_map_[group_name].connecting_requests[handle] = r; // connecting_socket will delete itself. ConnectingSocket* connecting_socket = new ConnectingSocket(group_name, handle, client_socket_factory_, this); - int rv = connecting_socket->Connect(host, port); + int rv = connecting_socket->Connect(resolve_info); return rv; } @@ -419,7 +406,7 @@ void TCPClientSocketPool::DoReleaseSocket(const std::string& group_name, group.pending_requests.pop_front(); int rv = RequestSocket( - group_name, r.host, r.port, r.priority, r.handle, r.callback); + group_name, r.resolve_info, r.priority, r.handle, r.callback); if (rv != ERR_IO_PENDING) r.callback->Run(rv); return; diff --git a/net/base/tcp_client_socket_pool.h b/net/base/tcp_client_socket_pool.h index 82255c5..ad75585 100644 --- a/net/base/tcp_client_socket_pool.h +++ b/net/base/tcp_client_socket_pool.h @@ -31,8 +31,7 @@ class TCPClientSocketPool : public ClientSocketPool { // ClientSocketPool methods: virtual int RequestSocket(const std::string& group_name, - const std::string& host, - int port, + const HostResolver::RequestInfo& resolve_info, int priority, ClientSocketHandle* handle, CompletionCallback* callback); @@ -62,11 +61,22 @@ class TCPClientSocketPool : public ClientSocketPool { // A Request is allocated per call to RequestSocket that results in // ERR_IO_PENDING. struct Request { + // HostResolver::RequestInfo has no default constructor, so fudge something. + Request() : resolve_info(std::string(), 0) {} + + Request(ClientSocketHandle* handle, + CompletionCallback* callback, + int priority, + const HostResolver::RequestInfo& resolve_info, + LoadState load_state) + : handle(handle), callback(callback), priority(priority), + resolve_info(resolve_info), load_state(load_state) { + } + ClientSocketHandle* handle; CompletionCallback* callback; int priority; - std::string host; - int port; + HostResolver::RequestInfo resolve_info; LoadState load_state; }; @@ -118,7 +128,7 @@ class TCPClientSocketPool : public ClientSocketPool { // Begins the host resolution and the TCP connect. Returns OK on success // and ERR_IO_PENDING if it cannot immediately service the request. // Otherwise, it returns a net error code. - int Connect(const std::string& host, int port); + int Connect(const HostResolver::RequestInfo& resolve_info); // Called by the TCPClientSocketPool to cancel this ConnectingSocket. Only // necessary if a ClientSocketHandle is reused. diff --git a/net/base/tcp_client_socket_pool_unittest.cc b/net/base/tcp_client_socket_pool_unittest.cc index 54b6330..2d19605 100644 --- a/net/base/tcp_client_socket_pool_unittest.cc +++ b/net/base/tcp_client_socket_pool_unittest.cc @@ -232,7 +232,8 @@ class TCPClientSocketPoolTest : public testing::Test { TEST_F(TCPClientSocketPoolTest, Basic) { TestCompletionCallback callback; ClientSocketHandle handle(pool_.get()); - int rv = handle.Init("a", "www.google.com", 80, 0, &callback); + HostResolver::RequestInfo info("www.google.com", 80); + int rv = handle.Init("a", info, 0, &callback); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_FALSE(handle.is_initialized()); EXPECT_FALSE(handle.socket()); @@ -252,8 +253,8 @@ TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) { host_mapper->AddSimulatedFailure("unresolvable.host.name"); ScopedHostMapper scoped_host_mapper(host_mapper); TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); + HostResolver::RequestInfo info("unresolvable.host.name", 80); + EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req.WaitForResult()); } @@ -261,8 +262,9 @@ TEST_F(TCPClientSocketPoolTest, InitConnectionFailure) { client_socket_factory_.set_client_socket_type( MockClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET); TestSocketRequest req(pool_.get(), &request_order_); + HostResolver::RequestInfo info("unresolvable.host.name", 80); EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); + req.handle.Init("a", info, 5, &req)); EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult()); } @@ -275,13 +277,14 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests) { // Create connections or queue up requests. // First request finishes asynchronously. - int rv = reqs[0]->handle.Init("a", "www.google.com", 80, 5, reqs[0].get()); + HostResolver::RequestInfo info("www.google.com", 80); + int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, reqs[0]->WaitForResult()); // Rest of them finish synchronously, since they're in the HostCache. for (int i = 1; i < kMaxSocketsPerGroup; ++i) { - rv = reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get()); + rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); EXPECT_EQ(OK, rv); request_order_.push_back(reqs[i].get()); } @@ -289,8 +292,7 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests) { // The rest are pending since we've used all active sockets. for (int i = 0; i < kNumPendingRequests; ++i) { rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, kPriorities[i], - reqs[kMaxSocketsPerGroup + i].get()); + "a", info, kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); EXPECT_EQ(ERR_IO_PENDING, rv); } @@ -336,13 +338,14 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) { // Create connections or queue up requests. // First request finishes asynchronously. - int rv = reqs[0]->handle.Init("a", "www.google.com", 80, 5, reqs[0].get()); + HostResolver::RequestInfo info("www.google.com", 80); + int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, reqs[0]->WaitForResult()); // Rest of them finish synchronously, since they're in the HostCache. for (int i = 1; i < kMaxSocketsPerGroup; ++i) { - rv = reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get()); + rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); EXPECT_EQ(OK, rv); request_order_.push_back(reqs[i].get()); } @@ -350,7 +353,7 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) { // The rest are pending since we've used all active sockets. for (int i = 0; i < kNumPendingRequests; ++i) { EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, 0, reqs[kMaxSocketsPerGroup + i].get())); + "a", info, 0, reqs[kMaxSocketsPerGroup + i].get())); } // Release any connections until we have no connections. @@ -379,8 +382,8 @@ TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) { // ClientSocketPool which will crash if the group was not cleared properly. TEST_F(TCPClientSocketPoolTest, CancelRequestClearGroup) { TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "www.google.com", 80, 5, &req)); + HostResolver::RequestInfo info("www.google.com", 80); + EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); req.handle.Reset(); PlatformThread::Sleep(100); @@ -397,10 +400,9 @@ TEST_F(TCPClientSocketPoolTest, TwoRequestsCancelOne) { TestSocketRequest req(pool_.get(), &request_order_); TestSocketRequest req2(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "www.google.com", 80, 5, &req)); - EXPECT_EQ(ERR_IO_PENDING, - req2.handle.Init("a", "www.google.com", 80, 5, &req2)); + HostResolver::RequestInfo info("www.google.com", 80); + EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); + EXPECT_EQ(ERR_IO_PENDING, req2.handle.Init("a", info, 5, &req2)); req.handle.Reset(); @@ -417,14 +419,13 @@ TEST_F(TCPClientSocketPoolTest, ConnectCancelConnect) { TestCompletionCallback callback; TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", "www.google.com", 80, 5, &callback)); + HostResolver::RequestInfo info("www.google.com", 80); + EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", info, 5, &callback)); handle.Reset(); TestCompletionCallback callback2; - EXPECT_EQ(ERR_IO_PENDING, - handle.Init("a", "www.google.com", 80, 5, &callback2)); + EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", info, 5, &callback2)); // At this point, handle has two ConnectingSockets out for it. Due to the // host cache, the host resolution for both will return in the same loop of @@ -449,15 +450,16 @@ TEST_F(TCPClientSocketPoolTest, CancelRequest) { reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); // Create connections or queue up requests. + HostResolver::RequestInfo info("www.google.com", 80); // First request finishes asynchronously. - int rv = reqs[0]->handle.Init("a", "www.google.com", 80, 5, reqs[0].get()); + int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, reqs[0]->WaitForResult()); // Rest of them finish synchronously, since they're in the HostCache. for (int i = 1; i < kMaxSocketsPerGroup; ++i) { - rv = reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get()); + rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); EXPECT_EQ(OK, rv); request_order_.push_back(reqs[i].get()); } @@ -465,8 +467,7 @@ TEST_F(TCPClientSocketPoolTest, CancelRequest) { // The rest are pending since we've used all active sockets. for (int i = 0; i < kNumPendingRequests; ++i) { EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, kPriorities[i], - reqs[kMaxSocketsPerGroup + i].get())); + "a", info, kPriorities[i], reqs[kMaxSocketsPerGroup + i].get())); } // Cancel a request. diff --git a/net/base/tcp_client_socket_unittest.cc b/net/base/tcp_client_socket_unittest.cc index fe37c71..21f524e 100644 --- a/net/base/tcp_client_socket_unittest.cc +++ b/net/base/tcp_client_socket_unittest.cc @@ -87,7 +87,8 @@ void TCPClientSocketTest::SetUp() { AddressList addr; HostResolver resolver; - int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL, NULL); + HostResolver::RequestInfo info("localhost", listen_port_); + int rv = resolver.Resolve(info, &addr, NULL, NULL); CHECK(rv == OK); sock_.reset(new TCPClientSocket(addr)); } diff --git a/net/base/tcp_pinger_unittest.cc b/net/base/tcp_pinger_unittest.cc index edf29a5..d09f42a 100644 --- a/net/base/tcp_pinger_unittest.cc +++ b/net/base/tcp_pinger_unittest.cc @@ -67,7 +67,8 @@ TEST_F(TCPPingerTest, Ping) { net::AddressList addr; net::HostResolver resolver; - int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL, NULL); + net::HostResolver::RequestInfo info("localhost", listen_port_); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(rv, net::OK); net::TCPPinger pinger(addr); @@ -82,7 +83,8 @@ TEST_F(TCPPingerTest, PingFail) { // "Kill" "server" listen_sock_ = NULL; - int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL, NULL); + net::HostResolver::RequestInfo info("localhost", listen_port_); + int rv = resolver.Resolve(info, &addr, NULL, NULL); EXPECT_EQ(rv, net::OK); net::TCPPinger pinger(addr); diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 87f9217..18bd808 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -339,13 +339,13 @@ int FtpNetworkTransaction::DoCtrlResolveHost() { host = request_->url.host(); port = request_->url.EffectiveIntPort(); - DidStartDnsResolution(host, this); - return resolver_.Resolve(host, port, &addresses_, &io_callback_); + HostResolver::RequestInfo info(host, port); + // No known referrer. + return resolver_.Resolve(info, &addresses_, &io_callback_); } int FtpNetworkTransaction::DoCtrlResolveHostComplete(int result) { bool ok = (result == OK); - DidFinishDnsResolutionWithStatus(ok, GURL(), this); if (ok) { next_state_ = STATE_CTRL_CONNECT; return result; @@ -832,14 +832,14 @@ int FtpNetworkTransaction::DoDataResolveHost() { next_state_ = STATE_DATA_RESOLVE_HOST_COMPLETE; - DidStartDnsResolution(data_connection_ip_, this); - return resolver_.Resolve(data_connection_ip_, data_connection_port_, - &addresses_, &io_callback_); + HostResolver::RequestInfo info(data_connection_ip_, + data_connection_port_); + // No known referrer. + return resolver_.Resolve(info, &addresses_, &io_callback_); } int FtpNetworkTransaction::DoDataResolveHostComplete(int result) { bool ok = (result == OK); - DidFinishDnsResolutionWithStatus(ok, GURL(), this); if (ok) { next_state_ = STATE_DATA_CONNECT; return result; diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 4fbd5cb..d5cd81f 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -570,7 +570,26 @@ int HttpNetworkTransaction::DoInitConnection() { connection_group.append(request_->url.GetOrigin().spec()); DCHECK(!connection_group.empty()); - int rv = connection_.Init(connection_group, host, port, request_->priority, + + HostResolver::RequestInfo resolve_info(host, port); + + // The referrer is used by the DNS prefetch system to corellate resolutions + // with the page that triggered them. It doesn't impact the actual addresses + // that we resolve to. + resolve_info.set_referrer(request_->referrer); + +// TODO(eroman): Enable this! +// Needs some unit-tests before turning on. +// http://crbug.com/13163 +#if 0 + // If the user is refreshing the page, bypass the host cache. + if (request_->load_flags & LOAD_BYPASS_CACHE || + request_->load_flags & LOAD_DISABLE_CACHE) { + resolve_info.allow_cached_response = false; + } +#endif + + int rv = connection_.Init(connection_group, resolve_info, request_->priority, &io_callback_); return rv; } diff --git a/net/net.gyp b/net/net.gyp index c6c92b5..d187781 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -61,7 +61,6 @@ 'base/data_url.h', 'base/directory_lister.cc', 'base/directory_lister.h', - 'base/dns_resolution_observer.cc', 'base/dns_resolution_observer.h', 'base/effective_tld_names.cc', 'base/effective_tld_names.dat', diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc index 38e0a83..ad4f1eb6 100644 --- a/net/proxy/proxy_resolver_v8.cc +++ b/net/proxy/proxy_resolver_v8.cc @@ -70,15 +70,16 @@ class SyncHostResolverBridge // Run the resolve on host_resolver_loop, and wait for result. int Resolve(const std::string& hostname, net::AddressList* addresses) { - int kPort = 80; // Doesn't matter. + // Port number doesn't matter. + HostResolver::RequestInfo info(hostname, 80); // Hack for tests -- run synchronously on current thread. if (!host_resolver_loop_) - return host_resolver_->Resolve(hostname, kPort, addresses, NULL, NULL); + return host_resolver_->Resolve(info, addresses, NULL, NULL); // Otherwise start an async resolve on the resolver's thread. host_resolver_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, - &SyncHostResolverBridge::StartResolve, hostname, kPort, addresses)); + &SyncHostResolverBridge::StartResolve, info, addresses)); // Wait for the resolve to complete in the resolver's thread. event_.Wait(); @@ -87,12 +88,10 @@ class SyncHostResolverBridge private: // Called on host_resolver_loop_. - void StartResolve(const std::string& hostname, - int port, + void StartResolve(const HostResolver::RequestInfo& info, net::AddressList* addresses) { DCHECK_EQ(host_resolver_loop_, MessageLoop::current()); - int error = host_resolver_->Resolve( - hostname, port, addresses, &callback_, NULL); + int error = host_resolver_->Resolve(info, addresses, &callback_, NULL); if (error != ERR_IO_PENDING) OnResolveCompletion(error); // Completed synchronously. } |