| Index: net/base/async_host_resolver.cc | 
| diff --git a/net/base/async_host_resolver.cc b/net/base/async_host_resolver.cc | 
| index 134d814a9039cf9fe549a18caad62ec8c3271180..992767b1d7c7a65da90f91aee0fff3c0915e150e 100644 | 
| --- a/net/base/async_host_resolver.cc | 
| +++ b/net/base/async_host_resolver.cc | 
| @@ -80,6 +80,7 @@ HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves, | 
| max_transactions, | 
| max_pending_requests, | 
| base::Bind(&base::RandInt), | 
| +      HostCache::CreateDefaultCache(), | 
| NULL, | 
| net_log); | 
| return resolver; | 
| @@ -111,7 +112,7 @@ class AsyncHostResolver::Request { | 
| RequestPriority priority() const { return info_.priority(); } | 
| const BoundNetLog& source_net_log() const { return source_net_log_; } | 
| const BoundNetLog& request_net_log() const { return request_net_log_; } | 
| -  const AddressList* addresses() const { return addresses_; } | 
| +  void set_addresses(const AddressList& addresses) { *addresses_ = addresses; } | 
|  | 
| void OnComplete(int result, const IPAddressList& ip_addresses) { | 
| DCHECK(callback_); | 
| @@ -136,12 +137,14 @@ AsyncHostResolver::AsyncHostResolver(const IPEndPoint& dns_server, | 
| size_t max_transactions, | 
| size_t max_pending_requests, | 
| const RandIntCallback& rand_int_cb, | 
| +                                     HostCache* cache, | 
| ClientSocketFactory* factory, | 
| NetLog* net_log) | 
| : max_transactions_(max_transactions), | 
| max_pending_requests_(max_pending_requests), | 
| dns_server_(dns_server), | 
| rand_int_cb_(rand_int_cb), | 
| +      cache_(cache), | 
| factory_(factory), | 
| next_request_id_(0), | 
| net_log_(net_log) { | 
| @@ -176,22 +179,26 @@ int AsyncHostResolver::Resolve(const RequestInfo& info, | 
| rv = ResolveAsIp(info, ip_number, addresses); | 
| else if (!DNSDomainFromDot(info.hostname(), &dns_name)) | 
| rv = ERR_NAME_NOT_RESOLVED; | 
| -  else if (info.only_use_cached_response())  // TODO(agayev): support caching | 
| -    rv = ERR_NAME_NOT_RESOLVED; | 
|  | 
| Request* request = CreateNewRequest( | 
| info, dns_name, callback, addresses, source_net_log); | 
|  | 
| OnStart(request); | 
| +  if (rv == ERR_UNEXPECTED) { | 
| +    if (ServeFromCache(request)) | 
| +      rv = OK; | 
| +    else if (info.only_use_cached_response()) | 
| +      rv = ERR_NAME_NOT_RESOLVED; | 
| +  } | 
| + | 
| if (rv != ERR_UNEXPECTED) { | 
| OnFinish(request, rv); | 
| delete request; | 
| -    return rv; | 
| +    return rv;  // Synchronous resolution ends here. | 
| } | 
|  | 
| if (out_req) | 
| *out_req = reinterpret_cast<RequestHandle>(request); | 
| - | 
| if (AttachToRequestList(request)) | 
| return ERR_IO_PENDING; | 
| if (transactions_.size() < max_transactions_) | 
| @@ -285,7 +292,6 @@ void AsyncHostResolver::OnTransactionComplete( | 
| int result, | 
| const DnsTransaction* transaction, | 
| const IPAddressList& ip_addresses) { | 
| - | 
| DCHECK(std::find(transactions_.begin(), transactions_.end(), transaction) | 
| != transactions_.end()); | 
| DCHECK(requestlist_map_.find(transaction->key()) != requestlist_map_.end()); | 
| @@ -300,6 +306,27 @@ void AsyncHostResolver::OnTransactionComplete( | 
| request->OnComplete(result, ip_addresses); | 
| } | 
|  | 
| +  // It is possible that the requests that caused |transaction| to be | 
| +  // created are cancelled by the time |transaction| completes.  In that | 
| +  // case |requests| would be empty.  We are knowingly throwing away the | 
| +  // result of a DNS resolution in that case, because (a) if there are no | 
| +  // requests, we do not have info to obtain a key from, (b) DnsTransaction | 
| +  // does not have info(), adding one into it just temporarily doesn't make | 
| +  // sense, since HostCache will be replaced with RR cache soon, (c) | 
| +  // recreating info from DnsTransaction::Key adds a lot of temporary | 
| +  // code/functions (like converting back from qtype to AddressFamily.) | 
| +  // Also, we only cache positive results.  All of this will change when RR | 
| +  // cache is added. | 
| +  if (result == OK && cache_.get() && !requests.empty()) { | 
| +    Request* request = requests.front(); | 
| +    HostResolver::RequestInfo info = request->info(); | 
| +    HostCache::Key key( | 
| +        info.hostname(), info.address_family(), info.host_resolver_flags()); | 
| +    AddressList addrlist = | 
| +      AddressList::CreateFromIPAddressList(ip_addresses, info.port()); | 
| +    cache_->Set(key, result, addrlist, base::TimeTicks::Now()); | 
| +  } | 
| + | 
| // Cleanup requests. | 
| STLDeleteElements(&requests); | 
| requestlist_map_.erase(transaction->key()); | 
| @@ -310,6 +337,31 @@ void AsyncHostResolver::OnTransactionComplete( | 
| ProcessPending(); | 
| } | 
|  | 
| +bool AsyncHostResolver::ServeFromCache(Request* request) const { | 
| +  // Sanity check -- it shouldn't be the case that allow_cached_response is | 
| +  // false while only_use_cached_response is true. | 
| +  DCHECK(request->info().allow_cached_response() || | 
| +         !request->info().only_use_cached_response()); | 
| + | 
| +  if (!cache_.get() || !request->info().allow_cached_response()) | 
| +    return false; | 
| + | 
| +  HostResolver::RequestInfo info = request->info(); | 
| +  HostCache::Key key(info.hostname(), info.address_family(), | 
| +                     info.host_resolver_flags()); | 
| +  const HostCache::Entry* cache_entry = cache_->Lookup( | 
| +      key, base::TimeTicks::Now()); | 
| +  if (cache_entry) { | 
| +    request->request_net_log().AddEvent( | 
| +        NetLog::TYPE_ASYNC_HOST_RESOLVER_CACHE_HIT, NULL); | 
| +    DCHECK_EQ(OK, cache_entry->error); | 
| +    request->set_addresses( | 
| +        CreateAddressListUsingPort(cache_entry->addrlist, info.port())); | 
| +    return true; | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest( | 
| const RequestInfo& info, | 
| const std::string& dns_name, | 
| @@ -378,7 +430,7 @@ AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) { | 
| return NULL; | 
| } | 
|  | 
| -size_t AsyncHostResolver::GetNumPending() { | 
| +size_t AsyncHostResolver::GetNumPending() const { | 
| size_t num_pending = 0; | 
| for (size_t i = 0; i < arraysize(pending_requests_); ++i) | 
| num_pending += pending_requests_[i].size(); | 
|  |