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";
57 const uint64 kEmbeddedPageVersionDefault
= 1;
58 #elif defined(OS_ANDROID)
59 const uint64 kEmbeddedPageVersionDefault
= 1;
60 // Use this variant to enable EmbeddedSearch SearchBox API in the results page.
61 const uint64 kEmbeddedSearchEnabledVersion
= 2;
63 const uint64 kEmbeddedPageVersionDefault
= 2;
66 const char kHideVerbatimFlagName
[] = "hide_verbatim";
67 const char kPrefetchSearchResultsFlagName
[] = "prefetch_results";
68 const char kPrefetchSearchResultsOnSRP
[] = "prefetch_results_srp";
70 // Controls whether to reuse prerendered Instant Search base page to commit any
72 const char kReuseInstantSearchBasePage
[] = "reuse_instant_search_base_page";
74 const char kDisplaySearchButtonFlagName
[] = "display_search_button";
75 const char kOriginChipFlagName
[] = "origin_chip";
76 const char kOriginChipV2FlagName
[] = "origin_chip_v2";
77 #if !defined(OS_IOS) && !defined(OS_ANDROID)
78 const char kEnableQueryExtractionFlagName
[] = "query_extraction";
80 const char kShouldShowGoogleLocalNTPFlagName
[] = "google_local_ntp";
82 // Constants for the field trial name and group prefix.
83 // Note in M30 and below this field trial was named "InstantExtended" and in
84 // M31 was renamed to EmbeddedSearch for clarity and cleanliness. Since we
85 // can't easilly sync up Finch configs with the pushing of this change to
86 // Dev & Canary, for now the code accepts both names.
87 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
89 const char kInstantExtendedFieldTrialName
[] = "InstantExtended";
90 const char kEmbeddedSearchFieldTrialName
[] = "EmbeddedSearch";
92 // If the field trial's group name ends with this string its configuration will
93 // be ignored and Instant Extended will not be enabled by default.
94 const char kDisablingSuffix
[] = "DISABLED";
96 // Status of the New Tab URL for the default Search provider. NOTE: Used in a
97 // UMA histogram so values should only be added at the end and not reordered.
99 // Valid URL that should be used.
100 NEW_TAB_URL_VALID
= 0,
102 // Corrupt state (e.g. no profile or template url).
105 // URL should not be used because in incognito window.
106 NEW_TAB_URL_INCOGNITO
= 2,
108 // No New Tab URL set for provider.
109 NEW_TAB_URL_NOT_SET
= 3,
111 // URL is not secure.
112 NEW_TAB_URL_INSECURE
= 4,
114 // URL should not be used because Suggest is disabled.
115 // Not used anymore, see crbug.com/340424.
116 // NEW_TAB_URL_SUGGEST_OFF = 5,
118 // URL should not be used because it is blocked for a supervised user.
119 NEW_TAB_URL_BLOCKED
= 6,
124 // Used to set the Instant support state of the Navigation entry.
125 const char kInstantSupportStateKey
[] = "instant_support_state";
127 const char kInstantSupportEnabled
[] = "Instant support enabled";
128 const char kInstantSupportDisabled
[] = "Instant support disabled";
129 const char kInstantSupportUnknown
[] = "Instant support unknown";
131 InstantSupportState
StringToInstantSupportState(const base::string16
& value
) {
132 if (value
== base::ASCIIToUTF16(kInstantSupportEnabled
))
133 return INSTANT_SUPPORT_YES
;
134 else if (value
== base::ASCIIToUTF16(kInstantSupportDisabled
))
135 return INSTANT_SUPPORT_NO
;
137 return INSTANT_SUPPORT_UNKNOWN
;
140 base::string16
InstantSupportStateToString(InstantSupportState state
) {
142 case INSTANT_SUPPORT_NO
:
143 return base::ASCIIToUTF16(kInstantSupportDisabled
);
144 case INSTANT_SUPPORT_YES
:
145 return base::ASCIIToUTF16(kInstantSupportEnabled
);
146 case INSTANT_SUPPORT_UNKNOWN
:
147 return base::ASCIIToUTF16(kInstantSupportUnknown
);
149 return base::ASCIIToUTF16(kInstantSupportUnknown
);
152 TemplateURL
* GetDefaultSearchProviderTemplateURL(Profile
* profile
) {
154 TemplateURLService
* template_url_service
=
155 TemplateURLServiceFactory::GetForProfile(profile
);
156 if (template_url_service
)
157 return template_url_service
->GetDefaultSearchProvider();
162 GURL
TemplateURLRefToGURL(const TemplateURLRef
& ref
,
164 bool append_extra_query_params
,
165 bool force_instant_results
) {
166 TemplateURLRef::SearchTermsArgs search_terms_args
=
167 TemplateURLRef::SearchTermsArgs(base::string16());
168 search_terms_args
.omnibox_start_margin
= start_margin
;
169 search_terms_args
.append_extra_query_params
= append_extra_query_params
;
170 search_terms_args
.force_instant_results
= force_instant_results
;
171 return GURL(ref
.ReplaceSearchTerms(search_terms_args
));
174 bool MatchesAnySearchURL(const GURL
& url
, TemplateURL
* template_url
) {
176 TemplateURLRefToGURL(template_url
->url_ref(), kDisableStartMargin
, false,
178 if (search_url
.is_valid() &&
179 search::MatchesOriginAndPath(url
, search_url
))
182 // "URLCount() - 1" because we already tested url_ref above.
183 for (size_t i
= 0; i
< template_url
->URLCount() - 1; ++i
) {
184 TemplateURLRef
ref(template_url
, i
);
185 search_url
= TemplateURLRefToGURL(ref
, kDisableStartMargin
, false, false);
186 if (search_url
.is_valid() &&
187 search::MatchesOriginAndPath(url
, search_url
))
194 // Returns true if |contents| is rendered inside the Instant process for
196 bool IsRenderedInInstantProcess(const content::WebContents
* contents
,
198 const content::RenderProcessHost
* process_host
=
199 contents
->GetRenderProcessHost();
203 const InstantService
* instant_service
=
204 InstantServiceFactory::GetForProfile(profile
);
205 if (!instant_service
)
208 return instant_service
->IsInstantProcess(process_host
->GetID());
211 // |url| should either have a secure scheme or have a non-HTTPS base URL that
212 // the user specified using --google-base-url. (This allows testers to use
213 // --google-base-url to point at non-HTTPS servers, which eases testing.)
214 bool IsSuitableURLForInstant(const GURL
& url
, const TemplateURL
* template_url
) {
215 return template_url
->HasSearchTermsReplacementKey(url
) &&
216 (url
.SchemeIsSecure() ||
217 google_util::StartsWithCommandLineGoogleBaseURL(url
));
220 // Returns true if |url| can be used as an Instant URL for |profile|.
221 bool IsInstantURL(const GURL
& url
, Profile
* profile
) {
222 if (!IsInstantExtendedAPIEnabled())
228 const GURL
new_tab_url(GetNewTabPageURL(profile
));
229 if (new_tab_url
.is_valid() &&
230 search::MatchesOriginAndPath(url
, new_tab_url
))
233 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
237 if (!IsSuitableURLForInstant(url
, template_url
))
240 const TemplateURLRef
& instant_url_ref
= template_url
->instant_url_ref();
241 const GURL instant_url
=
242 TemplateURLRefToGURL(instant_url_ref
, kDisableStartMargin
, false, false);
243 if (!instant_url
.is_valid())
246 if (search::MatchesOriginAndPath(url
, instant_url
))
249 return IsQueryExtractionEnabled() && MatchesAnySearchURL(url
, template_url
);
252 base::string16
GetSearchTermsImpl(const content::WebContents
* contents
,
253 const content::NavigationEntry
* entry
) {
254 if (!contents
|| !IsQueryExtractionEnabled())
255 return base::string16();
257 // For security reasons, don't extract search terms if the page is not being
258 // rendered in the privileged Instant renderer process. This is to protect
259 // against a malicious page somehow scripting the search results page and
260 // faking search terms in the URL. Random pages can't get into the Instant
261 // renderer and scripting doesn't work cross-process, so if the page is in
262 // the Instant process, we know it isn't being exploited.
263 Profile
* profile
= Profile::FromBrowserContext(contents
->GetBrowserContext());
264 if (IsInstantExtendedAPIEnabled() &&
265 !IsRenderedInInstantProcess(contents
, profile
) &&
266 ((entry
== contents
->GetController().GetLastCommittedEntry()) ||
267 !ShouldAssignURLToInstantRenderer(entry
->GetURL(), profile
)))
268 return base::string16();
270 // Check to see if search terms have already been extracted.
271 base::string16 search_terms
= GetSearchTermsFromNavigationEntry(entry
);
272 if (!search_terms
.empty())
275 if (!IsQueryExtractionAllowedForURL(profile
, entry
->GetVirtualURL()))
276 return base::string16();
278 // Otherwise, extract from the URL.
279 return ExtractSearchTermsFromURL(profile
, entry
->GetVirtualURL());
282 bool IsURLAllowedForSupervisedUser(const GURL
& url
, Profile
* profile
) {
283 #if defined(ENABLE_MANAGED_USERS)
284 ManagedUserService
* managed_user_service
=
285 ManagedUserServiceFactory::GetForProfile(profile
);
286 ManagedModeURLFilter
* url_filter
=
287 managed_user_service
->GetURLFilterForUIThread();
288 if (url_filter
->GetFilteringBehaviorForURL(url
) ==
289 ManagedModeURLFilter::BLOCK
) {
296 // Returns whether |new_tab_url| can be used as a URL for the New Tab page.
297 // NEW_TAB_URL_VALID means a valid URL; other enum values imply an invalid URL.
298 NewTabURLState
IsValidNewTabURL(Profile
* profile
, const GURL
& new_tab_url
) {
299 if (profile
->IsOffTheRecord())
300 return NEW_TAB_URL_INCOGNITO
;
301 if (!new_tab_url
.is_valid())
302 return NEW_TAB_URL_NOT_SET
;
303 if (!new_tab_url
.SchemeIsSecure())
304 return NEW_TAB_URL_INSECURE
;
305 if (!IsURLAllowedForSupervisedUser(new_tab_url
, profile
))
306 return NEW_TAB_URL_BLOCKED
;
307 return NEW_TAB_URL_VALID
;
310 // Used to look up the URL to use for the New Tab page. Also tracks how we
311 // arrived at that URL so it can be logged with UMA.
312 struct NewTabURLDetails
{
313 NewTabURLDetails(const GURL
& url
, NewTabURLState state
)
314 : url(url
), state(state
) {}
316 static NewTabURLDetails
ForProfile(Profile
* profile
) {
317 const GURL
local_url(chrome::kChromeSearchLocalNtpUrl
);
318 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
319 if (!profile
|| !template_url
)
320 return NewTabURLDetails(local_url
, NEW_TAB_URL_BAD
);
322 GURL search_provider_url
= TemplateURLRefToGURL(
323 template_url
->new_tab_url_ref(), kDisableStartMargin
, false, false);
324 NewTabURLState state
= IsValidNewTabURL(profile
, search_provider_url
);
326 case NEW_TAB_URL_VALID
:
327 // We can use the search provider's page.
328 return NewTabURLDetails(search_provider_url
, state
);
329 case NEW_TAB_URL_INCOGNITO
:
330 // Incognito has its own New Tab.
331 return NewTabURLDetails(GURL(), state
);
333 // Use the local New Tab otherwise.
334 return NewTabURLDetails(local_url
, state
);
339 NewTabURLState state
;
344 // Negative start-margin values prevent the "es_sm" parameter from being used.
345 const int kDisableStartMargin
= -1;
347 bool IsInstantExtendedAPIEnabled() {
350 #elif defined(OS_ANDROID)
351 return EmbeddedSearchPageVersion() == kEmbeddedSearchEnabledVersion
;
354 #endif // defined(OS_IOS)
357 // Determine what embedded search page version to request from the user's
358 // default search provider. If 0, the embedded search UI should not be enabled.
359 uint64
EmbeddedSearchPageVersion() {
360 #if defined(OS_ANDROID)
361 if (CommandLine::ForCurrentProcess()->HasSwitch(
362 switches::kEnableEmbeddedSearchAPI
)) {
363 return kEmbeddedSearchEnabledVersion
;
367 FieldTrialFlags flags
;
368 if (GetFieldTrialInfo(&flags
)) {
369 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName
,
370 kEmbeddedPageVersionDefault
,
373 return kEmbeddedPageVersionDefault
;
376 std::string
InstantExtendedEnabledParam(bool for_search
) {
377 if (for_search
&& !chrome::IsQueryExtractionEnabled())
378 return std::string();
379 return std::string(google_util::kInstantExtendedAPIParam
) + "=" +
380 base::Uint64ToString(EmbeddedSearchPageVersion()) + "&";
383 std::string
ForceInstantResultsParam(bool for_prerender
) {
384 return (for_prerender
|| !IsInstantExtendedAPIEnabled()) ?
385 "ion=1&" : std::string();
388 bool IsQueryExtractionEnabled() {
389 #if defined(OS_IOS) || defined(OS_ANDROID)
392 if (!IsInstantExtendedAPIEnabled())
395 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
396 if (command_line
->HasSwitch(switches::kEnableQueryExtraction
))
399 FieldTrialFlags flags
;
400 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
401 kEnableQueryExtractionFlagName
, false, flags
);
402 #endif // defined(OS_IOS) || defined(OS_ANDROID)
405 base::string16
ExtractSearchTermsFromURL(Profile
* profile
, const GURL
& url
) {
406 if (url
.is_valid() && url
== GetSearchResultPrefetchBaseURL(profile
)) {
407 // InstantSearchPrerenderer has the search query for the Instant search base
409 InstantSearchPrerenderer
* prerenderer
=
410 InstantSearchPrerenderer::GetForProfile(profile
);
411 // TODO(kmadhusu): Remove this CHECK after the investigation of
414 return prerenderer
->get_last_query();
417 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
418 base::string16 search_terms
;
420 template_url
->ExtractSearchTermsFromURL(url
, &search_terms
);
424 bool IsQueryExtractionAllowedForURL(Profile
* profile
, const GURL
& url
) {
425 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
426 return template_url
&& IsSuitableURLForInstant(url
, template_url
);
429 base::string16
GetSearchTermsFromNavigationEntry(
430 const content::NavigationEntry
* entry
) {
431 base::string16 search_terms
;
433 entry
->GetExtraData(sessions::kSearchTermsKey
, &search_terms
);
437 base::string16
GetSearchTerms(const content::WebContents
* contents
) {
439 return base::string16();
441 const content::NavigationEntry
* entry
=
442 contents
->GetController().GetVisibleEntry();
444 return base::string16();
446 if (IsInstantExtendedAPIEnabled()) {
447 InstantSupportState state
=
448 GetInstantSupportStateFromNavigationEntry(*entry
);
449 if (state
== INSTANT_SUPPORT_NO
)
450 return base::string16();
453 return GetSearchTermsImpl(contents
, entry
);
456 bool ShouldAssignURLToInstantRenderer(const GURL
& url
, Profile
* profile
) {
457 return url
.is_valid() &&
459 IsInstantExtendedAPIEnabled() &&
460 (url
.SchemeIs(chrome::kChromeSearchScheme
) ||
461 IsInstantURL(url
, profile
));
464 bool ShouldUseProcessPerSiteForInstantURL(const GURL
& url
, Profile
* profile
) {
465 return ShouldAssignURLToInstantRenderer(url
, profile
) &&
466 (url
.host() == chrome::kChromeSearchLocalNtpHost
||
467 url
.host() == chrome::kChromeSearchRemoteNtpHost
);
470 bool IsNTPURL(const GURL
& url
, Profile
* profile
) {
474 if (!IsInstantExtendedAPIEnabled())
475 return url
== GURL(chrome::kChromeUINewTabURL
);
477 const base::string16 search_terms
= ExtractSearchTermsFromURL(profile
, url
);
479 ((IsInstantURL(url
, profile
) && search_terms
.empty()) ||
480 url
== GURL(chrome::kChromeSearchLocalNtpUrl
));
483 bool IsInstantNTP(const content::WebContents
* contents
) {
487 return NavEntryIsInstantNTP(contents
,
488 contents
->GetController().GetVisibleEntry());
491 bool NavEntryIsInstantNTP(const content::WebContents
* contents
,
492 const content::NavigationEntry
* entry
) {
493 if (!contents
|| !entry
|| !IsInstantExtendedAPIEnabled())
496 Profile
* profile
= Profile::FromBrowserContext(contents
->GetBrowserContext());
497 if (!IsRenderedInInstantProcess(contents
, profile
))
500 if (entry
->GetURL() == GetLocalInstantURL(profile
))
503 GURL
new_tab_url(GetNewTabPageURL(profile
));
504 return new_tab_url
.is_valid() &&
505 search::MatchesOriginAndPath(entry
->GetURL(), new_tab_url
);
508 bool IsSuggestPrefEnabled(Profile
* profile
) {
509 return profile
&& !profile
->IsOffTheRecord() && profile
->GetPrefs() &&
510 profile
->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled
);
513 GURL
GetInstantURL(Profile
* profile
, int start_margin
,
514 bool force_instant_results
) {
515 if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile
))
518 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
523 TemplateURLRefToGURL(template_url
->instant_url_ref(), start_margin
, true,
524 force_instant_results
);
525 if (!instant_url
.is_valid() ||
526 !template_url
->HasSearchTermsReplacementKey(instant_url
))
529 // Extended mode requires HTTPS. Force it unless the base URL was overridden
530 // on the command line, in which case we allow HTTP (see comments on
531 // IsSuitableURLForInstant()).
532 if (!instant_url
.SchemeIsSecure() &&
533 !google_util::StartsWithCommandLineGoogleBaseURL(instant_url
)) {
534 GURL::Replacements replacements
;
535 const std::string
secure_scheme(content::kHttpsScheme
);
536 replacements
.SetSchemeStr(secure_scheme
);
537 instant_url
= instant_url
.ReplaceComponents(replacements
);
540 if (!IsURLAllowedForSupervisedUser(instant_url
, profile
))
546 // Returns URLs associated with the default search engine for |profile|.
547 std::vector
<GURL
> GetSearchURLs(Profile
* profile
) {
548 std::vector
<GURL
> result
;
549 TemplateURL
* template_url
= GetDefaultSearchProviderTemplateURL(profile
);
552 for (size_t i
= 0; i
< template_url
->URLCount(); ++i
) {
553 TemplateURLRef
ref(template_url
, i
);
554 result
.push_back(TemplateURLRefToGURL(ref
, kDisableStartMargin
, false,
560 GURL
GetNewTabPageURL(Profile
* profile
) {
561 return NewTabURLDetails::ForProfile(profile
).url
;
564 GURL
GetSearchResultPrefetchBaseURL(Profile
* profile
) {
565 return ShouldPrefetchSearchResults() ?
566 GetInstantURL(profile
, kDisableStartMargin
, true) : GURL();
569 bool ShouldPrefetchSearchResults() {
570 if (CommandLine::ForCurrentProcess()->HasSwitch(
571 switches::kPrefetchSearchResults
)) {
575 FieldTrialFlags flags
;
576 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
577 kPrefetchSearchResultsFlagName
, false, flags
);
580 bool ShouldReuseInstantSearchBasePage() {
581 if (CommandLine::ForCurrentProcess()->HasSwitch(
582 switches::kPrefetchSearchResults
)) {
586 if (!ShouldPrefetchSearchResults())
589 FieldTrialFlags flags
;
590 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
591 kReuseInstantSearchBasePage
, false, flags
);
594 GURL
GetLocalInstantURL(Profile
* profile
) {
595 return GURL(chrome::kChromeSearchLocalNtpUrl
);
598 bool ShouldHideTopVerbatimMatch() {
599 FieldTrialFlags flags
;
600 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
601 kHideVerbatimFlagName
, false, flags
);
604 DisplaySearchButtonConditions
GetDisplaySearchButtonConditions() {
605 const CommandLine
* cl
= CommandLine::ForCurrentProcess();
606 if (cl
->HasSwitch(switches::kDisableSearchButtonInOmnibox
))
607 return DISPLAY_SEARCH_BUTTON_NEVER
;
608 if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr
))
609 return DISPLAY_SEARCH_BUTTON_FOR_STR
;
610 if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip
))
611 return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP
;
612 if (cl
->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways
))
613 return DISPLAY_SEARCH_BUTTON_ALWAYS
;
615 FieldTrialFlags flags
;
616 if (!GetFieldTrialInfo(&flags
))
617 return DISPLAY_SEARCH_BUTTON_NEVER
;
619 GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName
, 0, flags
);
620 return (value
< DISPLAY_SEARCH_BUTTON_NUM_VALUES
) ?
621 static_cast<DisplaySearchButtonConditions
>(value
) :
622 DISPLAY_SEARCH_BUTTON_NEVER
;
625 bool ShouldDisplayOriginChip() {
626 return GetOriginChipPosition() != ORIGIN_CHIP_DISABLED
;
629 OriginChipPosition
GetOriginChipPosition() {
630 if (ShouldDisplayOriginChipV2())
631 return ORIGIN_CHIP_DISABLED
;
633 const CommandLine
* cl
= CommandLine::ForCurrentProcess();
634 if (cl
->HasSwitch(switches::kDisableOriginChip
))
635 return ORIGIN_CHIP_DISABLED
;
636 if (cl
->HasSwitch(switches::kEnableOriginChipLeadingLocationBar
))
637 return ORIGIN_CHIP_LEADING_LOCATION_BAR
;
638 if (cl
->HasSwitch(switches::kEnableOriginChip
) ||
639 cl
->HasSwitch(switches::kEnableOriginChipTrailingLocationBar
))
640 return ORIGIN_CHIP_TRAILING_LOCATION_BAR
;
641 if (cl
->HasSwitch(switches::kEnableOriginChipLeadingMenuButton
))
642 return ORIGIN_CHIP_LEADING_MENU_BUTTON
;
644 FieldTrialFlags flags
;
645 if (!GetFieldTrialInfo(&flags
))
646 return ORIGIN_CHIP_DISABLED
;
648 GetUInt64ValueForFlagWithDefault(kOriginChipFlagName
, 0, flags
);
649 return (value
< ORIGIN_CHIP_NUM_VALUES
) ?
650 static_cast<OriginChipPosition
>(value
) :
651 ORIGIN_CHIP_DISABLED
;
654 bool ShouldDisplayOriginChipV2() {
655 return GetOriginChipV2HideTrigger() != ORIGIN_CHIP_V2_DISABLED
;
658 OriginChipV2HideTrigger
GetOriginChipV2HideTrigger() {
659 const CommandLine
* cl
= CommandLine::ForCurrentProcess();
660 if (cl
->HasSwitch(switches::kDisableOriginChipV2
))
661 return ORIGIN_CHIP_V2_DISABLED
;
662 if (cl
->HasSwitch(switches::kEnableOriginChipV2HideOnMouseRelease
))
663 return ORIGIN_CHIP_V2_HIDE_ON_MOUSE_RELEASE
;
664 if (cl
->HasSwitch(switches::kEnableOriginChipV2HideOnUserInput
))
665 return ORIGIN_CHIP_V2_HIDE_ON_USER_INPUT
;
667 FieldTrialFlags flags
;
668 if (!GetFieldTrialInfo(&flags
))
669 return ORIGIN_CHIP_V2_DISABLED
;
671 GetUInt64ValueForFlagWithDefault(kOriginChipV2FlagName
, 0, flags
);
672 return (value
< ORIGIN_CHIP_V2_NUM_VALUES
) ?
673 static_cast<OriginChipV2HideTrigger
>(value
) :
674 ORIGIN_CHIP_V2_DISABLED
;
677 bool ShouldShowGoogleLocalNTP() {
678 FieldTrialFlags flags
;
679 return !GetFieldTrialInfo(&flags
) || GetBoolValueForFlagWithDefault(
680 kShouldShowGoogleLocalNTPFlagName
, true, flags
);
683 GURL
GetEffectiveURLForInstant(const GURL
& url
, Profile
* profile
) {
684 CHECK(ShouldAssignURLToInstantRenderer(url
, profile
))
685 << "Error granting Instant access.";
687 if (url
.SchemeIs(chrome::kChromeSearchScheme
))
690 GURL
effective_url(url
);
692 // Replace the scheme with "chrome-search:".
693 url::Replacements
<char> replacements
;
694 std::string
search_scheme(chrome::kChromeSearchScheme
);
695 replacements
.SetScheme(search_scheme
.data(),
696 url::Component(0, search_scheme
.length()));
698 // If this is the URL for a server-provided NTP, replace the host with
700 std::string
remote_ntp_host(chrome::kChromeSearchRemoteNtpHost
);
701 NewTabURLDetails details
= NewTabURLDetails::ForProfile(profile
);
702 if (details
.state
== NEW_TAB_URL_VALID
&&
703 search::MatchesOriginAndPath(url
, details
.url
)) {
704 replacements
.SetHost(remote_ntp_host
.c_str(),
705 url::Component(0, remote_ntp_host
.length()));
708 effective_url
= effective_url
.ReplaceComponents(replacements
);
709 return effective_url
;
712 bool HandleNewTabURLRewrite(GURL
* url
,
713 content::BrowserContext
* browser_context
) {
714 if (!IsInstantExtendedAPIEnabled())
717 if (!url
->SchemeIs(content::kChromeUIScheme
) ||
718 url
->host() != chrome::kChromeUINewTabHost
)
721 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
722 NewTabURLDetails
details(NewTabURLDetails::ForProfile(profile
));
723 UMA_HISTOGRAM_ENUMERATION("NewTabPage.URLState",
724 details
.state
, NEW_TAB_URL_MAX
);
725 if (details
.url
.is_valid()) {
732 bool HandleNewTabURLReverseRewrite(GURL
* url
,
733 content::BrowserContext
* browser_context
) {
734 if (!IsInstantExtendedAPIEnabled())
737 // Do nothing in incognito.
738 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
739 if (profile
&& profile
->IsOffTheRecord())
742 if (search::MatchesOriginAndPath(
743 GURL(chrome::kChromeSearchLocalNtpUrl
), *url
)) {
744 *url
= GURL(chrome::kChromeUINewTabURL
);
748 GURL
new_tab_url(GetNewTabPageURL(profile
));
749 if (new_tab_url
.is_valid() &&
750 search::MatchesOriginAndPath(new_tab_url
, *url
)) {
751 *url
= GURL(chrome::kChromeUINewTabURL
);
758 void SetInstantSupportStateInNavigationEntry(InstantSupportState state
,
759 content::NavigationEntry
* entry
) {
763 entry
->SetExtraData(kInstantSupportStateKey
,
764 InstantSupportStateToString(state
));
767 InstantSupportState
GetInstantSupportStateFromNavigationEntry(
768 const content::NavigationEntry
& entry
) {
769 base::string16 value
;
770 if (!entry
.GetExtraData(kInstantSupportStateKey
, &value
))
771 return INSTANT_SUPPORT_UNKNOWN
;
773 return StringToInstantSupportState(value
);
776 bool ShouldPrefetchSearchResultsOnSRP() {
777 FieldTrialFlags flags
;
778 return GetFieldTrialInfo(&flags
) && GetBoolValueForFlagWithDefault(
779 kPrefetchSearchResultsOnSRP
, false, flags
);
782 void EnableQueryExtractionForTesting() {
783 CommandLine
* cl
= CommandLine::ForCurrentProcess();
784 cl
->AppendSwitch(switches::kEnableQueryExtraction
);
787 bool GetFieldTrialInfo(FieldTrialFlags
* flags
) {
788 // Get the group name. If the EmbeddedSearch trial doesn't exist, look for
789 // the older InstantExtended name.
790 std::string group_name
= base::FieldTrialList::FindFullName(
791 kEmbeddedSearchFieldTrialName
);
792 if (group_name
.empty()) {
793 group_name
= base::FieldTrialList::FindFullName(
794 kInstantExtendedFieldTrialName
);
797 if (EndsWith(group_name
, kDisablingSuffix
, true))
800 // We have a valid trial that isn't disabled. Extract the flags.
801 std::string
group_prefix(group_name
);
802 size_t first_space
= group_name
.find(" ");
803 if (first_space
!= std::string::npos
) {
804 // There is a flags section of the group name. Split that out and parse it.
805 group_prefix
= group_name
.substr(0, first_space
);
806 if (!base::SplitStringIntoKeyValuePairs(group_name
.substr(first_space
),
808 // Failed to parse the flags section. Assume the whole group name is
816 // Given a FieldTrialFlags object, returns the string value of the provided
818 std::string
GetStringValueForFlagWithDefault(const std::string
& flag
,
819 const std::string
& default_value
,
820 const FieldTrialFlags
& flags
) {
821 FieldTrialFlags::const_iterator i
;
822 for (i
= flags
.begin(); i
!= flags
.end(); i
++) {
823 if (i
->first
== flag
)
826 return default_value
;
829 // Given a FieldTrialFlags object, returns the uint64 value of the provided
831 uint64
GetUInt64ValueForFlagWithDefault(const std::string
& flag
,
832 uint64 default_value
,
833 const FieldTrialFlags
& flags
) {
835 std::string str_value
=
836 GetStringValueForFlagWithDefault(flag
, std::string(), flags
);
837 if (base::StringToUint64(str_value
, &value
))
839 return default_value
;
842 // Given a FieldTrialFlags object, returns the boolean value of the provided
844 bool GetBoolValueForFlagWithDefault(const std::string
& flag
,
846 const FieldTrialFlags
& flags
) {
847 return !!GetUInt64ValueForFlagWithDefault(flag
, default_value
? 1 : 0, flags
);
850 } // namespace chrome