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