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

Side by Side Diff: components/suggestions/suggestions_service.cc

Issue 766053010: SuggestionsService undo blacklist functionality. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix uninitialized test variable Created 6 years 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 "components/suggestions/suggestions_service.h" 5 #include "components/suggestions/suggestions_service.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/message_loop/message_loop_proxy.h"
(...skipping 12 matching lines...) Expand all
23 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
24 #include "net/base/url_util.h" 24 #include "net/base/url_util.h"
25 #include "net/http/http_response_headers.h" 25 #include "net/http/http_response_headers.h"
26 #include "net/http/http_status_code.h" 26 #include "net/http/http_status_code.h"
27 #include "net/http/http_util.h" 27 #include "net/http/http_util.h"
28 #include "net/url_request/url_fetcher.h" 28 #include "net/url_request/url_fetcher.h"
29 #include "net/url_request/url_request_status.h" 29 #include "net/url_request/url_request_status.h"
30 #include "url/gurl.h" 30 #include "url/gurl.h"
31 31
32 using base::CancelableClosure; 32 using base::CancelableClosure;
33 using base::TimeDelta;
34 using base::TimeTicks;
33 35
34 namespace suggestions { 36 namespace suggestions {
35 37
36 namespace { 38 namespace {
37 39
38 // Used to UMA log the state of the last response from the server. 40 // Used to UMA log the state of the last response from the server.
39 enum SuggestionsResponseState { 41 enum SuggestionsResponseState {
40 RESPONSE_EMPTY, 42 RESPONSE_EMPTY,
41 RESPONSE_INVALID, 43 RESPONSE_INVALID,
42 RESPONSE_VALID, 44 RESPONSE_VALID,
(...skipping 24 matching lines...) Expand all
67 const SuggestionsProfile& suggestions, 69 const SuggestionsProfile& suggestions,
68 std::vector<SuggestionsService::ResponseCallback>* requestors) { 70 std::vector<SuggestionsService::ResponseCallback>* requestors) {
69 std::vector<SuggestionsService::ResponseCallback> temp_requestors; 71 std::vector<SuggestionsService::ResponseCallback> temp_requestors;
70 temp_requestors.swap(*requestors); 72 temp_requestors.swap(*requestors);
71 std::vector<SuggestionsService::ResponseCallback>::iterator it; 73 std::vector<SuggestionsService::ResponseCallback>::iterator it;
72 for (it = temp_requestors.begin(); it != temp_requestors.end(); ++it) { 74 for (it = temp_requestors.begin(); it != temp_requestors.end(); ++it) {
73 if (!it->is_null()) it->Run(suggestions); 75 if (!it->is_null()) it->Run(suggestions);
74 } 76 }
75 } 77 }
76 78
77 // Default delay used when scheduling a blacklist request. 79 // Default delay used when scheduling a request.
78 const int kBlacklistDefaultDelaySec = 1; 80 const int kDefaultSchedulingDelaySec = 1;
79 81
80 // Multiplier on the delay used when scheduling a blacklist request, in case the 82 // Multiplier on the delay used when re-scheduling a failed request.
81 // last observed request was unsuccessful. 83 const int kSchedulingBackoffMultiplier = 2;
82 const int kBlacklistBackoffMultiplier = 2;
83 84
84 // Maximum valid delay for scheduling a request. Candidate delays larger than 85 // Maximum valid delay for scheduling a request. Candidate delays larger than
85 // this are rejected. This means the maximum backoff is at least 300 / 2, i.e. 86 // this are rejected. This means the maximum backoff is at least 5 / 2 minutes.
86 // 2.5 minutes. 87 const int kSchedulingMaxDelaySec = 5 * 60;
87 const int kBlacklistMaxDelaySec = 300; // 5 minutes
88 88
89 } // namespace 89 } // namespace
90 90
91 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; 91 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions";
92 const char kSuggestionsFieldTrialControlParam[] = "control"; 92 const char kSuggestionsFieldTrialControlParam[] = "control";
93 const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; 93 const char kSuggestionsFieldTrialStateEnabled[] = "enabled";
94 94
95 // TODO(mathp): Put this in TemplateURL. 95 // TODO(mathp): Put this in TemplateURL.
96 const char kSuggestionsURL[] = "https://www.google.com/chromesuggestions?t=2"; 96 const char kSuggestionsURL[] = "https://www.google.com/chromesuggestions?t=2";
97 const char kSuggestionsBlacklistURLPrefix[] = 97 const char kSuggestionsBlacklistURLPrefix[] =
98 "https://www.google.com/chromesuggestions/blacklist?t=2&url="; 98 "https://www.google.com/chromesuggestions/blacklist?t=2&url=";
99 const char kSuggestionsBlacklistURLParam[] = "url"; 99 const char kSuggestionsBlacklistURLParam[] = "url";
100 100
101 // The default expiry timeout is 72 hours. 101 // The default expiry timeout is 72 hours.
102 const int64 kDefaultExpiryUsec = 72 * base::Time::kMicrosecondsPerHour; 102 const int64 kDefaultExpiryUsec = 72 * base::Time::kMicrosecondsPerHour;
103 103
104 SuggestionsService::SuggestionsService( 104 SuggestionsService::SuggestionsService(
105 net::URLRequestContextGetter* url_request_context, 105 net::URLRequestContextGetter* url_request_context,
106 scoped_ptr<SuggestionsStore> suggestions_store, 106 scoped_ptr<SuggestionsStore> suggestions_store,
107 scoped_ptr<ImageManager> thumbnail_manager, 107 scoped_ptr<ImageManager> thumbnail_manager,
108 scoped_ptr<BlacklistStore> blacklist_store) 108 scoped_ptr<BlacklistStore> blacklist_store)
109 : url_request_context_(url_request_context), 109 : url_request_context_(url_request_context),
110 suggestions_store_(suggestions_store.Pass()), 110 suggestions_store_(suggestions_store.Pass()),
111 thumbnail_manager_(thumbnail_manager.Pass()), 111 thumbnail_manager_(thumbnail_manager.Pass()),
112 blacklist_store_(blacklist_store.Pass()), 112 blacklist_store_(blacklist_store.Pass()),
113 blacklist_delay_sec_(kBlacklistDefaultDelaySec), 113 scheduling_delay_(TimeDelta::FromSeconds(kDefaultSchedulingDelaySec)),
114 suggestions_url_(kSuggestionsURL), 114 suggestions_url_(kSuggestionsURL),
115 blacklist_url_prefix_(kSuggestionsBlacklistURLPrefix), 115 blacklist_url_prefix_(kSuggestionsBlacklistURLPrefix),
116 weak_ptr_factory_(this) {} 116 weak_ptr_factory_(this) {}
117 117
118 SuggestionsService::~SuggestionsService() {} 118 SuggestionsService::~SuggestionsService() {}
119 119
120 // static 120 // static
121 bool SuggestionsService::IsControlGroup() { 121 bool SuggestionsService::IsControlGroup() {
122 return GetExperimentParam(kSuggestionsFieldTrialControlParam) == 122 return GetExperimentParam(kSuggestionsFieldTrialControlParam) ==
123 kSuggestionsFieldTrialStateEnabled; 123 kSuggestionsFieldTrialStateEnabled;
(...skipping 23 matching lines...) Expand all
147 } 147 }
148 148
149 void SuggestionsService::GetPageThumbnail( 149 void SuggestionsService::GetPageThumbnail(
150 const GURL& url, 150 const GURL& url,
151 base::Callback<void(const GURL&, const SkBitmap*)> callback) { 151 base::Callback<void(const GURL&, const SkBitmap*)> callback) {
152 thumbnail_manager_->GetImageForURL(url, callback); 152 thumbnail_manager_->GetImageForURL(url, callback);
153 } 153 }
154 154
155 void SuggestionsService::BlacklistURL( 155 void SuggestionsService::BlacklistURL(
156 const GURL& candidate_url, 156 const GURL& candidate_url,
157 const SuggestionsService::ResponseCallback& callback) { 157 const SuggestionsService::ResponseCallback& callback,
158 const base::Closure& fail_callback) {
158 DCHECK(thread_checker_.CalledOnValidThread()); 159 DCHECK(thread_checker_.CalledOnValidThread());
160
161 if (!blacklist_store_->BlacklistUrl(candidate_url)) {
162 fail_callback.Run();
163 return;
164 }
165
159 waiting_requestors_.push_back(callback); 166 waiting_requestors_.push_back(callback);
167 ServeFromCache();
168 // Blacklist uploads are scheduled on any request completion, so only schedule
169 // an upload if there is no ongoing request.
170 if (!pending_request_.get()) {
171 ScheduleBlacklistUpload();
172 }
173 }
160 174
161 // Blacklist locally for immediate effect and serve the requestors. 175 void SuggestionsService::UndoBlacklistURL(
162 blacklist_store_->BlacklistUrl(candidate_url); 176 const GURL& url,
163 ServeFromCache(); 177 const SuggestionsService::ResponseCallback& callback,
164 178 const base::Closure& fail_callback) {
165 // Send blacklisting request. Even if this request ends up not being sent 179 DCHECK(thread_checker_.CalledOnValidThread());
166 // because of an ongoing request, a blacklist request is later scheduled. 180 TimeDelta time_delta;
167 // TODO(mathp): Currently, this will not send a request if there is already 181 if (blacklist_store_->GetTimeUntilURLReadyForUpload(url, &time_delta) &&
168 // a request in flight (for suggestions or blacklist). Should we prioritize 182 time_delta > TimeDelta::FromSeconds(0) &&
169 // blacklist requests since they actually carry a payload? 183 blacklist_store_->RemoveUrl(url)) {
170 IssueRequestIfNoneOngoing( 184 // The URL was not yet candidate for upload to the server and could be
171 BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); 185 // removed from the blacklist.
186 waiting_requestors_.push_back(callback);
187 ServeFromCache();
188 return;
189 }
190 fail_callback.Run();
172 } 191 }
173 192
174 // static 193 // static
175 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, 194 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request,
176 GURL* url) { 195 GURL* url) {
177 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), 196 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(),
178 kSuggestionsBlacklistURLPrefix, 197 kSuggestionsBlacklistURLPrefix,
179 true); 198 true);
180 if (!is_blacklist_request) return false; 199 if (!is_blacklist_request) return false;
181 200
(...skipping 30 matching lines...) Expand all
212 } 231 }
213 } 232 }
214 233
215 void SuggestionsService::IssueRequestIfNoneOngoing(const GURL& url) { 234 void SuggestionsService::IssueRequestIfNoneOngoing(const GURL& url) {
216 // If there is an ongoing request, let it complete. 235 // If there is an ongoing request, let it complete.
217 if (pending_request_.get()) { 236 if (pending_request_.get()) {
218 return; 237 return;
219 } 238 }
220 pending_request_.reset(CreateSuggestionsRequest(url)); 239 pending_request_.reset(CreateSuggestionsRequest(url));
221 pending_request_->Start(); 240 pending_request_->Start();
222 last_request_started_time_ = base::TimeTicks::Now(); 241 last_request_started_time_ = TimeTicks::Now();
223 } 242 }
224 243
225 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { 244 net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) {
226 net::URLFetcher* request = 245 net::URLFetcher* request =
227 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); 246 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this);
228 request->SetLoadFlags(net::LOAD_DISABLE_CACHE); 247 request->SetLoadFlags(net::LOAD_DISABLE_CACHE);
229 request->SetRequestContext(url_request_context_); 248 request->SetRequestContext(url_request_context_);
230 // Add Chrome experiment state to the request headers. 249 // Add Chrome experiment state to the request headers.
231 net::HttpRequestHeaders headers; 250 net::HttpRequestHeaders headers;
232 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( 251 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders(
(...skipping 11 matching lines...) Expand all
244 263
245 const net::URLRequestStatus& request_status = request->GetStatus(); 264 const net::URLRequestStatus& request_status = request->GetStatus();
246 if (request_status.status() != net::URLRequestStatus::SUCCESS) { 265 if (request_status.status() != net::URLRequestStatus::SUCCESS) {
247 // This represents network errors (i.e. the server did not provide a 266 // This represents network errors (i.e. the server did not provide a
248 // response). 267 // response).
249 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", 268 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode",
250 -request_status.error()); 269 -request_status.error());
251 DVLOG(1) << "Suggestions server request failed with error: " 270 DVLOG(1) << "Suggestions server request failed with error: "
252 << request_status.error() << ": " 271 << request_status.error() << ": "
253 << net::ErrorToString(request_status.error()); 272 << net::ErrorToString(request_status.error());
254 ScheduleBlacklistUpload(false); 273 UpdateBlacklistDelay(false);
274 ScheduleBlacklistUpload();
255 return; 275 return;
256 } 276 }
257 277
258 const int response_code = request->GetResponseCode(); 278 const int response_code = request->GetResponseCode();
259 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); 279 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code);
260 if (response_code != net::HTTP_OK) { 280 if (response_code != net::HTTP_OK) {
261 // A non-200 response code means that server has no (longer) suggestions for 281 // A non-200 response code means that server has no (longer) suggestions for
262 // this user. Aggressively clear the cache. 282 // this user. Aggressively clear the cache.
263 suggestions_store_->ClearSuggestions(); 283 suggestions_store_->ClearSuggestions();
264 ScheduleBlacklistUpload(false); 284 UpdateBlacklistDelay(false);
285 ScheduleBlacklistUpload();
265 return; 286 return;
266 } 287 }
267 288
268 const base::TimeDelta latency = 289 const TimeDelta latency = TimeTicks::Now() - last_request_started_time_;
269 base::TimeTicks::Now() - last_request_started_time_;
270 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); 290 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency);
271 291
272 // Handle a successful blacklisting. 292 // Handle a successful blacklisting.
273 GURL blacklisted_url; 293 GURL blacklisted_url;
274 if (GetBlacklistedUrl(*source, &blacklisted_url)) { 294 if (GetBlacklistedUrl(*source, &blacklisted_url)) {
275 blacklist_store_->RemoveUrl(blacklisted_url); 295 blacklist_store_->RemoveUrl(blacklisted_url);
276 } 296 }
277 297
278 std::string suggestions_data; 298 std::string suggestions_data;
279 bool success = request->GetResponseAsString(&suggestions_data); 299 bool success = request->GetResponseAsString(&suggestions_data);
280 DCHECK(success); 300 DCHECK(success);
281 301
282 // Parse the received suggestions and update the cache, or take proper action 302 // Parse the received suggestions and update the cache, or take proper action
283 // in the case of invalid response. 303 // in the case of invalid response.
284 SuggestionsProfile suggestions; 304 SuggestionsProfile suggestions;
285 if (suggestions_data.empty()) { 305 if (suggestions_data.empty()) {
286 LogResponseState(RESPONSE_EMPTY); 306 LogResponseState(RESPONSE_EMPTY);
287 suggestions_store_->ClearSuggestions(); 307 suggestions_store_->ClearSuggestions();
288 } else if (suggestions.ParseFromString(suggestions_data)) { 308 } else if (suggestions.ParseFromString(suggestions_data)) {
289 LogResponseState(RESPONSE_VALID); 309 LogResponseState(RESPONSE_VALID);
290 int64 now_usec = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) 310 int64 now_usec = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch())
291 .ToInternalValue(); 311 .ToInternalValue();
292 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec); 312 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec);
293 suggestions_store_->StoreSuggestions(suggestions); 313 suggestions_store_->StoreSuggestions(suggestions);
294 } else { 314 } else {
295 LogResponseState(RESPONSE_INVALID); 315 LogResponseState(RESPONSE_INVALID);
296 } 316 }
297 317
298 ScheduleBlacklistUpload(true); 318 UpdateBlacklistDelay(true);
319 ScheduleBlacklistUpload();
299 } 320 }
300 321
301 void SuggestionsService::Shutdown() { 322 void SuggestionsService::Shutdown() {
302 // Cancel pending request, then serve existing requestors from cache. 323 // Cancel pending request, then serve existing requestors from cache.
303 pending_request_.reset(NULL); 324 pending_request_.reset(NULL);
304 ServeFromCache(); 325 ServeFromCache();
305 } 326 }
306 327
307 void SuggestionsService::ServeFromCache() { 328 void SuggestionsService::ServeFromCache() {
308 SuggestionsProfile suggestions; 329 SuggestionsProfile suggestions;
309 // In case of empty cache or error, |suggestions| stays empty. 330 // In case of empty cache or error, |suggestions| stays empty.
310 suggestions_store_->LoadSuggestions(&suggestions); 331 suggestions_store_->LoadSuggestions(&suggestions);
311 thumbnail_manager_->Initialize(suggestions); 332 thumbnail_manager_->Initialize(suggestions);
312 FilterAndServe(&suggestions); 333 FilterAndServe(&suggestions);
313 } 334 }
314 335
315 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { 336 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) {
316 blacklist_store_->FilterSuggestions(suggestions); 337 blacklist_store_->FilterSuggestions(suggestions);
317 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); 338 DispatchRequestsAndClear(*suggestions, &waiting_requestors_);
318 } 339 }
319 340
320 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { 341 void SuggestionsService::ScheduleBlacklistUpload() {
321 DCHECK(thread_checker_.CalledOnValidThread()); 342 DCHECK(thread_checker_.CalledOnValidThread());
322 343 TimeDelta time_delta;
323 UpdateBlacklistDelay(last_request_successful); 344 if (blacklist_store_->GetTimeUntilReadyForUpload(&time_delta)) {
324 345 // Blacklist cache is not empty: schedule.
325 // Schedule a blacklist upload task.
326 GURL blacklist_url;
327 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) {
328 base::Closure blacklist_cb = 346 base::Closure blacklist_cb =
329 base::Bind(&SuggestionsService::UploadOneFromBlacklist, 347 base::Bind(&SuggestionsService::UploadOneFromBlacklist,
330 weak_ptr_factory_.GetWeakPtr()); 348 weak_ptr_factory_.GetWeakPtr());
331 base::MessageLoopProxy::current()->PostDelayedTask( 349 base::MessageLoopProxy::current()->PostDelayedTask(
332 FROM_HERE, blacklist_cb, 350 FROM_HERE, blacklist_cb, time_delta + scheduling_delay_);
333 base::TimeDelta::FromSeconds(blacklist_delay_sec_));
334 } 351 }
335 } 352 }
336 353
337 void SuggestionsService::UploadOneFromBlacklist() { 354 void SuggestionsService::UploadOneFromBlacklist() {
338 DCHECK(thread_checker_.CalledOnValidThread()); 355 DCHECK(thread_checker_.CalledOnValidThread());
339 356
340 GURL blacklist_url; 357 GURL blacklist_url;
341 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) 358 if (blacklist_store_->GetCandidateForUpload(&blacklist_url)) {
342 return; // Local blacklist is empty. 359 // Issue a blacklisting request. Even if this request ends up not being sent
360 // because of an ongoing request, a blacklist request is later scheduled.
361 IssueRequestIfNoneOngoing(
362 BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url));
363 return;
364 }
343 365
344 // Send blacklisting request. Even if this request ends up not being sent 366 // Even though there's no candidate for upload, the blacklist might not be
345 // because of an ongoing request, a blacklist request is later scheduled. 367 // empty.
346 IssueRequestIfNoneOngoing( 368 ScheduleBlacklistUpload();
347 BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url));
348 } 369 }
349 370
350 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { 371 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) {
351 DCHECK(thread_checker_.CalledOnValidThread()); 372 DCHECK(thread_checker_.CalledOnValidThread());
352 373
353 if (last_request_successful) { 374 if (last_request_successful) {
354 blacklist_delay_sec_ = kBlacklistDefaultDelaySec; 375 scheduling_delay_ = TimeDelta::FromSeconds(kDefaultSchedulingDelaySec);
355 } else { 376 } else {
356 int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier; 377 TimeDelta candidate_delay =
357 if (candidate_delay < kBlacklistMaxDelaySec) 378 scheduling_delay_ * kSchedulingBackoffMultiplier;
358 blacklist_delay_sec_ = candidate_delay; 379 if (candidate_delay < TimeDelta::FromSeconds(kSchedulingMaxDelaySec))
380 scheduling_delay_ = candidate_delay;
359 } 381 }
360 } 382 }
361 383
362 } // namespace suggestions 384 } // namespace suggestions
OLDNEW
« no previous file with comments | « components/suggestions/suggestions_service.h ('k') | components/suggestions/suggestions_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698