Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: chrome/browser/net/predictor_api.cc

Issue 3032014: Support both preconnection, and pre-resolution for subresources... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/net/predictor_api.h ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/net/predictor_api.h" 5 #include "chrome/browser/net/predictor_api.h"
6 6
7 #include <map> 7 #include <map>
8 #include <string> 8 #include <string>
9 9
10 #include "base/singleton.h" 10 #include "base/singleton.h"
(...skipping 17 matching lines...) Expand all
28 #include "chrome/common/notification_service.h" 28 #include "chrome/common/notification_service.h"
29 #include "chrome/common/pref_names.h" 29 #include "chrome/common/pref_names.h"
30 #include "net/base/host_resolver.h" 30 #include "net/base/host_resolver.h"
31 #include "net/base/host_resolver_impl.h" 31 #include "net/base/host_resolver_impl.h"
32 32
33 using base::Time; 33 using base::Time;
34 using base::TimeDelta; 34 using base::TimeDelta;
35 35
36 namespace chrome_browser_net { 36 namespace chrome_browser_net {
37 37
38 static void DnsMotivatedPrefetch(const GURL& url, 38 static void ResolveOnUIThread(const GURL& url,
39 UrlInfo::ResolutionMotivation motivation); 39 UrlInfo::ResolutionMotivation motivation);
40 40
41 static void DnsPrefetchMotivatedList(const UrlList& urls, 41 static void DnsPrefetchMotivatedList(const UrlList& urls,
42 UrlInfo::ResolutionMotivation motivation); 42 UrlInfo::ResolutionMotivation motivation);
43 43
44 static UrlList GetPredictedUrlListAtStartup( 44 static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
45 PrefService* user_prefs, PrefService* local_state); 45 PrefService* local_state);
46 46
47 // static 47 // static
48 const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8; 48 const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8;
49 49
50 // static 50 // static
51 const int PredictorInit::kMaxPrefetchQueueingDelayMs = 500; 51 const int PredictorInit::kMaxPrefetchQueueingDelayMs = 500;
52 52
53 // A version number for prefs that are saved. This should be incremented when 53 // A version number for prefs that are saved. This should be incremented when
54 // we change the format so that we discard old data. 54 // we change the format so that we discard old data.
55 static const int kPredictorStartupFormatVersion = 1; 55 static const int kPredictorStartupFormatVersion = 1;
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 static base::TimeTicks last_prefetch_for_host; 179 static base::TimeTicks last_prefetch_for_host;
180 base::TimeTicks now = base::TimeTicks::Now(); 180 base::TimeTicks now = base::TimeTicks::Now();
181 if (!is_new_host_request) { 181 if (!is_new_host_request) {
182 const int kMinPreresolveSeconds(10); 182 const int kMinPreresolveSeconds(10);
183 if (kMinPreresolveSeconds > (now - last_prefetch_for_host).InSeconds()) 183 if (kMinPreresolveSeconds > (now - last_prefetch_for_host).InSeconds())
184 return; 184 return;
185 } 185 }
186 last_prefetch_for_host = now; 186 last_prefetch_for_host = now;
187 187
188 GURL canonical_url(CanonicalizeUrl(url)); 188 GURL canonical_url(CanonicalizeUrl(url));
189 UrlInfo::ResolutionMotivation motivation(UrlInfo::OMNIBOX_MOTIVATED);
189 190
190 if (predictor->preconnect_enabled() && preconnectable) { 191 if (predictor->preconnect_enabled() && preconnectable) {
191 static base::TimeTicks last_keepalive; 192 static base::TimeTicks last_keepalive;
192 // TODO(jar): The wild guess of 30 seconds could be tuned/tested, but it 193 // TODO(jar): The wild guess of 30 seconds could be tuned/tested, but it
193 // currently is just a guess that most sockets will remain open for at least 194 // currently is just a guess that most sockets will remain open for at least
194 // 30 seconds. 195 // 30 seconds.
195 const int kMaxSearchKeepaliveSeconds(30); 196 const int kMaxSearchKeepaliveSeconds(30);
196 if ((now - last_keepalive).InSeconds() < kMaxSearchKeepaliveSeconds) 197 if ((now - last_keepalive).InSeconds() < kMaxSearchKeepaliveSeconds)
197 return; 198 return;
198 last_keepalive = now; 199 last_keepalive = now;
199 200
200 if (Preconnect::PreconnectOnUIThread(canonical_url)) 201 Preconnect::PreconnectOnUIThread(canonical_url, motivation);
201 return; // Skip pre-resolution, since we'll open a connection. 202 return; // Skip pre-resolution, since we'll open a connection.
202 } 203 }
203 204
204 // Perform at least DNS pre-resolution. 205 // Perform at least DNS pre-resolution.
205 DnsMotivatedPrefetch(canonical_url, UrlInfo::OMNIBOX_MOTIVATED); 206 ResolveOnUIThread(canonical_url, motivation);
206 } 207 }
207 208
208 static void DnsMotivatedPrefetch(const GURL& url, 209 static void ResolveOnUIThread(const GURL& url,
209 UrlInfo::ResolutionMotivation motivation) { 210 UrlInfo::ResolutionMotivation motivation) {
210 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); 211 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
211 if (!dns_prefetch_enabled || NULL == predictor || !url.has_host()) 212 if (!dns_prefetch_enabled || NULL == predictor || !url.has_host())
212 return; 213 return;
213 214
214 ChromeThread::PostTask( 215 ChromeThread::PostTask(
215 ChromeThread::IO, 216 ChromeThread::IO,
216 FROM_HERE, 217 FROM_HERE,
217 NewRunnableMethod(predictor, 218 NewRunnableMethod(predictor,
218 &Predictor::Resolve, url, motivation)); 219 &Predictor::Resolve, url, motivation));
219 } 220 }
220 221
221 //------------------------------------------------------------------------------ 222 //------------------------------------------------------------------------------
222 // This section intermingles prefetch results with actual browser HTTP 223 // This section intermingles prefetch results with actual browser HTTP
223 // network activity. It supports calculating of the benefit of a prefetch, as 224 // network activity. It supports calculating of the benefit of a prefetch, as
224 // well as recording what prefetched hostname resolutions might be potentially 225 // well as recording what prefetched hostname resolutions might be potentially
225 // helpful during the next chrome-startup. 226 // helpful during the next chrome-startup.
226 //------------------------------------------------------------------------------ 227 //------------------------------------------------------------------------------
227 228
228 // This function determines if there was a saving by prefetching the hostname
229 // for which the navigation_info is supplied.
230 static bool AccruePrefetchBenefits(const GURL& referrer_url,
231 UrlInfo* navigation_info) {
232 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
233 if (!dns_prefetch_enabled || NULL == predictor)
234 return false;
235 DCHECK(referrer_url == referrer_url.GetWithEmptyPath());
236 return predictor->AccruePrefetchBenefits(referrer_url, navigation_info);
237 }
238
239 void PredictSubresources(const GURL& url) {
240 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
241 if (!dns_prefetch_enabled || NULL == predictor)
242 return;
243 predictor->PredictSubresources(url);
244 }
245
246 void PredictFrameSubresources(const GURL& url) { 229 void PredictFrameSubresources(const GURL& url) {
247 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 230 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
248 if (!dns_prefetch_enabled || NULL == predictor) 231 if (!dns_prefetch_enabled || NULL == predictor)
249 return; 232 return;
250 predictor->PredictFrameSubresources(url); 233 predictor->PredictFrameSubresources(url);
251 } 234 }
252 235
253 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) { 236 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
254 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 237 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
255 if (!dns_prefetch_enabled || NULL == predictor) 238 if (!dns_prefetch_enabled || NULL == predictor)
256 return; 239 return;
257 predictor->LearnFromNavigation(referring_url, target_url); 240 predictor->LearnFromNavigation(referring_url, target_url);
258 } 241 }
259 242
260 // The observer class needs to connect starts and finishes of HTTP network 243 // The observer class needs to connect starts and finishes of HTTP network
261 // resolutions. We use the following type for that map. 244 // resolutions. We use the following type for that map.
262 typedef std::map<int, UrlInfo> ObservedResolutionMap; 245 typedef std::map<int, UrlInfo> ObservedResolutionMap;
263 246
264 // There will only be one instance ever created of the following Observer 247 // There will only be one instance ever created of the following Observer
265 // class. The PrefetchObserver lives on the IO thread, and intercepts DNS 248 // class. The PrefetchObserver lives on the IO thread, and intercepts DNS
266 // resolutions made by the network stack. 249 // resolutions made by the network stack. This is only used to identify startup
250 // time resolutions (for re-resolution during our next process startup).
267 class PrefetchObserver : public net::HostResolver::Observer { 251 class PrefetchObserver : public net::HostResolver::Observer {
268 public: 252 public:
269 typedef std::map<GURL, UrlInfo> FirstResolutionMap; 253 typedef std::set<GURL> FirstResolutions;
270 254
271 // net::HostResolver::Observer implementation: 255 // net::HostResolver::Observer implementation:
272 virtual void OnStartResolution( 256 virtual void OnStartResolution(
273 int request_id, 257 int request_id,
274 const net::HostResolver::RequestInfo& request_info); 258 const net::HostResolver::RequestInfo& request_info) {}
275 virtual void OnFinishResolutionWithStatus(
276 int request_id,
277 bool was_resolved,
278 const net::HostResolver::RequestInfo& request_info);
279 virtual void OnCancelResolution(
280 int request_id,
281 const net::HostResolver::RequestInfo& request_info);
282 259
283 void DnsGetFirstResolutionsHtml(std::string* output); 260 virtual void OnFinishResolutionWithStatus(int id, bool was_resolved,
261 const net::HostResolver::RequestInfo& info);
262
263 virtual void OnCancelResolution(int id,
264 const net::HostResolver::RequestInfo& info) {}
265
266 void DnsGetFirstResolutionsHtml(std::string* output);
284 void GetInitialDnsResolutionList(ListValue* startup_list); 267 void GetInitialDnsResolutionList(ListValue* startup_list);
285 268
286 private: 269 private:
287 void StartupListAppend(const UrlInfo& navigation_info); 270 void StartupListAppend(const std::string& host, int port);
288 271
289 // Map of pending resolutions seen by observer. 272 // List of the first N URL resolutions observed in this run.
290 ObservedResolutionMap resolutions_; 273 FirstResolutions first_resolutions_;
291 // List of the first N hostname resolutions observed in this run. 274 // The number of URLs we'll save for pre-resolving at next startup.
292 FirstResolutionMap first_resolutions_;
293 // The number of hostnames we'll save for prefetching at next startup.
294 static const size_t kStartupResolutionCount = 10; 275 static const size_t kStartupResolutionCount = 10;
295 }; 276 };
296 277
297 // TODO(willchan): Look at killing this global. 278 // TODO(willchan): Look at killing this global.
298 static PrefetchObserver* g_prefetch_observer = NULL; 279 static PrefetchObserver* g_prefetch_observer = NULL;
299 280
300 //------------------------------------------------------------------------------ 281 //------------------------------------------------------------------------------
301 // Member definitions for above Observer class. 282 // Member definitions for above Observer class.
302 283
303 void PrefetchObserver::OnStartResolution(
304 int request_id,
305 const net::HostResolver::RequestInfo& request_info) {
306 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
307 if (request_info.is_speculative())
308 return; // One of our own requests.
309 if (!request_info.hostname().length())
310 return; // PAC scripts may create queries without a hostname.
311
312 UrlInfo navigation_info;
313 // TODO(jar): Remove hack which guestimates ssl via port number, and perhaps
314 // have actual URL passed down in request_info instead.
315 bool is_ssl(443 == request_info.port());
316 std::string url_spec = is_ssl ? "https://" : "http://";
317 url_spec += request_info.hostname();
318 url_spec += ":";
319 url_spec += IntToString(request_info.port());
320 navigation_info.SetUrl(GURL(url_spec));
321 navigation_info.SetStartedState();
322
323 // This entry will be deleted either by OnFinishResolutionWithStatus(), or
324 // by OnCancelResolution().
325 resolutions_[request_id] = navigation_info;
326 }
327
328 void PrefetchObserver::OnFinishResolutionWithStatus( 284 void PrefetchObserver::OnFinishResolutionWithStatus(
329 int request_id, 285 int request_id,
330 bool was_resolved, 286 bool was_resolved,
331 const net::HostResolver::RequestInfo& request_info) { 287 const net::HostResolver::RequestInfo& request_info) {
332 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 288 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
333 if (request_info.is_speculative()) 289 if (!was_resolved)
334 return; // One of our own requests. 290 return; // Don't remember failures.
335 if (!request_info.hostname().length())
336 return; // PAC scripts may create queries without a hostname.
337 UrlInfo navigation_info;
338 size_t startup_count = 0;
339 {
340 ObservedResolutionMap::iterator it = resolutions_.find(request_id);
341 if (resolutions_.end() == it) {
342 NOTREACHED();
343 return;
344 }
345 navigation_info = it->second;
346 resolutions_.erase(it);
347 startup_count = first_resolutions_.size();
348 }
349
350 navigation_info.SetFinishedState(was_resolved); // Get timing info
351 AccruePrefetchBenefits(CanonicalizeUrl(request_info.referrer()),
352 &navigation_info);
353
354 // Handle sub-resource resolutions now that the critical navigational
355 // resolution has completed. This prevents us from in any way delaying that
356 // navigational resolution.
357 std::string url_spec;
358 StringAppendF(&url_spec, "http%s://%s:%d", "",
359 request_info.hostname().c_str(), request_info.port());
360 PredictSubresources(GURL(url_spec));
361
362 if (kStartupResolutionCount <= startup_count || !was_resolved)
363 return;
364 // TODO(jar): Don't add host to our list if it is a non-linked lookup, and
365 // instead rely on Referrers to pull this in automatically with the enclosing
366 // page load (once we start to persist elements of our referrer tree).
367 StartupListAppend(navigation_info);
368 }
369
370 void PrefetchObserver::OnCancelResolution(
371 int request_id,
372 const net::HostResolver::RequestInfo& request_info) {
373 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
374 if (request_info.is_speculative()) 291 if (request_info.is_speculative())
375 return; // One of our own requests. 292 return; // One of our own requests.
376 if (!request_info.hostname().length()) 293 if (!request_info.hostname().length())
377 return; // PAC scripts may create queries without a hostname. 294 return; // PAC scripts may create queries without a hostname.
378 295
379 // Remove the entry from |resolutions| that was added by OnStartResolution(). 296 StartupListAppend(request_info.hostname(), request_info.port());
380 ObservedResolutionMap::iterator it = resolutions_.find(request_id);
381 if (resolutions_.end() == it) {
382 NOTREACHED();
383 return;
384 }
385 resolutions_.erase(it);
386 } 297 }
387 298
388 void PrefetchObserver::StartupListAppend(const UrlInfo& navigation_info) { 299 void PrefetchObserver::StartupListAppend(const std::string& host, int port) {
389 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 300 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
390 301
391 if (!on_the_record_switch || NULL == predictor) 302 if (!on_the_record_switch || NULL == predictor)
392 return; 303 return;
393 if (kStartupResolutionCount <= first_resolutions_.size()) 304 if (kStartupResolutionCount <= first_resolutions_.size())
394 return; // Someone just added the last item. 305 return; // Someone just added the last item.
395 if (ContainsKey(first_resolutions_, navigation_info.url())) 306
396 return; // We already have this hostname listed. 307 // TODO(jar): Switch to using speculative_interceptor_ instead of
397 first_resolutions_[navigation_info.url()] = navigation_info; 308 // PrefetchObserver.
309 bool is_ssl(443 == port);
310 std::string url_spec = is_ssl ? "https://" : "http://";
311 url_spec += host;
312 url_spec += ":";
313 url_spec += IntToString(port);
314
315 GURL url(url_spec);
316 first_resolutions_.insert(url);
398 } 317 }
399 318
400 void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) { 319 void PrefetchObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
401 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 320 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
402 DCHECK(startup_list); 321 DCHECK(startup_list);
403 startup_list->Clear(); 322 startup_list->Clear();
404 DCHECK_EQ(0u, startup_list->GetSize()); 323 DCHECK_EQ(0u, startup_list->GetSize());
405 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion)); 324 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
406 for (FirstResolutionMap::iterator it = first_resolutions_.begin(); 325 for (FirstResolutions::iterator it = first_resolutions_.begin();
407 it != first_resolutions_.end(); 326 it != first_resolutions_.end();
408 ++it) { 327 ++it) {
409 DCHECK(it->first == CanonicalizeUrl(it->first)); 328 DCHECK(*it == CanonicalizeUrl(*it));
410 startup_list->Append(new StringValue(it->first.spec())); 329 startup_list->Append(new StringValue(it->spec()));
411 } 330 }
412 } 331 }
413 332
414 void PrefetchObserver::DnsGetFirstResolutionsHtml(std::string* output) { 333 void PrefetchObserver::DnsGetFirstResolutionsHtml(std::string* output) {
415 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 334 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
416 335
417 UrlInfo::DnsInfoTable resolution_list; 336 UrlInfo::UrlInfoTable resolution_list;
418 { 337 {
419 for (FirstResolutionMap::iterator it(first_resolutions_.begin()); 338 for (FirstResolutions::iterator it(first_resolutions_.begin());
420 it != first_resolutions_.end(); 339 it != first_resolutions_.end();
421 it++) { 340 it++) {
422 resolution_list.push_back(it->second); 341 UrlInfo info;
342 info.SetUrl(*it);
343 // TODO(jar): Need to set time of info.GetDuration();
344 resolution_list.push_back(info);
423 } 345 }
424 } 346 }
425 UrlInfo::GetHtmlTable(resolution_list, 347 UrlInfo::GetHtmlTable(resolution_list,
426 "Future startups will prefetch DNS records for ", false, output); 348 "Future startups will prefetch DNS records for ", false, output);
427 } 349 }
428 350
429 //------------------------------------------------------------------------------ 351 //------------------------------------------------------------------------------
430 // Support observer to detect opening and closing of OffTheRecord windows. 352 // Support observer to detect opening and closing of OffTheRecord windows.
431 // This object lives on the UI thread. 353 // This object lives on the UI thread.
432 354
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 Preconnect::SetPreconnectDespiteProxy(proconnect_despite_proxy); 672 Preconnect::SetPreconnectDespiteProxy(proconnect_despite_proxy);
751 673
752 DCHECK(!predictor); 674 DCHECK(!predictor);
753 InitNetworkPredictor(max_queueing_delay, max_concurrent, user_prefs, 675 InitNetworkPredictor(max_queueing_delay, max_concurrent, user_prefs,
754 local_state, preconnect_enabled); 676 local_state, preconnect_enabled);
755 } 677 }
756 } 678 }
757 679
758 680
759 } // namespace chrome_browser_net 681 } // namespace chrome_browser_net
OLDNEW
« no previous file with comments | « chrome/browser/net/predictor_api.h ('k') | chrome/browser/net/predictor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698