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

Side by Side Diff: chrome/browser/search/suggestions/suggestions_service.cc

Issue 330473003: Offline blacklisting for SuggestionsService. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 6 years, 5 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
OLDNEW
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
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 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 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 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 kSuggestionsFieldTrialControlParam[] = "control"; 105 const char kSuggestionsFieldTrialControlParam[] = "control";
83 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; 106 const char kSuggestionsFieldTrialStateEnabled[] = "enabled";
84 const char kSuggestionsFieldTrialTimeoutMs[] = "timeout_ms"; 107 const char kSuggestionsFieldTrialTimeoutMs[] = "timeout_ms";
85 108
109 namespace {
110
111 std::string GetBlacklistUrlPrefix() {
112 std::stringstream blacklist_url_prefix_stream;
113 blacklist_url_prefix_stream
114 << GetExperimentParam(kSuggestionsFieldTrialURLParam)
115 << GetExperimentParam(kSuggestionsFieldTrialBlacklistPathParam) << "?"
116 << GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam) << "&"
117 << GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam) << "=";
118 return blacklist_url_prefix_stream.str();
119 }
120
121 } // namespace
122
86 SuggestionsService::SuggestionsService( 123 SuggestionsService::SuggestionsService(
87 Profile* profile, scoped_ptr<SuggestionsStore> suggestions_store, 124 Profile* profile, scoped_ptr<SuggestionsStore> suggestions_store,
88 scoped_ptr<ThumbnailManager> thumbnail_manager) 125 scoped_ptr<ThumbnailManager> thumbnail_manager,
126 scoped_ptr<BlacklistStore> blacklist_store)
89 : suggestions_store_(suggestions_store.Pass()), 127 : suggestions_store_(suggestions_store.Pass()),
128 blacklist_store_(blacklist_store.Pass()),
90 thumbnail_manager_(thumbnail_manager.Pass()), 129 thumbnail_manager_(thumbnail_manager.Pass()),
91 profile_(profile), 130 profile_(profile),
131 blacklist_delay_sec_(kBlacklistDefaultDelaySec),
92 weak_ptr_factory_(this), 132 weak_ptr_factory_(this),
93 request_timeout_ms_(kDefaultRequestTimeoutMs) { 133 request_timeout_ms_(kDefaultRequestTimeoutMs) {
94 // Obtain various parameters from Variations. 134 // Obtain various parameters from Variations.
95 suggestions_url_ = 135 suggestions_url_ =
96 GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam) + 136 GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam) + "?" +
97 GetExperimentParam(kSuggestionsFieldTrialSuggestionsSuffixParam)); 137 GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam));
98 blacklist_url_prefix_ = 138 blacklist_url_prefix_ = GetBlacklistUrlPrefix();
99 GetExperimentParam(kSuggestionsFieldTrialURLParam) +
100 GetExperimentParam(kSuggestionsFieldTrialBlacklistSuffixParam);
101 std::string timeout = GetExperimentParam(kSuggestionsFieldTrialTimeoutMs); 139 std::string timeout = GetExperimentParam(kSuggestionsFieldTrialTimeoutMs);
102 int temp_timeout; 140 int temp_timeout;
103 if (!timeout.empty() && base::StringToInt(timeout, &temp_timeout)) { 141 if (!timeout.empty() && base::StringToInt(timeout, &temp_timeout)) {
104 request_timeout_ms_ = temp_timeout; 142 request_timeout_ms_ = temp_timeout;
105 } 143 }
106 } 144 }
107 145
108 SuggestionsService::~SuggestionsService() {} 146 SuggestionsService::~SuggestionsService() {}
109 147
110 // static 148 // static
(...skipping 28 matching lines...) Expand all
139 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 177 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
140 if (pending_request_.get()) { 178 if (pending_request_.get()) {
141 // Request already exists, so just add requestor to queue. 179 // Request already exists, so just add requestor to queue.
142 waiting_requestors_.push_back(callback); 180 waiting_requestors_.push_back(callback);
143 return; 181 return;
144 } 182 }
145 183
146 // Form new request. 184 // Form new request.
147 DCHECK(waiting_requestors_.empty()); 185 DCHECK(waiting_requestors_.empty());
148 waiting_requestors_.push_back(callback); 186 waiting_requestors_.push_back(callback);
149 187 IssueRequest(suggestions_url_);
150 pending_request_.reset(CreateSuggestionsRequest(suggestions_url_));
151 pending_request_->Start();
152 last_request_started_time_ = base::TimeTicks::Now();
153 } 188 }
154 189
155 void SuggestionsService::GetPageThumbnail( 190 void SuggestionsService::GetPageThumbnail(
156 const GURL& url, 191 const GURL& url,
157 base::Callback<void(const GURL&, const SkBitmap*)> callback) { 192 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
158 thumbnail_manager_->GetPageThumbnail(url, callback); 193 thumbnail_manager_->GetPageThumbnail(url, callback);
159 } 194 }
160 195
161 void SuggestionsService::BlacklistURL( 196 void SuggestionsService::BlacklistURL(
162 const GURL& candidate_url, SuggestionsService::ResponseCallback callback) { 197 const GURL& candidate_url,
198 const SuggestionsService::ResponseCallback& callback) {
163 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 199 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
164 waiting_requestors_.push_back(callback); 200 waiting_requestors_.push_back(callback);
165 201
166 if (pending_request_.get()) { 202 // Blacklist locally, for immediate effect.
167 if (IsBlacklistRequest(pending_request_.get())) { 203 if (!blacklist_store_->BlacklistUrl(candidate_url)) {
168 // Pending request is a blacklist request. Silently drop the new blacklist 204 DVLOG(1) << "Failed blacklisting attempt.";
169 // request. TODO - handle this case. 205 return;
170 return;
171 } else {
172 // Pending request is not a blacklist request - cancel it and go on to
173 // issuing a blacklist request. Also ensure the timeout closure does not
174 // run; instead we'll wait for the updated suggestions before servicing
175 // requestors.
176 pending_request_.reset(NULL);
177 pending_timeout_closure_.reset(NULL);
178 }
179 } 206 }
180 207
181 // Send blacklisting request. 208 // If there's an ongoing request, let it complete.
182 // TODO(manzagop): make this a PUT request instead of a GET request. 209 if (pending_request_.get()) return;
183 GURL url(blacklist_url_prefix_ + 210
184 net::EscapeQueryParamValue(candidate_url.spec(), true)); 211 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url));
185 pending_request_.reset(CreateSuggestionsRequest(url)); 212 }
186 pending_request_->Start(); 213
187 last_request_started_time_ = base::TimeTicks::Now(); 214 // static
215 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request,
216 GURL* url) {
217 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(),
218 GetBlacklistUrlPrefix(), true);
219 if (!is_blacklist_request) return false;
220
221 // Extract the blacklisted URL from the blacklist request.
222 std::string blacklisted;
223 if (!net::GetValueForKeyInQuery(
224 request.GetOriginalURL(),
225 GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam),
226 &blacklisted))
227 return false;
228
229 GURL blacklisted_url(blacklisted);
230 blacklisted_url.Swap(url);
231 return true;
188 } 232 }
189 233
190 // static 234 // static
191 void SuggestionsService::RegisterProfilePrefs( 235 void SuggestionsService::RegisterProfilePrefs(
192 user_prefs::PrefRegistrySyncable* registry) { 236 user_prefs::PrefRegistrySyncable* registry) {
193 SuggestionsStore::RegisterProfilePrefs(registry); 237 SuggestionsStore::RegisterProfilePrefs(registry);
238 BlacklistStore::RegisterProfilePrefs(registry);
239 }
240
241 void SuggestionsService::IssueRequest(const GURL& url) {
242 pending_request_.reset(CreateSuggestionsRequest(url));
243 pending_request_->Start();
244 last_request_started_time_ = base::TimeTicks::Now();
245 }
246
247 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) {
248 net::URLFetcher* request =
249 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this);
250 request->SetLoadFlags(net::LOAD_DISABLE_CACHE);
251 request->SetRequestContext(profile_->GetRequestContext());
252 // Add Chrome experiment state to the request headers.
253 net::HttpRequestHeaders headers;
254 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders(
255 request->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers);
256 request->SetExtraRequestHeaders(headers.ToString());
257 return request;
194 } 258 }
195 259
196 void SuggestionsService::OnRequestTimeout() { 260 void SuggestionsService::OnRequestTimeout() {
197 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 261 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
198 ServeFromCache(); 262 ServeFromCache();
199 } 263 }
200 264
201 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { 265 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) {
202 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 266 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
203 DCHECK_EQ(pending_request_.get(), source); 267 DCHECK_EQ(pending_request_.get(), source);
204 268
205 // We no longer need the timeout closure. Delete it whether or not it has run 269 // We no longer need the timeout closure. Delete it whether or not it has run.
206 // (if it hasn't, this cancels it). 270 // If it hasn't, this cancels it.
207 pending_timeout_closure_.reset(); 271 pending_timeout_closure_.reset();
208 272
209 // The fetcher will be deleted when the request is handled. 273 // The fetcher will be deleted when the request is handled.
210 scoped_ptr<const net::URLFetcher> request(pending_request_.release()); 274 scoped_ptr<const net::URLFetcher> request(pending_request_.release());
211 const net::URLRequestStatus& request_status = request->GetStatus(); 275 const net::URLRequestStatus& request_status = request->GetStatus();
212 if (request_status.status() != net::URLRequestStatus::SUCCESS) { 276 if (request_status.status() != net::URLRequestStatus::SUCCESS) {
213 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", 277 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode",
214 -request_status.error()); 278 -request_status.error());
215 DVLOG(1) << "Suggestions server request failed with error: " 279 DVLOG(1) << "Suggestions server request failed with error: "
216 << request_status.error() << ": " 280 << request_status.error() << ": "
217 << net::ErrorToString(request_status.error()); 281 << net::ErrorToString(request_status.error());
218 // Dispatch the cached profile on error. 282 // Dispatch the cached profile on error.
219 ServeFromCache(); 283 ServeFromCache();
284 ScheduleBlacklistUpload(false);
220 return; 285 return;
221 } 286 }
222 287
223 // Log the response code. 288 // Log the response code.
224 const int response_code = request->GetResponseCode(); 289 const int response_code = request->GetResponseCode();
225 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); 290 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code);
226 if (response_code != net::HTTP_OK) { 291 if (response_code != net::HTTP_OK) {
227 // Aggressively clear the store. 292 // Aggressively clear the store.
228 suggestions_store_->ClearSuggestions(); 293 suggestions_store_->ClearSuggestions();
229 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_); 294 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_);
295 ScheduleBlacklistUpload(false);
230 return; 296 return;
231 } 297 }
232 298
233 const base::TimeDelta latency = 299 const base::TimeDelta latency =
234 base::TimeTicks::Now() - last_request_started_time_; 300 base::TimeTicks::Now() - last_request_started_time_;
235 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); 301 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency);
236 302
303 // Handle a successful blacklisting.
304 GURL blacklisted_url;
305 if (GetBlacklistedUrl(*source, &blacklisted_url)) {
306 blacklist_store_->RemoveUrl(blacklisted_url);
307 }
308
237 std::string suggestions_data; 309 std::string suggestions_data;
238 bool success = request->GetResponseAsString(&suggestions_data); 310 bool success = request->GetResponseAsString(&suggestions_data);
239 DCHECK(success); 311 DCHECK(success);
240 312
241 // Compute suggestions, and dispatch then to requestors. On error still 313 // Compute suggestions, and dispatch then to requestors. On error still
242 // dispatch empty suggestions. 314 // dispatch empty suggestions.
243 SuggestionsProfile suggestions; 315 SuggestionsProfile suggestions;
244 if (suggestions_data.empty()) { 316 if (suggestions_data.empty()) {
245 LogResponseState(RESPONSE_EMPTY); 317 LogResponseState(RESPONSE_EMPTY);
246 suggestions_store_->ClearSuggestions(); 318 suggestions_store_->ClearSuggestions();
247 } else if (suggestions.ParseFromString(suggestions_data)) { 319 } else if (suggestions.ParseFromString(suggestions_data)) {
248 LogResponseState(RESPONSE_VALID); 320 LogResponseState(RESPONSE_VALID);
249 thumbnail_manager_->InitializeThumbnailMap(suggestions); 321 thumbnail_manager_->InitializeThumbnailMap(suggestions);
250 suggestions_store_->StoreSuggestions(suggestions); 322 suggestions_store_->StoreSuggestions(suggestions);
251 } else { 323 } else {
252 LogResponseState(RESPONSE_INVALID); 324 LogResponseState(RESPONSE_INVALID);
253 suggestions_store_->LoadSuggestions(&suggestions); 325 suggestions_store_->LoadSuggestions(&suggestions);
254 } 326 }
255 327
256 DispatchRequestsAndClear(suggestions, &waiting_requestors_); 328 FilterAndServe(&suggestions);
329 ScheduleBlacklistUpload(true);
257 } 330 }
258 331
259 void SuggestionsService::Shutdown() { 332 void SuggestionsService::Shutdown() {
260 // Cancel pending request and timeout closure, then serve existing requestors 333 // Cancel pending request and timeout closure, then serve existing requestors
261 // from cache. 334 // from cache.
262 pending_request_.reset(NULL); 335 pending_request_.reset(NULL);
263 pending_timeout_closure_.reset(NULL); 336 pending_timeout_closure_.reset(NULL);
264 ServeFromCache(); 337 ServeFromCache();
265 } 338 }
266 339
267 bool SuggestionsService::IsBlacklistRequest(net::URLFetcher* request) const {
268 DCHECK(request);
269 return StartsWithASCII(request->GetOriginalURL().spec(),
270 blacklist_url_prefix_, true);
271 }
272
273 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) {
274 net::URLFetcher* request =
275 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this);
276 request->SetLoadFlags(net::LOAD_DISABLE_CACHE);
277 request->SetRequestContext(profile_->GetRequestContext());
278 // Add Chrome experiment state to the request headers.
279 net::HttpRequestHeaders headers;
280 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders(
281 request->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers);
282 request->SetExtraRequestHeaders(headers.ToString());
283 return request;
284 }
285
286 void SuggestionsService::ServeFromCache() { 340 void SuggestionsService::ServeFromCache() {
287 SuggestionsProfile suggestions; 341 SuggestionsProfile suggestions;
288 suggestions_store_->LoadSuggestions(&suggestions); 342 suggestions_store_->LoadSuggestions(&suggestions);
289 DispatchRequestsAndClear(suggestions, &waiting_requestors_); 343 FilterAndServe(&suggestions);
344 }
345
346 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) {
347 blacklist_store_->FilterSuggestions(suggestions);
348 DispatchRequestsAndClear(*suggestions, &waiting_requestors_);
349 }
350
351 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) {
352 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
353
354 UpdateBlacklistDelay(last_request_successful);
355
356 // Schedule a blacklist upload task.
357 GURL blacklist_url;
358 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) {
359 base::Closure blacklist_cb =
360 base::Bind(&SuggestionsService::UploadOneFromBlacklist,
361 weak_ptr_factory_.GetWeakPtr());
362 BrowserThread::PostDelayedTask(
363 BrowserThread::UI, FROM_HERE, blacklist_cb,
364 base::TimeDelta::FromSeconds(blacklist_delay_sec_));
365 }
366 }
367
368 void SuggestionsService::UploadOneFromBlacklist() {
369 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
370
371 // If there's an ongoing request, let it complete.
372 if (pending_request_.get()) return;
373
374 GURL blacklist_url;
375 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url))
376 return; // Local blacklist is empty.
377
378 // Send blacklisting request.
379 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url));
380 }
381
382 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) {
383 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
384
385 if (last_request_successful) {
386 blacklist_delay_sec_ = kBlacklistDefaultDelaySec;
387 } else {
388 int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier;
389 if (candidate_delay < kBlacklistMaxDelaySec)
390 blacklist_delay_sec_ = candidate_delay;
391 }
290 } 392 }
291 393
292 } // namespace suggestions 394 } // namespace suggestions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698