Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "chrome/browser/net/predictor.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <sstream> | 10 #include <sstream> |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 | 97 |
| 98 static int g_max_queueing_delay_ms = | 98 static int g_max_queueing_delay_ms = |
| 99 Predictor::kMaxSpeculativeResolveQueueDelayMs; | 99 Predictor::kMaxSpeculativeResolveQueueDelayMs; |
| 100 static size_t g_max_parallel_resolves = | 100 static size_t g_max_parallel_resolves = |
| 101 Predictor::kMaxSpeculativeParallelResolves; | 101 Predictor::kMaxSpeculativeParallelResolves; |
| 102 | 102 |
| 103 // A version number for prefs that are saved. This should be incremented when | 103 // A version number for prefs that are saved. This should be incremented when |
| 104 // we change the format so that we discard old data. | 104 // we change the format so that we discard old data. |
| 105 static const int kPredictorStartupFormatVersion = 1; | 105 static const int kPredictorStartupFormatVersion = 1; |
| 106 | 106 |
| 107 class Predictor::LookupRequest { | |
| 108 public: | |
| 109 LookupRequest(Predictor* predictor, | |
| 110 net::HostResolver* host_resolver, | |
| 111 const GURL& url) | |
| 112 : predictor_(predictor), | |
| 113 url_(url), | |
| 114 resolver_(host_resolver) { | |
| 115 } | |
| 116 | |
| 117 // Return underlying network resolver status. | |
| 118 // net::OK ==> Host was found synchronously. | |
| 119 // net:ERR_IO_PENDING ==> Network will callback later with result. | |
| 120 // anything else ==> Host was not found synchronously. | |
| 121 int Start() { | |
| 122 net::HostResolver::RequestInfo resolve_info( | |
| 123 net::HostPortPair::FromURL(url_)); | |
| 124 | |
| 125 // Make a note that this is a speculative resolve request. This allows us | |
| 126 // to separate it from real navigations in the observer's callback, and | |
| 127 // lets the HostResolver know it can de-prioritize it. | |
| 128 resolve_info.set_is_speculative(true); | |
| 129 return resolver_.Resolve( | |
| 130 resolve_info, | |
| 131 net::DEFAULT_PRIORITY, | |
| 132 &addresses_, | |
| 133 base::Bind(&LookupRequest::OnLookupFinished, base::Unretained(this)), | |
| 134 net::BoundNetLog()); | |
| 135 } | |
| 136 | |
| 137 private: | |
| 138 void OnLookupFinished(int result) { | |
| 139 predictor_->OnLookupFinished(this, url_, result == net::OK); | |
| 140 } | |
| 141 | |
| 142 Predictor* predictor_; // The predictor which started us. | |
| 143 | |
| 144 const GURL url_; // Hostname to resolve. | |
| 145 net::SingleRequestHostResolver resolver_; | |
| 146 net::AddressList addresses_; | |
| 147 | |
| 148 DISALLOW_COPY_AND_ASSIGN(LookupRequest); | |
| 149 }; | |
| 150 | |
| 151 Predictor::Predictor(bool preconnect_enabled, bool predictor_enabled) | 107 Predictor::Predictor(bool preconnect_enabled, bool predictor_enabled) |
| 152 : url_request_context_getter_(NULL), | 108 : url_request_context_getter_(NULL), |
| 153 predictor_enabled_(predictor_enabled), | 109 predictor_enabled_(predictor_enabled), |
| 154 user_prefs_(NULL), | 110 user_prefs_(NULL), |
| 155 profile_io_data_(NULL), | 111 profile_io_data_(NULL), |
| 112 num_pending_lookups_(0), | |
| 156 peak_pending_lookups_(0), | 113 peak_pending_lookups_(0), |
| 157 shutdown_(false), | 114 shutdown_(false), |
| 158 max_concurrent_dns_lookups_(g_max_parallel_resolves), | 115 max_concurrent_dns_lookups_(g_max_parallel_resolves), |
| 159 max_dns_queue_delay_( | 116 max_dns_queue_delay_( |
| 160 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), | 117 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), |
| 161 host_resolver_(NULL), | |
| 162 transport_security_state_(NULL), | 118 transport_security_state_(NULL), |
| 163 ssl_config_service_(NULL), | 119 ssl_config_service_(NULL), |
| 164 proxy_service_(NULL), | 120 proxy_service_(NULL), |
| 165 preconnect_enabled_(preconnect_enabled), | 121 preconnect_enabled_(preconnect_enabled), |
| 166 consecutive_omnibox_preconnect_count_(0), | 122 consecutive_omnibox_preconnect_count_(0), |
| 167 next_trim_time_(base::TimeTicks::Now() + | 123 next_trim_time_(base::TimeTicks::Now() + |
| 168 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)), | 124 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)), |
| 169 observer_(NULL) { | 125 observer_(NULL) { |
| 170 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 126 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 171 } | 127 } |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 } | 347 } |
| 392 | 348 |
| 393 // ---------------------- End UI methods. ------------------------------------- | 349 // ---------------------- End UI methods. ------------------------------------- |
| 394 | 350 |
| 395 // --------------------- Start IO methods. ------------------------------------ | 351 // --------------------- Start IO methods. ------------------------------------ |
| 396 | 352 |
| 397 void Predictor::Shutdown() { | 353 void Predictor::Shutdown() { |
| 398 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 354 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 399 DCHECK(!shutdown_); | 355 DCHECK(!shutdown_); |
| 400 shutdown_ = true; | 356 shutdown_ = true; |
| 401 | |
| 402 STLDeleteElements(&pending_lookups_); | |
| 403 } | 357 } |
| 404 | 358 |
| 405 void Predictor::DiscardAllResults() { | 359 void Predictor::DiscardAllResults() { |
| 406 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 360 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 407 // Delete anything listed so far in this session that shows in about:dns. | 361 // Delete anything listed so far in this session that shows in about:dns. |
| 408 referrers_.clear(); | 362 referrers_.clear(); |
| 409 | 363 |
| 410 | 364 |
| 411 // Try to delete anything in our work queue. | 365 // Try to delete anything in our work queue. |
| 412 while (!work_queue_.IsEmpty()) { | 366 while (!work_queue_.IsEmpty()) { |
| 413 // Emulate processing cycle as though host was not found. | 367 // Emulate processing cycle as though host was not found. |
| 414 GURL url = work_queue_.Pop(); | 368 GURL url = work_queue_.Pop(); |
| 415 UrlInfo* info = &results_[url]; | 369 UrlInfo* info = &results_[url]; |
| 416 DCHECK(info->HasUrl(url)); | 370 DCHECK(info->HasUrl(url)); |
| 417 info->SetAssignedState(); | 371 info->SetAssignedState(); |
| 418 info->SetNoSuchNameState(); | 372 info->SetNoSuchNameState(); |
| 419 } | 373 } |
| 420 // Now every result_ is either resolved, or is being resolved | 374 // Now every result_ is either resolved, or is being resolved. |
| 421 // (see LookupRequest). | |
| 422 | 375 |
| 423 // Step through result_, recording names of all hosts that can't be erased. | 376 // Step through result_, recording names of all hosts that can't be erased. |
| 424 // We can't erase anything being worked on. | 377 // We can't erase anything being worked on. |
| 425 Results assignees; | 378 Results assignees; |
| 426 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { | 379 for (Results::iterator it = results_.begin(); results_.end() != it; ++it) { |
| 427 GURL url(it->first); | 380 GURL url(it->first); |
| 428 UrlInfo* info = &it->second; | 381 UrlInfo* info = &it->second; |
| 429 DCHECK(info->HasUrl(url)); | 382 DCHECK(info->HasUrl(url)); |
| 430 if (info->is_assigned()) { | 383 if (info->is_assigned()) { |
| 431 info->SetPendingDeleteState(); | 384 info->SetPendingDeleteState(); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 686 | 639 |
| 687 void Predictor::FinalizeInitializationOnIOThread( | 640 void Predictor::FinalizeInitializationOnIOThread( |
| 688 const UrlList& startup_urls, | 641 const UrlList& startup_urls, |
| 689 base::ListValue* referral_list, | 642 base::ListValue* referral_list, |
| 690 IOThread* io_thread, | 643 IOThread* io_thread, |
| 691 ProfileIOData* profile_io_data) { | 644 ProfileIOData* profile_io_data) { |
| 692 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 645 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 693 | 646 |
| 694 profile_io_data_ = profile_io_data; | 647 profile_io_data_ = profile_io_data; |
| 695 initial_observer_.reset(new InitialObserver()); | 648 initial_observer_.reset(new InitialObserver()); |
| 696 host_resolver_ = io_thread->globals()->host_resolver.get(); | |
| 697 | 649 |
| 698 net::URLRequestContext* context = | 650 net::URLRequestContext* context = |
| 699 url_request_context_getter_->GetURLRequestContext(); | 651 url_request_context_getter_->GetURLRequestContext(); |
| 700 transport_security_state_ = context->transport_security_state(); | 652 transport_security_state_ = context->transport_security_state(); |
| 701 ssl_config_service_ = context->ssl_config_service(); | 653 ssl_config_service_ = context->ssl_config_service(); |
| 702 proxy_service_ = context->proxy_service(); | 654 proxy_service_ = context->proxy_service(); |
| 703 | 655 |
| 704 // base::WeakPtrFactory instances need to be created and destroyed | 656 // base::WeakPtrFactory instances need to be created and destroyed |
| 705 // on the same thread. The predictor lives on the IO thread and will die | 657 // on the same thread. The predictor lives on the IO thread and will die |
| 706 // from there so now that we're on the IO thread we need to properly | 658 // from there so now that we're on the IO thread we need to properly |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 869 void Predictor::PreconnectUrlOnIOThread( | 821 void Predictor::PreconnectUrlOnIOThread( |
| 870 const GURL& original_url, | 822 const GURL& original_url, |
| 871 const GURL& first_party_for_cookies, | 823 const GURL& first_party_for_cookies, |
| 872 UrlInfo::ResolutionMotivation motivation, | 824 UrlInfo::ResolutionMotivation motivation, |
| 873 bool allow_credentials, | 825 bool allow_credentials, |
| 874 int count) { | 826 int count) { |
| 875 // Skip the HSTS redirect. | 827 // Skip the HSTS redirect. |
| 876 GURL url = GetHSTSRedirectOnIOThread(original_url); | 828 GURL url = GetHSTSRedirectOnIOThread(original_url); |
| 877 | 829 |
| 878 // TODO(csharrison): The observer should only be notified after the null check | 830 // TODO(csharrison): The observer should only be notified after the null check |
| 879 // for the URLRequestContextGetter. The predictor tests should be fixed to | 831 // for the ProfileIOData. The predictor tests should be fixed to allow for |
| 880 // allow for this, as they currently expect a callback with no getter. | 832 // this, as they currently expect a callback with no getter. |
| 881 // URLRequestContextGetter is null. Tests rely on this behavior. | |
| 882 if (observer_) { | 833 if (observer_) { |
| 883 observer_->OnPreconnectUrl( | 834 observer_->OnPreconnectUrl( |
| 884 url, first_party_for_cookies, motivation, count); | 835 url, first_party_for_cookies, motivation, count); |
| 885 } | 836 } |
| 886 | 837 |
| 887 net::URLRequestContextGetter* getter = url_request_context_getter_.get(); | 838 if (!profile_io_data_) |
| 888 if (!getter) | |
| 889 return; | 839 return; |
| 890 | 840 |
| 891 // Translate the motivation from UrlRequest motivations to HttpRequest | 841 // Translate the motivation from UrlRequest motivations to HttpRequest |
| 892 // motivations. | 842 // motivations. |
| 893 net::HttpRequestInfo::RequestMotivation request_motivation = | 843 net::HttpRequestInfo::RequestMotivation request_motivation = |
| 894 net::HttpRequestInfo::NORMAL_MOTIVATION; | 844 net::HttpRequestInfo::NORMAL_MOTIVATION; |
| 895 switch (motivation) { | 845 switch (motivation) { |
| 896 case UrlInfo::OMNIBOX_MOTIVATED: | 846 case UrlInfo::OMNIBOX_MOTIVATED: |
| 897 request_motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED; | 847 request_motivation = net::HttpRequestInfo::OMNIBOX_MOTIVATED; |
| 898 break; | 848 break; |
| 899 case UrlInfo::LEARNED_REFERAL_MOTIVATED: | 849 case UrlInfo::LEARNED_REFERAL_MOTIVATED: |
| 900 request_motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED; | 850 request_motivation = net::HttpRequestInfo::PRECONNECT_MOTIVATED; |
| 901 break; | 851 break; |
| 902 case UrlInfo::MOUSE_OVER_MOTIVATED: | 852 case UrlInfo::MOUSE_OVER_MOTIVATED: |
| 903 case UrlInfo::SELF_REFERAL_MOTIVATED: | 853 case UrlInfo::SELF_REFERAL_MOTIVATED: |
| 904 case UrlInfo::EARLY_LOAD_MOTIVATED: | 854 case UrlInfo::EARLY_LOAD_MOTIVATED: |
| 905 request_motivation = net::HttpRequestInfo::EARLY_LOAD_MOTIVATED; | 855 request_motivation = net::HttpRequestInfo::EARLY_LOAD_MOTIVATED; |
| 906 break; | 856 break; |
| 907 default: | 857 default: |
| 908 // Other motivations should never happen here. | 858 // Other motivations should never happen here. |
| 909 NOTREACHED(); | 859 NOTREACHED(); |
| 910 break; | 860 break; |
| 911 } | 861 } |
| 912 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation, | 862 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation, |
| 913 UrlInfo::MAX_MOTIVATED); | 863 UrlInfo::MAX_MOTIVATED); |
| 914 content::PreconnectUrl(getter, url, first_party_for_cookies, count, | 864 content::PreconnectUrl(profile_io_data_->GetResourceContext(), url, |
| 915 allow_credentials, request_motivation); | 865 first_party_for_cookies, count, allow_credentials, |
| 866 request_motivation); | |
| 916 } | 867 } |
| 917 | 868 |
| 918 void Predictor::PredictFrameSubresources(const GURL& url, | 869 void Predictor::PredictFrameSubresources(const GURL& url, |
| 919 const GURL& first_party_for_cookies) { | 870 const GURL& first_party_for_cookies) { |
| 920 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | 871 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
| 921 BrowserThread::CurrentlyOn(BrowserThread::IO)); | 872 BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 922 if (!predictor_enabled_) | 873 if (!predictor_enabled_) |
| 923 return; | 874 return; |
| 924 if (!CanPreresolveAndPreconnect()) | 875 if (!CanPreresolveAndPreconnect()) |
| 925 return; | 876 return; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1016 UrlInfo* queued_info = AppendToResolutionQueue(future_url->first, | 967 UrlInfo* queued_info = AppendToResolutionQueue(future_url->first, |
| 1017 motivation); | 968 motivation); |
| 1018 if (queued_info) | 969 if (queued_info) |
| 1019 queued_info->SetReferringHostname(url); | 970 queued_info->SetReferringHostname(url); |
| 1020 } | 971 } |
| 1021 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution, | 972 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution, |
| 1022 SUBRESOURCE_VALUE_MAX); | 973 SUBRESOURCE_VALUE_MAX); |
| 1023 } | 974 } |
| 1024 } | 975 } |
| 1025 | 976 |
| 1026 void Predictor::OnLookupFinished(LookupRequest* request, const GURL& url, | 977 void Predictor::OnLookupFinished(const GURL& url, int result) { |
| 1027 bool found) { | |
| 1028 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 978 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1029 | 979 |
| 1030 LookupFinished(request, url, found); | 980 LookupFinished(url, result == net::OK); |
| 1031 pending_lookups_.erase(request); | 981 DCHECK_GT(num_pending_lookups_, 0u); |
| 1032 delete request; | 982 num_pending_lookups_--; |
| 1033 | |
| 1034 StartSomeQueuedResolutions(); | 983 StartSomeQueuedResolutions(); |
| 1035 } | 984 } |
| 1036 | 985 |
| 1037 void Predictor::LookupFinished(LookupRequest* request, const GURL& url, | 986 void Predictor::LookupFinished(const GURL& url, bool found) { |
| 1038 bool found) { | |
| 1039 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 987 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1040 UrlInfo* info = &results_[url]; | 988 UrlInfo* info = &results_[url]; |
| 1041 DCHECK(info->HasUrl(url)); | 989 DCHECK(info->HasUrl(url)); |
| 1042 if (info->is_marked_to_delete()) { | 990 if (info->is_marked_to_delete()) { |
| 1043 results_.erase(url); | 991 results_.erase(url); |
| 1044 } else { | 992 } else { |
| 1045 if (found) | 993 if (found) |
| 1046 info->SetFoundState(); | 994 info->SetFoundState(); |
| 1047 else | 995 else |
| 1048 info->SetNoSuchNameState(); | 996 info->SetNoSuchNameState(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1108 break; | 1056 break; |
| 1109 info = &results_[work_queue_.Pop()]; | 1057 info = &results_[work_queue_.Pop()]; |
| 1110 info->SetAssignedState(); | 1058 info->SetAssignedState(); |
| 1111 } | 1059 } |
| 1112 return true; | 1060 return true; |
| 1113 } | 1061 } |
| 1114 | 1062 |
| 1115 void Predictor::StartSomeQueuedResolutions() { | 1063 void Predictor::StartSomeQueuedResolutions() { |
| 1116 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1064 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1117 | 1065 |
| 1118 // If the queue is disabled, just make LookupRequests for all entries. | 1066 // If the queue is disabled, just make requests for all entries. |
| 1119 bool enable_queue = base::FeatureList::IsEnabled(kUsePredictorDNSQueue); | 1067 bool enable_queue = base::FeatureList::IsEnabled(kUsePredictorDNSQueue); |
| 1120 while (!work_queue_.IsEmpty() && | 1068 while ( |
| 1121 (!enable_queue || | 1069 !work_queue_.IsEmpty() && |
| 1122 pending_lookups_.size() < max_concurrent_dns_lookups_)) { | 1070 (!enable_queue || num_pending_lookups_ < max_concurrent_dns_lookups_)) { |
| 1123 const GURL url(work_queue_.Pop()); | 1071 const GURL url(work_queue_.Pop()); |
| 1124 UrlInfo* info = &results_[url]; | 1072 UrlInfo* info = &results_[url]; |
| 1125 DCHECK(info->HasUrl(url)); | 1073 DCHECK(info->HasUrl(url)); |
| 1126 info->SetAssignedState(); | 1074 info->SetAssignedState(); |
| 1127 | 1075 |
| 1128 // Only perform congestion control if the queue is enabled. | 1076 // Only perform congestion control if the queue is enabled. |
| 1129 if (enable_queue && CongestionControlPerformed(info)) { | 1077 if (enable_queue && CongestionControlPerformed(info)) { |
| 1130 DCHECK(work_queue_.IsEmpty()); | 1078 DCHECK(work_queue_.IsEmpty()); |
| 1131 return; | 1079 return; |
| 1132 } | 1080 } |
| 1133 | 1081 |
| 1134 LookupRequest* request = new LookupRequest(this, host_resolver_, url); | 1082 int status = content::PreresolveUrl( |
| 1135 | 1083 profile_io_data_->GetResourceContext(), url, |
| 1136 int status = request->Start(); | 1084 base::Bind(&Predictor::OnLookupFinished, base::Unretained(this), url)); |
|
kinuko
2016/05/24 09:15:27
Who guarantees the callback is called while |this|
Charlie Harrison
2016/05/24 13:14:22
Good question. The semantics shouldn't be changed
kinuko
2016/05/24 14:38:34
If we just want to disallow running the callback w
Charlie Harrison
2016/05/24 16:06:36
That works :) I scanned through the ownership and
| |
| 1137 if (status == net::ERR_IO_PENDING) { | 1085 if (status == net::ERR_IO_PENDING) { |
| 1138 // Will complete asynchronously. | 1086 // Will complete asynchronously. |
| 1139 pending_lookups_.insert(request); | 1087 num_pending_lookups_++; |
| 1140 peak_pending_lookups_ = std::max(peak_pending_lookups_, | 1088 peak_pending_lookups_ = |
| 1141 pending_lookups_.size()); | 1089 std::max(peak_pending_lookups_, num_pending_lookups_); |
| 1142 } else { | 1090 } else { |
| 1143 // Completed synchronously (was already cached by HostResolver), or else | 1091 // Completed synchronously (was already cached by HostResolver), or else |
| 1144 // there was (equivalently) some network error that prevents us from | 1092 // there was (equivalently) some network error that prevents us from |
| 1145 // finding the name. Status net::OK means it was "found." | 1093 // finding the name. Status net::OK means it was "found." |
| 1146 LookupFinished(request, url, status == net::OK); | 1094 LookupFinished(url, status == net::OK); |
| 1147 delete request; | |
| 1148 } | 1095 } |
| 1149 } | 1096 } |
| 1150 } | 1097 } |
| 1151 | 1098 |
| 1152 void Predictor::TrimReferrers() { | 1099 void Predictor::TrimReferrers() { |
| 1153 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1100 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1154 if (!urls_being_trimmed_.empty()) | 1101 if (!urls_being_trimmed_.empty()) |
| 1155 return; // There is incremental trimming in progress already. | 1102 return; // There is incremental trimming in progress already. |
| 1156 | 1103 |
| 1157 // Check to see if it is time to trim yet. | 1104 // Check to see if it is time to trim yet. |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1359 } | 1306 } |
| 1360 | 1307 |
| 1361 void SimplePredictor::ShutdownOnUIThread() { | 1308 void SimplePredictor::ShutdownOnUIThread() { |
| 1362 SetShutdown(true); | 1309 SetShutdown(true); |
| 1363 } | 1310 } |
| 1364 | 1311 |
| 1365 bool SimplePredictor::CanPrefetchAndPrerender() const { return true; } | 1312 bool SimplePredictor::CanPrefetchAndPrerender() const { return true; } |
| 1366 bool SimplePredictor::CanPreresolveAndPreconnect() const { return true; } | 1313 bool SimplePredictor::CanPreresolveAndPreconnect() const { return true; } |
| 1367 | 1314 |
| 1368 } // namespace chrome_browser_net | 1315 } // namespace chrome_browser_net |
| OLD | NEW |