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";
65 // Controls whether to reuse prerendered Instant Search base page to commit any
67 const char kReuseInstantSearchBasePage[] = "reuse_instant_search_base_page";
69 const char kDisplaySearchButtonFlagName[] = "display_search_button";
70 const char kOriginChipFlagName[] = "origin_chip";
71 #if !defined(OS_IOS) && !defined(OS_ANDROID)
72 const char kEnableQueryExtractionFlagName[] = "query_extraction";
75 // Constants for the field trial name and group prefix.
76 // Note in M30 and below this field trial was named "InstantExtended" and in
77 // M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
78 // can't easilly sync up Finch configs with the pushing of this change to
79 // Dev & Canary, for now the code accepts both names.
80 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
82 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
83 const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
85 // If the field trial's group name ends with this string its configuration will
86 // be ignored and Instant Extended will not be enabled by default.
87 const char kDisablingSuffix[] = "DISABLED";
89 // Used to set the Instant support state of the Navigation entry.
90 const char kInstantSupportStateKey[] = "instant_support_state";
92 const char kInstantSupportEnabled[] = "Instant support enabled";
93 const char kInstantSupportDisabled[] = "Instant support disabled";
94 const char kInstantSupportUnknown[] = "Instant support unknown";
96 InstantSupportState StringToInstantSupportState(const base::string16& value) {
97 if (value == base::ASCIIToUTF16(kInstantSupportEnabled))
98 return INSTANT_SUPPORT_YES;
99 else if (value == base::ASCIIToUTF16(kInstantSupportDisabled))
100 return INSTANT_SUPPORT_NO;
102 return INSTANT_SUPPORT_UNKNOWN;
105 base::string16 InstantSupportStateToString(InstantSupportState state) {
107 case INSTANT_SUPPORT_NO:
108 return base::ASCIIToUTF16(kInstantSupportDisabled);
109 case INSTANT_SUPPORT_YES:
110 return base::ASCIIToUTF16(kInstantSupportEnabled);
111 case INSTANT_SUPPORT_UNKNOWN:
112 return base::ASCIIToUTF16(kInstantSupportUnknown);
114 return base::ASCIIToUTF16(kInstantSupportUnknown);
117 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) {
118 TemplateURLService* template_url_service =
119 TemplateURLServiceFactory::GetForProfile(profile);
120 if (template_url_service)
121 return template_url_service->GetDefaultSearchProvider();
125 GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
127 bool append_extra_query_params,
128 bool force_instant_results) {
129 TemplateURLRef::SearchTermsArgs search_terms_args =
130 TemplateURLRef::SearchTermsArgs(base::string16());
131 search_terms_args.omnibox_start_margin = start_margin;
132 search_terms_args.append_extra_query_params = append_extra_query_params;
133 search_terms_args.force_instant_results = force_instant_results;
134 return GURL(ref.ReplaceSearchTerms(search_terms_args));
137 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) {
139 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false,
141 if (search_url.is_valid() &&
142 search::MatchesOriginAndPath(url, search_url))
145 // "URLCount() - 1" because we already tested url_ref above.
146 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
147 TemplateURLRef ref(template_url, i);
148 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false, false);
149 if (search_url.is_valid() &&
150 search::MatchesOriginAndPath(url, search_url))
157 // Returns true if |contents| is rendered inside the Instant process for
159 bool IsRenderedInInstantProcess(const content::WebContents* contents,
161 const content::RenderProcessHost* process_host =
162 contents->GetRenderProcessHost();
166 const InstantService* instant_service =
167 InstantServiceFactory::GetForProfile(profile);
168 if (!instant_service)
171 return instant_service->IsInstantProcess(process_host->GetID());
174 // Returns true if |url| passes some basic checks that must succeed for it to be
175 // usable as an instant URL:
176 // (1) It contains the search terms replacement key of |template_url|, which is
177 // expected to be the TemplateURL* for the default search provider.
178 // (2) Either it has a secure scheme, or else the user has manually specified a
179 // --google-base-url and it uses that base URL. (This allows testers to use
180 // --google-base-url to point at non-HTTPS servers, which eases testing.)
181 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
182 return template_url->HasSearchTermsReplacementKey(url) &&
183 (url.SchemeIsSecure() ||
184 google_util::StartsWithCommandLineGoogleBaseURL(url));
187 // Returns true if |url| can be used as an Instant URL for |profile|.
188 bool IsInstantURL(const GURL& url, Profile* profile) {
189 if (!IsInstantExtendedAPIEnabled())
195 const GURL new_tab_url(GetNewTabPageURL(profile));
196 if (new_tab_url.is_valid() &&
197 search::MatchesOriginAndPath(url, new_tab_url))
200 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
204 if (!IsSuitableURLForInstant(url, template_url))
207 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
208 const GURL instant_url =
209 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false, false);
210 if (!instant_url.is_valid())
213 if (search::MatchesOriginAndPath(url, instant_url))
216 return IsQueryExtractionEnabled() && MatchesAnySearchURL(url, template_url);
219 base::string16 GetSearchTermsImpl(const content::WebContents* contents,
220 const content::NavigationEntry* entry) {
221 if (!contents || !IsQueryExtractionEnabled())
222 return base::string16();
224 // For security reasons, don't extract search terms if the page is not being
225 // rendered in the privileged Instant renderer process. This is to protect
226 // against a malicious page somehow scripting the search results page and
227 // faking search terms in the URL. Random pages can't get into the Instant
228 // renderer and scripting doesn't work cross-process, so if the page is in
229 // the Instant process, we know it isn't being exploited.
230 // Since iOS and Android doesn't use the instant framework, these checks are
231 // disabled for the two platforms.
232 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
233 #if !defined(OS_IOS) && !defined(OS_ANDROID)
234 if (!IsRenderedInInstantProcess(contents, profile) &&
235 ((entry == contents->GetController().GetLastCommittedEntry()) ||
236 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
237 return base::string16();
238 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
239 // Check to see if search terms have already been extracted.
240 base::string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
241 if (!search_terms.empty())
244 // Otherwise, extract from the URL.
245 return GetSearchTermsFromURL(profile, entry->GetVirtualURL());
248 bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) {
249 #if defined(ENABLE_MANAGED_USERS)
250 ManagedUserService* managed_user_service =
251 ManagedUserServiceFactory::GetForProfile(profile);
252 ManagedModeURLFilter* url_filter =
253 managed_user_service->GetURLFilterForUIThread();
254 if (url_filter->GetFilteringBehaviorForURL(url) ==
255 ManagedModeURLFilter::BLOCK) {
264 // Negative start-margin values prevent the "es_sm" parameter from being used.
265 const int kDisableStartMargin = -1;
267 bool IsInstantExtendedAPIEnabled() {
268 #if defined(OS_IOS) || defined(OS_ANDROID)
272 #endif // defined(OS_IOS) || defined(OS_ANDROID)
275 // Determine what embedded search page version to request from the user's
276 // default search provider. If 0, the embedded search UI should not be enabled.
277 uint64 EmbeddedSearchPageVersion() {
278 FieldTrialFlags flags;
279 if (GetFieldTrialInfo(&flags)) {
280 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
281 kEmbeddedPageVersionDefault,
284 return kEmbeddedPageVersionDefault;
287 bool IsQueryExtractionEnabled() {
288 #if defined(OS_IOS) || defined(OS_ANDROID)
291 if (!IsInstantExtendedAPIEnabled())
294 const CommandLine* command_line = CommandLine::ForCurrentProcess();
295 if (command_line->HasSwitch(switches::kEnableQueryExtraction))
298 FieldTrialFlags flags;
299 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
300 kEnableQueryExtractionFlagName, false, flags);
301 #endif // defined(OS_IOS) || defined(OS_ANDROID)
304 base::string16 GetSearchTermsFromURL(Profile* profile, const GURL& url) {
305 if (url.is_valid() && url == GetSearchResultPrefetchBaseURL(profile)) {
306 // InstantSearchPrerenderer has the search query for the Instant search base
308 InstantSearchPrerenderer* prerenderer =
309 InstantSearchPrerenderer::GetForProfile(profile);
311 return prerenderer->get_last_query();
314 base::string16 search_terms;
315 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
316 if (template_url && IsSuitableURLForInstant(url, template_url))
317 template_url->ExtractSearchTermsFromURL(url, &search_terms);
321 base::string16 GetSearchTermsFromNavigationEntry(
322 const content::NavigationEntry* entry) {
323 base::string16 search_terms;
325 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms);
329 base::string16 GetSearchTerms(const content::WebContents* contents) {
331 return base::string16();
333 const content::NavigationEntry* entry =
334 contents->GetController().GetVisibleEntry();
336 return base::string16();
338 #if !defined(OS_IOS) && !defined(OS_ANDROID)
339 // iOS and Android doesn't use the Instant framework, disable this check for
340 // the two platforms.
341 InstantSupportState state = GetInstantSupportStateFromNavigationEntry(*entry);
342 if (state == INSTANT_SUPPORT_NO)
343 return base::string16();
344 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
346 return GetSearchTermsImpl(contents, entry);
349 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) {
350 return url.is_valid() &&
352 IsInstantExtendedAPIEnabled() &&
353 (url.SchemeIs(chrome::kChromeSearchScheme) ||
354 IsInstantURL(url, profile));
357 bool ShouldUseProcessPerSiteForInstantURL(const GURL& url, Profile* profile) {
358 return ShouldAssignURLToInstantRenderer(url, profile) &&
359 (url.host() == chrome::kChromeSearchLocalNtpHost ||
360 url.host() == chrome::kChromeSearchOnlineNtpHost);
363 bool IsNTPURL(const GURL& url, Profile* profile) {
367 if (!IsInstantExtendedAPIEnabled())
368 return url == GURL(chrome::kChromeUINewTabURL);
371 ((IsInstantURL(url, profile) &&
372 GetSearchTermsFromURL(profile, url).empty()) ||
373 url == GURL(chrome::kChromeSearchLocalNtpUrl));
376 bool IsInstantNTP(const content::WebContents* contents) {
380 return NavEntryIsInstantNTP(contents,
381 contents->GetController().GetVisibleEntry());
384 bool NavEntryIsInstantNTP(const content::WebContents* contents,
385 const content::NavigationEntry* entry) {
386 if (!contents || !entry || !IsInstantExtendedAPIEnabled())
389 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
390 if (!IsRenderedInInstantProcess(contents, profile))
393 if (entry->GetURL() == GetLocalInstantURL(profile))
396 GURL new_tab_url(GetNewTabPageURL(profile));
397 return new_tab_url.is_valid() &&
398 search::MatchesOriginAndPath(entry->GetURL(), new_tab_url);
401 bool IsSuggestPrefEnabled(Profile* profile) {
402 return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
403 profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
406 GURL GetInstantURL(Profile* profile, int start_margin,
407 bool force_instant_results) {
408 if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
411 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
416 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true,
417 force_instant_results);
418 if (!instant_url.is_valid() ||
419 !template_url->HasSearchTermsReplacementKey(instant_url))
422 // Extended mode requires HTTPS. Force it unless the base URL was overridden
423 // on the command line, in which case we allow HTTP (see comments on
424 // IsSuitableURLForInstant()).
425 if (!instant_url.SchemeIsSecure() &&
426 !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
427 GURL::Replacements replacements;
428 const std::string secure_scheme(content::kHttpsScheme);
429 replacements.SetSchemeStr(secure_scheme);
430 instant_url = instant_url.ReplaceComponents(replacements);
433 if (!IsURLAllowedForSupervisedUser(instant_url, profile))
439 // Returns URLs associated with the default search engine for |profile|.
440 std::vector<GURL> GetSearchURLs(Profile* profile) {
441 std::vector<GURL> result;
442 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
445 for (size_t i = 0; i < template_url->URLCount(); ++i) {
446 TemplateURLRef ref(template_url, i);
447 result.push_back(TemplateURLRefToGURL(ref, kDisableStartMargin, false,
453 GURL GetNewTabPageURL(Profile* profile) {
454 if (!profile || profile->IsOffTheRecord())
457 if (!IsSuggestPrefEnabled(profile))
458 return GURL(chrome::kChromeSearchLocalNtpUrl);
460 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
462 return GURL(chrome::kChromeSearchLocalNtpUrl);
464 GURL url(TemplateURLRefToGURL(template_url->new_tab_url_ref(),
465 kDisableStartMargin, false, false));
466 if (!url.is_valid() || !url.SchemeIsSecure())
467 return GURL(chrome::kChromeSearchLocalNtpUrl);
469 if (!IsURLAllowedForSupervisedUser(url, profile))
470 return GURL(chrome::kChromeSearchLocalNtpUrl);
475 GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
476 return ShouldPrefetchSearchResults() ?
477 GetInstantURL(profile, kDisableStartMargin, true) : GURL();
480 bool ShouldPrefetchSearchResults() {
481 FieldTrialFlags flags;
482 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
483 kPrefetchSearchResultsFlagName, false, flags);
486 bool ShouldReuseInstantSearchBasePage() {
487 if (!ShouldPrefetchSearchResults())
490 FieldTrialFlags flags;
491 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
492 kReuseInstantSearchBasePage, false, flags);
495 GURL GetLocalInstantURL(Profile* profile) {
496 return GURL(chrome::kChromeSearchLocalNtpUrl);
499 bool ShouldHideTopVerbatimMatch() {
500 FieldTrialFlags flags;
501 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
502 kHideVerbatimFlagName, false, flags);
505 DisplaySearchButtonConditions GetDisplaySearchButtonConditions() {
506 const CommandLine* cl = CommandLine::ForCurrentProcess();
507 if (cl->HasSwitch(switches::kDisableSearchButtonInOmnibox)) {
508 return DISPLAY_SEARCH_BUTTON_NEVER;
509 } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr)) {
510 return DISPLAY_SEARCH_BUTTON_FOR_STR;
511 } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip)) {
512 return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP;
513 } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways)) {
514 return DISPLAY_SEARCH_BUTTON_ALWAYS;
517 FieldTrialFlags flags;
518 if (!GetFieldTrialInfo(&flags))
519 return DISPLAY_SEARCH_BUTTON_NEVER;
521 GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName, 0, flags);
522 return (value < DISPLAY_SEARCH_BUTTON_NUM_VALUES) ?
523 static_cast<DisplaySearchButtonConditions>(value) :
524 DISPLAY_SEARCH_BUTTON_NEVER;
527 bool ShouldDisplayOriginChip() {
528 return GetOriginChipPosition() != ORIGIN_CHIP_DISABLED;
531 OriginChipPosition GetOriginChipPosition() {
532 const CommandLine* cl = CommandLine::ForCurrentProcess();
533 if (cl->HasSwitch(switches::kDisableOriginChip)) {
534 return ORIGIN_CHIP_DISABLED;
535 } else if (cl->HasSwitch(switches::kEnableOriginChipLeadingLocationBar)) {
536 return ORIGIN_CHIP_LEADING_LOCATION_BAR;
537 } else if (cl->HasSwitch(switches::kEnableOriginChip) ||
538 cl->HasSwitch(switches::kEnableOriginChipTrailingLocationBar)) {
539 return ORIGIN_CHIP_TRAILING_LOCATION_BAR;
540 } else if (cl->HasSwitch(switches::kEnableOriginChipLeadingMenuButton)) {
541 return ORIGIN_CHIP_LEADING_MENU_BUTTON;
544 FieldTrialFlags flags;
545 if (!GetFieldTrialInfo(&flags))
546 return ORIGIN_CHIP_DISABLED;
548 GetUInt64ValueForFlagWithDefault(kOriginChipFlagName, 0, flags);
549 return (value < ORIGIN_CHIP_NUM_VALUES) ?
550 static_cast<OriginChipPosition>(value) :
551 ORIGIN_CHIP_DISABLED;
554 GURL GetEffectiveURLForInstant(const GURL& url, Profile* profile) {
555 CHECK(ShouldAssignURLToInstantRenderer(url, profile))
556 << "Error granting Instant access.";
558 if (url.SchemeIs(chrome::kChromeSearchScheme))
561 GURL effective_url(url);
563 // Replace the scheme with "chrome-search:".
564 url_canon::Replacements<char> replacements;
565 std::string search_scheme(chrome::kChromeSearchScheme);
566 replacements.SetScheme(search_scheme.data(),
567 url_parse::Component(0, search_scheme.length()));
569 // If the URL corresponds to an online NTP, replace the host with
571 std::string online_ntp_host(chrome::kChromeSearchOnlineNtpHost);
572 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
574 const GURL instant_url = TemplateURLRefToGURL(
575 template_url->instant_url_ref(), kDisableStartMargin, false, false);
576 if (instant_url.is_valid() &&
577 search::MatchesOriginAndPath(url, instant_url)) {
578 replacements.SetHost(online_ntp_host.c_str(),
579 url_parse::Component(0, online_ntp_host.length()));
583 effective_url = effective_url.ReplaceComponents(replacements);
584 return effective_url;
587 bool HandleNewTabURLRewrite(GURL* url,
588 content::BrowserContext* browser_context) {
589 if (!IsInstantExtendedAPIEnabled())
592 if (!url->SchemeIs(chrome::kChromeUIScheme) ||
593 url->host() != chrome::kChromeUINewTabHost)
596 Profile* profile = Profile::FromBrowserContext(browser_context);
597 GURL new_tab_url(GetNewTabPageURL(profile));
598 if (!new_tab_url.is_valid())
605 bool HandleNewTabURLReverseRewrite(GURL* url,
606 content::BrowserContext* browser_context) {
607 if (!IsInstantExtendedAPIEnabled())
610 Profile* profile = Profile::FromBrowserContext(browser_context);
611 GURL new_tab_url(GetNewTabPageURL(profile));
612 if (!new_tab_url.is_valid() ||
613 !search::MatchesOriginAndPath(new_tab_url, *url))
616 *url = GURL(chrome::kChromeUINewTabURL);
620 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
621 content::NavigationEntry* entry) {
625 entry->SetExtraData(kInstantSupportStateKey,
626 InstantSupportStateToString(state));
629 InstantSupportState GetInstantSupportStateFromNavigationEntry(
630 const content::NavigationEntry& entry) {
631 base::string16 value;
632 if (!entry.GetExtraData(kInstantSupportStateKey, &value))
633 return INSTANT_SUPPORT_UNKNOWN;
635 return StringToInstantSupportState(value);
638 bool ShouldPrefetchSearchResultsOnSRP() {
639 FieldTrialFlags flags;
640 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
641 kPrefetchSearchResultsOnSRP, false, flags);
644 void EnableQueryExtractionForTesting() {
645 CommandLine* cl = CommandLine::ForCurrentProcess();
646 cl->AppendSwitch(switches::kEnableQueryExtraction);
649 bool GetFieldTrialInfo(FieldTrialFlags* flags) {
650 // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
651 // the older InstantExtended name.
652 std::string group_name = base::FieldTrialList::FindFullName(
653 kEmbeddedSearchFieldTrialName);
654 if (group_name.empty()) {
655 group_name = base::FieldTrialList::FindFullName(
656 kInstantExtendedFieldTrialName);
659 if (EndsWith(group_name, kDisablingSuffix, true))
662 // We have a valid trial that isn't disabled. Extract the flags.
663 std::string group_prefix(group_name);
664 size_t first_space = group_name.find(" ");
665 if (first_space != std::string::npos) {
666 // There is a flags section of the group name. Split that out and parse it.
667 group_prefix = group_name.substr(0, first_space);
668 if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
670 // Failed to parse the flags section. Assume the whole group name is
678 // Given a FieldTrialFlags object, returns the string value of the provided
680 std::string GetStringValueForFlagWithDefault(const std::string& flag,
681 const std::string& default_value,
682 const FieldTrialFlags& flags) {
683 FieldTrialFlags::const_iterator i;
684 for (i = flags.begin(); i != flags.end(); i++) {
685 if (i->first == flag)
688 return default_value;
691 // Given a FieldTrialFlags object, returns the uint64 value of the provided
693 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
694 uint64 default_value,
695 const FieldTrialFlags& flags) {
697 std::string str_value =
698 GetStringValueForFlagWithDefault(flag, std::string(), flags);
699 if (base::StringToUint64(str_value, &value))
701 return default_value;
704 // Given a FieldTrialFlags object, returns the boolean value of the provided
706 bool GetBoolValueForFlagWithDefault(const std::string& flag,
708 const FieldTrialFlags& flags) {
709 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
712 } // namespace chrome