| 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 "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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |