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/metrics/histogram.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/google/google_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/search/instant_service.h"
19 #include "chrome/browser/search/instant_service_factory.h"
20 #include "chrome/browser/search_engines/template_url_service.h"
21 #include "chrome/browser/search_engines/template_url_service_factory.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_instant_controller.h"
24 #include "chrome/browser/ui/browser_iterator.h"
25 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/common/search_urls.h"
29 #include "chrome/common/url_constants.h"
30 #include "components/sessions/serialized_navigation_entry.h"
31 #include "components/user_prefs/pref_registry_syncable.h"
32 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/render_process_host.h"
34 #include "content/public/browser/web_contents.h"
35 #include "grit/generated_resources.h"
36 #include "ui/base/l10n/l10n_util.h"
38 #if defined(ENABLE_MANAGED_USERS)
39 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
40 #include "chrome/browser/managed_mode/managed_user_service.h"
41 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
48 // Configuration options for Embedded Search.
49 // EmbeddedSearch field trials are named in such a way that we can parse out
50 // the experiment configuration from the trial's group name in order to give
51 // us maximum flexability in running experiments.
52 // Field trial groups should be named things like "Group7 espv:2 instant:1".
53 // The first token is always GroupN for some integer N, followed by a
54 // space-delimited list of key:value pairs which correspond to these flags:
55 const char kEmbeddedPageVersionFlagName[] = "espv";
56 #if defined(OS_IOS) || defined(OS_ANDROID)
57 const uint64 kEmbeddedPageVersionDefault = 1;
59 const uint64 kEmbeddedPageVersionDefault = 2;
62 const char kHideVerbatimFlagName[] = "hide_verbatim";
63 const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
64 const char kPrefetchSearchResultsOnSRP[] = "prefetch_results_srp";
66 // Controls whether to reuse prerendered Instant Search base page to commit any
68 const char kReuseInstantSearchBasePage[] = "reuse_instant_search_base_page";
70 const char kDisplaySearchButtonFlagName[] = "display_search_button";
71 const char kOriginChipFlagName[] = "origin_chip";
72 const char kOriginChipV2FlagName[] = "origin_chip_v2";
73 #if !defined(OS_IOS) && !defined(OS_ANDROID)
74 const char kEnableQueryExtractionFlagName[] = "query_extraction";
76 const char kShouldShowGoogleLocalNTPFlagName[] = "google_local_ntp";
78 // Constants for the field trial name and group prefix.
79 // Note in M30 and below this field trial was named "InstantExtended" and in
80 // M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
81 // can't easilly sync up Finch configs with the pushing of this change to
82 // Dev & Canary, for now the code accepts both names.
83 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
85 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
86 const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
88 // If the field trial's group name ends with this string its configuration will
89 // be ignored and Instant Extended will not be enabled by default.
90 const char kDisablingSuffix[] = "DISABLED";
92 // Status of the New Tab URL for the default Search provider. NOTE: Used in a
93 // UMA histogram so values should only be added at the end and not reordered.
95 // Valid URL that should be used.
96 NEW_TAB_URL_VALID = 0,
98 // Corrupt state (e.g. no profile or template url).
101 // URL should not be used because in incognito window.
102 NEW_TAB_URL_INCOGNITO = 2,
104 // No New Tab URL set for provider.
105 NEW_TAB_URL_NOT_SET = 3,
107 // URL is not secure.
108 NEW_TAB_URL_INSECURE = 4,
110 // URL should not be used because Suggest is disabled.
111 NEW_TAB_URL_SUGGEST_OFF = 5,
113 // URL should not be used because it is blocked for a supervised user.
114 NEW_TAB_URL_BLOCKED = 6,
119 // Used to set the Instant support state of the Navigation entry.
120 const char kInstantSupportStateKey[] = "instant_support_state";
122 const char kInstantSupportEnabled[] = "Instant support enabled";
123 const char kInstantSupportDisabled[] = "Instant support disabled";
124 const char kInstantSupportUnknown[] = "Instant support unknown";
126 InstantSupportState StringToInstantSupportState(const base::string16& value) {
127 if (value == base::ASCIIToUTF16(kInstantSupportEnabled))
128 return INSTANT_SUPPORT_YES;
129 else if (value == base::ASCIIToUTF16(kInstantSupportDisabled))
130 return INSTANT_SUPPORT_NO;
132 return INSTANT_SUPPORT_UNKNOWN;
135 base::string16 InstantSupportStateToString(InstantSupportState state) {
137 case INSTANT_SUPPORT_NO:
138 return base::ASCIIToUTF16(kInstantSupportDisabled);
139 case INSTANT_SUPPORT_YES:
140 return base::ASCIIToUTF16(kInstantSupportEnabled);
141 case INSTANT_SUPPORT_UNKNOWN:
142 return base::ASCIIToUTF16(kInstantSupportUnknown);
144 return base::ASCIIToUTF16(kInstantSupportUnknown);
147 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) {
149 TemplateURLService* template_url_service =
150 TemplateURLServiceFactory::GetForProfile(profile);
151 if (template_url_service)
152 return template_url_service->GetDefaultSearchProvider();
157 GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
159 bool append_extra_query_params,
160 bool force_instant_results) {
161 TemplateURLRef::SearchTermsArgs search_terms_args =
162 TemplateURLRef::SearchTermsArgs(base::string16());
163 search_terms_args.omnibox_start_margin = start_margin;
164 search_terms_args.append_extra_query_params = append_extra_query_params;
165 search_terms_args.force_instant_results = force_instant_results;
166 return GURL(ref.ReplaceSearchTerms(search_terms_args));
169 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) {
171 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false,
173 if (search_url.is_valid() &&
174 search::MatchesOriginAndPath(url, search_url))
177 // "URLCount() - 1" because we already tested url_ref above.
178 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
179 TemplateURLRef ref(template_url, i);
180 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false, false);
181 if (search_url.is_valid() &&
182 search::MatchesOriginAndPath(url, search_url))
189 // Returns true if |contents| is rendered inside the Instant process for
191 bool IsRenderedInInstantProcess(const content::WebContents* contents,
193 const content::RenderProcessHost* process_host =
194 contents->GetRenderProcessHost();
198 const InstantService* instant_service =
199 InstantServiceFactory::GetForProfile(profile);
200 if (!instant_service)
203 return instant_service->IsInstantProcess(process_host->GetID());
206 // |url| should either have a secure scheme or have a non-HTTPS base URL that
207 // the user specified using --google-base-url. (This allows testers to use
208 // --google-base-url to point at non-HTTPS servers, which eases testing.)
209 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
210 return template_url->HasSearchTermsReplacementKey(url) &&
211 (url.SchemeIsSecure() ||
212 google_util::StartsWithCommandLineGoogleBaseURL(url));
215 // Returns true if |url| can be used as an Instant URL for |profile|.
216 bool IsInstantURL(const GURL& url, Profile* profile) {
217 if (!IsInstantExtendedAPIEnabled())
223 const GURL new_tab_url(GetNewTabPageURL(profile));
224 if (new_tab_url.is_valid() &&
225 search::MatchesOriginAndPath(url, new_tab_url))
228 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
232 if (!IsSuitableURLForInstant(url, template_url))
235 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
236 const GURL instant_url =
237 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false, false);
238 if (!instant_url.is_valid())
241 if (search::MatchesOriginAndPath(url, instant_url))
244 return IsQueryExtractionEnabled() && MatchesAnySearchURL(url, template_url);
247 base::string16 GetSearchTermsImpl(const content::WebContents* contents,
248 const content::NavigationEntry* entry) {
249 if (!contents || !IsQueryExtractionEnabled())
250 return base::string16();
252 // For security reasons, don't extract search terms if the page is not being
253 // rendered in the privileged Instant renderer process. This is to protect
254 // against a malicious page somehow scripting the search results page and
255 // faking search terms in the URL. Random pages can't get into the Instant
256 // renderer and scripting doesn't work cross-process, so if the page is in
257 // the Instant process, we know it isn't being exploited.
258 // Since iOS and Android doesn't use the instant framework, these checks are
259 // disabled for the two platforms.
260 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
261 #if !defined(OS_IOS) && !defined(OS_ANDROID)
262 if (!IsRenderedInInstantProcess(contents, profile) &&
263 ((entry == contents->GetController().GetLastCommittedEntry()) ||
264 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
265 return base::string16();
266 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
267 // Check to see if search terms have already been extracted.
268 base::string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
269 if (!search_terms.empty())
272 if (!IsQueryExtractionAllowedForURL(profile, entry->GetVirtualURL()))
273 return base::string16();
275 // Otherwise, extract from the URL.
276 return ExtractSearchTermsFromURL(profile, entry->GetVirtualURL());
279 bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) {
280 #if defined(ENABLE_MANAGED_USERS)
281 ManagedUserService* managed_user_service =
282 ManagedUserServiceFactory::GetForProfile(profile);
283 ManagedModeURLFilter* url_filter =
284 managed_user_service->GetURLFilterForUIThread();
285 if (url_filter->GetFilteringBehaviorForURL(url) ==
286 ManagedModeURLFilter::BLOCK) {
293 // Returns whether |new_tab_url| can be used as a URL for the New Tab page.
294 // NEW_TAB_URL_VALID means a valid URL; other enum values imply an invalid URL.
295 NewTabURLState IsValidNewTabURL(Profile* profile, const GURL& new_tab_url) {
296 if (profile->IsOffTheRecord())
297 return NEW_TAB_URL_INCOGNITO;
298 if (!new_tab_url.is_valid())
299 return NEW_TAB_URL_NOT_SET;
300 if (!new_tab_url.SchemeIsSecure())
301 return NEW_TAB_URL_INSECURE;
302 if (!IsSuggestPrefEnabled(profile))
303 return NEW_TAB_URL_SUGGEST_OFF;
304 if (!IsURLAllowedForSupervisedUser(new_tab_url, profile))
305 return NEW_TAB_URL_BLOCKED;
306 return NEW_TAB_URL_VALID;
309 // Used to look up the URL to use for the New Tab page. Also tracks how we
310 // arrived at that URL so it can be logged with UMA.
311 struct NewTabURLDetails {
312 NewTabURLDetails(const GURL& url, NewTabURLState state)
313 : url(url), state(state) {}
315 static NewTabURLDetails ForProfile(Profile* profile) {
316 const GURL local_url(chrome::kChromeSearchLocalNtpUrl);
317 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
318 if (!profile || !template_url)
319 return NewTabURLDetails(local_url, NEW_TAB_URL_BAD);
321 GURL search_provider_url = TemplateURLRefToGURL(
322 template_url->new_tab_url_ref(), kDisableStartMargin, false, false);
323 NewTabURLState state = IsValidNewTabURL(profile, search_provider_url);
325 case NEW_TAB_URL_VALID:
326 // We can use the search provider's page.
327 return NewTabURLDetails(search_provider_url, state);
328 case NEW_TAB_URL_INCOGNITO:
329 // Incognito has its own New Tab.
330 return NewTabURLDetails(GURL(), state);
332 // Use the local New Tab otherwise.
333 return NewTabURLDetails(local_url, state);
338 NewTabURLState state;
343 // Negative start-margin values prevent the "es_sm" parameter from being used.
344 const int kDisableStartMargin = -1;
346 bool IsInstantExtendedAPIEnabled() {
347 #if defined(OS_IOS) || defined(OS_ANDROID)
351 #endif // defined(OS_IOS) || defined(OS_ANDROID)
354 // Determine what embedded search page version to request from the user's
355 // default search provider. If 0, the embedded search UI should not be enabled.
356 uint64 EmbeddedSearchPageVersion() {
357 FieldTrialFlags flags;
358 if (GetFieldTrialInfo(&flags)) {
359 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
360 kEmbeddedPageVersionDefault,
363 return kEmbeddedPageVersionDefault;
366 std::string InstantExtendedEnabledParam(bool for_search) {
367 if (for_search && !chrome::IsQueryExtractionEnabled())
368 return std::string();
369 return std::string(google_util::kInstantExtendedAPIParam) + "=" +
370 base::Uint64ToString(EmbeddedSearchPageVersion()) + "&";
373 std::string ForceInstantResultsParam(bool for_prerender) {
374 return (for_prerender || !IsInstantExtendedAPIEnabled()) ?
375 "ion=1&" : std::string();
378 bool IsQueryExtractionEnabled() {
379 #if defined(OS_IOS) || defined(OS_ANDROID)
382 if (!IsInstantExtendedAPIEnabled())
385 const CommandLine* command_line = CommandLine::ForCurrentProcess();
386 if (command_line->HasSwitch(switches::kEnableQueryExtraction))
389 FieldTrialFlags flags;
390 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
391 kEnableQueryExtractionFlagName, false, flags);
392 #endif // defined(OS_IOS) || defined(OS_ANDROID)
395 base::string16 ExtractSearchTermsFromURL(Profile* profile, const GURL& url) {
396 if (url.is_valid() && url == GetSearchResultPrefetchBaseURL(profile)) {
397 // InstantSearchPrerenderer has the search query for the Instant search base
399 InstantSearchPrerenderer* prerenderer =
400 InstantSearchPrerenderer::GetForProfile(profile);
402 return prerenderer->get_last_query();
405 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
406 base::string16 search_terms;
408 template_url->ExtractSearchTermsFromURL(url, &search_terms);
412 bool IsQueryExtractionAllowedForURL(Profile* profile, const GURL& url) {
413 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
414 return template_url && IsSuitableURLForInstant(url, template_url);
417 base::string16 GetSearchTermsFromNavigationEntry(
418 const content::NavigationEntry* entry) {
419 base::string16 search_terms;
421 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms);
425 base::string16 GetSearchTerms(const content::WebContents* contents) {
427 return base::string16();
429 const content::NavigationEntry* entry =
430 contents->GetController().GetVisibleEntry();
432 return base::string16();
434 #if !defined(OS_IOS) && !defined(OS_ANDROID)
435 // iOS and Android doesn't use the Instant framework, disable this check for
436 // the two platforms.
437 InstantSupportState state = GetInstantSupportStateFromNavigationEntry(*entry);
438 if (state == INSTANT_SUPPORT_NO)
439 return base::string16();
440 #endif // !defined(OS_IOS) && !defined(OS_ANDROID)
442 return GetSearchTermsImpl(contents, entry);
445 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) {
446 return url.is_valid() &&
448 IsInstantExtendedAPIEnabled() &&
449 (url.SchemeIs(chrome::kChromeSearchScheme) ||
450 IsInstantURL(url, profile));
453 bool ShouldUseProcessPerSiteForInstantURL(const GURL& url, Profile* profile) {
454 return ShouldAssignURLToInstantRenderer(url, profile) &&
455 (url.host() == chrome::kChromeSearchLocalNtpHost ||
456 url.host() == chrome::kChromeSearchRemoteNtpHost);
459 bool IsNTPURL(const GURL& url, Profile* profile) {
463 if (!IsInstantExtendedAPIEnabled())
464 return url == GURL(chrome::kChromeUINewTabURL);
466 const base::string16 search_terms = ExtractSearchTermsFromURL(profile, url);
468 ((IsInstantURL(url, profile) && search_terms.empty()) ||
469 url == GURL(chrome::kChromeSearchLocalNtpUrl));
472 bool IsInstantNTP(const content::WebContents* contents) {
476 return NavEntryIsInstantNTP(contents,
477 contents->GetController().GetVisibleEntry());
480 bool NavEntryIsInstantNTP(const content::WebContents* contents,
481 const content::NavigationEntry* entry) {
482 if (!contents || !entry || !IsInstantExtendedAPIEnabled())
485 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
486 if (!IsRenderedInInstantProcess(contents, profile))
489 if (entry->GetURL() == GetLocalInstantURL(profile))
492 GURL new_tab_url(GetNewTabPageURL(profile));
493 return new_tab_url.is_valid() &&
494 search::MatchesOriginAndPath(entry->GetURL(), new_tab_url);
497 bool IsSuggestPrefEnabled(Profile* profile) {
498 return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
499 profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
502 GURL GetInstantURL(Profile* profile, int start_margin,
503 bool force_instant_results) {
504 if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
507 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
512 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true,
513 force_instant_results);
514 if (!instant_url.is_valid() ||
515 !template_url->HasSearchTermsReplacementKey(instant_url))
518 // Extended mode requires HTTPS. Force it unless the base URL was overridden
519 // on the command line, in which case we allow HTTP (see comments on
520 // IsSuitableURLForInstant()).
521 if (!instant_url.SchemeIsSecure() &&
522 !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
523 GURL::Replacements replacements;
524 const std::string secure_scheme(content::kHttpsScheme);
525 replacements.SetSchemeStr(secure_scheme);
526 instant_url = instant_url.ReplaceComponents(replacements);
529 if (!IsURLAllowedForSupervisedUser(instant_url, profile))
535 // Returns URLs associated with the default search engine for |profile|.
536 std::vector<GURL> GetSearchURLs(Profile* profile) {
537 std::vector<GURL> result;
538 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
541 for (size_t i = 0; i < template_url->URLCount(); ++i) {
542 TemplateURLRef ref(template_url, i);
543 result.push_back(TemplateURLRefToGURL(ref, kDisableStartMargin, false,
549 GURL GetNewTabPageURL(Profile* profile) {
550 return NewTabURLDetails::ForProfile(profile).url;
553 GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
554 return ShouldPrefetchSearchResults() ?
555 GetInstantURL(profile, kDisableStartMargin, true) : GURL();
558 bool ShouldPrefetchSearchResults() {
559 if (CommandLine::ForCurrentProcess()->HasSwitch(
560 switches::kPrefetchSearchResults)) {
564 FieldTrialFlags flags;
565 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
566 kPrefetchSearchResultsFlagName, false, flags);
569 bool ShouldReuseInstantSearchBasePage() {
570 if (CommandLine::ForCurrentProcess()->HasSwitch(
571 switches::kPrefetchSearchResults)) {
575 if (!ShouldPrefetchSearchResults())
578 FieldTrialFlags flags;
579 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
580 kReuseInstantSearchBasePage, false, flags);
583 GURL GetLocalInstantURL(Profile* profile) {
584 return GURL(chrome::kChromeSearchLocalNtpUrl);
587 bool ShouldHideTopVerbatimMatch() {
588 FieldTrialFlags flags;
589 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
590 kHideVerbatimFlagName, false, flags);
593 DisplaySearchButtonConditions GetDisplaySearchButtonConditions() {
594 const CommandLine* cl = CommandLine::ForCurrentProcess();
595 if (cl->HasSwitch(switches::kDisableSearchButtonInOmnibox))
596 return DISPLAY_SEARCH_BUTTON_NEVER;
597 if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr))
598 return DISPLAY_SEARCH_BUTTON_FOR_STR;
599 if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip))
600 return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP;
601 if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways))
602 return DISPLAY_SEARCH_BUTTON_ALWAYS;
604 FieldTrialFlags flags;
605 if (!GetFieldTrialInfo(&flags))
606 return DISPLAY_SEARCH_BUTTON_NEVER;
608 GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName, 0, flags);
609 return (value < DISPLAY_SEARCH_BUTTON_NUM_VALUES) ?
610 static_cast<DisplaySearchButtonConditions>(value) :
611 DISPLAY_SEARCH_BUTTON_NEVER;
614 bool ShouldDisplayOriginChip() {
615 return GetOriginChipPosition() != ORIGIN_CHIP_DISABLED;
618 OriginChipPosition GetOriginChipPosition() {
619 if (ShouldDisplayOriginChipV2())
620 return ORIGIN_CHIP_DISABLED;
622 const CommandLine* cl = CommandLine::ForCurrentProcess();
623 if (cl->HasSwitch(switches::kDisableOriginChip))
624 return ORIGIN_CHIP_DISABLED;
625 if (cl->HasSwitch(switches::kEnableOriginChipLeadingLocationBar))
626 return ORIGIN_CHIP_LEADING_LOCATION_BAR;
627 if (cl->HasSwitch(switches::kEnableOriginChip) ||
628 cl->HasSwitch(switches::kEnableOriginChipTrailingLocationBar))
629 return ORIGIN_CHIP_TRAILING_LOCATION_BAR;
630 if (cl->HasSwitch(switches::kEnableOriginChipLeadingMenuButton))
631 return ORIGIN_CHIP_LEADING_MENU_BUTTON;
633 FieldTrialFlags flags;
634 if (!GetFieldTrialInfo(&flags))
635 return ORIGIN_CHIP_DISABLED;
637 GetUInt64ValueForFlagWithDefault(kOriginChipFlagName, 0, flags);
638 return (value < ORIGIN_CHIP_NUM_VALUES) ?
639 static_cast<OriginChipPosition>(value) :
640 ORIGIN_CHIP_DISABLED;
643 bool ShouldDisplayOriginChipV2() {
644 return GetOriginChipV2HideTrigger() != ORIGIN_CHIP_V2_DISABLED;
647 OriginChipV2HideTrigger GetOriginChipV2HideTrigger() {
648 const CommandLine* cl = CommandLine::ForCurrentProcess();
649 if (cl->HasSwitch(switches::kDisableOriginChipV2))
650 return ORIGIN_CHIP_V2_DISABLED;
651 if (cl->HasSwitch(switches::kEnableOriginChipV2HideOnMouseRelease))
652 return ORIGIN_CHIP_V2_HIDE_ON_MOUSE_RELEASE;
653 if (cl->HasSwitch(switches::kEnableOriginChipV2HideOnUserInput))
654 return ORIGIN_CHIP_V2_HIDE_ON_USER_INPUT;
656 FieldTrialFlags flags;
657 if (!GetFieldTrialInfo(&flags))
658 return ORIGIN_CHIP_V2_DISABLED;
660 GetUInt64ValueForFlagWithDefault(kOriginChipV2FlagName, 0, flags);
661 return (value < ORIGIN_CHIP_V2_NUM_VALUES) ?
662 static_cast<OriginChipV2HideTrigger>(value) :
663 ORIGIN_CHIP_V2_DISABLED;
666 bool ShouldShowGoogleLocalNTP() {
667 FieldTrialFlags flags;
668 return !GetFieldTrialInfo(&flags) || GetBoolValueForFlagWithDefault(
669 kShouldShowGoogleLocalNTPFlagName, true, flags);
672 GURL GetEffectiveURLForInstant(const GURL& url, Profile* profile) {
673 CHECK(ShouldAssignURLToInstantRenderer(url, profile))
674 << "Error granting Instant access.";
676 if (url.SchemeIs(chrome::kChromeSearchScheme))
679 GURL effective_url(url);
681 // Replace the scheme with "chrome-search:".
682 url_canon::Replacements<char> replacements;
683 std::string search_scheme(chrome::kChromeSearchScheme);
684 replacements.SetScheme(search_scheme.data(),
685 url_parse::Component(0, search_scheme.length()));
687 // If this is the URL for a server-provided NTP, replace the host with
689 std::string remote_ntp_host(chrome::kChromeSearchRemoteNtpHost);
690 NewTabURLDetails details = NewTabURLDetails::ForProfile(profile);
691 if (details.state == NEW_TAB_URL_VALID &&
692 search::MatchesOriginAndPath(url, details.url)) {
693 replacements.SetHost(remote_ntp_host.c_str(),
694 url_parse::Component(0, remote_ntp_host.length()));
697 effective_url = effective_url.ReplaceComponents(replacements);
698 return effective_url;
701 bool HandleNewTabURLRewrite(GURL* url,
702 content::BrowserContext* browser_context) {
703 if (!IsInstantExtendedAPIEnabled())
706 if (!url->SchemeIs(content::kChromeUIScheme) ||
707 url->host() != chrome::kChromeUINewTabHost)
710 Profile* profile = Profile::FromBrowserContext(browser_context);
711 NewTabURLDetails details(NewTabURLDetails::ForProfile(profile));
712 UMA_HISTOGRAM_ENUMERATION("NewTabPage.URLState",
713 details.state, NEW_TAB_URL_MAX);
714 if (details.url.is_valid()) {
721 bool HandleNewTabURLReverseRewrite(GURL* url,
722 content::BrowserContext* browser_context) {
723 if (!IsInstantExtendedAPIEnabled())
726 // Do nothing in incognito.
727 Profile* profile = Profile::FromBrowserContext(browser_context);
728 if (profile && profile->IsOffTheRecord())
731 if (search::MatchesOriginAndPath(
732 GURL(chrome::kChromeSearchLocalNtpUrl), *url)) {
733 *url = GURL(chrome::kChromeUINewTabURL);
737 GURL new_tab_url(GetNewTabPageURL(profile));
738 if (new_tab_url.is_valid() &&
739 search::MatchesOriginAndPath(new_tab_url, *url)) {
740 *url = GURL(chrome::kChromeUINewTabURL);
747 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
748 content::NavigationEntry* entry) {
752 entry->SetExtraData(kInstantSupportStateKey,
753 InstantSupportStateToString(state));
756 InstantSupportState GetInstantSupportStateFromNavigationEntry(
757 const content::NavigationEntry& entry) {
758 base::string16 value;
759 if (!entry.GetExtraData(kInstantSupportStateKey, &value))
760 return INSTANT_SUPPORT_UNKNOWN;
762 return StringToInstantSupportState(value);
765 bool ShouldPrefetchSearchResultsOnSRP() {
766 FieldTrialFlags flags;
767 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
768 kPrefetchSearchResultsOnSRP, false, flags);
771 void EnableQueryExtractionForTesting() {
772 CommandLine* cl = CommandLine::ForCurrentProcess();
773 cl->AppendSwitch(switches::kEnableQueryExtraction);
776 bool GetFieldTrialInfo(FieldTrialFlags* flags) {
777 // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
778 // the older InstantExtended name.
779 std::string group_name = base::FieldTrialList::FindFullName(
780 kEmbeddedSearchFieldTrialName);
781 if (group_name.empty()) {
782 group_name = base::FieldTrialList::FindFullName(
783 kInstantExtendedFieldTrialName);
786 if (EndsWith(group_name, kDisablingSuffix, true))
789 // We have a valid trial that isn't disabled. Extract the flags.
790 std::string group_prefix(group_name);
791 size_t first_space = group_name.find(" ");
792 if (first_space != std::string::npos) {
793 // There is a flags section of the group name. Split that out and parse it.
794 group_prefix = group_name.substr(0, first_space);
795 if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
797 // Failed to parse the flags section. Assume the whole group name is
805 // Given a FieldTrialFlags object, returns the string value of the provided
807 std::string GetStringValueForFlagWithDefault(const std::string& flag,
808 const std::string& default_value,
809 const FieldTrialFlags& flags) {
810 FieldTrialFlags::const_iterator i;
811 for (i = flags.begin(); i != flags.end(); i++) {
812 if (i->first == flag)
815 return default_value;
818 // Given a FieldTrialFlags object, returns the uint64 value of the provided
820 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
821 uint64 default_value,
822 const FieldTrialFlags& flags) {
824 std::string str_value =
825 GetStringValueForFlagWithDefault(flag, std::string(), flags);
826 if (base::StringToUint64(str_value, &value))
828 return default_value;
831 // Given a FieldTrialFlags object, returns the boolean value of the provided
833 bool GetBoolValueForFlagWithDefault(const std::string& flag,
835 const FieldTrialFlags& flags) {
836 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
839 } // namespace chrome