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