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 "components/suggestions/suggestions_service.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/message_loop/message_loop_proxy.h" |
11 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
12 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" |
13 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
14 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
15 #include "base/time/time.h" | 16 #include "base/time/time.h" |
16 #include "chrome/browser/search/suggestions/blacklist_store.h" | |
17 #include "chrome/browser/search/suggestions/suggestions_store.h" | |
18 #include "components/pref_registry/pref_registry_syncable.h" | 17 #include "components/pref_registry/pref_registry_syncable.h" |
| 18 #include "components/suggestions/blacklist_store.h" |
| 19 #include "components/suggestions/suggestions_store.h" |
19 #include "components/variations/variations_associated_data.h" | 20 #include "components/variations/variations_associated_data.h" |
20 #include "components/variations/variations_http_header_provider.h" | 21 #include "components/variations/variations_http_header_provider.h" |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "net/base/escape.h" | 22 #include "net/base/escape.h" |
23 #include "net/base/load_flags.h" | 23 #include "net/base/load_flags.h" |
24 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
25 #include "net/base/url_util.h" | 25 #include "net/base/url_util.h" |
26 #include "net/http/http_response_headers.h" | 26 #include "net/http/http_response_headers.h" |
27 #include "net/http/http_status_code.h" | 27 #include "net/http/http_status_code.h" |
28 #include "net/http/http_util.h" | 28 #include "net/http/http_util.h" |
29 #include "net/url_request/url_fetcher.h" | 29 #include "net/url_request/url_fetcher.h" |
30 #include "net/url_request/url_request_status.h" | 30 #include "net/url_request/url_request_status.h" |
31 #include "url/gurl.h" | 31 #include "url/gurl.h" |
32 | 32 |
33 using base::CancelableClosure; | 33 using base::CancelableClosure; |
34 using content::BrowserThread; | |
35 | 34 |
36 namespace suggestions { | 35 namespace suggestions { |
37 | 36 |
38 namespace { | 37 namespace { |
39 | 38 |
40 // Used to UMA log the state of the last response from the server. | 39 // Used to UMA log the state of the last response from the server. |
41 enum SuggestionsResponseState { | 40 enum SuggestionsResponseState { |
42 RESPONSE_EMPTY, | 41 RESPONSE_EMPTY, |
43 RESPONSE_INVALID, | 42 RESPONSE_INVALID, |
44 RESPONSE_VALID, | 43 RESPONSE_VALID, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 } | 148 } |
150 | 149 |
151 // static | 150 // static |
152 bool SuggestionsService::IsControlGroup() { | 151 bool SuggestionsService::IsControlGroup() { |
153 return GetExperimentParam(kSuggestionsFieldTrialControlParam) == | 152 return GetExperimentParam(kSuggestionsFieldTrialControlParam) == |
154 kSuggestionsFieldTrialStateEnabled; | 153 kSuggestionsFieldTrialStateEnabled; |
155 } | 154 } |
156 | 155 |
157 void SuggestionsService::FetchSuggestionsData( | 156 void SuggestionsService::FetchSuggestionsData( |
158 SuggestionsService::ResponseCallback callback) { | 157 SuggestionsService::ResponseCallback callback) { |
159 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 158 DCHECK(thread_checker_.CalledOnValidThread()); |
160 | 159 |
161 FetchSuggestionsDataNoTimeout(callback); | 160 FetchSuggestionsDataNoTimeout(callback); |
162 | 161 |
163 // Post a task to serve the cached suggestions if the request hasn't completed | 162 // Post a task to serve the cached suggestions if the request hasn't completed |
164 // after some time. Cancels the previous such task, if one existed. | 163 // after some time. Cancels the previous such task, if one existed. |
165 pending_timeout_closure_.reset(new CancelableClosure(base::Bind( | 164 pending_timeout_closure_.reset(new CancelableClosure(base::Bind( |
166 &SuggestionsService::OnRequestTimeout, weak_ptr_factory_.GetWeakPtr()))); | 165 &SuggestionsService::OnRequestTimeout, weak_ptr_factory_.GetWeakPtr()))); |
167 BrowserThread::PostDelayedTask( | 166 base::MessageLoopProxy::current()->PostDelayedTask( |
168 BrowserThread::UI, FROM_HERE, pending_timeout_closure_->callback(), | 167 FROM_HERE, pending_timeout_closure_->callback(), |
169 base::TimeDelta::FromMilliseconds(request_timeout_ms_)); | 168 base::TimeDelta::FromMilliseconds(request_timeout_ms_)); |
170 } | 169 } |
171 | 170 |
172 void SuggestionsService::FetchSuggestionsDataNoTimeout( | 171 void SuggestionsService::FetchSuggestionsDataNoTimeout( |
173 SuggestionsService::ResponseCallback callback) { | 172 SuggestionsService::ResponseCallback callback) { |
174 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 173 DCHECK(thread_checker_.CalledOnValidThread()); |
175 if (pending_request_.get()) { | 174 if (pending_request_.get()) { |
176 // Request already exists, so just add requestor to queue. | 175 // Request already exists, so just add requestor to queue. |
177 waiting_requestors_.push_back(callback); | 176 waiting_requestors_.push_back(callback); |
178 return; | 177 return; |
179 } | 178 } |
180 | 179 |
181 // Form new request. | 180 // Form new request. |
182 DCHECK(waiting_requestors_.empty()); | 181 DCHECK(waiting_requestors_.empty()); |
183 waiting_requestors_.push_back(callback); | 182 waiting_requestors_.push_back(callback); |
184 IssueRequest(suggestions_url_); | 183 IssueRequest(suggestions_url_); |
185 } | 184 } |
186 | 185 |
187 void SuggestionsService::GetPageThumbnail( | 186 void SuggestionsService::GetPageThumbnail( |
188 const GURL& url, | 187 const GURL& url, |
189 base::Callback<void(const GURL&, const SkBitmap*)> callback) { | 188 base::Callback<void(const GURL&, const SkBitmap*)> callback) { |
190 thumbnail_manager_->GetImageForURL(url, callback); | 189 thumbnail_manager_->GetImageForURL(url, callback); |
191 } | 190 } |
192 | 191 |
193 void SuggestionsService::BlacklistURL( | 192 void SuggestionsService::BlacklistURL( |
194 const GURL& candidate_url, | 193 const GURL& candidate_url, |
195 const SuggestionsService::ResponseCallback& callback) { | 194 const SuggestionsService::ResponseCallback& callback) { |
196 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 195 DCHECK(thread_checker_.CalledOnValidThread()); |
197 waiting_requestors_.push_back(callback); | 196 waiting_requestors_.push_back(callback); |
198 | 197 |
199 // Blacklist locally, for immediate effect. | 198 // Blacklist locally, for immediate effect. |
200 if (!blacklist_store_->BlacklistUrl(candidate_url)) { | 199 if (!blacklist_store_->BlacklistUrl(candidate_url)) { |
201 DVLOG(1) << "Failed blacklisting attempt."; | 200 DVLOG(1) << "Failed blacklisting attempt."; |
202 return; | 201 return; |
203 } | 202 } |
204 | 203 |
205 // If there's an ongoing request, let it complete. | 204 // If there's an ongoing request, let it complete. |
206 if (pending_request_.get()) return; | 205 if (pending_request_.get()) return; |
207 | |
208 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); | 206 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); |
209 } | 207 } |
210 | 208 |
211 // static | 209 // static |
212 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, | 210 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, |
213 GURL* url) { | 211 GURL* url) { |
214 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), | 212 bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), |
215 GetBlacklistUrlPrefix(), true); | 213 GetBlacklistUrlPrefix(), true); |
216 if (!is_blacklist_request) return false; | 214 if (!is_blacklist_request) return false; |
217 | 215 |
(...skipping 30 matching lines...) Expand all Loading... |
248 request->SetRequestContext(url_request_context_); | 246 request->SetRequestContext(url_request_context_); |
249 // Add Chrome experiment state to the request headers. | 247 // Add Chrome experiment state to the request headers. |
250 net::HttpRequestHeaders headers; | 248 net::HttpRequestHeaders headers; |
251 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 249 variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( |
252 request->GetOriginalURL(), false, false, &headers); | 250 request->GetOriginalURL(), false, false, &headers); |
253 request->SetExtraRequestHeaders(headers.ToString()); | 251 request->SetExtraRequestHeaders(headers.ToString()); |
254 return request; | 252 return request; |
255 } | 253 } |
256 | 254 |
257 void SuggestionsService::OnRequestTimeout() { | 255 void SuggestionsService::OnRequestTimeout() { |
258 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 256 DCHECK(thread_checker_.CalledOnValidThread()); |
259 ServeFromCache(); | 257 ServeFromCache(); |
260 } | 258 } |
261 | 259 |
262 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { | 260 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { |
263 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 261 DCHECK(thread_checker_.CalledOnValidThread()); |
264 DCHECK_EQ(pending_request_.get(), source); | 262 DCHECK_EQ(pending_request_.get(), source); |
265 | |
266 // We no longer need the timeout closure. Delete it whether or not it has run. | 263 // We no longer need the timeout closure. Delete it whether or not it has run. |
267 // If it hasn't, this cancels it. | 264 // If it hasn't, this cancels it. |
268 pending_timeout_closure_.reset(); | 265 pending_timeout_closure_.reset(); |
269 | 266 |
270 // The fetcher will be deleted when the request is handled. | 267 // The fetcher will be deleted when the request is handled. |
271 scoped_ptr<const net::URLFetcher> request(pending_request_.release()); | 268 scoped_ptr<const net::URLFetcher> request(pending_request_.release()); |
272 const net::URLRequestStatus& request_status = request->GetStatus(); | 269 const net::URLRequestStatus& request_status = request->GetStatus(); |
273 if (request_status.status() != net::URLRequestStatus::SUCCESS) { | 270 if (request_status.status() != net::URLRequestStatus::SUCCESS) { |
274 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", | 271 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", |
275 -request_status.error()); | 272 -request_status.error()); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 suggestions_store_->LoadSuggestions(&suggestions); | 336 suggestions_store_->LoadSuggestions(&suggestions); |
340 FilterAndServe(&suggestions); | 337 FilterAndServe(&suggestions); |
341 } | 338 } |
342 | 339 |
343 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { | 340 void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { |
344 blacklist_store_->FilterSuggestions(suggestions); | 341 blacklist_store_->FilterSuggestions(suggestions); |
345 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); | 342 DispatchRequestsAndClear(*suggestions, &waiting_requestors_); |
346 } | 343 } |
347 | 344 |
348 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { | 345 void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { |
349 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 346 DCHECK(thread_checker_.CalledOnValidThread()); |
350 | 347 |
351 UpdateBlacklistDelay(last_request_successful); | 348 UpdateBlacklistDelay(last_request_successful); |
352 | 349 |
353 // Schedule a blacklist upload task. | 350 // Schedule a blacklist upload task. |
354 GURL blacklist_url; | 351 GURL blacklist_url; |
355 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) { | 352 if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) { |
356 base::Closure blacklist_cb = | 353 base::Closure blacklist_cb = |
357 base::Bind(&SuggestionsService::UploadOneFromBlacklist, | 354 base::Bind(&SuggestionsService::UploadOneFromBlacklist, |
358 weak_ptr_factory_.GetWeakPtr()); | 355 weak_ptr_factory_.GetWeakPtr()); |
359 BrowserThread::PostDelayedTask( | 356 base::MessageLoopProxy::current()->PostDelayedTask( |
360 BrowserThread::UI, FROM_HERE, blacklist_cb, | 357 FROM_HERE, blacklist_cb, |
361 base::TimeDelta::FromSeconds(blacklist_delay_sec_)); | 358 base::TimeDelta::FromSeconds(blacklist_delay_sec_)); |
362 } | 359 } |
363 } | 360 } |
364 | 361 |
365 void SuggestionsService::UploadOneFromBlacklist() { | 362 void SuggestionsService::UploadOneFromBlacklist() { |
366 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 363 DCHECK(thread_checker_.CalledOnValidThread()); |
367 | 364 |
368 // If there's an ongoing request, let it complete. | 365 // If there's an ongoing request, let it complete. |
369 if (pending_request_.get()) return; | 366 if (pending_request_.get()) return; |
370 | 367 |
371 GURL blacklist_url; | 368 GURL blacklist_url; |
372 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) | 369 if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) |
373 return; // Local blacklist is empty. | 370 return; // Local blacklist is empty. |
374 | 371 |
375 // Send blacklisting request. | 372 // Send blacklisting request. |
376 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); | 373 IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); |
377 } | 374 } |
378 | 375 |
379 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { | 376 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { |
380 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 377 DCHECK(thread_checker_.CalledOnValidThread()); |
381 | 378 |
382 if (last_request_successful) { | 379 if (last_request_successful) { |
383 blacklist_delay_sec_ = kBlacklistDefaultDelaySec; | 380 blacklist_delay_sec_ = kBlacklistDefaultDelaySec; |
384 } else { | 381 } else { |
385 int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier; | 382 int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier; |
386 if (candidate_delay < kBlacklistMaxDelaySec) | 383 if (candidate_delay < kBlacklistMaxDelaySec) |
387 blacklist_delay_sec_ = candidate_delay; | 384 blacklist_delay_sec_ = candidate_delay; |
388 } | 385 } |
389 } | 386 } |
390 | 387 |
391 } // namespace suggestions | 388 } // namespace suggestions |
OLD | NEW |