1 // Copyright 2012 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/search.h"
7 #include "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/google/google_util.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/search/instant_service.h"
18 #include "chrome/browser/search/instant_service_factory.h"
19 #include "chrome/browser/search_engines/template_url_service.h"
20 #include "chrome/browser/search_engines/template_url_service_factory.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_instant_controller.h"
23 #include "chrome/browser/ui/browser_iterator.h"
24 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/common/search_urls.h"
28 #include "chrome/common/url_constants.h"
29 #include "components/sessions/serialized_navigation_entry.h"
30 #include "components/user_prefs/pref_registry_syncable.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "grit/generated_resources.h"
35 #include "ui/base/l10n/l10n_util.h"
37 #if defined(ENABLE_MANAGED_USERS)
38 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
39 #include "chrome/browser/managed_mode/managed_user_service.h"
40 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
47 // Configuration options for Embedded Search.
48 // EmbeddedSearch field trials are named in such a way that we can parse out
49 // the experiment configuration from the trial's group name in order to give
50 // us maximum flexability in running experiments.
51 // Field trial groups should be named things like "Group7 espv:2 instant:1".
52 // The first token is always GroupN for some integer N, followed by a
53 // space-delimited list of key:value pairs which correspond to these flags:
54 const char kEmbeddedPageVersionFlagName
[] = "espv";
55 #if defined(OS_IOS) || defined(OS_ANDROID)
56 const uint64 kEmbeddedPageVersionDefault
= 1;
58 const uint64 kEmbeddedPageVersionDefault
= 2;
61 const char kHideVerbatimFlagName
[] = "hide_verbatim";
62 const char kPrefetchSearchResultsFlagName
[] = "prefetch_results";
63 const char kPrefetchSearchResultsOnSRP
[] = "prefetch_results_srp";
64 const char kDisplaySearchButtonFlagName
[] = "display_search_button";
65 const char kOriginChipFlagName
[] = "origin_chip";
66 #if !defined(OS_IOS) && !defined(OS_ANDROID)
67 const char kEnableQueryExtractionFlagName
[] = "query_extraction";
70 // Constants for the field trial name and group prefix.
71 // Note in M30 and below this field trial was named "InstantExtended" and in
72 // M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
73 // can't easilly sync up Finch configs with the pushing of this change to
74 // Dev & Canary, for now the code accepts both names.
75 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
77 const char kInstantExtendedFieldTrialName
[] = "InstantExtended";
78 const char kEmbeddedSearchFieldTrialName
[] = "EmbeddedSearch";
80 // If the field trial's group name ends with this string its configuration will
81 // be ignored and Instant Extended will not be enabled by default.
82 const char kDisablingSuffix
[] = "DISABLED";
84 // Used to set the Instant support state of the Navigation entry.
85 const char kInstantSupportStateKey
[] = "instant_support_state";
87 const char kInstantSupportEnabled
[] = "Instant support enabled";
88 const char kInstantSupportDisabled
[] = "Instant support disabled";
89 const char kInstantSupportUnknown
[] = "Instant support unknown";
91 InstantSupportState
StringToInstantSupportState(const base::string16
& value
) {
92 if (value
== base::ASCIIToUTF16(kInstantSupportEnabled
))
93 return INSTANT_SUPPORT_YES
;
94 else if (value
== base::ASCIIToUTF16(kInstantSupportDisabled
))
95 return INSTANT_SUPPORT_NO
;
97 return INSTANT_SUPPORT_UNKNOWN
;
100 base::string16
InstantSupportStateToString(InstantSupportState state
) {
102 case INSTANT_SUPPORT_NO
:
103 return base::ASCIIToUTF16(kInstantSupportDisabled
);
104 case INSTANT_SUPPORT_YES
:
105 return base::ASCIIToUTF16(kInstantSupportEnabled
);
106 case INSTANT_SUPPORT_UNKNOWN
:
107 return base::ASCIIToUTF16(kInstantSupportUnknown
);
109 return base::ASCIIToUTF16(kInstantSupportUnknown
);
112 TemplateURL
* GetDefaultSearchProviderTemplateURL(Profile
* profile
) {
113 TemplateURLService
* template_url_service
=
114 TemplateURLServiceFactory::GetForProfile(profile
);
115 if (template_url_service
)
116 return template_url_service
->GetDefaultSearchProvider();
120 GURL
TemplateURLRefToGURL(const TemplateURLRef
& ref
,
122 bool append_extra_query_params
,
123 bool force_instant_results
) {
124 TemplateURLRef::SearchTermsArgs search_terms_args
=
125 TemplateURLRef::SearchTermsArgs(base::string16());
126 search_terms_args
.omnibox_start_margin
= start_margin
;
127 search_terms_args
.append_extra_query_params
= append_extra_query_params
;
128 search_terms_args
.force_instant_results
= force_instant_results
;
129 return GURL(ref
.ReplaceSearchTerms(search_terms_args
));
132 bool MatchesAnySearchURL(const GURL
& url
, TemplateURL
* template_url
) {
134 TemplateURLRefToGURL(template_url
->url_ref(), kDisableStartMargin
, false,
136 if (search_url
.is_valid() &&
137 search::MatchesOriginAndPath(url
, search_url
))
140 // "URLCount() - 1" because we already tested url_ref above.
141 for (size_t i
= 0; i
< template_url
->URLCount() - 1; ++i
) {
142 TemplateURLRef
ref(template_url
, i
);
143 search_url
= TemplateURLRefToGURL(ref
, kDisableStartMargin
, false, false);
144 if (search_url
.is_valid() &&
145 search::MatchesOriginAndPath(url
, search_url
))
152 // Returns true if |contents| is rendered inside the Instant process for
154 bool IsRenderedInInstantProcess(const content::WebContents
* contents
,
156 const content::RenderProcessHost
* process_host
=
157 contents
->GetRenderProcessHost();
161 const InstantService
* instant_service
=
162 InstantServiceFactory::GetForProfile(profile
);
163 if (!instant_service
)
166 return instant_service
->IsInstantProcess(process_host
->GetID());
169 // Returns true if |url| passes some basic checks that must succeed for it to be
170 // usable as an instant URL:
171 // (1) It contains the search terms replacement key of |template_url|, which is
172 // expected to be the TemplateURL* for the default search provider.
173 // (2) Either it has a secure scheme, or else the user has manually specified a
174 // --google-base-url and it uses that base URL. (This allows testers to use
175 // --google-base-url to point at non-HTTPS servers, which eases testing.)
176 bool IsSuitableURLForInstant(const GURL
& url
, const TemplateURL
* template_url
) {
177 return template_url
->HasSearchTermsReplacementKey(url
) &&
178 (url
.SchemeIsSecure() ||
179 google_util::StartsWithCommandLineGoogleBaseURL(url
));
182 // Returns true if |url| can be used as an Instant URL for |profile|.
183 bool IsInstantURL(const GURL
& url
, Profile
* profile
) {
184 if (!IsInstantExtendedAPIEnabled())
190 const GURL
new_tab_url(GetNewTabPageURL(profile
));
191 if (new_tab_url
.is_valid() &&
192 search::MatchesOriginAndPath(url
, new_tab_url
))
195 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
199 if (!IsSuitableURLForInstant(url
, template_url
))
202 const TemplateURLRef
& instant_url_ref
= template_url
->instant_url_ref();
203 const GURL instant_url
=
204 TemplateURLRefToGURL(instant_url_ref
, kDisableStartMargin
, false, false);
205 if (!instant_url
.is_valid())
208 if (search::MatchesOriginAndPath(url
, instant_url
))
211 return IsQueryExtractionEnabled() && MatchesAnySearchURL(url
, template_url
);
214 base::string16
GetSearchTermsImpl(const content::WebContents
* contents
,
215 const content::NavigationEntry
* entry
) {
216 if (!contents
|| !IsQueryExtractionEnabled())
217 return base::string16();
219 // For security reasons, don't extract search terms if the page is not being
220 // rendered in the privileged Instant renderer process. This is to protect
221 // against a malicious page somehow scripting the search results page and
222 // faking search terms in the URL. Random pages can't get into the Instant
223 // renderer and scripting doesn't work cross-process, so if the page is in
224 // the Instant process, we know it isn't being exploited.
225 // Since iOS and Android doesn't use the instant framework, these checks are
226 // disabled for the two platforms.
227 Profile
* profile
= Profile::FromBrowserContext(contents
->GetBrowserContext());
228 #if !defined(OS_IOS) && !defined(OS_ANDROID)
229 if (!IsRenderedInInstantProcess(contents
, profile
) &&
230 ((entry
== contents
->GetController().GetLastCommittedEntry()) ||
231 !ShouldAssignURLToInstantRenderer(entry
->GetURL(), profile
)))
232 return base::string16();
233 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
234 // Check to see if search terms have already been extracted.
235 base::string16 search_terms
= GetSearchTermsFromNavigationEntry(entry
);
236 if (!search_terms
.empty())
239 // Otherwise, extract from the URL.
240 return GetSearchTermsFromURL(profile
, entry
->GetVirtualURL());
243 bool IsURLAllowedForSupervisedUser(const GURL
& url
, Profile
* profile
) {
244 #if defined(ENABLE_MANAGED_USERS)
245 ManagedUserService
* managed_user_service
=
246 ManagedUserServiceFactory::GetForProfile(profile
);
247 ManagedModeURLFilter
* url_filter
=
248 managed_user_service
->GetURLFilterForUIThread();
249 if (url_filter
->GetFilteringBehaviorForURL(url
) ==
250 ManagedModeURLFilter::BLOCK
) {
259 // Negative start-margin values prevent the "es_sm" parameter from being used.
260 const int kDisableStartMargin
= -1;
262 bool IsInstantExtendedAPIEnabled() {
263 #if defined(OS_IOS) || defined(OS_ANDROID)
267 #endif // defined(OS_IOS) || defined(OS_ANDROID)
270 // Determine what embedded search page version to request from the user's
271 // default search provider. If 0, the embedded search UI should not be enabled.
272 uint64
EmbeddedSearchPageVersion() {
273 FieldTrialFlags flags
;
274 if (GetFieldTrialInfo(&flags
)) {
275 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName
,
276 kEmbeddedPageVersionDefault
,
279 return kEmbeddedPageVersionDefault
;
282 bool IsQueryExtractionEnabled() {
283 #if defined(OS_IOS) || defined(OS_ANDROID)
286 if (!IsInstantExtendedAPIEnabled())
289 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
290 if (command_line
->HasSwitch(switches::kEnableQueryExtraction
))
293 FieldTrialFlags flags
;
294 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
295 kEnableQueryExtractionFlagName
, false, flags
);
296 #endif // defined(OS_IOS) || defined(OS_ANDROID)
299 base::string16
GetSearchTermsFromURL(Profile
* profile
, const GURL
& url
) {
300 if (url
.is_valid() && url
== GetSearchResultPrefetchBaseURL(profile
)) {
301 // InstantSearchPrerenderer has the search query for the Instant search base
303 InstantSearchPrerenderer
* prerenderer
=
304 InstantSearchPrerenderer::GetForProfile(profile
);
306 return prerenderer
->get_last_query();
309 base::string16 search_terms
;
310 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
311 if (template_url
&& IsSuitableURLForInstant(url
, template_url
))
312 template_url
->ExtractSearchTermsFromURL(url
, &search_terms
);
316 base::string16
GetSearchTermsFromNavigationEntry(
317 const content::NavigationEntry
* entry
) {
318 base::string16 search_terms
;
320 entry
->GetExtraData(sessions::kSearchTermsKey
, &search_terms
);
324 base::string16
GetSearchTerms(const content::WebContents
* contents
) {
326 return base::string16();
328 const content::NavigationEntry
* entry
=
329 contents
->GetController().GetVisibleEntry();
331 return base::string16();
333 #if !defined(OS_IOS) && !defined(OS_ANDROID)
334 // iOS and Android doesn't use the Instant framework, disable this check for
335 // the two platforms.
336 InstantSupportState state
= GetInstantSupportStateFromNavigationEntry(*entry
);
337 if (state
== INSTANT_SUPPORT_NO
)
338 return base::string16();
339 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
341 return GetSearchTermsImpl(contents
, entry
);
344 bool ShouldAssignURLToInstantRenderer(const GURL
& url
, Profile
* profile
) {
345 return url
.is_valid() &&
347 IsInstantExtendedAPIEnabled() &&
348 (url
.SchemeIs(chrome::kChromeSearchScheme
) ||
349 IsInstantURL(url
, profile
));
352 bool ShouldUseProcessPerSiteForInstantURL(const GURL
& url
, Profile
* profile
) {
353 return ShouldAssignURLToInstantRenderer(url
, profile
) &&
354 (url
.host() == chrome::kChromeSearchLocalNtpHost
||
355 url
.host() == chrome::kChromeSearchOnlineNtpHost
);
358 bool IsNTPURL(const GURL
& url
, Profile
* profile
) {
362 if (!IsInstantExtendedAPIEnabled())
363 return url
== GURL(chrome::kChromeUINewTabURL
);
366 ((IsInstantURL(url
, profile
) &&
367 GetSearchTermsFromURL(profile
, url
).empty()) ||
368 url
== GURL(chrome::kChromeSearchLocalNtpUrl
));
371 bool IsInstantNTP(const content::WebContents
* contents
) {
375 return NavEntryIsInstantNTP(contents
,
376 contents
->GetController().GetVisibleEntry());
379 bool NavEntryIsInstantNTP(const content::WebContents
* contents
,
380 const content::NavigationEntry
* entry
) {
381 if (!contents
|| !entry
|| !IsInstantExtendedAPIEnabled())
384 Profile
* profile
= Profile::FromBrowserContext(contents
->GetBrowserContext());
385 if (!IsRenderedInInstantProcess(contents
, profile
))
388 if (entry
->GetURL() == GetLocalInstantURL(profile
))
391 GURL
new_tab_url(GetNewTabPageURL(profile
));
392 return new_tab_url
.is_valid() &&
393 search::MatchesOriginAndPath(entry
->GetURL(), new_tab_url
);
396 bool IsSuggestPrefEnabled(Profile
* profile
) {
397 return profile
&& !profile
->IsOffTheRecord() && profile
->GetPrefs() &&
398 profile
->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled
);
401 GURL
GetInstantURL(Profile
* profile
, int start_margin
,
402 bool force_instant_results
) {
403 if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile
))
406 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
411 TemplateURLRefToGURL(template_url
->instant_url_ref(), start_margin
, true,
412 force_instant_results
);
413 if (!instant_url
.is_valid() ||
414 !template_url
->HasSearchTermsReplacementKey(instant_url
))
417 // Extended mode requires HTTPS. Force it unless the base URL was overridden
418 // on the command line, in which case we allow HTTP (see comments on
419 // IsSuitableURLForInstant()).
420 if (!instant_url
.SchemeIsSecure() &&
421 !google_util::StartsWithCommandLineGoogleBaseURL(instant_url
)) {
422 GURL::Replacements replacements
;
423 const std::string
secure_scheme(content::kHttpsScheme
);
424 replacements
.SetSchemeStr(secure_scheme
);
425 instant_url
= instant_url
.ReplaceComponents(replacements
);
428 if (!IsURLAllowedForSupervisedUser(instant_url
, profile
))
434 // Returns URLs associated with the default search engine for |profile|.
435 std::vector
<GURL
> GetSearchURLs(Profile
* profile
) {
436 std::vector
<GURL
> result
;
437 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
440 for (size_t i
= 0; i
< template_url
->URLCount(); ++i
) {
441 TemplateURLRef
ref(template_url
, i
);
442 result
.push_back(TemplateURLRefToGURL(ref
, kDisableStartMargin
, false,
448 GURL
GetNewTabPageURL(Profile
* profile
) {
449 if (!profile
|| profile
->IsOffTheRecord())
452 if (!IsSuggestPrefEnabled(profile
))
453 return GURL(chrome::kChromeSearchLocalNtpUrl
);
455 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
457 return GURL(chrome::kChromeSearchLocalNtpUrl
);
459 GURL
url(TemplateURLRefToGURL(template_url
->new_tab_url_ref(),
460 kDisableStartMargin
, false, false));
461 if (!url
.is_valid() || !url
.SchemeIsSecure())
462 return GURL(chrome::kChromeSearchLocalNtpUrl
);
464 if (!IsURLAllowedForSupervisedUser(url
, profile
))
465 return GURL(chrome::kChromeSearchLocalNtpUrl
);
470 GURL
GetSearchResultPrefetchBaseURL(Profile
* profile
) {
471 return ShouldPrefetchSearchResults() ?
472 GetInstantURL(profile
, kDisableStartMargin
, true) : GURL();
475 bool ShouldPrefetchSearchResults() {
476 FieldTrialFlags flags
;
477 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
478 kPrefetchSearchResultsFlagName
, false, flags
);
481 GURL
GetLocalInstantURL(Profile
* profile
) {
482 return GURL(chrome::kChromeSearchLocalNtpUrl
);
485 bool ShouldHideTopVerbatimMatch() {
486 FieldTrialFlags flags
;
487 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
488 kHideVerbatimFlagName
, false, flags
);
491 DisplaySearchButtonConditions
GetDisplaySearchButtonConditions() {
492 const CommandLine
* cl
= CommandLine::ForCurrentProcess();
493 if (cl
->HasSwitch(switches::kDisableSearchButtonInOmnibox
)) {
494 return DISPLAY_SEARCH_BUTTON_NEVER
;
495 } else if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr
)) {
496 return DISPLAY_SEARCH_BUTTON_FOR_STR
;
497 } else if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip
)) {
498 return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP
;
499 } else if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways
)) {
500 return DISPLAY_SEARCH_BUTTON_ALWAYS
;
503 FieldTrialFlags flags
;
504 if (!GetFieldTrialInfo(&flags
))
505 return DISPLAY_SEARCH_BUTTON_NEVER
;
507 GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName
, 0, flags
);
508 return (value
< DISPLAY_SEARCH_BUTTON_NUM_VALUES
) ?
509 static_cast<DisplaySearchButtonConditions
>(value
) :
510 DISPLAY_SEARCH_BUTTON_NEVER
;
513 bool ShouldDisplayOriginChip() {
514 return GetOriginChipPosition() != ORIGIN_CHIP_DISABLED
;
517 OriginChipPosition
GetOriginChipPosition() {
518 const CommandLine
* cl
= CommandLine::ForCurrentProcess();
519 if (cl
->HasSwitch(switches::kDisableOriginChip
)) {
520 return ORIGIN_CHIP_DISABLED
;
521 } else if (cl
->HasSwitch(switches::kEnableOriginChipLeadingLocationBar
)) {
522 return ORIGIN_CHIP_LEADING_LOCATION_BAR
;
523 } else if (cl
->HasSwitch(switches::kEnableOriginChip
) ||
524 cl
->HasSwitch(switches::kEnableOriginChipTrailingLocationBar
)) {
525 return ORIGIN_CHIP_TRAILING_LOCATION_BAR
;
526 } else if (cl
->HasSwitch(switches::kEnableOriginChipLeadingMenuButton
)) {
527 return ORIGIN_CHIP_LEADING_MENU_BUTTON
;
530 FieldTrialFlags flags
;
531 if (!GetFieldTrialInfo(&flags
))
532 return ORIGIN_CHIP_DISABLED
;
534 GetUInt64ValueForFlagWithDefault(kOriginChipFlagName
, 0, flags
);
535 return (value
< ORIGIN_CHIP_NUM_VALUES
) ?
536 static_cast<OriginChipPosition
>(value
) :
537 ORIGIN_CHIP_DISABLED
;
540 GURL
GetEffectiveURLForInstant(const GURL
& url
, Profile
* profile
) {
541 CHECK(ShouldAssignURLToInstantRenderer(url
, profile
))
542 << "Error granting Instant access.";
544 if (url
.SchemeIs(chrome::kChromeSearchScheme
))
547 GURL
effective_url(url
);
549 // Replace the scheme with "chrome-search:".
550 url_canon::Replacements
<char> replacements
;
551 std::string
search_scheme(chrome::kChromeSearchScheme
);
552 replacements
.SetScheme(search_scheme
.data(),
553 url_parse::Component(0, search_scheme
.length()));
555 // If the URL corresponds to an online NTP, replace the host with
557 std::string
online_ntp_host(chrome::kChromeSearchOnlineNtpHost
);
558 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
560 const GURL instant_url
= TemplateURLRefToGURL(
561 template_url
->instant_url_ref(), kDisableStartMargin
, false, false);
562 if (instant_url
.is_valid() &&
563 search::MatchesOriginAndPath(url
, instant_url
)) {
564 replacements
.SetHost(online_ntp_host
.c_str(),
565 url_parse::Component(0, online_ntp_host
.length()));
569 effective_url
= effective_url
.ReplaceComponents(replacements
);
570 return effective_url
;
573 bool HandleNewTabURLRewrite(GURL
* url
,
574 content::BrowserContext
* browser_context
) {
575 if (!IsInstantExtendedAPIEnabled())
578 if (!url
->SchemeIs(chrome::kChromeUIScheme
) ||
579 url
->host() != chrome::kChromeUINewTabHost
)
582 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
583 GURL
new_tab_url(GetNewTabPageURL(profile
));
584 if (!new_tab_url
.is_valid())
591 bool HandleNewTabURLReverseRewrite(GURL
* url
,
592 content::BrowserContext
* browser_context
) {
593 if (!IsInstantExtendedAPIEnabled())
596 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
597 GURL
new_tab_url(GetNewTabPageURL(profile
));
598 if (!new_tab_url
.is_valid() ||
599 !search::MatchesOriginAndPath(new_tab_url
, *url
))
602 *url
= GURL(chrome::kChromeUINewTabURL
);
606 void SetInstantSupportStateInNavigationEntry(InstantSupportState state
,
607 content::NavigationEntry
* entry
) {
611 entry
->SetExtraData(kInstantSupportStateKey
,
612 InstantSupportStateToString(state
));
615 InstantSupportState
GetInstantSupportStateFromNavigationEntry(
616 const content::NavigationEntry
& entry
) {
617 base::string16 value
;
618 if (!entry
.GetExtraData(kInstantSupportStateKey
, &value
))
619 return INSTANT_SUPPORT_UNKNOWN
;
621 return StringToInstantSupportState(value
);
624 bool ShouldPrefetchSearchResultsOnSRP() {
625 FieldTrialFlags flags
;
626 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
627 kPrefetchSearchResultsOnSRP
, false, flags
);
630 void EnableQueryExtractionForTesting() {
631 CommandLine
* cl
= CommandLine::ForCurrentProcess();
632 cl
->AppendSwitch(switches::kEnableQueryExtraction
);
635 bool GetFieldTrialInfo(FieldTrialFlags
* flags
) {
636 // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
637 // the older InstantExtended name.
638 std::string group_name
= base::FieldTrialList::FindFullName(
639 kEmbeddedSearchFieldTrialName
);
640 if (group_name
.empty()) {
641 group_name
= base::FieldTrialList::FindFullName(
642 kInstantExtendedFieldTrialName
);
645 if (EndsWith(group_name
, kDisablingSuffix
, true))
648 // We have a valid trial that isn't disabled. Extract the flags.
649 std::string
group_prefix(group_name
);
650 size_t first_space
= group_name
.find(" ");
651 if (first_space
!= std::string::npos
) {
652 // There is a flags section of the group name. Split that out and parse it.
653 group_prefix
= group_name
.substr(0, first_space
);
654 if (!base::SplitStringIntoKeyValuePairs(group_name
.substr(first_space
),
656 // Failed to parse the flags section. Assume the whole group name is
664 // Given a FieldTrialFlags object, returns the string value of the provided
666 std::string
GetStringValueForFlagWithDefault(const std::string
& flag
,
667 const std::string
& default_value
,
668 const FieldTrialFlags
& flags
) {
669 FieldTrialFlags::const_iterator i
;
670 for (i
= flags
.begin(); i
!= flags
.end(); i
++) {
671 if (i
->first
== flag
)
674 return default_value
;
677 // Given a FieldTrialFlags object, returns the uint64 value of the provided
679 uint64
GetUInt64ValueForFlagWithDefault(const std::string
& flag
,
680 uint64 default_value
,
681 const FieldTrialFlags
& flags
) {
683 std::string str_value
=
684 GetStringValueForFlagWithDefault(flag
, std::string(), flags
);
685 if (base::StringToUint64(str_value
, &value
))
687 return default_value
;
690 // Given a FieldTrialFlags object, returns the boolean value of the provided
692 bool GetBoolValueForFlagWithDefault(const std::string
& flag
,
694 const FieldTrialFlags
& flags
) {
695 return !!GetUInt64ValueForFlagWithDefault(flag
, default_value
? 1 : 0, flags
);
698 } // namespace chrome