Index: chrome/browser/search/suggestions/suggestions_service.cc |
diff --git a/chrome/browser/search/suggestions/suggestions_service.cc b/chrome/browser/search/suggestions/suggestions_service.cc |
deleted file mode 100644 |
index 60e7dbe66543a2dc8bc059c99124e8e18be39fc6..0000000000000000000000000000000000000000 |
--- a/chrome/browser/search/suggestions/suggestions_service.cc |
+++ /dev/null |
@@ -1,391 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/search/suggestions/suggestions_service.h" |
- |
-#include <sstream> |
-#include <string> |
- |
-#include "base/memory/scoped_ptr.h" |
-#include "base/metrics/histogram.h" |
-#include "base/metrics/sparse_histogram.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_util.h" |
-#include "base/time/time.h" |
-#include "chrome/browser/search/suggestions/blacklist_store.h" |
-#include "chrome/browser/search/suggestions/suggestions_store.h" |
-#include "components/pref_registry/pref_registry_syncable.h" |
-#include "components/variations/variations_associated_data.h" |
-#include "components/variations/variations_http_header_provider.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "net/base/escape.h" |
-#include "net/base/load_flags.h" |
-#include "net/base/net_errors.h" |
-#include "net/base/url_util.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_status_code.h" |
-#include "net/http/http_util.h" |
-#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_request_status.h" |
-#include "url/gurl.h" |
- |
-using base::CancelableClosure; |
-using content::BrowserThread; |
- |
-namespace suggestions { |
- |
-namespace { |
- |
-// Used to UMA log the state of the last response from the server. |
-enum SuggestionsResponseState { |
- RESPONSE_EMPTY, |
- RESPONSE_INVALID, |
- RESPONSE_VALID, |
- RESPONSE_STATE_SIZE |
-}; |
- |
-// Will log the supplied response |state|. |
-void LogResponseState(SuggestionsResponseState state) { |
- UMA_HISTOGRAM_ENUMERATION("Suggestions.ResponseState", state, |
- RESPONSE_STATE_SIZE); |
-} |
- |
-// Obtains the experiment parameter under the supplied |key|, or empty string |
-// if the parameter does not exist. |
-std::string GetExperimentParam(const std::string& key) { |
- return chrome_variations::GetVariationParamValue(kSuggestionsFieldTrialName, |
- key); |
-} |
- |
-GURL BuildBlacklistRequestURL(const std::string& blacklist_url_prefix, |
- const GURL& candidate_url) { |
- return GURL(blacklist_url_prefix + |
- net::EscapeQueryParamValue(candidate_url.spec(), true)); |
-} |
- |
-// Runs each callback in |requestors| on |suggestions|, then deallocates |
-// |requestors|. |
-void DispatchRequestsAndClear( |
- const SuggestionsProfile& suggestions, |
- std::vector<SuggestionsService::ResponseCallback>* requestors) { |
- std::vector<SuggestionsService::ResponseCallback>::iterator it; |
- for (it = requestors->begin(); it != requestors->end(); ++it) { |
- if (!it->is_null()) it->Run(suggestions); |
- } |
- std::vector<SuggestionsService::ResponseCallback>().swap(*requestors); |
-} |
- |
-const int kDefaultRequestTimeoutMs = 200; |
- |
-// Default delay used when scheduling a blacklist request. |
-const int kBlacklistDefaultDelaySec = 1; |
- |
-// Multiplier on the delay used when scheduling a blacklist request, in case the |
-// last observed request was unsuccessful. |
-const int kBlacklistBackoffMultiplier = 2; |
- |
-// Maximum valid delay for scheduling a request. Candidate delays larger than |
-// this are rejected. This means the maximum backoff is at least 300 / 2, i.e. |
-// 2.5 minutes. |
-const int kBlacklistMaxDelaySec = 300; // 5 minutes |
- |
-} // namespace |
- |
-const char kSuggestionsFieldTrialName[] = "ChromeSuggestions"; |
-const char kSuggestionsFieldTrialURLParam[] = "url"; |
-const char kSuggestionsFieldTrialCommonParamsParam[] = "common_params"; |
-const char kSuggestionsFieldTrialBlacklistPathParam[] = "blacklist_path"; |
-const char kSuggestionsFieldTrialBlacklistUrlParam[] = "blacklist_url_param"; |
-const char kSuggestionsFieldTrialStateParam[] = "state"; |
-const char kSuggestionsFieldTrialControlParam[] = "control"; |
-const char kSuggestionsFieldTrialStateEnabled[] = "enabled"; |
-const char kSuggestionsFieldTrialTimeoutMs[] = "timeout_ms"; |
- |
-namespace { |
- |
-std::string GetBlacklistUrlPrefix() { |
- std::stringstream blacklist_url_prefix_stream; |
- blacklist_url_prefix_stream |
- << GetExperimentParam(kSuggestionsFieldTrialURLParam) |
- << GetExperimentParam(kSuggestionsFieldTrialBlacklistPathParam) << "?" |
- << GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam) << "&" |
- << GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam) << "="; |
- return blacklist_url_prefix_stream.str(); |
-} |
- |
-} // namespace |
- |
-SuggestionsService::SuggestionsService( |
- net::URLRequestContextGetter* url_request_context, |
- scoped_ptr<SuggestionsStore> suggestions_store, |
- scoped_ptr<ImageManager> thumbnail_manager, |
- scoped_ptr<BlacklistStore> blacklist_store) |
- : suggestions_store_(suggestions_store.Pass()), |
- blacklist_store_(blacklist_store.Pass()), |
- thumbnail_manager_(thumbnail_manager.Pass()), |
- url_request_context_(url_request_context), |
- blacklist_delay_sec_(kBlacklistDefaultDelaySec), |
- weak_ptr_factory_(this), |
- request_timeout_ms_(kDefaultRequestTimeoutMs) { |
- // Obtain various parameters from Variations. |
- suggestions_url_ = |
- GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam) + "?" + |
- GetExperimentParam(kSuggestionsFieldTrialCommonParamsParam)); |
- blacklist_url_prefix_ = GetBlacklistUrlPrefix(); |
- std::string timeout = GetExperimentParam(kSuggestionsFieldTrialTimeoutMs); |
- int temp_timeout; |
- if (!timeout.empty() && base::StringToInt(timeout, &temp_timeout)) { |
- request_timeout_ms_ = temp_timeout; |
- } |
-} |
- |
-SuggestionsService::~SuggestionsService() {} |
- |
-// static |
-bool SuggestionsService::IsEnabled() { |
- return GetExperimentParam(kSuggestionsFieldTrialStateParam) == |
- kSuggestionsFieldTrialStateEnabled; |
-} |
- |
-// static |
-bool SuggestionsService::IsControlGroup() { |
- return GetExperimentParam(kSuggestionsFieldTrialControlParam) == |
- kSuggestionsFieldTrialStateEnabled; |
-} |
- |
-void SuggestionsService::FetchSuggestionsData( |
- SuggestionsService::ResponseCallback callback) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- |
- FetchSuggestionsDataNoTimeout(callback); |
- |
- // Post a task to serve the cached suggestions if the request hasn't completed |
- // after some time. Cancels the previous such task, if one existed. |
- pending_timeout_closure_.reset(new CancelableClosure(base::Bind( |
- &SuggestionsService::OnRequestTimeout, weak_ptr_factory_.GetWeakPtr()))); |
- BrowserThread::PostDelayedTask( |
- BrowserThread::UI, FROM_HERE, pending_timeout_closure_->callback(), |
- base::TimeDelta::FromMilliseconds(request_timeout_ms_)); |
-} |
- |
-void SuggestionsService::FetchSuggestionsDataNoTimeout( |
- SuggestionsService::ResponseCallback callback) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- if (pending_request_.get()) { |
- // Request already exists, so just add requestor to queue. |
- waiting_requestors_.push_back(callback); |
- return; |
- } |
- |
- // Form new request. |
- DCHECK(waiting_requestors_.empty()); |
- waiting_requestors_.push_back(callback); |
- IssueRequest(suggestions_url_); |
-} |
- |
-void SuggestionsService::GetPageThumbnail( |
- const GURL& url, |
- base::Callback<void(const GURL&, const SkBitmap*)> callback) { |
- thumbnail_manager_->GetImageForURL(url, callback); |
-} |
- |
-void SuggestionsService::BlacklistURL( |
- const GURL& candidate_url, |
- const SuggestionsService::ResponseCallback& callback) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- waiting_requestors_.push_back(callback); |
- |
- // Blacklist locally, for immediate effect. |
- if (!blacklist_store_->BlacklistUrl(candidate_url)) { |
- DVLOG(1) << "Failed blacklisting attempt."; |
- return; |
- } |
- |
- // If there's an ongoing request, let it complete. |
- if (pending_request_.get()) return; |
- |
- IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, candidate_url)); |
-} |
- |
-// static |
-bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, |
- GURL* url) { |
- bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(), |
- GetBlacklistUrlPrefix(), true); |
- if (!is_blacklist_request) return false; |
- |
- // Extract the blacklisted URL from the blacklist request. |
- std::string blacklisted; |
- if (!net::GetValueForKeyInQuery( |
- request.GetOriginalURL(), |
- GetExperimentParam(kSuggestionsFieldTrialBlacklistUrlParam), |
- &blacklisted)) |
- return false; |
- |
- GURL blacklisted_url(blacklisted); |
- blacklisted_url.Swap(url); |
- return true; |
-} |
- |
-// static |
-void SuggestionsService::RegisterProfilePrefs( |
- user_prefs::PrefRegistrySyncable* registry) { |
- SuggestionsStore::RegisterProfilePrefs(registry); |
- BlacklistStore::RegisterProfilePrefs(registry); |
-} |
- |
-void SuggestionsService::IssueRequest(const GURL& url) { |
- pending_request_.reset(CreateSuggestionsRequest(url)); |
- pending_request_->Start(); |
- last_request_started_time_ = base::TimeTicks::Now(); |
-} |
- |
-net::URLFetcher* SuggestionsService::CreateSuggestionsRequest(const GURL& url) { |
- net::URLFetcher* request = |
- net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); |
- request->SetLoadFlags(net::LOAD_DISABLE_CACHE); |
- request->SetRequestContext(url_request_context_); |
- // Add Chrome experiment state to the request headers. |
- net::HttpRequestHeaders headers; |
- variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( |
- request->GetOriginalURL(), false, false, &headers); |
- request->SetExtraRequestHeaders(headers.ToString()); |
- return request; |
-} |
- |
-void SuggestionsService::OnRequestTimeout() { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- ServeFromCache(); |
-} |
- |
-void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- DCHECK_EQ(pending_request_.get(), source); |
- |
- // We no longer need the timeout closure. Delete it whether or not it has run. |
- // If it hasn't, this cancels it. |
- pending_timeout_closure_.reset(); |
- |
- // The fetcher will be deleted when the request is handled. |
- scoped_ptr<const net::URLFetcher> request(pending_request_.release()); |
- const net::URLRequestStatus& request_status = request->GetStatus(); |
- if (request_status.status() != net::URLRequestStatus::SUCCESS) { |
- UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode", |
- -request_status.error()); |
- DVLOG(1) << "Suggestions server request failed with error: " |
- << request_status.error() << ": " |
- << net::ErrorToString(request_status.error()); |
- // Dispatch the cached profile on error. |
- ServeFromCache(); |
- ScheduleBlacklistUpload(false); |
- return; |
- } |
- |
- // Log the response code. |
- const int response_code = request->GetResponseCode(); |
- UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode", response_code); |
- if (response_code != net::HTTP_OK) { |
- // Aggressively clear the store. |
- suggestions_store_->ClearSuggestions(); |
- DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_); |
- ScheduleBlacklistUpload(false); |
- return; |
- } |
- |
- const base::TimeDelta latency = |
- base::TimeTicks::Now() - last_request_started_time_; |
- UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency); |
- |
- // Handle a successful blacklisting. |
- GURL blacklisted_url; |
- if (GetBlacklistedUrl(*source, &blacklisted_url)) { |
- blacklist_store_->RemoveUrl(blacklisted_url); |
- } |
- |
- std::string suggestions_data; |
- bool success = request->GetResponseAsString(&suggestions_data); |
- DCHECK(success); |
- |
- // Compute suggestions, and dispatch then to requestors. On error still |
- // dispatch empty suggestions. |
- SuggestionsProfile suggestions; |
- if (suggestions_data.empty()) { |
- LogResponseState(RESPONSE_EMPTY); |
- suggestions_store_->ClearSuggestions(); |
- } else if (suggestions.ParseFromString(suggestions_data)) { |
- LogResponseState(RESPONSE_VALID); |
- thumbnail_manager_->Initialize(suggestions); |
- suggestions_store_->StoreSuggestions(suggestions); |
- } else { |
- LogResponseState(RESPONSE_INVALID); |
- suggestions_store_->LoadSuggestions(&suggestions); |
- } |
- |
- FilterAndServe(&suggestions); |
- ScheduleBlacklistUpload(true); |
-} |
- |
-void SuggestionsService::Shutdown() { |
- // Cancel pending request and timeout closure, then serve existing requestors |
- // from cache. |
- pending_request_.reset(NULL); |
- pending_timeout_closure_.reset(NULL); |
- ServeFromCache(); |
-} |
- |
-void SuggestionsService::ServeFromCache() { |
- SuggestionsProfile suggestions; |
- suggestions_store_->LoadSuggestions(&suggestions); |
- FilterAndServe(&suggestions); |
-} |
- |
-void SuggestionsService::FilterAndServe(SuggestionsProfile* suggestions) { |
- blacklist_store_->FilterSuggestions(suggestions); |
- DispatchRequestsAndClear(*suggestions, &waiting_requestors_); |
-} |
- |
-void SuggestionsService::ScheduleBlacklistUpload(bool last_request_successful) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- |
- UpdateBlacklistDelay(last_request_successful); |
- |
- // Schedule a blacklist upload task. |
- GURL blacklist_url; |
- if (blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) { |
- base::Closure blacklist_cb = |
- base::Bind(&SuggestionsService::UploadOneFromBlacklist, |
- weak_ptr_factory_.GetWeakPtr()); |
- BrowserThread::PostDelayedTask( |
- BrowserThread::UI, FROM_HERE, blacklist_cb, |
- base::TimeDelta::FromSeconds(blacklist_delay_sec_)); |
- } |
-} |
- |
-void SuggestionsService::UploadOneFromBlacklist() { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- |
- // If there's an ongoing request, let it complete. |
- if (pending_request_.get()) return; |
- |
- GURL blacklist_url; |
- if (!blacklist_store_->GetFirstUrlFromBlacklist(&blacklist_url)) |
- return; // Local blacklist is empty. |
- |
- // Send blacklisting request. |
- IssueRequest(BuildBlacklistRequestURL(blacklist_url_prefix_, blacklist_url)); |
-} |
- |
-void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- |
- if (last_request_successful) { |
- blacklist_delay_sec_ = kBlacklistDefaultDelaySec; |
- } else { |
- int candidate_delay = blacklist_delay_sec_ * kBlacklistBackoffMultiplier; |
- if (candidate_delay < kBlacklistMaxDelaySec) |
- blacklist_delay_sec_ = candidate_delay; |
- } |
-} |
- |
-} // namespace suggestions |