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

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

Powered by Google App Engine
This is Rietveld 408576698