Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/search/suggestions/suggestions_service.h" | 5 #include "chrome/browser/search/suggestions/suggestions_service.h" |
| 6 | 6 |
| 7 #include <sstream> | |
| 8 #include <string> | |
| 9 | |
| 7 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/metrics/field_trial.h" | 11 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 10 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" |
| 11 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 12 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 13 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 14 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
| 15 #include "chrome/browser/history/history_types.h" | 18 #include "chrome/browser/history/history_types.h" |
| 16 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 19 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 20 #include "chrome/browser/profiles/profile.h" |
| 21 #include "chrome/browser/search/suggestions/blacklist_store.h" | |
| 18 #include "chrome/browser/search/suggestions/suggestions_store.h" | 22 #include "chrome/browser/search/suggestions/suggestions_store.h" |
| 19 #include "components/pref_registry/pref_registry_syncable.h" | 23 #include "components/pref_registry/pref_registry_syncable.h" |
| 20 #include "components/variations/variations_associated_data.h" | 24 #include "components/variations/variations_associated_data.h" |
| 21 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 22 #include "net/base/escape.h" | 26 #include "net/base/escape.h" |
| 23 #include "net/base/load_flags.h" | 27 #include "net/base/load_flags.h" |
| 24 #include "net/base/net_errors.h" | 28 #include "net/base/net_errors.h" |
| 29 #include "net/base/url_util.h" | |
| 25 #include "net/http/http_response_headers.h" | 30 #include "net/http/http_response_headers.h" |
| 26 #include "net/http/http_status_code.h" | 31 #include "net/http/http_status_code.h" |
| 27 #include "net/http/http_util.h" | 32 #include "net/http/http_util.h" |
| 28 #include "net/url_request/url_fetcher.h" | 33 #include "net/url_request/url_fetcher.h" |
| 29 #include "net/url_request/url_request_status.h" | 34 #include "net/url_request/url_request_status.h" |
| 30 #include "url/gurl.h" | 35 #include "url/gurl.h" |
| 31 | 36 |
| 32 using base::CancelableClosure; | 37 using base::CancelableClosure; |
| 33 using content::BrowserThread; | 38 using content::BrowserThread; |
| 34 | 39 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 50 RESPONSE_STATE_SIZE); | 55 RESPONSE_STATE_SIZE); |
| 51 } | 56 } |
| 52 | 57 |
| 53 // Obtains the experiment parameter under the supplied |key|, or empty string | 58 // Obtains the experiment parameter under the supplied |key|, or empty string |
| 54 // if the parameter does not exist. | 59 // if the parameter does not exist. |
| 55 std::string GetExperimentParam(const std::string& key) { | 60 std::string GetExperimentParam(const std::string& key) { |
| 56 return chrome_variations::GetVariationParamValue(kSuggestionsFieldTrialName, | 61 return chrome_variations::GetVariationParamValue(kSuggestionsFieldTrialName, |
| 57 key); | 62 key); |
| 58 } | 63 } |
| 59 | 64 |
| 65 GURL BuildBlacklistRequestURL(const std::string& blacklist_url_prefix, | |
| 66 const GURL& candidate_url) { | |
| 67 return GURL(blacklist_url_prefix + | |
| 68 net::EscapeQueryParamValue(candidate_url.spec(), true)); | |
| 69 } | |
| 70 | |
| 60 // Runs each callback in |requestors| on |suggestions|, then deallocates | 71 // Runs each callback in |requestors| on |suggestions|, then deallocates |
| 61 // |requestors|. | 72 // |requestors|. |
| 62 void DispatchRequestsAndClear( | 73 void DispatchRequestsAndClear( |
| 63 const SuggestionsProfile& suggestions, | 74 const SuggestionsProfile& suggestions, |
| 64 std::vector<SuggestionsService::ResponseCallback>* requestors) { | 75 std::vector<SuggestionsService::ResponseCallback>* requestors) { |
| 65 std::vector<SuggestionsService::ResponseCallback>::iterator it; | 76 std::vector<SuggestionsService::ResponseCallback>::iterator it; |
| 66 for (it = requestors->begin(); it != requestors->end(); ++it) { | 77 for (it = requestors->begin(); it != requestors->end(); ++it) { |
| 67 it->Run(suggestions); | 78 if (!it->is_null()) it->Run(suggestions); |
| 68 } | 79 } |
| 69 std::vector<SuggestionsService::ResponseCallback>().swap(*requestors); | 80 std::vector<SuggestionsService::ResponseCallback>().swap(*requestors); |
| 70 } | 81 } |
| 71 | 82 |
| 72 const int kDefaultRequestTimeoutMs = 200; | 83 const int kDefaultRequestTimeoutMs = 200; |
| 73 | 84 |
| 85 // Default delay used when scheduling a blacklist request. | |
| 86 const unsigned int kBlacklistDefaultDelaySec = 1; | |
| 87 | |
| 88 // Multiplier on the delay used when scheduling a blacklist request, in case the | |
| 89 // last observed request was unsuccessful. | |
| 90 const unsigned int kBlacklistBackoffMultiplier = 2; | |
| 91 | |
| 92 // Maximum valid delay for scheduling a request. Candidate delays larger than | |
| 93 // this are rejected. This means the maximum backoff is at least 300 / 2, i.e. | |
| 94 // 2.5 minutes. | |
| 95 const unsigned int kBlacklistMaxDelaySec = 300; // 5 minutes | |
| 96 | |
| 74 } // namespace | 97 } // namespace |
| 75 | 98 |
| 76 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; | 99 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; |
| 77 const char kSuggestionsFieldTrialURLParam[] = "url"; | 100 const char kSuggestionsFieldTrialURLParam[] = "url"; |
| 78 const char kSuggestionsFieldTrialSuggestionsSuffixParam[] = | 101 const char kSuggestionsFieldTrialCommonParamsParam[] = "common_params"; |
| 79 "suggestions_suffix"; | 102 const char kSuggestionsFieldTrialBlacklistPathParam[] = "blacklist_path"; |
| 80 const char kSuggestionsFieldTrialBlacklistSuffixParam[] = "blacklist_suffix"; | 103 const char kSuggestionsFieldTrialBlacklistUrlParam[] = "blacklist_url_param"; |
| 81 const char kSuggestionsFieldTrialStateParam[] = "state"; | 104 const char kSuggestionsFieldTrialStateParam[] = "state"; |
| 82 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; | 105 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; |
| 83 const char kSuggestionsFieldTrialTimeoutMs[] = "timeout_ms"; | 106 const char kSuggestionsFieldTrialTimeoutMs[] = "timeout_ms"; |
| 84 | 107 |
| 108 namespace { | |
| 109 | |
| 110 std::string GetBlacklistUrlPrefix() { | |
| 111 std::stringstream blacklist_url_prefix_stream; | |
| 112 blacklist_url_prefix_stream | |
| 113 << GetExperimentParam(kSuggestionsFieldTrialURLParam) | |
| 114 << GetExperimentParam(kSuggestionsFieldTrialBlacklistPathParam) << "?" | |
| 115 << GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam) << "&" | |
| 116 << GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam) << "="; | |
| 117 return blacklist_url_prefix_stream.str(); | |
| 118 } | |
| 119 | |
| 120 } // namespace | |
| 121 | |
| 85 SuggestionsService::SuggestionsService( | 122 SuggestionsService::SuggestionsService( |
| 86 Profile* profile, scoped_ptr<SuggestionsStore> suggestions_store) | 123 Profile* profile, scoped_ptr<SuggestionsStore> suggestions_store, |
| 124 scoped_ptr<BlacklistStore> blacklist_store) | |
| 87 : suggestions_store_(suggestions_store.Pass()), | 125 : suggestions_store_(suggestions_store.Pass()), |
| 126 blacklist_store_(blacklist_store.Pass()), | |
| 88 thumbnail_manager_(new ThumbnailManager(profile)), | 127 thumbnail_manager_(new ThumbnailManager(profile)), |
| 89 profile_(profile), | 128 profile_(profile), |
| 129 | |
|
Mathieu
2014/06/18 19:04:53
extra line?
manzagop (departed)
2014/06/19 14:36:55
Done. Funny, clang-format was happy with it.
| |
| 130 blacklist_delay_sec_(kBlacklistDefaultDelaySec), | |
| 90 weak_ptr_factory_(this), | 131 weak_ptr_factory_(this), |
| 91 request_timeout_ms_(kDefaultRequestTimeoutMs) { | 132 request_timeout_ms_(kDefaultRequestTimeoutMs) { |
| 92 // Obtain various parameters from Variations. | 133 // Obtain various parameters from Variations. |
| 93 suggestions_url_ = | 134 suggestions_url_ = |
| 94 GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam) + | 135 GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam) + "?" + |
| 95 GetExperimentParam(kSuggestionsFieldTrialSuggestionsSuffixParam)); | 136 GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam)); |
| 96 blacklist_url_prefix_ = | 137 blacklist_url_prefix_ = GetBlacklistUrlPrefix(); |
| 97 GetExperimentParam(kSuggestionsFieldTrialURLParam) + | |
| 98 GetExperimentParam(kSuggestionsFieldTrialBlacklistSuffixParam); | |
| 99 std::string timeout = GetExperimentParam(kSuggestionsFieldTrialTimeoutMs); | 138 std::string timeout = GetExperimentParam(kSuggestionsFieldTrialTimeoutMs); |
| 100 int temp_timeout; | 139 int temp_timeout; |
| 101 if (!timeout.empty() && base::StringToInt(timeout, &temp_timeout)) { | 140 if (!timeout.empty() && base::StringToInt(timeout, &temp_timeout)) { |
| 102 request_timeout_ms_ = temp_timeout; | 141 request_timeout_ms_ = temp_timeout; |
| 103 } | 142 } |
| 104 } | 143 } |
| 105 | 144 |
| 106 SuggestionsService::~SuggestionsService() {} | 145 SuggestionsService::~SuggestionsService() {} |
| 107 | 146 |
| 108 // static | 147 // static |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 131 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 170 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 132 if (pending_request_.get()) { | 171 if (pending_request_.get()) { |
| 133 // Request already exists, so just add requestor to queue. | 172 // Request already exists, so just add requestor to queue. |
| 134 waiting_requestors_.push_back(callback); | 173 waiting_requestors_.push_back(callback); |
| 135 return; | 174 return; |
| 136 } | 175 } |
| 137 | 176 |
| 138 // Form new request. | 177 // Form new request. |
| 139 DCHECK(waiting_requestors_.empty()); | 178 DCHECK(waiting_requestors_.empty()); |
| 140 waiting_requestors_.push_back(callback); | 179 waiting_requestors_.push_back(callback); |
| 141 | 180 IssueRequest(suggestions_url_); |
| 142 pending_request_.reset(CreateSuggestionsRequest(suggestions_url_)); | |
| 143 pending_request_->Start(); | |
| 144 last_request_started_time_ = base::TimeTicks::Now(); | |
| 145 } | 181 } |
| 146 | 182 |
| 147 void SuggestionsService::GetPageThumbnail( | 183 void SuggestionsService::GetPageThumbnail( |
| 148 const GURL& url, | 184 const GURL& url, |
| 149 base::Callback<void(const GURL&, const SkBitmap*)> callback) { | 185 base::Callback<void(const GURL&, const SkBitmap*)> callback) { |
| 150 thumbnail_manager_->GetPageThumbnail(url, callback); | 186 thumbnail_manager_->GetPageThumbnail(url, callback); |
| 151 } | 187 } |
| 152 | 188 |
| 153 void SuggestionsService::BlacklistURL( | 189 void SuggestionsService::BlacklistURL( |
| 154 const GURL& candidate_url, SuggestionsService::ResponseCallback callback) { | 190 const GURL& candidate_url, |
| 191 const SuggestionsService::ResponseCallback& callback) { | |
| 155 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 156 waiting_requestors_.push_back(callback); | 193 waiting_requestors_.push_back(callback); |
| 157 | 194 |
| 158 if (pending_request_.get()) { | 195 // Blacklist locally, for immediate effect. |
| 159 if (IsBlacklistRequest(pending_request_.get())) { | 196 if (!blacklist_store_->BlacklistUrl(candidate_url)) { |
| 160 // Pending request is a blacklist request. Silently drop the new blacklist | 197 DVLOG(1) << "Failed blacklisting attempt."; |
| 161 // request. TODO - handle this case. | 198 return; |
| 162 return; | |
| 163 } else { | |
| 164 // Pending request is not a blacklist request - cancel it and go on to | |
| 165 // issuing a blacklist request. Also ensure the timeout closure does not | |
| 166 // run; instead we'll wait for the updated suggestions before servicing | |
| 167 // requestors. | |
| 168 pending_request_.reset(NULL); | |
| 169 pending_timeout_closure_.reset(NULL); | |
| 170 } | |
| 171 } | 199 } |
| 172 | 200 |
| 173 // Send blacklisting request. | 201 // If there's an ongoing request, let it complete. |
| 174 // TODO(manzagop): make this a PUT request instead of a GET request. | 202 if (pending_request_.get()) return; |
| 175 GURL url(blacklist_url_prefix_ + | 203 |
| 176 net::EscapeQueryParamValue(candidate_url.spec(), true)); | 204 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); |
| 177 pending_request_.reset(CreateSuggestionsRequest(url)); | 205 } |
| 178 pending_request_->Start(); | 206 |
| 179 last_request_started_time_ = base::TimeTicks::Now(); | 207 // static |
| 208 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, | |
| 209 GURL* url) { | |
| 210 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), | |
| 211 GetBlacklistUrlPrefix(), true); | |
| 212 if (!is_blacklist_request) return false; | |
| 213 | |
| 214 // Extract the blacklisted url from the blacklist request. | |
|
Mathieu
2014/06/18 19:04:53
*URL
manzagop (departed)
2014/06/19 14:36:56
Done. Arg! Sorry, I know I keep writing it lowerca
| |
| 215 std::string blacklisted; | |
| 216 if (!net::GetValueForKeyInQuery( | |
| 217 request.GetOriginalURL(), | |
| 218 GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam), | |
| 219 &blacklisted)) | |
| 220 return false; | |
| 221 | |
| 222 GURL blacklisted_url(blacklisted); | |
| 223 blacklisted_url.Swap(url); | |
| 224 return true; | |
| 180 } | 225 } |
| 181 | 226 |
| 182 // static | 227 // static |
| 183 void SuggestionsService::RegisterProfilePrefs( | 228 void SuggestionsService::RegisterProfilePrefs( |
| 184 user_prefs::PrefRegistrySyncable* registry) { | 229 user_prefs::PrefRegistrySyncable* registry) { |
| 185 SuggestionsStore::RegisterProfilePrefs(registry); | 230 SuggestionsStore::RegisterProfilePrefs(registry); |
| 231 BlacklistStore::RegisterProfilePrefs(registry); | |
| 232 } | |
| 233 | |
| 234 void SuggestionsService::IssueRequest(const GURL& url) { | |
| 235 pending_request_.reset(CreateSuggestionsRequest(url)); | |
| 236 pending_request_->Start(); | |
| 237 last_request_started_time_ = base::TimeTicks::Now(); | |
| 238 } | |
| 239 | |
| 240 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { | |
| 241 net::URLFetcher* request = | |
| 242 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); | |
| 243 request->SetLoadFlags(net::LOAD_DISABLE_CACHE); | |
| 244 request->SetRequestContext(profile_->GetRequestContext()); | |
| 245 // Add Chrome experiment state to the request headers. | |
| 246 net::HttpRequestHeaders headers; | |
| 247 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | |
| 248 request->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | |
| 249 request->SetExtraRequestHeaders(headers.ToString()); | |
| 250 return request; | |
| 186 } | 251 } |
| 187 | 252 |
| 188 void SuggestionsService::OnRequestTimeout() { | 253 void SuggestionsService::OnRequestTimeout() { |
| 189 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 254 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 190 ServeFromCache(); | 255 ServeFromCache(); |
| 191 } | 256 } |
| 192 | 257 |
| 193 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { | 258 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { |
| 194 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 259 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 195 DCHECK_EQ(pending_request_.get(), source); | 260 DCHECK_EQ(pending_request_.get(), source); |
| 196 | 261 |
| 197 // We no longer need the timeout closure. Delete it whether or not it has run | 262 // We no longer need the timeout closure. Delete it whether or not it has run. |
| 198 // (if it hasn't, this cancels it). | 263 // If it hasn't, this cancels it. |
| 199 pending_timeout_closure_.reset(); | 264 pending_timeout_closure_.reset(); |
| 200 | 265 |
| 201 // The fetcher will be deleted when the request is handled. | 266 // The fetcher will be deleted when the request is handled. |
| 202 scoped_ptr<const net::URLFetcher> request(pending_request_.release()); | 267 scoped_ptr<const net::URLFetcher> request(pending_request_.release()); |
| 203 const net::URLRequestStatus& request_status = request->GetStatus(); | 268 const net::URLRequestStatus& request_status = request->GetStatus(); |
| 204 if (request_status.status() != net::URLRequestStatus::SUCCESS) { | 269 if (request_status.status() != net::URLRequestStatus::SUCCESS) { |
| 205 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", | 270 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", |
| 206 -request_status.error()); | 271 -request_status.error()); |
| 207 DVLOG(1) << "Suggestions server request failed with error: " | 272 DVLOG(1) << "Suggestions server request failed with error: " |
| 208 << request_status.error() << ": " | 273 << request_status.error() << ": " |
| 209 << net::ErrorToString(request_status.error()); | 274 << net::ErrorToString(request_status.error()); |
| 210 // Dispatch the cached profile on error. | 275 // Dispatch the cached profile on error. |
| 211 ServeFromCache(); | 276 ServeFromCache(); |
| 277 ScheduleBlacklistUpload(false); | |
| 212 return; | 278 return; |
| 213 } | 279 } |
| 214 | 280 |
| 215 // Log the response code. | 281 // Log the response code. |
| 216 const int response_code = request->GetResponseCode(); | 282 const int response_code = request->GetResponseCode(); |
| 217 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); | 283 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); |
| 218 if (response_code != net::HTTP_OK) { | 284 if (response_code != net::HTTP_OK) { |
| 219 // Aggressively clear the store. | 285 // Aggressively clear the store. |
| 220 suggestions_store_->ClearSuggestions(); | 286 suggestions_store_->ClearSuggestions(); |
| 221 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_); | 287 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_); |
| 288 ScheduleBlacklistUpload(false); | |
| 222 return; | 289 return; |
| 223 } | 290 } |
| 224 | 291 |
| 225 const base::TimeDelta latency = | 292 const base::TimeDelta latency = |
| 226 base::TimeTicks::Now() - last_request_started_time_; | 293 base::TimeTicks::Now() - last_request_started_time_; |
| 227 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); | 294 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); |
| 228 | 295 |
| 296 // Handle a successful blacklisting. | |
| 297 GURL blacklisted_url; | |
| 298 if (GetBlacklistedUrl(*source, &blacklisted_url)) { | |
| 299 blacklist_store_->RemoveUrl(blacklisted_url); | |
| 300 } | |
| 301 | |
| 229 std::string suggestions_data; | 302 std::string suggestions_data; |
| 230 bool success = request->GetResponseAsString(&suggestions_data); | 303 bool success = request->GetResponseAsString(&suggestions_data); |
| 231 DCHECK(success); | 304 DCHECK(success); |
| 232 | 305 |
| 233 // Compute suggestions, and dispatch then to requestors. On error still | 306 // Compute suggestions, and dispatch then to requestors. On error still |
| 234 // dispatch empty suggestions. | 307 // dispatch empty suggestions. |
| 235 SuggestionsProfile suggestions; | 308 SuggestionsProfile suggestions; |
| 236 if (suggestions_data.empty()) { | 309 if (suggestions_data.empty()) { |
| 237 LogResponseState(RESPONSE_EMPTY); | 310 LogResponseState(RESPONSE_EMPTY); |
| 238 suggestions_store_->ClearSuggestions(); | 311 suggestions_store_->ClearSuggestions(); |
| 239 } else if (suggestions.ParseFromString(suggestions_data)) { | 312 } else if (suggestions.ParseFromString(suggestions_data)) { |
| 240 LogResponseState(RESPONSE_VALID); | 313 LogResponseState(RESPONSE_VALID); |
| 241 thumbnail_manager_->InitializeThumbnailMap(suggestions); | 314 thumbnail_manager_->InitializeThumbnailMap(suggestions); |
| 242 suggestions_store_->StoreSuggestions(suggestions); | 315 suggestions_store_->StoreSuggestions(suggestions); |
| 243 } else { | 316 } else { |
| 244 LogResponseState(RESPONSE_INVALID); | 317 LogResponseState(RESPONSE_INVALID); |
| 245 suggestions_store_->LoadSuggestions(&suggestions); | 318 suggestions_store_->LoadSuggestions(&suggestions); |
| 246 } | 319 } |
| 247 | 320 |
| 248 DispatchRequestsAndClear(suggestions, &waiting_requestors_); | 321 FilterAndServe(&suggestions); |
| 322 ScheduleBlacklistUpload(true); | |
| 249 } | 323 } |
| 250 | 324 |
| 251 void SuggestionsService::Shutdown() { | 325 void SuggestionsService::Shutdown() { |
| 252 // Cancel pending request and timeout closure, then serve existing requestors | 326 // Cancel pending request and timeout closure, then serve existing requestors |
| 253 // from cache. | 327 // from cache. |
| 254 pending_request_.reset(NULL); | 328 pending_request_.reset(NULL); |
| 255 pending_timeout_closure_.reset(NULL); | 329 pending_timeout_closure_.reset(NULL); |
| 256 ServeFromCache(); | 330 ServeFromCache(); |
| 257 } | 331 } |
| 258 | 332 |
| 259 bool SuggestionsService::IsBlacklistRequest(net::URLFetcher* request) const { | |
| 260 DCHECK(request); | |
| 261 return StartsWithASCII(request->GetOriginalURL().spec(), | |
| 262 blacklist_url_prefix_, true); | |
| 263 } | |
| 264 | |
| 265 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { | |
| 266 net::URLFetcher* request = | |
| 267 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); | |
| 268 request->SetLoadFlags(net::LOAD_DISABLE_CACHE); | |
| 269 request->SetRequestContext(profile_->GetRequestContext()); | |
| 270 // Add Chrome experiment state to the request headers. | |
| 271 net::HttpRequestHeaders headers; | |
| 272 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | |
| 273 request->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | |
| 274 request->SetExtraRequestHeaders(headers.ToString()); | |
| 275 return request; | |
| 276 } | |
| 277 | |
| 278 void SuggestionsService::ServeFromCache() { | 333 void SuggestionsService::ServeFromCache() { |
| 279 SuggestionsProfile suggestions; | 334 SuggestionsProfile suggestions; |
| 280 suggestions_store_->LoadSuggestions(&suggestions); | 335 suggestions_store_->LoadSuggestions(&suggestions); |
| 281 DispatchRequestsAndClear(suggestions, &waiting_requestors_); | 336 FilterAndServe(&suggestions); |
| 337 } | |
| 338 | |
| 339 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { | |
| 340 blacklist_store_->FilterSuggestions(suggestions); | |
| 341 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); | |
| 342 } | |
| 343 | |
| 344 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { | |
| 345 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 346 | |
| 347 UpdateBlacklistDelay(last_request_successful); | |
| 348 | |
| 349 // Schedule a blacklist upload task. | |
| 350 GURL blacklist_url; | |
| 351 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) { | |
| 352 base::Closure blacklist_cb = | |
| 353 base::Bind(&SuggestionsService::UploadOneFromBlacklist, | |
| 354 weak_ptr_factory_.GetWeakPtr()); | |
| 355 BrowserThread::PostDelayedTask( | |
| 356 BrowserThread::UI, FROM_HERE, blacklist_cb, | |
| 357 base::TimeDelta::FromSeconds(blacklist_delay_sec_)); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 void SuggestionsService::UploadOneFromBlacklist() { | |
| 362 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 363 | |
| 364 // If there's an ongoing request, let it complete. | |
| 365 if (pending_request_.get()) return; | |
| 366 | |
| 367 GURL blacklist_url; | |
| 368 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) | |
| 369 return; // Local blacklist is empty. | |
| 370 | |
| 371 // Send blacklisting request. | |
| 372 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); | |
| 373 } | |
| 374 | |
| 375 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { | |
| 376 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 377 | |
| 378 if (last_request_successful) { | |
| 379 blacklist_delay_sec_ = kBlacklistDefaultDelaySec; | |
| 380 } else { | |
| 381 unsigned int candidate_delay = | |
| 382 blacklist_delay_sec_ * kBlacklistBackoffMultiplier; | |
| 383 if (candidate_delay < kBlacklistMaxDelaySec) | |
| 384 blacklist_delay_sec_ = candidate_delay; | |
| 385 } | |
| 282 } | 386 } |
| 283 | 387 |
| 284 } // namespace suggestions | 388 } // namespace suggestions |
| OLD | NEW |