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.
4
5#include "chrome/browser/search/search.h"
6
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/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_factory.h"
20#include "chrome/browser/search_engines/ui_thread_search_terms_data.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/google/core/browser/google_util.h"
30#include "components/pref_registry/pref_registry_syncable.h"
31#include "components/search/search.h"
32#include "components/search_engines/template_url_service.h"
33#include "components/sessions/serialized_navigation_entry.h"
34#include "content/public/browser/navigation_entry.h"
35#include "content/public/browser/render_process_host.h"
36#include "content/public/browser/web_contents.h"
37
38#if defined(ENABLE_MANAGED_USERS)
39#include "chrome/browser/supervised_user/supervised_user_service.h"
40#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
41#include "chrome/browser/supervised_user/supervised_user_url_filter.h"
42#endif
43
44namespace chrome {
45
46namespace {
47
48const char kPrefetchSearchResultsOnSRP[] = "prefetch_results_srp";
49const char kAllowPrefetchNonDefaultMatch[] = "allow_prefetch_non_default_match";
50const char kPrerenderInstantUrlOnOmniboxFocus[] =
51    "prerender_instant_url_on_omnibox_focus";
52
53#if defined(OS_ANDROID)
54const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
55
56// Controls whether to reuse prerendered Instant Search base page to commit any
57// search query.
58const char kReuseInstantSearchBasePage[] = "reuse_instant_search_base_page";
59#endif
60
61// Controls whether to use the alternate Instant search base URL. This allows
62// experimentation of Instant search.
63const char kUseAltInstantURL[] = "use_alternate_instant_url";
64const char kUseSearchPathForInstant[] = "use_search_path_for_instant";
65const char kAltInstantURLPath[] = "search";
66const char kAltInstantURLQueryParams[] = "&qbp=1";
67
68const char kDisplaySearchButtonFlagName[] = "display_search_button";
69const char kOriginChipFlagName[] = "origin_chip";
70#if !defined(OS_IOS) && !defined(OS_ANDROID)
71const char kEnableQueryExtractionFlagName[] = "query_extraction";
72#endif
73const char kShouldShowGoogleLocalNTPFlagName[] = "google_local_ntp";
74
75// Status of the New Tab URL for the default Search provider. NOTE: Used in a
76// UMA histogram so values should only be added at the end and not reordered.
77enum NewTabURLState {
78  // Valid URL that should be used.
79  NEW_TAB_URL_VALID = 0,
80
81  // Corrupt state (e.g. no profile or template url).
82  NEW_TAB_URL_BAD = 1,
83
84  // URL should not be used because in incognito window.
85  NEW_TAB_URL_INCOGNITO = 2,
86
87  // No New Tab URL set for provider.
88  NEW_TAB_URL_NOT_SET = 3,
89
90  // URL is not secure.
91  NEW_TAB_URL_INSECURE = 4,
92
93  // URL should not be used because Suggest is disabled.
94  // Not used anymore, see crbug.com/340424.
95  // NEW_TAB_URL_SUGGEST_OFF = 5,
96
97  // URL should not be used because it is blocked for a supervised user.
98  NEW_TAB_URL_BLOCKED = 6,
99
100  NEW_TAB_URL_MAX
101};
102
103// Used to set the Instant support state of the Navigation entry.
104const char kInstantSupportStateKey[] = "instant_support_state";
105
106const char kInstantSupportEnabled[] = "Instant support enabled";
107const char kInstantSupportDisabled[] = "Instant support disabled";
108const char kInstantSupportUnknown[] = "Instant support unknown";
109
110InstantSupportState StringToInstantSupportState(const base::string16& value) {
111  if (value == base::ASCIIToUTF16(kInstantSupportEnabled))
112    return INSTANT_SUPPORT_YES;
113  else if (value == base::ASCIIToUTF16(kInstantSupportDisabled))
114    return INSTANT_SUPPORT_NO;
115  else
116    return INSTANT_SUPPORT_UNKNOWN;
117}
118
119base::string16 InstantSupportStateToString(InstantSupportState state) {
120  switch (state) {
121    case INSTANT_SUPPORT_NO:
122      return base::ASCIIToUTF16(kInstantSupportDisabled);
123    case INSTANT_SUPPORT_YES:
124      return base::ASCIIToUTF16(kInstantSupportEnabled);
125    case INSTANT_SUPPORT_UNKNOWN:
126      return base::ASCIIToUTF16(kInstantSupportUnknown);
127  }
128  return base::ASCIIToUTF16(kInstantSupportUnknown);
129}
130
131TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) {
132  if (profile) {
133    TemplateURLService* template_url_service =
134        TemplateURLServiceFactory::GetForProfile(profile);
135    if (template_url_service)
136      return template_url_service->GetDefaultSearchProvider();
137  }
138  return NULL;
139}
140
141GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
142                          const SearchTermsData& search_terms_data,
143                          bool append_extra_query_params,
144                          bool force_instant_results) {
145  TemplateURLRef::SearchTermsArgs search_terms_args =
146      TemplateURLRef::SearchTermsArgs(base::string16());
147  search_terms_args.append_extra_query_params = append_extra_query_params;
148  search_terms_args.force_instant_results = force_instant_results;
149  return GURL(ref.ReplaceSearchTerms(search_terms_args, search_terms_data));
150}
151
152bool MatchesAnySearchURL(const GURL& url,
153                         TemplateURL* template_url,
154                         const SearchTermsData& search_terms_data) {
155  GURL search_url = TemplateURLRefToGURL(template_url->url_ref(),
156                                         search_terms_data, false, false);
157  if (search_url.is_valid() &&
158      search::MatchesOriginAndPath(url, search_url))
159    return true;
160
161  // "URLCount() - 1" because we already tested url_ref above.
162  for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
163    TemplateURLRef ref(template_url, i);
164    search_url = TemplateURLRefToGURL(ref, search_terms_data, false, false);
165    if (search_url.is_valid() &&
166        search::MatchesOriginAndPath(url, search_url))
167      return true;
168  }
169
170  return false;
171}
172
173
174
175// |url| should either have a secure scheme or have a non-HTTPS base URL that
176// the user specified using --google-base-url. (This allows testers to use
177// --google-base-url to point at non-HTTPS servers, which eases testing.)
178bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
179  return template_url->HasSearchTermsReplacementKey(url) &&
180      (url.SchemeIsSecure() ||
181       google_util::StartsWithCommandLineGoogleBaseURL(url));
182}
183
184// Returns true if |url| can be used as an Instant URL for |profile|.
185bool IsInstantURL(const GURL& url, Profile* profile) {
186  if (!IsInstantExtendedAPIEnabled())
187    return false;
188
189  if (!url.is_valid())
190    return false;
191
192  const GURL new_tab_url(GetNewTabPageURL(profile));
193  if (new_tab_url.is_valid() &&
194      search::MatchesOriginAndPath(url, new_tab_url))
195    return true;
196
197  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
198  if (!template_url)
199    return false;
200
201  if (!IsSuitableURLForInstant(url, template_url))
202    return false;
203
204  const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
205  UIThreadSearchTermsData search_terms_data(profile);
206  const GURL instant_url = TemplateURLRefToGURL(
207      instant_url_ref, search_terms_data, false, false);
208  if (!instant_url.is_valid())
209    return false;
210
211  if (search::MatchesOriginAndPath(url, instant_url))
212    return true;
213
214  return IsQueryExtractionEnabled() &&
215      MatchesAnySearchURL(url, template_url, search_terms_data);
216}
217
218base::string16 GetSearchTermsImpl(const content::WebContents* contents,
219                                  const content::NavigationEntry* entry) {
220  if (!contents || !IsQueryExtractionEnabled())
221    return base::string16();
222
223  // For security reasons, don't extract search terms if the page is not being
224  // rendered in the privileged Instant renderer process. This is to protect
225  // against a malicious page somehow scripting the search results page and
226  // faking search terms in the URL. Random pages can't get into the Instant
227  // renderer and scripting doesn't work cross-process, so if the page is in
228  // the Instant process, we know it isn't being exploited.
229  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
230  if (IsInstantExtendedAPIEnabled() &&
231      !IsRenderedInInstantProcess(contents, profile) &&
232      ((entry == contents->GetController().GetLastCommittedEntry()) ||
233       !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
234    return base::string16();
235
236  // Check to see if search terms have already been extracted.
237  base::string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
238  if (!search_terms.empty())
239    return search_terms;
240
241  if (!IsQueryExtractionAllowedForURL(profile, entry->GetVirtualURL()))
242    return base::string16();
243
244  // Otherwise, extract from the URL.
245  return ExtractSearchTermsFromURL(profile, entry->GetVirtualURL());
246}
247
248bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) {
249#if defined(ENABLE_MANAGED_USERS)
250  SupervisedUserService* supervised_user_service =
251      SupervisedUserServiceFactory::GetForProfile(profile);
252  SupervisedUserURLFilter* url_filter =
253      supervised_user_service->GetURLFilterForUIThread();
254  if (url_filter->GetFilteringBehaviorForURL(url) ==
255          SupervisedUserURLFilter::BLOCK) {
256    return false;
257  }
258#endif
259  return true;
260}
261
262// Returns whether |new_tab_url| can be used as a URL for the New Tab page.
263// NEW_TAB_URL_VALID means a valid URL; other enum values imply an invalid URL.
264NewTabURLState IsValidNewTabURL(Profile* profile, const GURL& new_tab_url) {
265  if (profile->IsOffTheRecord())
266    return NEW_TAB_URL_INCOGNITO;
267  if (!new_tab_url.is_valid())
268    return NEW_TAB_URL_NOT_SET;
269  if (!new_tab_url.SchemeIsSecure())
270    return NEW_TAB_URL_INSECURE;
271  if (!IsURLAllowedForSupervisedUser(new_tab_url, profile))
272    return NEW_TAB_URL_BLOCKED;
273  return NEW_TAB_URL_VALID;
274}
275
276// Used to look up the URL to use for the New Tab page. Also tracks how we
277// arrived at that URL so it can be logged with UMA.
278struct NewTabURLDetails {
279  NewTabURLDetails(const GURL& url, NewTabURLState state)
280      : url(url), state(state) {}
281
282  static NewTabURLDetails ForProfile(Profile* profile) {
283    const GURL local_url(chrome::kChromeSearchLocalNtpUrl);
284    TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
285    if (!profile || !template_url)
286      return NewTabURLDetails(local_url, NEW_TAB_URL_BAD);
287
288    GURL search_provider_url = TemplateURLRefToGURL(
289        template_url->new_tab_url_ref(), UIThreadSearchTermsData(profile),
290        false, false);
291    NewTabURLState state = IsValidNewTabURL(profile, search_provider_url);
292    switch (state) {
293      case NEW_TAB_URL_VALID:
294        // We can use the search provider's page.
295        return NewTabURLDetails(search_provider_url, state);
296      case NEW_TAB_URL_INCOGNITO:
297        // Incognito has its own New Tab.
298        return NewTabURLDetails(GURL(), state);
299      default:
300        // Use the local New Tab otherwise.
301        return NewTabURLDetails(local_url, state);
302    }
303  }
304
305  GURL url;
306  NewTabURLState state;
307};
308
309}  // namespace
310
311// Negative start-margin values prevent the "es_sm" parameter from being used.
312const int kDisableStartMargin = -1;
313
314std::string InstantExtendedEnabledParam(bool for_search) {
315  if (for_search && !chrome::IsQueryExtractionEnabled())
316    return std::string();
317  return std::string(google_util::kInstantExtendedAPIParam) + "=" +
318      base::Uint64ToString(EmbeddedSearchPageVersion()) + "&";
319}
320
321std::string ForceInstantResultsParam(bool for_prerender) {
322  return (for_prerender || !IsInstantExtendedAPIEnabled()) ?
323      "ion=1&" : std::string();
324}
325
326bool IsQueryExtractionEnabled() {
327#if defined(OS_IOS) || defined(OS_ANDROID)
328  return true;
329#else
330  if (!IsInstantExtendedAPIEnabled())
331    return false;
332
333  const CommandLine* command_line = CommandLine::ForCurrentProcess();
334  if (command_line->HasSwitch(switches::kEnableQueryExtraction))
335    return true;
336
337  FieldTrialFlags flags;
338  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
339      kEnableQueryExtractionFlagName, false, flags);
340#endif  // defined(OS_IOS) || defined(OS_ANDROID)
341}
342
343base::string16 ExtractSearchTermsFromURL(Profile* profile, const GURL& url) {
344  if (url.is_valid() && url == GetSearchResultPrefetchBaseURL(profile)) {
345    // InstantSearchPrerenderer has the search query for the Instant search base
346    // page.
347    InstantSearchPrerenderer* prerenderer =
348        InstantSearchPrerenderer::GetForProfile(profile);
349    // TODO(kmadhusu): Remove this CHECK after the investigation of
350    // crbug.com/367204.
351    CHECK(prerenderer);
352    return prerenderer->get_last_query();
353  }
354
355  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
356  base::string16 search_terms;
357  if (template_url)
358    template_url->ExtractSearchTermsFromURL(
359        url, UIThreadSearchTermsData(profile), &search_terms);
360  return search_terms;
361}
362
363bool IsQueryExtractionAllowedForURL(Profile* profile, const GURL& url) {
364  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
365  return template_url && IsSuitableURLForInstant(url, template_url);
366}
367
368base::string16 GetSearchTermsFromNavigationEntry(
369    const content::NavigationEntry* entry) {
370  base::string16 search_terms;
371  if (entry)
372    entry->GetExtraData(sessions::kSearchTermsKey, &search_terms);
373  return search_terms;
374}
375
376base::string16 GetSearchTerms(const content::WebContents* contents) {
377  if (!contents)
378    return base::string16();
379
380  const content::NavigationEntry* entry =
381      contents->GetController().GetVisibleEntry();
382  if (!entry)
383    return base::string16();
384
385  if (IsInstantExtendedAPIEnabled()) {
386    InstantSupportState state =
387        GetInstantSupportStateFromNavigationEntry(*entry);
388    if (state == INSTANT_SUPPORT_NO)
389      return base::string16();
390  }
391
392  return GetSearchTermsImpl(contents, entry);
393}
394
395bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) {
396  return url.is_valid() &&
397         profile &&
398         IsInstantExtendedAPIEnabled() &&
399         (url.SchemeIs(chrome::kChromeSearchScheme) ||
400          IsInstantURL(url, profile));
401}
402
403bool IsRenderedInInstantProcess(const content::WebContents* contents,
404                                Profile* profile) {
405  const content::RenderProcessHost* process_host =
406      contents->GetRenderProcessHost();
407  if (!process_host)
408    return false;
409
410  const InstantService* instant_service =
411      InstantServiceFactory::GetForProfile(profile);
412  if (!instant_service)
413    return false;
414
415  return instant_service->IsInstantProcess(process_host->GetID());
416}
417
418bool ShouldUseProcessPerSiteForInstantURL(const GURL& url, Profile* profile) {
419  return ShouldAssignURLToInstantRenderer(url, profile) &&
420      (url.host() == chrome::kChromeSearchLocalNtpHost ||
421       url.host() == chrome::kChromeSearchRemoteNtpHost);
422}
423
424bool IsNTPURL(const GURL& url, Profile* profile) {
425  if (!url.is_valid())
426    return false;
427
428  if (!IsInstantExtendedAPIEnabled())
429    return url == GURL(chrome::kChromeUINewTabURL);
430
431  const base::string16 search_terms = ExtractSearchTermsFromURL(profile, url);
432  return profile &&
433      ((IsInstantURL(url, profile) && search_terms.empty()) ||
434       url == GURL(chrome::kChromeSearchLocalNtpUrl));
435}
436
437bool IsInstantNTP(const content::WebContents* contents) {
438  if (!contents)
439    return false;
440
441  return NavEntryIsInstantNTP(contents,
442                              contents->GetController().GetVisibleEntry());
443}
444
445bool NavEntryIsInstantNTP(const content::WebContents* contents,
446                          const content::NavigationEntry* entry) {
447  if (!contents || !entry || !IsInstantExtendedAPIEnabled())
448    return false;
449
450  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
451  if (!IsRenderedInInstantProcess(contents, profile))
452    return false;
453
454  if (entry->GetURL() == GetLocalInstantURL(profile))
455    return true;
456
457  GURL new_tab_url(GetNewTabPageURL(profile));
458  return new_tab_url.is_valid() &&
459      search::MatchesOriginAndPath(entry->GetURL(), new_tab_url);
460}
461
462bool IsSuggestPrefEnabled(Profile* profile) {
463  return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
464         profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
465}
466
467GURL GetInstantURL(Profile* profile, bool force_instant_results) {
468  if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
469    return GURL();
470
471  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
472  if (!template_url)
473    return GURL();
474
475  GURL instant_url = TemplateURLRefToGURL(
476      template_url->instant_url_ref(), UIThreadSearchTermsData(profile),
477      true, force_instant_results);
478  if (!instant_url.is_valid() ||
479      !template_url->HasSearchTermsReplacementKey(instant_url))
480    return GURL();
481
482  // Extended mode requires HTTPS.  Force it unless the base URL was overridden
483  // on the command line, in which case we allow HTTP (see comments on
484  // IsSuitableURLForInstant()).
485  if (!instant_url.SchemeIsSecure() &&
486      !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
487    GURL::Replacements replacements;
488    const std::string secure_scheme(url::kHttpsScheme);
489    replacements.SetSchemeStr(secure_scheme);
490    instant_url = instant_url.ReplaceComponents(replacements);
491  }
492
493  if (!IsURLAllowedForSupervisedUser(instant_url, profile))
494    return GURL();
495
496  if (ShouldUseAltInstantURL()) {
497    GURL::Replacements replacements;
498      const std::string path(
499          ShouldUseSearchPathForInstant() ? kAltInstantURLPath : std::string());
500    if (!path.empty())
501      replacements.SetPathStr(path);
502    const std::string query(
503        instant_url.query() + std::string(kAltInstantURLQueryParams));
504    replacements.SetQueryStr(query);
505    instant_url = instant_url.ReplaceComponents(replacements);
506  }
507  return instant_url;
508}
509
510// Returns URLs associated with the default search engine for |profile|.
511std::vector<GURL> GetSearchURLs(Profile* profile) {
512  std::vector<GURL> result;
513  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
514  if (!template_url)
515    return result;
516  for (size_t i = 0; i < template_url->URLCount(); ++i) {
517    TemplateURLRef ref(template_url, i);
518    result.push_back(TemplateURLRefToGURL(ref, UIThreadSearchTermsData(profile),
519                                          false, false));
520  }
521  return result;
522}
523
524GURL GetNewTabPageURL(Profile* profile) {
525  return NewTabURLDetails::ForProfile(profile).url;
526}
527
528GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
529  return ShouldPrefetchSearchResults() ? GetInstantURL(profile, true) : GURL();
530}
531
532bool ShouldPrefetchSearchResults() {
533  if (!IsInstantExtendedAPIEnabled())
534    return false;
535
536#if defined(OS_ANDROID)
537  if (CommandLine::ForCurrentProcess()->HasSwitch(
538          switches::kPrefetchSearchResults)) {
539    return true;
540  }
541
542  FieldTrialFlags flags;
543  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
544      kPrefetchSearchResultsFlagName, false, flags);
545#else
546  return true;
547#endif
548}
549
550bool ShouldAllowPrefetchNonDefaultMatch() {
551  if (!ShouldPrefetchSearchResults())
552    return false;
553
554  FieldTrialFlags flags;
555  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
556      kAllowPrefetchNonDefaultMatch, false, flags);
557}
558
559bool ShouldPrerenderInstantUrlOnOmniboxFocus() {
560  if (!ShouldPrefetchSearchResults())
561    return false;
562
563  FieldTrialFlags flags;
564  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
565      kPrerenderInstantUrlOnOmniboxFocus, false, flags);
566}
567
568bool ShouldReuseInstantSearchBasePage() {
569  if (!ShouldPrefetchSearchResults())
570    return false;
571
572#if defined(OS_ANDROID)
573  FieldTrialFlags flags;
574  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
575      kReuseInstantSearchBasePage, false, flags);
576#else
577  return true;
578#endif
579}
580
581GURL GetLocalInstantURL(Profile* profile) {
582  return GURL(chrome::kChromeSearchLocalNtpUrl);
583}
584
585DisplaySearchButtonConditions GetDisplaySearchButtonConditions() {
586  const CommandLine* cl = CommandLine::ForCurrentProcess();
587  if (cl->HasSwitch(switches::kDisableSearchButtonInOmnibox))
588    return DISPLAY_SEARCH_BUTTON_NEVER;
589  if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr))
590    return DISPLAY_SEARCH_BUTTON_FOR_STR;
591  if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip))
592    return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP;
593  if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways))
594    return DISPLAY_SEARCH_BUTTON_ALWAYS;
595
596  FieldTrialFlags flags;
597  if (!GetFieldTrialInfo(&flags))
598    return DISPLAY_SEARCH_BUTTON_NEVER;
599  uint64 value =
600      GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName, 0, flags);
601  return (value < DISPLAY_SEARCH_BUTTON_NUM_VALUES) ?
602      static_cast<DisplaySearchButtonConditions>(value) :
603      DISPLAY_SEARCH_BUTTON_NEVER;
604}
605
606bool ShouldDisplayOriginChip() {
607  return GetOriginChipCondition() != ORIGIN_CHIP_DISABLED;
608}
609
610OriginChipCondition GetOriginChipCondition() {
611  const CommandLine* cl = CommandLine::ForCurrentProcess();
612  if (cl->HasSwitch(switches::kDisableOriginChip))
613    return ORIGIN_CHIP_DISABLED;
614  if (cl->HasSwitch(switches::kEnableOriginChipAlways))
615    return ORIGIN_CHIP_ALWAYS;
616  if (cl->HasSwitch(switches::kEnableOriginChipOnSrp))
617    return ORIGIN_CHIP_ON_SRP;
618
619  FieldTrialFlags flags;
620  if (!GetFieldTrialInfo(&flags))
621    return ORIGIN_CHIP_DISABLED;
622  uint64 value =
623      GetUInt64ValueForFlagWithDefault(kOriginChipFlagName, 0, flags);
624  return (value < ORIGIN_CHIP_NUM_VALUES) ?
625      static_cast<OriginChipCondition>(value) : ORIGIN_CHIP_DISABLED;
626}
627
628bool ShouldShowGoogleLocalNTP() {
629  FieldTrialFlags flags;
630  return !GetFieldTrialInfo(&flags) || GetBoolValueForFlagWithDefault(
631      kShouldShowGoogleLocalNTPFlagName, true, flags);
632}
633
634GURL GetEffectiveURLForInstant(const GURL& url, Profile* profile) {
635  CHECK(ShouldAssignURLToInstantRenderer(url, profile))
636      << "Error granting Instant access.";
637
638  if (url.SchemeIs(chrome::kChromeSearchScheme))
639    return url;
640
641  GURL effective_url(url);
642
643  // Replace the scheme with "chrome-search:".
644  url::Replacements<char> replacements;
645  std::string search_scheme(chrome::kChromeSearchScheme);
646  replacements.SetScheme(search_scheme.data(),
647                         url::Component(0, search_scheme.length()));
648
649  // If this is the URL for a server-provided NTP, replace the host with
650  // "remote-ntp".
651  std::string remote_ntp_host(chrome::kChromeSearchRemoteNtpHost);
652  NewTabURLDetails details = NewTabURLDetails::ForProfile(profile);
653  if (details.state == NEW_TAB_URL_VALID &&
654      search::MatchesOriginAndPath(url, details.url)) {
655    replacements.SetHost(remote_ntp_host.c_str(),
656                         url::Component(0, remote_ntp_host.length()));
657  }
658
659  effective_url = effective_url.ReplaceComponents(replacements);
660  return effective_url;
661}
662
663bool HandleNewTabURLRewrite(GURL* url,
664                            content::BrowserContext* browser_context) {
665  if (!IsInstantExtendedAPIEnabled())
666    return false;
667
668  if (!url->SchemeIs(content::kChromeUIScheme) ||
669      url->host() != chrome::kChromeUINewTabHost)
670    return false;
671
672  Profile* profile = Profile::FromBrowserContext(browser_context);
673  NewTabURLDetails details(NewTabURLDetails::ForProfile(profile));
674  UMA_HISTOGRAM_ENUMERATION("NewTabPage.URLState",
675                            details.state, NEW_TAB_URL_MAX);
676  if (details.url.is_valid()) {
677    *url = details.url;
678    return true;
679  }
680  return false;
681}
682
683bool HandleNewTabURLReverseRewrite(GURL* url,
684                                   content::BrowserContext* browser_context) {
685  if (!IsInstantExtendedAPIEnabled())
686    return false;
687
688  // Do nothing in incognito.
689  Profile* profile = Profile::FromBrowserContext(browser_context);
690  if (profile && profile->IsOffTheRecord())
691    return false;
692
693  if (search::MatchesOriginAndPath(
694      GURL(chrome::kChromeSearchLocalNtpUrl), *url)) {
695    *url = GURL(chrome::kChromeUINewTabURL);
696    return true;
697  }
698
699  GURL new_tab_url(GetNewTabPageURL(profile));
700  if (new_tab_url.is_valid() &&
701      search::MatchesOriginAndPath(new_tab_url, *url)) {
702    *url = GURL(chrome::kChromeUINewTabURL);
703    return true;
704  }
705
706  return false;
707}
708
709void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
710                                             content::NavigationEntry* entry) {
711  if (!entry)
712    return;
713
714  entry->SetExtraData(kInstantSupportStateKey,
715                      InstantSupportStateToString(state));
716}
717
718InstantSupportState GetInstantSupportStateFromNavigationEntry(
719    const content::NavigationEntry& entry) {
720  base::string16 value;
721  if (!entry.GetExtraData(kInstantSupportStateKey, &value))
722    return INSTANT_SUPPORT_UNKNOWN;
723
724  return StringToInstantSupportState(value);
725}
726
727bool ShouldPrefetchSearchResultsOnSRP() {
728  FieldTrialFlags flags;
729  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
730      kPrefetchSearchResultsOnSRP, false, flags);
731}
732
733void EnableQueryExtractionForTesting() {
734  CommandLine* cl = CommandLine::ForCurrentProcess();
735  cl->AppendSwitch(switches::kEnableQueryExtraction);
736}
737
738bool ShouldUseAltInstantURL() {
739  FieldTrialFlags flags;
740  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
741      kUseAltInstantURL, false, flags);
742}
743
744bool ShouldUseSearchPathForInstant() {
745  FieldTrialFlags flags;
746  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
747      kUseSearchPathForInstant, false, flags);
748}
749
750}  // namespace chrome
751