| 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 |