QUIC - cleanup changes to sync chromium tree with internal source.
[chromium-blink-merge.git] / components / search / search.cc
blob1d0d6ada2bb8df297fae133e31fe6aaf09b580b8
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 "components/search/search.h"
7 #include "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "components/google/core/browser/google_util.h"
14 #include "components/search/search_switches.h"
15 #include "components/search_engines/template_url.h"
16 #include "url/gurl.h"
18 namespace search {
20 namespace {
22 // Configuration options for Embedded Search.
23 // EmbeddedSearch field trials are named in such a way that we can parse out
24 // the experiment configuration from the trial's group name in order to give
25 // us maximum flexability in running experiments.
26 // Field trial groups should be named things like "Group7 espv:2 instant:1".
27 // The first token is always GroupN for some integer N, followed by a
28 // space-delimited list of key:value pairs which correspond to these flags:
29 const char kEmbeddedPageVersionFlagName[] = "espv";
31 #if defined(OS_IOS)
32 const uint64 kEmbeddedPageVersionDefault = 1;
33 #elif defined(OS_ANDROID)
34 const uint64 kEmbeddedPageVersionDefault = 1;
35 // Use this variant to enable EmbeddedSearch SearchBox API in the results page.
36 const uint64 kEmbeddedSearchEnabledVersion = 2;
37 #else
38 const uint64 kEmbeddedPageVersionDefault = 2;
39 #endif
41 // Constants for the field trial name and group prefix.
42 // Note in M30 and below this field trial was named "InstantExtended" and in
43 // M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
44 // can't easilly sync up Finch configs with the pushing of this change to
45 // Dev & Canary, for now the code accepts both names.
46 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
47 // channel.
48 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
49 const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
51 // If the field trial's group name ends with this string its configuration will
52 // be ignored and Instant Extended will not be enabled by default.
53 const char kDisablingSuffix[] = "DISABLED";
55 #if !defined(OS_IOS) && !defined(OS_ANDROID)
56 const char kEnableQueryExtractionFlagName[] = "query_extraction";
57 #endif
59 const char kAllowPrefetchNonDefaultMatch[] = "allow_prefetch_non_default_match";
61 #if defined(OS_ANDROID)
62 const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
64 // Controls whether to reuse prerendered Instant Search base page to commit any
65 // search query.
66 const char kReuseInstantSearchBasePage[] = "reuse_instant_search_base_page";
67 #endif
69 } // namespace
71 // Negative start-margin values prevent the "es_sm" parameter from being used.
72 const int kDisableStartMargin = -1;
74 bool IsInstantExtendedAPIEnabled() {
75 #if defined(OS_IOS)
76 return false;
77 #elif defined(OS_ANDROID)
78 return EmbeddedSearchPageVersion() == kEmbeddedSearchEnabledVersion;
79 #else
80 return true;
81 #endif // defined(OS_IOS)
84 // Determine what embedded search page version to request from the user's
85 // default search provider. If 0, the embedded search UI should not be enabled.
86 uint64 EmbeddedSearchPageVersion() {
87 #if defined(OS_ANDROID)
88 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
89 switches::kEnableEmbeddedSearchAPI)) {
90 return kEmbeddedSearchEnabledVersion;
92 #endif
94 FieldTrialFlags flags;
95 if (GetFieldTrialInfo(&flags)) {
96 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
97 kEmbeddedPageVersionDefault,
98 flags);
100 return kEmbeddedPageVersionDefault;
103 bool GetFieldTrialInfo(FieldTrialFlags* flags) {
104 // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
105 // the older InstantExtended name.
106 std::string group_name = base::FieldTrialList::FindFullName(
107 kEmbeddedSearchFieldTrialName);
108 if (group_name.empty()) {
109 group_name = base::FieldTrialList::FindFullName(
110 kInstantExtendedFieldTrialName);
113 if (base::EndsWith(group_name, kDisablingSuffix,
114 base::CompareCase::SENSITIVE))
115 return false;
117 // We have a valid trial that isn't disabled. Extract the flags.
118 std::string group_prefix(group_name);
119 size_t first_space = group_name.find(" ");
120 if (first_space != std::string::npos) {
121 // There is a flags section of the group name. Split that out and parse it.
122 group_prefix = group_name.substr(0, first_space);
123 if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
124 ':', ' ', flags)) {
125 // Failed to parse the flags section. Assume the whole group name is
126 // invalid.
127 return false;
130 return true;
133 // Given a FieldTrialFlags object, returns the string value of the provided
134 // flag.
135 std::string GetStringValueForFlagWithDefault(const std::string& flag,
136 const std::string& default_value,
137 const FieldTrialFlags& flags) {
138 FieldTrialFlags::const_iterator i;
139 for (i = flags.begin(); i != flags.end(); i++) {
140 if (i->first == flag)
141 return i->second;
143 return default_value;
146 // Given a FieldTrialFlags object, returns the uint64 value of the provided
147 // flag.
148 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
149 uint64 default_value,
150 const FieldTrialFlags& flags) {
151 uint64 value;
152 std::string str_value =
153 GetStringValueForFlagWithDefault(flag, std::string(), flags);
154 if (base::StringToUint64(str_value, &value))
155 return value;
156 return default_value;
159 // Given a FieldTrialFlags object, returns the boolean value of the provided
160 // flag.
161 bool GetBoolValueForFlagWithDefault(const std::string& flag,
162 bool default_value,
163 const FieldTrialFlags& flags) {
164 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
167 std::string InstantExtendedEnabledParam(bool for_search) {
168 if (for_search && !IsQueryExtractionEnabled())
169 return std::string();
170 return std::string(google_util::kInstantExtendedAPIParam) + "=" +
171 base::Uint64ToString(EmbeddedSearchPageVersion()) + "&";
174 std::string ForceInstantResultsParam(bool for_prerender) {
175 return (for_prerender || !IsInstantExtendedAPIEnabled()) ? "ion=1&"
176 : std::string();
179 bool IsQueryExtractionEnabled() {
180 #if defined(OS_IOS) || defined(OS_ANDROID)
181 return false;
182 #else
183 if (!IsInstantExtendedAPIEnabled())
184 return false;
186 const base::CommandLine* command_line =
187 base::CommandLine::ForCurrentProcess();
188 if (command_line->HasSwitch(switches::kEnableQueryExtraction))
189 return true;
191 FieldTrialFlags flags;
192 return GetFieldTrialInfo(&flags) &&
193 GetBoolValueForFlagWithDefault(kEnableQueryExtractionFlagName, false,
194 flags);
195 #endif // defined(OS_IOS) || defined(OS_ANDROID)
198 bool ShouldPrefetchSearchResults() {
199 if (!IsInstantExtendedAPIEnabled())
200 return false;
202 #if defined(OS_ANDROID)
203 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
204 switches::kPrefetchSearchResults)) {
205 return true;
208 FieldTrialFlags flags;
209 return GetFieldTrialInfo(&flags) &&
210 GetBoolValueForFlagWithDefault(kPrefetchSearchResultsFlagName, false,
211 flags);
212 #else
213 return true;
214 #endif
217 bool ShouldReuseInstantSearchBasePage() {
218 if (!ShouldPrefetchSearchResults())
219 return false;
221 #if defined(OS_ANDROID)
222 FieldTrialFlags flags;
223 return GetFieldTrialInfo(&flags) &&
224 GetBoolValueForFlagWithDefault(kReuseInstantSearchBasePage, false,
225 flags);
226 #else
227 return true;
228 #endif
231 bool ShouldAllowPrefetchNonDefaultMatch() {
232 if (!ShouldPrefetchSearchResults())
233 return false;
235 FieldTrialFlags flags;
236 return GetFieldTrialInfo(&flags) &&
237 GetBoolValueForFlagWithDefault(kAllowPrefetchNonDefaultMatch, false,
238 flags);
241 // |url| should either have a secure scheme or have a non-HTTPS base URL that
242 // the user specified using --google-base-url. (This allows testers to use
243 // --google-base-url to point at non-HTTPS servers, which eases testing.)
244 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
245 return template_url->HasSearchTermsReplacementKey(url) &&
246 (url.SchemeIsCryptographic() ||
247 google_util::StartsWithCommandLineGoogleBaseURL(url));
250 void EnableQueryExtractionForTesting() {
251 #if !defined(OS_IOS) && !defined(OS_ANDROID)
252 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
253 cl->AppendSwitch(switches::kEnableQueryExtraction);
254 #endif
257 } // namespace search