Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / search / search.cc
blob46ea5d7e4e3ab02515a255dc344330ff31a90a0b
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"
42 #endif
44 namespace chrome {
46 namespace {
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)
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;
62 #else
63 const uint64 kEmbeddedPageVersionDefault = 2;
64 #endif
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
71 // search query.
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";
79 #endif
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
88 // channel.
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.
98 enum NewTabURLState {
99 // Valid URL that should be used.
100 NEW_TAB_URL_VALID = 0,
102 // Corrupt state (e.g. no profile or template url).
103 NEW_TAB_URL_BAD = 1,
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,
121 NEW_TAB_URL_MAX
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;
136 else
137 return INSTANT_SUPPORT_UNKNOWN;
140 base::string16 InstantSupportStateToString(InstantSupportState state) {
141 switch (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) {
153 if (profile) {
154 TemplateURLService* template_url_service =
155 TemplateURLServiceFactory::GetForProfile(profile);
156 if (template_url_service)
157 return template_url_service->GetDefaultSearchProvider();
159 return NULL;
162 GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
163 int start_margin,
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) {
175 GURL search_url =
176 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false,
177 false);
178 if (search_url.is_valid() &&
179 search::MatchesOriginAndPath(url, search_url))
180 return true;
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))
188 return true;
191 return false;
194 // Returns true if |contents| is rendered inside the Instant process for
195 // |profile|.
196 bool IsRenderedInInstantProcess(const content::WebContents* contents,
197 Profile* profile) {
198 const content::RenderProcessHost* process_host =
199 contents->GetRenderProcessHost();
200 if (!process_host)
201 return false;
203 const InstantService* instant_service =
204 InstantServiceFactory::GetForProfile(profile);
205 if (!instant_service)
206 return false;
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())
223 return false;
225 if (!url.is_valid())
226 return false;
228 const GURL new_tab_url(GetNewTabPageURL(profile));
229 if (new_tab_url.is_valid() &&
230 search::MatchesOriginAndPath(url, new_tab_url))
231 return true;
233 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
234 if (!template_url)
235 return false;
237 if (!IsSuitableURLForInstant(url, template_url))
238 return false;
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())
244 return false;
246 if (search::MatchesOriginAndPath(url, instant_url))
247 return true;
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())
273 return search_terms;
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) {
290 return false;
292 #endif
293 return true;
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);
325 switch (state) {
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);
332 default:
333 // Use the local New Tab otherwise.
334 return NewTabURLDetails(local_url, state);
338 GURL url;
339 NewTabURLState state;
342 } // namespace
344 // Negative start-margin values prevent the "es_sm" parameter from being used.
345 const int kDisableStartMargin = -1;
347 bool IsInstantExtendedAPIEnabled() {
348 #if defined(OS_IOS)
349 return false;
350 #elif defined(OS_ANDROID)
351 return EmbeddedSearchPageVersion() == kEmbeddedSearchEnabledVersion;
352 #else
353 return true;
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;
365 #endif
367 FieldTrialFlags flags;
368 if (GetFieldTrialInfo(&flags)) {
369 return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
370 kEmbeddedPageVersionDefault,
371 flags);
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)
390 return true;
391 #else
392 if (!IsInstantExtendedAPIEnabled())
393 return false;
395 const CommandLine* command_line = CommandLine::ForCurrentProcess();
396 if (command_line->HasSwitch(switches::kEnableQueryExtraction))
397 return true;
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
408 // page.
409 InstantSearchPrerenderer* prerenderer =
410 InstantSearchPrerenderer::GetForProfile(profile);
411 // TODO(kmadhusu): Remove this CHECK after the investigation of
412 // crbug.com/367204.
413 CHECK(prerenderer);
414 return prerenderer->get_last_query();
417 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
418 base::string16 search_terms;
419 if (template_url)
420 template_url->ExtractSearchTermsFromURL(url, &search_terms);
421 return 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;
432 if (entry)
433 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms);
434 return search_terms;
437 base::string16 GetSearchTerms(const content::WebContents* contents) {
438 if (!contents)
439 return base::string16();
441 const content::NavigationEntry* entry =
442 contents->GetController().GetVisibleEntry();
443 if (!entry)
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() &&
458 profile &&
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) {
471 if (!url.is_valid())
472 return false;
474 if (!IsInstantExtendedAPIEnabled())
475 return url == GURL(chrome::kChromeUINewTabURL);
477 const base::string16 search_terms = ExtractSearchTermsFromURL(profile, url);
478 return profile &&
479 ((IsInstantURL(url, profile) && search_terms.empty()) ||
480 url == GURL(chrome::kChromeSearchLocalNtpUrl));
483 bool IsInstantNTP(const content::WebContents* contents) {
484 if (!contents)
485 return false;
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())
494 return false;
496 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
497 if (!IsRenderedInInstantProcess(contents, profile))
498 return false;
500 if (entry->GetURL() == GetLocalInstantURL(profile))
501 return true;
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))
516 return GURL();
518 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
519 if (!template_url)
520 return GURL();
522 GURL instant_url =
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))
527 return GURL();
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))
541 return GURL();
543 return instant_url;
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);
550 if (!template_url)
551 return result;
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,
555 false));
557 return result;
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)) {
572 return true;
575 FieldTrialFlags flags;
576 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
577 kPrefetchSearchResultsFlagName, false, flags);
580 bool ShouldReuseInstantSearchBasePage() {
581 if (CommandLine::ForCurrentProcess()->HasSwitch(
582 switches::kPrefetchSearchResults)) {
583 return true;
586 if (!ShouldPrefetchSearchResults())
587 return false;
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;
618 uint64 value =
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;
647 uint64 value =
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;
670 uint64 value =
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))
688 return url;
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
699 // "remote-ntp".
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())
715 return false;
717 if (!url->SchemeIs(content::kChromeUIScheme) ||
718 url->host() != chrome::kChromeUINewTabHost)
719 return false;
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()) {
726 *url = details.url;
727 return true;
729 return false;
732 bool HandleNewTabURLReverseRewrite(GURL* url,
733 content::BrowserContext* browser_context) {
734 if (!IsInstantExtendedAPIEnabled())
735 return false;
737 // Do nothing in incognito.
738 Profile* profile = Profile::FromBrowserContext(browser_context);
739 if (profile && profile->IsOffTheRecord())
740 return false;
742 if (search::MatchesOriginAndPath(
743 GURL(chrome::kChromeSearchLocalNtpUrl), *url)) {
744 *url = GURL(chrome::kChromeUINewTabURL);
745 return true;
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);
752 return true;
755 return false;
758 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
759 content::NavigationEntry* entry) {
760 if (!entry)
761 return;
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))
798 return false;
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),
807 ':', ' ', flags)) {
808 // Failed to parse the flags section. Assume the whole group name is
809 // invalid.
810 return false;
813 return true;
816 // Given a FieldTrialFlags object, returns the string value of the provided
817 // flag.
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)
824 return i->second;
826 return default_value;
829 // Given a FieldTrialFlags object, returns the uint64 value of the provided
830 // flag.
831 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
832 uint64 default_value,
833 const FieldTrialFlags& flags) {
834 uint64 value;
835 std::string str_value =
836 GetStringValueForFlagWithDefault(flag, std::string(), flags);
837 if (base::StringToUint64(str_value, &value))
838 return value;
839 return default_value;
842 // Given a FieldTrialFlags object, returns the boolean value of the provided
843 // flag.
844 bool GetBoolValueForFlagWithDefault(const std::string& flag,
845 bool default_value,
846 const FieldTrialFlags& flags) {
847 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
850 } // namespace chrome