blob: 11f65d7e69db8213f2a0bf9224e3bcaef9500585 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295#include "chrome/browser/net/dns_master.h"
6
[email protected]1933eb202009-02-19 18:23:257#include <algorithm>
[email protected]319d9e6f2009-02-18 19:47:218#include <set>
[email protected]1933eb202009-02-19 18:23:259#include <sstream>
initial.commit09911bf2008-07-26 23:55:2910
[email protected]1933eb202009-02-19 18:23:2511#include "base/compiler_specific.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/histogram.h"
13#include "base/stats_counters.h"
[email protected]21dae9b2008-11-06 23:32:5314#include "base/string_util.h"
[email protected]1933eb202009-02-19 18:23:2515#include "base/time.h"
[email protected]6fad2632009-11-02 05:59:3716#include "chrome/browser/chrome_thread.h"
[email protected]760d970a2010-05-18 00:39:1817#include "chrome/browser/net/preconnect.h"
[email protected]1933eb202009-02-19 18:23:2518#include "net/base/address_list.h"
19#include "net/base/completion_callback.h"
[email protected]760d970a2010-05-18 00:39:1820#include "net/base/host_port_pair.h"
[email protected]1933eb202009-02-19 18:23:2521#include "net/base/host_resolver.h"
22#include "net/base/net_errors.h"
[email protected]9e743cd2010-03-16 07:03:5323#include "net/base/net_log.h"
[email protected]e1acf6f2008-10-27 20:43:3324
[email protected]602faf3c2009-06-27 14:35:4425using base::TimeDelta;
26
initial.commit09911bf2008-07-26 23:55:2927namespace chrome_browser_net {
28
[email protected]1933eb202009-02-19 18:23:2529class DnsMaster::LookupRequest {
30 public:
[email protected]fd2f8afe2009-06-11 21:53:5531 LookupRequest(DnsMaster* master,
[email protected]8a00f00a2009-06-12 00:49:3832 net::HostResolver* host_resolver,
[email protected]760d970a2010-05-18 00:39:1833 const net::HostPortPair& hostport)
[email protected]1933eb202009-02-19 18:23:2534 : ALLOW_THIS_IN_INITIALIZER_LIST(
35 net_callback_(this, &LookupRequest::OnLookupFinished)),
36 master_(master),
[email protected]760d970a2010-05-18 00:39:1837 hostport_(hostport),
[email protected]8a00f00a2009-06-12 00:49:3838 resolver_(host_resolver) {
initial.commit09911bf2008-07-26 23:55:2939 }
[email protected]1933eb202009-02-19 18:23:2540
[email protected]85398532009-06-16 21:32:1841 // Return underlying network resolver status.
42 // net::OK ==> Host was found synchronously.
43 // net:ERR_IO_PENDING ==> Network will callback later with result.
44 // anything else ==> Host was not found synchronously.
45 int Start() {
[email protected]760d970a2010-05-18 00:39:1846 net::HostResolver::RequestInfo resolve_info(hostport_.host, hostport_.port);
[email protected]2884a462009-06-15 05:08:4247
48 // Make a note that this is a speculative resolve request. This allows us
49 // to separate it from real navigations in the observer's callback, and
50 // lets the HostResolver know it can de-prioritize it.
51 resolve_info.set_is_speculative(true);
[email protected]ec08bb22009-08-12 00:25:1252 return resolver_.Resolve(
[email protected]9e743cd2010-03-16 07:03:5353 resolve_info, &addresses_, &net_callback_, net::BoundNetLog());
[email protected]1933eb202009-02-19 18:23:2554 }
55
56 private:
57 void OnLookupFinished(int result) {
[email protected]760d970a2010-05-18 00:39:1858 master_->OnLookupFinished(this, hostport_, result == net::OK);
[email protected]1933eb202009-02-19 18:23:2559 }
60
61 // HostResolver will call us using this callback when resolution is complete.
62 net::CompletionCallbackImpl<LookupRequest> net_callback_;
63
64 DnsMaster* master_; // Master which started us.
65
[email protected]760d970a2010-05-18 00:39:1866 const net::HostPortPair hostport_; // Hostname to resolve.
[email protected]8a00f00a2009-06-12 00:49:3867 net::SingleRequestHostResolver resolver_;
[email protected]1933eb202009-02-19 18:23:2568 net::AddressList addresses_;
69
70 DISALLOW_COPY_AND_ASSIGN(LookupRequest);
71};
72
[email protected]fd2f8afe2009-06-11 21:53:5573DnsMaster::DnsMaster(net::HostResolver* host_resolver,
[email protected]760d970a2010-05-18 00:39:1874 base::TimeDelta max_queue_delay,
75 size_t max_concurrent,
76 bool preconnect_enabled)
77 : peak_pending_lookups_(0),
78 shutdown_(false),
79 max_concurrent_lookups_(max_concurrent),
80 max_queue_delay_(max_queue_delay),
81 host_resolver_(host_resolver),
82 preconnect_enabled_(preconnect_enabled) {
83 Referrer::SetUsePreconnectValuations(preconnect_enabled);
[email protected]1933eb202009-02-19 18:23:2584}
85
86DnsMaster::~DnsMaster() {
87 DCHECK(shutdown_);
88}
89
90void DnsMaster::Shutdown() {
[email protected]ec86bea2009-12-08 18:35:1491 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]1933eb202009-02-19 18:23:2592 DCHECK(!shutdown_);
93 shutdown_ = true;
94
95 std::set<LookupRequest*>::iterator it;
96 for (it = pending_lookups_.begin(); it != pending_lookups_.end(); ++it)
97 delete *it;
initial.commit09911bf2008-07-26 23:55:2998}
99
100// Overloaded Resolve() to take a vector of names.
[email protected]21dae9b2008-11-06 23:32:53101void DnsMaster::ResolveList(const NameList& hostnames,
102 DnsHostInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14103 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55104
[email protected]1933eb202009-02-19 18:23:25105 NameList::const_iterator it;
106 for (it = hostnames.begin(); it < hostnames.end(); ++it)
[email protected]760d970a2010-05-18 00:39:18107 // TODO(jar): I should pass port all the way in from renderer.
108 AppendToResolutionQueue(net::HostPortPair(*it, 80), motivation);
initial.commit09911bf2008-07-26 23:55:29109}
110
111// Basic Resolve() takes an invidual name, and adds it
112// to the queue.
[email protected]760d970a2010-05-18 00:39:18113void DnsMaster::Resolve(const net::HostPortPair& hostport,
[email protected]21dae9b2008-11-06 23:32:53114 DnsHostInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14115 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18116 if (hostport.host.empty())
initial.commit09911bf2008-07-26 23:55:29117 return;
[email protected]760d970a2010-05-18 00:39:18118 AppendToResolutionQueue(hostport, motivation);
initial.commit09911bf2008-07-26 23:55:29119}
120
[email protected]760d970a2010-05-18 00:39:18121bool DnsMaster::AccruePrefetchBenefits(const net::HostPortPair& referrer,
[email protected]ec86bea2009-12-08 18:35:14122 DnsHostInfo* navigation_info) {
123 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18124 net::HostPortPair hostport = navigation_info->hostport();
125 Results::iterator it = results_.find(hostport);
[email protected]21dae9b2008-11-06 23:32:53126 if (it == results_.end()) {
[email protected]21dae9b2008-11-06 23:32:53127 // Use UMA histogram to quantify potential future gains here.
[email protected]553dba62009-02-24 19:08:23128 UMA_HISTOGRAM_LONG_TIMES("DNS.UnexpectedResolutionL",
[email protected]21dae9b2008-11-06 23:32:53129 navigation_info->resolve_duration());
130 navigation_info->DLogResultsStats("DNS UnexpectedResolution");
131
132 NonlinkNavigation(referrer, navigation_info);
133 return false;
134 }
135 DnsHostInfo& prefetched_host_info(it->second);
136
137 // Sometimes a host is used as a subresource by several referrers, so it is
138 // in our list, but was never motivated by a page-link-scan. In that case, it
139 // really is an "unexpected" navigation, and we should tally it, and augment
140 // our referrers_.
141 bool referrer_based_prefetch = !prefetched_host_info.was_linked();
142 if (referrer_based_prefetch) {
143 // This wasn't the first time this host refered to *some* referrer.
144 NonlinkNavigation(referrer, navigation_info);
145 }
146
147 DnsBenefit benefit = prefetched_host_info.AccruePrefetchBenefits(
148 navigation_info);
149 switch (benefit) {
150 case PREFETCH_NAME_FOUND:
151 case PREFETCH_NAME_NONEXISTANT:
[email protected]21dae9b2008-11-06 23:32:53152 cache_hits_.push_back(*navigation_info);
153 if (referrer_based_prefetch) {
[email protected]760d970a2010-05-18 00:39:18154 if (!referrer.host.empty()) {
155 referrers_[referrer].AccrueValue(
156 navigation_info->benefits_remaining(), hostport);
[email protected]21dae9b2008-11-06 23:32:53157 }
158 }
159 return true;
160
161 case PREFETCH_CACHE_EVICTION:
[email protected]760d970a2010-05-18 00:39:18162 cache_eviction_map_[hostport] = *navigation_info;
[email protected]21dae9b2008-11-06 23:32:53163 return false;
164
165 case PREFETCH_NO_BENEFIT:
166 // Prefetch never hit the network. Name was pre-cached.
167 return false;
168
169 default:
[email protected]760d970a2010-05-18 00:39:18170 NOTREACHED();
[email protected]21dae9b2008-11-06 23:32:53171 return false;
172 }
173}
174
[email protected]760d970a2010-05-18 00:39:18175void DnsMaster::NonlinkNavigation(const net::HostPortPair& referring_hostport,
[email protected]ec86bea2009-12-08 18:35:14176 const DnsHostInfo* navigation_info) {
177 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18178 if (referring_hostport.host.empty() ||
179 referring_hostport.Equals(navigation_info->hostport()))
[email protected]21dae9b2008-11-06 23:32:53180 return;
[email protected]760d970a2010-05-18 00:39:18181 referrers_[referring_hostport].SuggestHost(navigation_info->hostport());
[email protected]21dae9b2008-11-06 23:32:53182}
183
[email protected]760d970a2010-05-18 00:39:18184void DnsMaster::NavigatingTo(const net::HostPortPair& hostport) {
[email protected]ec86bea2009-12-08 18:35:14185 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18186 Referrers::iterator it = referrers_.find(hostport);
[email protected]1933eb202009-02-19 18:23:25187 if (referrers_.end() == it)
188 return;
189 Referrer* referrer = &(it->second);
[email protected]760d970a2010-05-18 00:39:18190 referrer->IncrementUseCount();
191 for (Referrer::iterator future_hostport = referrer->begin();
192 future_hostport != referrer->end(); ++future_hostport) {
193 if (preconnect_enabled_) {
194 if (future_hostport->second.IsPreconnectWorthDoing()) {
195 Preconnect::PreconnectOnIOThread(future_hostport->first);
196 continue; // No need he pre-resolve DNS.
197 }
198 // Fall through and do DNS pre-resolution.
199 }
[email protected]ec86bea2009-12-08 18:35:14200 DnsHostInfo* queued_info = AppendToResolutionQueue(
[email protected]760d970a2010-05-18 00:39:18201 future_hostport->first,
[email protected]1933eb202009-02-19 18:23:25202 DnsHostInfo::LEARNED_REFERAL_MOTIVATED);
203 if (queued_info)
[email protected]760d970a2010-05-18 00:39:18204 queued_info->SetReferringHostname(hostport);
initial.commit09911bf2008-07-26 23:55:29205 }
206}
207
initial.commit09911bf2008-07-26 23:55:29208// Provide sort order so all .com's are together, etc.
209struct RightToLeftStringSorter {
[email protected]760d970a2010-05-18 00:39:18210 bool operator()(const net::HostPortPair& left,
211 const net::HostPortPair& right) const {
212 return string_compare(left.host, right.host);
213 }
214 bool operator()(const GURL& left,
215 const GURL& right) const {
216 return string_compare(left.host(), right.host());
217 }
218
219 static bool string_compare(const std::string& left_host,
220 const std::string right_host) {
221 if (left_host == right_host) return true;
222 size_t left_already_matched = left_host.size();
223 size_t right_already_matched = right_host.size();
[email protected]21dae9b2008-11-06 23:32:53224
225 // Ensure both strings have characters.
226 if (!left_already_matched) return true;
227 if (!right_already_matched) return false;
228
229 // Watch for trailing dot, so we'll always be safe to go one beyond dot.
[email protected]760d970a2010-05-18 00:39:18230 if ('.' == left_host[left_already_matched - 1]) {
231 if ('.' != right_host[right_already_matched - 1])
initial.commit09911bf2008-07-26 23:55:29232 return true;
[email protected]21dae9b2008-11-06 23:32:53233 // Both have dots at end of string.
234 --left_already_matched;
235 --right_already_matched;
236 } else {
[email protected]760d970a2010-05-18 00:39:18237 if ('.' == right_host[right_already_matched - 1])
[email protected]21dae9b2008-11-06 23:32:53238 return false;
239 }
240
241 while (1) {
242 if (!left_already_matched) return true;
243 if (!right_already_matched) return false;
244
245 size_t left_length, right_length;
[email protected]760d970a2010-05-18 00:39:18246 size_t left_start = left_host.find_last_of('.', left_already_matched - 1);
[email protected]21dae9b2008-11-06 23:32:53247 if (std::string::npos == left_start) {
248 left_length = left_already_matched;
249 left_already_matched = left_start = 0;
250 } else {
251 left_length = left_already_matched - left_start;
252 left_already_matched = left_start;
253 ++left_start; // Don't compare the dot.
254 }
[email protected]760d970a2010-05-18 00:39:18255 size_t right_start = right_host.find_last_of('.',
256 right_already_matched - 1);
[email protected]21dae9b2008-11-06 23:32:53257 if (std::string::npos == right_start) {
258 right_length = right_already_matched;
259 right_already_matched = right_start = 0;
260 } else {
261 right_length = right_already_matched - right_start;
262 right_already_matched = right_start;
263 ++right_start; // Don't compare the dot.
264 }
265
[email protected]760d970a2010-05-18 00:39:18266 int diff = left_host.compare(left_start, left_host.size(),
267 right_host, right_start, right_host.size());
[email protected]21dae9b2008-11-06 23:32:53268 if (diff > 0) return false;
269 if (diff < 0) return true;
initial.commit09911bf2008-07-26 23:55:29270 }
271 }
272};
273
[email protected]21dae9b2008-11-06 23:32:53274void DnsMaster::GetHtmlReferrerLists(std::string* output) {
[email protected]ec86bea2009-12-08 18:35:14275 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]21dae9b2008-11-06 23:32:53276 if (referrers_.empty())
277 return;
278
279 // TODO(jar): Remove any plausible JavaScript from names before displaying.
280
[email protected]760d970a2010-05-18 00:39:18281 typedef std::set<net::HostPortPair, struct RightToLeftStringSorter>
282 SortedNames;
[email protected]21dae9b2008-11-06 23:32:53283 SortedNames sorted_names;
284
285 for (Referrers::iterator it = referrers_.begin();
286 referrers_.end() != it; ++it)
287 sorted_names.insert(it->first);
288
289 output->append("<br><table border>");
[email protected]760d970a2010-05-18 00:39:18290 output->append(
291 "<tr><th>Host for Page</th>"
292 "<th>Page Load<br>Count</th>"
293 "<th>Subresource<br>Navigations</th>"
294 "<th>Subresource<br>PreConnects</th>"
295 "<th>Expected<br>Connects</th>"
296 "<th>DNS<br>Savings</th>"
297 "<th>Subresource Spec</th></tr>");
[email protected]21dae9b2008-11-06 23:32:53298
299 for (SortedNames::iterator it = sorted_names.begin();
300 sorted_names.end() != it; ++it) {
301 Referrer* referrer = &(referrers_[*it]);
[email protected]760d970a2010-05-18 00:39:18302 bool first_set_of_futures = true;
303 for (Referrer::iterator future_hostport = referrer->begin();
304 future_hostport != referrer->end(); ++future_hostport) {
305 output->append("<tr align=right>");
306 if (first_set_of_futures)
307 StringAppendF(output, "<td rowspan=%d>%s</td><td rowspan=%d>%d</td>",
308 static_cast<int>(referrer->size()),
309 it->ToString().c_str(),
310 static_cast<int>(referrer->size()),
311 static_cast<int>(referrer->use_count()));
312 first_set_of_futures = false;
313 StringAppendF(output,
314 "<td>%d</td><td>%d</td><td>%2.3f</td><td>%dms</td><td>%s</td></tr>",
315 static_cast<int>(future_hostport->second.navigation_count()),
316 static_cast<int>(future_hostport->second.preconnection_count()),
317 static_cast<double>(future_hostport->second.subresource_use_rate()),
318 static_cast<int>(future_hostport->second.latency().InMilliseconds()),
319 future_hostport->first.ToString().c_str());
[email protected]21dae9b2008-11-06 23:32:53320 }
[email protected]21dae9b2008-11-06 23:32:53321 }
322 output->append("</table>");
323}
324
initial.commit09911bf2008-07-26 23:55:29325void DnsMaster::GetHtmlInfo(std::string* output) {
[email protected]ec86bea2009-12-08 18:35:14326 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29327 // Local lists for calling DnsHostInfo
328 DnsHostInfo::DnsInfoTable cache_hits;
329 DnsHostInfo::DnsInfoTable cache_evictions;
330 DnsHostInfo::DnsInfoTable name_not_found;
331 DnsHostInfo::DnsInfoTable network_hits;
332 DnsHostInfo::DnsInfoTable already_cached;
333
[email protected]ec86bea2009-12-08 18:35:14334 // Get copies of all useful data.
[email protected]760d970a2010-05-18 00:39:18335 typedef std::map<net::HostPortPair, DnsHostInfo, RightToLeftStringSorter>
336 Snapshot;
initial.commit09911bf2008-07-26 23:55:29337 Snapshot snapshot;
338 {
initial.commit09911bf2008-07-26 23:55:29339 // DnsHostInfo supports value semantics, so we can do a shallow copy.
340 for (Results::iterator it(results_.begin()); it != results_.end(); it++) {
341 snapshot[it->first] = it->second;
342 }
343 for (Results::iterator it(cache_eviction_map_.begin());
344 it != cache_eviction_map_.end();
345 it++) {
346 cache_evictions.push_back(it->second);
347 }
348 // Reverse list as we copy cache hits, so that new hits are at the top.
349 size_t index = cache_hits_.size();
350 while (index > 0) {
351 index--;
352 cache_hits.push_back(cache_hits_[index]);
353 }
354 }
355
356 // Partition the DnsHostInfo's into categories.
357 for (Snapshot::iterator it(snapshot.begin()); it != snapshot.end(); it++) {
358 if (it->second.was_nonexistant()) {
359 name_not_found.push_back(it->second);
360 continue;
361 }
362 if (!it->second.was_found())
363 continue; // Still being processed.
[email protected]602faf3c2009-06-27 14:35:44364 if (TimeDelta() != it->second.benefits_remaining()) {
initial.commit09911bf2008-07-26 23:55:29365 network_hits.push_back(it->second); // With no benefit yet.
366 continue;
367 }
368 if (DnsHostInfo::kMaxNonNetworkDnsLookupDuration >
369 it->second.resolve_duration()) {
370 already_cached.push_back(it->second);
371 continue;
372 }
373 // Remaining case is where prefetch benefit was significant, and was used.
374 // Since we shot those cases as historical hits, we won't bother here.
375 }
376
377 bool brief = false;
378#ifdef NDEBUG
379 brief = true;
380#endif // NDEBUG
381
382 // Call for display of each table, along with title.
383 DnsHostInfo::GetHtmlTable(cache_hits,
384 "Prefetching DNS records produced benefits for ", false, output);
385 DnsHostInfo::GetHtmlTable(cache_evictions,
386 "Cache evictions negated DNS prefetching benefits for ", brief, output);
387 DnsHostInfo::GetHtmlTable(network_hits,
388 "Prefetching DNS records was not yet beneficial for ", brief, output);
389 DnsHostInfo::GetHtmlTable(already_cached,
390 "Previously cached resolutions were found for ", brief, output);
391 DnsHostInfo::GetHtmlTable(name_not_found,
392 "Prefetching DNS records revealed non-existance for ", brief, output);
393}
394
[email protected]ec86bea2009-12-08 18:35:14395DnsHostInfo* DnsMaster::AppendToResolutionQueue(
[email protected]760d970a2010-05-18 00:39:18396 const net::HostPortPair& hostport,
[email protected]21dae9b2008-11-06 23:32:53397 DnsHostInfo::ResolutionMotivation motivation) {
[email protected]ec86bea2009-12-08 18:35:14398 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18399 DCHECK(!hostport.host.empty());
initial.commit09911bf2008-07-26 23:55:29400
[email protected]1933eb202009-02-19 18:23:25401 if (shutdown_)
402 return NULL;
403
[email protected]760d970a2010-05-18 00:39:18404 DnsHostInfo* info = &results_[hostport];
405 info->SetHostname(hostport); // Initialize or DCHECK.
initial.commit09911bf2008-07-26 23:55:29406 // TODO(jar): I need to discard names that have long since expired.
407 // Currently we only add to the domain map :-/
408
[email protected]760d970a2010-05-18 00:39:18409 DCHECK(info->HasHostname(hostport));
initial.commit09911bf2008-07-26 23:55:29410
[email protected]760d970a2010-05-18 00:39:18411 if (!info->NeedsDnsUpdate()) {
initial.commit09911bf2008-07-26 23:55:29412 info->DLogResultsStats("DNS PrefetchNotUpdated");
[email protected]21dae9b2008-11-06 23:32:53413 return NULL;
initial.commit09911bf2008-07-26 23:55:29414 }
415
[email protected]21dae9b2008-11-06 23:32:53416 info->SetQueuedState(motivation);
[email protected]760d970a2010-05-18 00:39:18417 work_queue_.Push(hostport, motivation);
[email protected]ec86bea2009-12-08 18:35:14418 StartSomeQueuedResolutions();
[email protected]21dae9b2008-11-06 23:32:53419 return info;
initial.commit09911bf2008-07-26 23:55:29420}
421
[email protected]ec86bea2009-12-08 18:35:14422void DnsMaster::StartSomeQueuedResolutions() {
[email protected]6fad2632009-11-02 05:59:37423 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55424
[email protected]a20bc092009-06-05 01:34:20425 while (!work_queue_.IsEmpty() &&
[email protected]e085c302009-06-01 18:31:36426 pending_lookups_.size() < max_concurrent_lookups_) {
[email protected]760d970a2010-05-18 00:39:18427 const net::HostPortPair hostport(work_queue_.Pop());
428 DnsHostInfo* info = &results_[hostport];
429 DCHECK(info->HasHostname(hostport));
initial.commit09911bf2008-07-26 23:55:29430 info->SetAssignedState();
431
[email protected]ec86bea2009-12-08 18:35:14432 if (CongestionControlPerformed(info)) {
[email protected]a20bc092009-06-05 01:34:20433 DCHECK(work_queue_.IsEmpty());
434 return;
435 }
436
[email protected]760d970a2010-05-18 00:39:18437 LookupRequest* request = new LookupRequest(this, host_resolver_, hostport);
[email protected]85398532009-06-16 21:32:18438 int status = request->Start();
439 if (status == net::ERR_IO_PENDING) {
[email protected]fd2f8afe2009-06-11 21:53:55440 // Will complete asynchronously.
[email protected]1933eb202009-02-19 18:23:25441 pending_lookups_.insert(request);
442 peak_pending_lookups_ = std::max(peak_pending_lookups_,
443 pending_lookups_.size());
444 } else {
[email protected]221f33362009-06-29 20:46:48445 // Completed synchronously (was already cached by HostResolver), or else
[email protected]85398532009-06-16 21:32:18446 // there was (equivalently) some network error that prevents us from
447 // finding the name. Status net::OK means it was "found."
[email protected]760d970a2010-05-18 00:39:18448 LookupFinished(request, hostport, status == net::OK);
[email protected]1933eb202009-02-19 18:23:25449 delete request;
450 }
451 }
initial.commit09911bf2008-07-26 23:55:29452}
453
[email protected]ec86bea2009-12-08 18:35:14454bool DnsMaster::CongestionControlPerformed(DnsHostInfo* info) {
455 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]a20bc092009-06-05 01:34:20456 // Note: queue_duration is ONLY valid after we go to assigned state.
[email protected]602faf3c2009-06-27 14:35:44457 if (info->queue_duration() < max_queue_delay_)
[email protected]a20bc092009-06-05 01:34:20458 return false;
459 // We need to discard all entries in our queue, as we're keeping them waiting
460 // too long. By doing this, we'll have a chance to quickly service urgent
461 // resolutions, and not have a bogged down system.
462 while (true) {
463 info->RemoveFromQueue();
464 if (work_queue_.IsEmpty())
465 break;
466 info = &results_[work_queue_.Pop()];
467 info->SetAssignedState();
468 }
469 return true;
470}
471
[email protected]1933eb202009-02-19 18:23:25472void DnsMaster::OnLookupFinished(LookupRequest* request,
[email protected]760d970a2010-05-18 00:39:18473 const net::HostPortPair& hostport,
474 bool found) {
[email protected]6fad2632009-11-02 05:59:37475 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]fd2f8afe2009-06-11 21:53:55476
[email protected]760d970a2010-05-18 00:39:18477 LookupFinished(request, hostport, found);
[email protected]85398532009-06-16 21:32:18478 pending_lookups_.erase(request);
479 delete request;
480
[email protected]ec86bea2009-12-08 18:35:14481 StartSomeQueuedResolutions();
[email protected]85398532009-06-16 21:32:18482}
483
[email protected]ec86bea2009-12-08 18:35:14484void DnsMaster::LookupFinished(LookupRequest* request,
[email protected]760d970a2010-05-18 00:39:18485 const net::HostPortPair& hostport,
[email protected]ec86bea2009-12-08 18:35:14486 bool found) {
487 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18488 DnsHostInfo* info = &results_[hostport];
489 DCHECK(info->HasHostname(hostport));
[email protected]a20bc092009-06-05 01:34:20490 if (info->is_marked_to_delete()) {
[email protected]760d970a2010-05-18 00:39:18491 results_.erase(hostport);
[email protected]a20bc092009-06-05 01:34:20492 } else {
[email protected]1933eb202009-02-19 18:23:25493 if (found)
494 info->SetFoundState();
495 else
496 info->SetNoSuchNameState();
[email protected]7c19b87b02009-01-26 16:19:44497 }
initial.commit09911bf2008-07-26 23:55:29498}
499
500void DnsMaster::DiscardAllResults() {
[email protected]ec86bea2009-12-08 18:35:14501 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
initial.commit09911bf2008-07-26 23:55:29502 // Delete anything listed so far in this session that shows in about:dns.
503 cache_eviction_map_.clear();
504 cache_hits_.clear();
[email protected]21dae9b2008-11-06 23:32:53505 referrers_.clear();
initial.commit09911bf2008-07-26 23:55:29506
507
508 // Try to delete anything in our work queue.
[email protected]a20bc092009-06-05 01:34:20509 while (!work_queue_.IsEmpty()) {
initial.commit09911bf2008-07-26 23:55:29510 // Emulate processing cycle as though host was not found.
[email protected]760d970a2010-05-18 00:39:18511 net::HostPortPair hostport = work_queue_.Pop();
512 DnsHostInfo* info = &results_[hostport];
513 DCHECK(info->HasHostname(hostport));
initial.commit09911bf2008-07-26 23:55:29514 info->SetAssignedState();
515 info->SetNoSuchNameState();
516 }
[email protected]1933eb202009-02-19 18:23:25517 // Now every result_ is either resolved, or is being resolved
518 // (see LookupRequest).
initial.commit09911bf2008-07-26 23:55:29519
520 // Step through result_, recording names of all hosts that can't be erased.
[email protected]1933eb202009-02-19 18:23:25521 // We can't erase anything being worked on.
initial.commit09911bf2008-07-26 23:55:29522 Results assignees;
523 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) {
[email protected]760d970a2010-05-18 00:39:18524 net::HostPortPair hostport(it->first);
initial.commit09911bf2008-07-26 23:55:29525 DnsHostInfo* info = &it->second;
[email protected]760d970a2010-05-18 00:39:18526 DCHECK(info->HasHostname(hostport));
initial.commit09911bf2008-07-26 23:55:29527 if (info->is_assigned()) {
528 info->SetPendingDeleteState();
[email protected]760d970a2010-05-18 00:39:18529 assignees[hostport] = *info;
initial.commit09911bf2008-07-26 23:55:29530 }
531 }
[email protected]e085c302009-06-01 18:31:36532 DCHECK(assignees.size() <= max_concurrent_lookups_);
initial.commit09911bf2008-07-26 23:55:29533 results_.clear();
[email protected]1933eb202009-02-19 18:23:25534 // Put back in the names being worked on.
initial.commit09911bf2008-07-26 23:55:29535 for (Results::iterator it = assignees.begin(); assignees.end() != it; ++it) {
536 DCHECK(it->second.is_marked_to_delete());
537 results_[it->first] = it->second;
538 }
539}
540
[email protected]03c5e862009-02-17 22:50:14541void DnsMaster::TrimReferrers() {
[email protected]ec86bea2009-12-08 18:35:14542 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18543 std::vector<net::HostPortPair> hosts;
[email protected]03c5e862009-02-17 22:50:14544 for (Referrers::const_iterator it = referrers_.begin();
545 it != referrers_.end(); ++it)
546 hosts.push_back(it->first);
547 for (size_t i = 0; i < hosts.size(); ++i)
548 if (!referrers_[hosts[i]].Trim())
549 referrers_.erase(hosts[i]);
550}
551
552void DnsMaster::SerializeReferrers(ListValue* referral_list) {
[email protected]ec86bea2009-12-08 18:35:14553 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]03c5e862009-02-17 22:50:14554 referral_list->Clear();
[email protected]760d970a2010-05-18 00:39:18555 referral_list->Append(new FundamentalValue(DNS_REFERRER_VERSION));
[email protected]03c5e862009-02-17 22:50:14556 for (Referrers::const_iterator it = referrers_.begin();
557 it != referrers_.end(); ++it) {
558 // Serialize the list of subresource names.
559 Value* subresource_list(it->second.Serialize());
560
561 // Create a list for each referer.
[email protected]760d970a2010-05-18 00:39:18562 ListValue* motivator(new ListValue);
563 motivator->Append(new FundamentalValue(it->first.port));
564 motivator->Append(new StringValue(it->first.host));
565 motivator->Append(subresource_list);
[email protected]03c5e862009-02-17 22:50:14566
[email protected]760d970a2010-05-18 00:39:18567 referral_list->Append(motivator);
[email protected]03c5e862009-02-17 22:50:14568 }
569}
570
571void DnsMaster::DeserializeReferrers(const ListValue& referral_list) {
[email protected]ec86bea2009-12-08 18:35:14572 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
[email protected]760d970a2010-05-18 00:39:18573 int format_version = -1;
574 if (referral_list.GetSize() > 0 &&
575 referral_list.GetInteger(0, &format_version) &&
576 format_version == DNS_REFERRER_VERSION) {
577 for (size_t i = 1; i < referral_list.GetSize(); ++i) {
578 ListValue* motivator;
579 if (!referral_list.GetList(i, &motivator)) {
580 NOTREACHED();
581 continue;
582 }
583 int motivating_port;
584 if (!motivator->GetInteger(0, &motivating_port)) {
585 NOTREACHED();
586 continue;
587 }
588 std::string motivating_host;
589 if (!motivator->GetString(1, &motivating_host)) {
590 NOTREACHED();
591 continue;
592 }
593 if (motivating_host.empty()) {
594 NOTREACHED();
595 continue;
596 }
597
598 Value* subresource_list;
599 if (!motivator->Get(2, &subresource_list)) {
600 NOTREACHED();
601 continue;
602 }
603 net::HostPortPair motivating_hostport(motivating_host, motivating_port);
604 referrers_[motivating_hostport].Deserialize(*subresource_list);
605 }
[email protected]03c5e862009-02-17 22:50:14606 }
607}
608
[email protected]a20bc092009-06-05 01:34:20609
610//------------------------------------------------------------------------------
611
612DnsMaster::HostNameQueue::HostNameQueue() {
613}
614
615DnsMaster::HostNameQueue::~HostNameQueue() {
616}
617
[email protected]760d970a2010-05-18 00:39:18618void DnsMaster::HostNameQueue::Push(const net::HostPortPair& hostport,
[email protected]a20bc092009-06-05 01:34:20619 DnsHostInfo::ResolutionMotivation motivation) {
620 switch (motivation) {
621 case DnsHostInfo::STATIC_REFERAL_MOTIVATED:
622 case DnsHostInfo::LEARNED_REFERAL_MOTIVATED:
623 case DnsHostInfo::MOUSE_OVER_MOTIVATED:
[email protected]760d970a2010-05-18 00:39:18624 rush_queue_.push(hostport);
[email protected]a20bc092009-06-05 01:34:20625 break;
626
627 default:
[email protected]760d970a2010-05-18 00:39:18628 background_queue_.push(hostport);
[email protected]a20bc092009-06-05 01:34:20629 break;
630 }
631}
632
633bool DnsMaster::HostNameQueue::IsEmpty() const {
634 return rush_queue_.empty() && background_queue_.empty();
635}
636
[email protected]760d970a2010-05-18 00:39:18637net::HostPortPair DnsMaster::HostNameQueue::Pop() {
[email protected]a20bc092009-06-05 01:34:20638 DCHECK(!IsEmpty());
639 if (!rush_queue_.empty()) {
[email protected]760d970a2010-05-18 00:39:18640 net::HostPortPair hostport(rush_queue_.front());
[email protected]a20bc092009-06-05 01:34:20641 rush_queue_.pop();
[email protected]760d970a2010-05-18 00:39:18642 return hostport;
[email protected]a20bc092009-06-05 01:34:20643 }
[email protected]760d970a2010-05-18 00:39:18644 net::HostPortPair hostport(background_queue_.front());
[email protected]a20bc092009-06-05 01:34:20645 background_queue_.pop();
[email protected]760d970a2010-05-18 00:39:18646 return hostport;
[email protected]a20bc092009-06-05 01:34:20647}
648
initial.commit09911bf2008-07-26 23:55:29649} // namespace chrome_browser_net