| // Copyright 2015 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. | 
 |  | 
 | #include "net/dns/host_resolver_mojo.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/callback_helpers.h" | 
 | #include "base/memory/ptr_util.h" | 
 | #include "mojo/public/cpp/bindings/binding.h" | 
 | #include "net/base/address_list.h" | 
 | #include "net/base/net_errors.h" | 
 |  | 
 | namespace net { | 
 | namespace { | 
 |  | 
 | // Default TTL for successful host resolutions. | 
 | const int kCacheEntryTTLSeconds = 5; | 
 |  | 
 | // Default TTL for unsuccessful host resolutions. | 
 | const int kNegativeCacheEntryTTLSeconds = 0; | 
 |  | 
 | HostCache::Key CacheKeyForRequest(const HostResolver::RequestInfo& info) { | 
 |   return HostCache::Key(info.hostname(), info.address_family(), | 
 |                         info.host_resolver_flags()); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | class HostResolverMojo::Job : public interfaces::HostResolverRequestClient { | 
 |  public: | 
 |   Job(const HostCache::Key& key, | 
 |       AddressList* addresses, | 
 |       const CompletionCallback& callback, | 
 |       mojo::InterfaceRequest<interfaces::HostResolverRequestClient> request, | 
 |       base::WeakPtr<HostCache> host_cache); | 
 |  | 
 |  private: | 
 |   // interfaces::HostResolverRequestClient override. | 
 |   void ReportResult(int32_t error, const AddressList& address_list) override; | 
 |  | 
 |   // Mojo error handler. | 
 |   void OnConnectionError(); | 
 |  | 
 |   const HostCache::Key key_; | 
 |   AddressList* addresses_; | 
 |   CompletionCallback callback_; | 
 |   mojo::Binding<interfaces::HostResolverRequestClient> binding_; | 
 |   base::WeakPtr<HostCache> host_cache_; | 
 | }; | 
 |  | 
 | class HostResolverMojo::RequestImpl : public HostResolver::Request { | 
 |  public: | 
 |   explicit RequestImpl(std::unique_ptr<Job> job) : job_(std::move(job)) {} | 
 |  | 
 |   ~RequestImpl() override {} | 
 |  | 
 |   void ChangeRequestPriority(RequestPriority priority) override {} | 
 |  | 
 |  private: | 
 |   std::unique_ptr<Job> job_; | 
 | }; | 
 |  | 
 | HostResolverMojo::HostResolverMojo(Impl* impl) | 
 |     : impl_(impl), | 
 |       host_cache_(HostCache::CreateDefaultCache()), | 
 |       host_cache_weak_factory_(host_cache_.get()) { | 
 | } | 
 |  | 
 | HostResolverMojo::~HostResolverMojo() = default; | 
 |  | 
 | int HostResolverMojo::Resolve(const RequestInfo& info, | 
 |                               RequestPriority priority, | 
 |                               AddressList* addresses, | 
 |                               const CompletionCallback& callback, | 
 |                               std::unique_ptr<Request>* request, | 
 |                               const NetLogWithSource& source_net_log) { | 
 |   DCHECK(thread_checker_.CalledOnValidThread()); | 
 |   DCHECK(request); | 
 |   DVLOG(1) << "Resolve " << info.host_port_pair().ToString(); | 
 |  | 
 |   HostCache::Key key = CacheKeyForRequest(info); | 
 |   int cached_result = ResolveFromCacheInternal(info, key, addresses); | 
 |   if (cached_result != ERR_DNS_CACHE_MISS) { | 
 |     DVLOG(1) << "Resolved " << info.host_port_pair().ToString() | 
 |              << " from cache"; | 
 |     return cached_result; | 
 |   } | 
 |  | 
 |   interfaces::HostResolverRequestClientPtr handle; | 
 |   std::unique_ptr<Job> job(new Job(key, addresses, callback, | 
 |                                    mojo::MakeRequest(&handle), | 
 |                                    host_cache_weak_factory_.GetWeakPtr())); | 
 |   request->reset(new RequestImpl(std::move(job))); | 
 |  | 
 |   impl_->ResolveDns(base::MakeUnique<HostResolver::RequestInfo>(info), | 
 |                     std::move(handle)); | 
 |   return ERR_IO_PENDING; | 
 | } | 
 |  | 
 | int HostResolverMojo::ResolveFromCache(const RequestInfo& info, | 
 |                                        AddressList* addresses, | 
 |                                        const NetLogWithSource& source_net_log) { | 
 |   DCHECK(thread_checker_.CalledOnValidThread()); | 
 |   DVLOG(1) << "ResolveFromCache " << info.host_port_pair().ToString(); | 
 |   return ResolveFromCacheInternal(info, CacheKeyForRequest(info), addresses); | 
 | } | 
 |  | 
 | HostCache* HostResolverMojo::GetHostCache() { | 
 |   return host_cache_.get(); | 
 | } | 
 |  | 
 | int HostResolverMojo::ResolveFromCacheInternal(const RequestInfo& info, | 
 |                                                const HostCache::Key& key, | 
 |                                                AddressList* addresses) { | 
 |   if (!info.allow_cached_response()) | 
 |     return ERR_DNS_CACHE_MISS; | 
 |  | 
 |   const HostCache::Entry* entry = | 
 |       host_cache_->Lookup(key, base::TimeTicks::Now()); | 
 |   if (!entry) | 
 |     return ERR_DNS_CACHE_MISS; | 
 |  | 
 |   *addresses = AddressList::CopyWithPort(entry->addresses(), info.port()); | 
 |   return entry->error(); | 
 | } | 
 |  | 
 | HostResolverMojo::Job::Job( | 
 |     const HostCache::Key& key, | 
 |     AddressList* addresses, | 
 |     const CompletionCallback& callback, | 
 |     mojo::InterfaceRequest<interfaces::HostResolverRequestClient> request, | 
 |     base::WeakPtr<HostCache> host_cache) | 
 |     : key_(key), | 
 |       addresses_(addresses), | 
 |       callback_(callback), | 
 |       binding_(this, std::move(request)), | 
 |       host_cache_(host_cache) { | 
 |   binding_.set_connection_error_handler(base::Bind( | 
 |       &HostResolverMojo::Job::OnConnectionError, base::Unretained(this))); | 
 | } | 
 |  | 
 | void HostResolverMojo::Job::ReportResult(int32_t error, | 
 |                                          const AddressList& address_list) { | 
 |   if (error == OK) | 
 |     *addresses_ = address_list; | 
 |   if (host_cache_) { | 
 |     base::TimeDelta ttl = base::TimeDelta::FromSeconds( | 
 |         error == OK ? kCacheEntryTTLSeconds : kNegativeCacheEntryTTLSeconds); | 
 |     HostCache::Entry entry(error, *addresses_, ttl); | 
 |     host_cache_->Set(key_, entry, base::TimeTicks::Now(), ttl); | 
 |   } | 
 |   if (binding_.is_bound()) | 
 |     binding_.Close(); | 
 |   base::ResetAndReturn(&callback_).Run(error); | 
 | } | 
 |  | 
 | void HostResolverMojo::Job::OnConnectionError() { | 
 |   ReportResult(ERR_FAILED, AddressList()); | 
 | } | 
 |  | 
 | }  // namespace net |