Componentize AccountReconcilor.
[chromium-blink-merge.git] / chrome / browser / search / suggestions / suggestions_service.cc
blobf6c0d5fc1dadc1dfdf0bc96347414c3ef277ef82
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
3 // found in the LICENSE file.
5 #include "chrome/browser/search/suggestions/suggestions_service.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/strings/string_util.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/history/history_types.h"
14 #include "chrome/browser/metrics/variations/variations_http_header_provider.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "components/variations/variations_associated_data.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/load_flags.h"
19 #include "net/base/net_errors.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_status_code.h"
22 #include "net/http/http_util.h"
23 #include "net/url_request/url_fetcher.h"
24 #include "net/url_request/url_request_status.h"
25 #include "url/gurl.h"
27 namespace suggestions {
29 namespace {
31 // Used to UMA log the state of the last response from the server.
32 enum SuggestionsResponseState {
33 RESPONSE_EMPTY,
34 RESPONSE_INVALID,
35 RESPONSE_VALID,
36 RESPONSE_STATE_SIZE
39 // Will log the supplied response |state|.
40 void LogResponseState(SuggestionsResponseState state) {
41 UMA_HISTOGRAM_ENUMERATION("Suggestions.ResponseState", state,
42 RESPONSE_STATE_SIZE);
45 // Obtains the experiment parameter under the supplied |key|.
46 std::string GetExperimentParam(const std::string& key) {
47 return chrome_variations::GetVariationParamValue(kSuggestionsFieldTrialName,
48 key);
51 // Runs each callback in |requestors| on |suggestions|, then deallocates
52 // |requestors|.
53 void DispatchRequestsAndClear(
54 const SuggestionsProfile& suggestions,
55 std::vector<SuggestionsService::ResponseCallback>* requestors) {
56 std::vector<SuggestionsService::ResponseCallback>::iterator it;
57 for (it = requestors->begin(); it != requestors->end(); ++it) {
58 it->Run(suggestions);
60 std::vector<SuggestionsService::ResponseCallback>().swap(*requestors);
63 } // namespace
65 const char kSuggestionsFieldTrialName[] = "ChromeSuggestions";
66 const char kSuggestionsFieldTrialURLParam[] = "url";
67 const char kSuggestionsFieldTrialStateParam[] = "state";
68 const char kSuggestionsFieldTrialStateEnabled[] = "enabled";
70 SuggestionsService::SuggestionsService(Profile* profile)
71 : profile_(profile) {
72 // Obtain the URL to use to fetch suggestions data from the Variations param.
73 suggestions_url_ = GURL(GetExperimentParam(kSuggestionsFieldTrialURLParam));
76 SuggestionsService::~SuggestionsService() {
79 // static
80 bool SuggestionsService::IsEnabled() {
81 return GetExperimentParam(kSuggestionsFieldTrialStateParam) ==
82 kSuggestionsFieldTrialStateEnabled;
85 void SuggestionsService::FetchSuggestionsData(
86 SuggestionsService::ResponseCallback callback) {
87 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
89 if (pending_request_.get()) {
90 // Request already exists, so just add requestor to queue.
91 waiting_requestors_.push_back(callback);
92 return;
95 // Form new request.
96 DCHECK(waiting_requestors_.empty());
97 waiting_requestors_.push_back(callback);
99 pending_request_.reset(net::URLFetcher::Create(
100 0, suggestions_url_, net::URLFetcher::GET, this));
101 pending_request_->SetLoadFlags(net::LOAD_DISABLE_CACHE);
102 pending_request_->SetRequestContext(profile_->GetRequestContext());
103 // Add Chrome experiment state to the request headers.
104 net::HttpRequestHeaders headers;
105 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->
106 AppendHeaders(pending_request_->GetOriginalURL(),
107 profile_->IsOffTheRecord(), false, &headers);
108 pending_request_->SetExtraRequestHeaders(headers.ToString());
109 pending_request_->Start();
111 last_request_started_time_ = base::TimeTicks::Now();
114 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) {
115 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
116 DCHECK_EQ(pending_request_.get(), source);
118 // The fetcher will be deleted when the request is handled.
119 scoped_ptr<const net::URLFetcher> request(pending_request_.release());
120 const net::URLRequestStatus& request_status = request->GetStatus();
121 if (request_status.status() != net::URLRequestStatus::SUCCESS) {
122 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FailedRequestErrorCode",
123 -request_status.error());
124 DVLOG(1) << "Suggestions server request failed with error: "
125 << request_status.error() << ": "
126 << net::ErrorToString(request_status.error());
127 // Dispatch an empty profile on error.
128 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_);
129 return;
132 // Log the response code.
133 const int response_code = request->GetResponseCode();
134 UMA_HISTOGRAM_SPARSE_SLOWLY("Suggestions.FetchResponseCode",
135 response_code);
136 if (response_code != net::HTTP_OK) {
137 // Dispatch an empty profile on error.
138 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_);
139 return;
142 const base::TimeDelta latency =
143 base::TimeTicks::Now() - last_request_started_time_;
144 UMA_HISTOGRAM_MEDIUM_TIMES("Suggestions.FetchSuccessLatency", latency);
146 std::string suggestions_data;
147 bool success = request->GetResponseAsString(&suggestions_data);
148 DCHECK(success);
150 // Compute suggestions, and dispatch then to requestors. On error still
151 // dispatch empty suggestions.
152 SuggestionsProfile suggestions;
153 if (suggestions_data.empty()) {
154 LogResponseState(RESPONSE_EMPTY);
155 } else if (suggestions.ParseFromString(suggestions_data)) {
156 LogResponseState(RESPONSE_VALID);
157 } else {
158 LogResponseState(RESPONSE_INVALID);
161 DispatchRequestsAndClear(suggestions, &waiting_requestors_);
164 void SuggestionsService::Shutdown() {
165 // Cancel pending request.
166 pending_request_.reset(NULL);
168 // Dispatch empty suggestions to requestors.
169 DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_);
172 } // namespace suggestions