Home | History | Annotate | Download | only in search
      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 
     44 namespace chrome {
     45 
     46 namespace {
     47 
     48 const char kPrefetchSearchResultsOnSRP[] = "prefetch_results_srp";
     49 const char kAllowPrefetchNonDefaultMatch[] = "allow_prefetch_non_default_match";
     50 const char kPrerenderInstantUrlOnOmniboxFocus[] =
     51     "prerender_instant_url_on_omnibox_focus";
     52 
     53 #if defined(OS_ANDROID)
     54 const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
     55 
     56 // Controls whether to reuse prerendered Instant Search base page to commit any
     57 // search query.
     58 const 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.
     63 const char kUseAltInstantURL[] = "use_alternate_instant_url";
     64 const char kUseSearchPathForInstant[] = "use_search_path_for_instant";
     65 const char kAltInstantURLPath[] = "search";
     66 const char kAltInstantURLQueryParams[] = "&qbp=1";
     67 
     68 const char kDisplaySearchButtonFlagName[] = "display_search_button";
     69 const char kOriginChipFlagName[] = "origin_chip";
     70 #if !defined(OS_IOS) && !defined(OS_ANDROID)
     71 const char kEnableQueryExtractionFlagName[] = "query_extraction";
     72 #endif
     73 const 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.
     77 enum 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.
    104 const char kInstantSupportStateKey[] = "instant_support_state";
    105 
    106 const char kInstantSupportEnabled[] = "Instant support enabled";
    107 const char kInstantSupportDisabled[] = "Instant support disabled";
    108 const char kInstantSupportUnknown[] = "Instant support unknown";
    109 
    110 InstantSupportState 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 
    119 base::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 
    131 TemplateURL* 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 
    141 GURL 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 
    152 bool 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.)
    178 bool 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|.
    185 bool 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 
    218 base::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 
    248 bool 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.
    264 NewTabURLState 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.
    278 struct 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.
    312 const int kDisableStartMargin = -1;
    313 
    314 std::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 
    321 std::string ForceInstantResultsParam(bool for_prerender) {
    322   return (for_prerender || !IsInstantExtendedAPIEnabled()) ?
    323       "ion=1&" : std::string();
    324 }
    325 
    326 bool 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 
    343 base::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 
    363 bool IsQueryExtractionAllowedForURL(Profile* profile, const GURL& url) {
    364   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
    365   return template_url && IsSuitableURLForInstant(url, template_url);
    366 }
    367 
    368 base::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 
    376 base::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 
    395 bool 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 
    403 bool 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 
    418 bool ShouldUseProcessPerSiteForInstantURL(const GURL& url, Profile* profile) {
    419   return ShouldAssignURLToInstantRenderer(url, profile) &&
    420       (url.host() == chrome::kChromeSearchLocalNtpHost ||
    421        url.host() == chrome::kChromeSearchRemoteNtpHost);
    422 }
    423 
    424 bool 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 
    437 bool IsInstantNTP(const content::WebContents* contents) {
    438   if (!contents)
    439     return false;
    440 
    441   return NavEntryIsInstantNTP(contents,
    442                               contents->GetController().GetVisibleEntry());
    443 }
    444 
    445 bool 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 
    462 bool IsSuggestPrefEnabled(Profile* profile) {
    463   return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
    464          profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
    465 }
    466 
    467 GURL 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|.
    511 std::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 
    524 GURL GetNewTabPageURL(Profile* profile) {
    525   return NewTabURLDetails::ForProfile(profile).url;
    526 }
    527 
    528 GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
    529   return ShouldPrefetchSearchResults() ? GetInstantURL(profile, true) : GURL();
    530 }
    531 
    532 bool 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 
    550 bool ShouldAllowPrefetchNonDefaultMatch() {
    551   if (!ShouldPrefetchSearchResults())
    552     return false;
    553 
    554   FieldTrialFlags flags;
    555   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    556       kAllowPrefetchNonDefaultMatch, false, flags);
    557 }
    558 
    559 bool ShouldPrerenderInstantUrlOnOmniboxFocus() {
    560   if (!ShouldPrefetchSearchResults())
    561     return false;
    562 
    563   FieldTrialFlags flags;
    564   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    565       kPrerenderInstantUrlOnOmniboxFocus, false, flags);
    566 }
    567 
    568 bool 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 
    581 GURL GetLocalInstantURL(Profile* profile) {
    582   return GURL(chrome::kChromeSearchLocalNtpUrl);
    583 }
    584 
    585 DisplaySearchButtonConditions 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 
    606 bool ShouldDisplayOriginChip() {
    607   return GetOriginChipCondition() != ORIGIN_CHIP_DISABLED;
    608 }
    609 
    610 OriginChipCondition 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 
    628 bool ShouldShowGoogleLocalNTP() {
    629   FieldTrialFlags flags;
    630   return !GetFieldTrialInfo(&flags) || GetBoolValueForFlagWithDefault(
    631       kShouldShowGoogleLocalNTPFlagName, true, flags);
    632 }
    633 
    634 GURL 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 
    663 bool 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 
    683 bool 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 
    709 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
    710                                              content::NavigationEntry* entry) {
    711   if (!entry)
    712     return;
    713 
    714   entry->SetExtraData(kInstantSupportStateKey,
    715                       InstantSupportStateToString(state));
    716 }
    717 
    718 InstantSupportState 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 
    727 bool ShouldPrefetchSearchResultsOnSRP() {
    728   FieldTrialFlags flags;
    729   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    730       kPrefetchSearchResultsOnSRP, false, flags);
    731 }
    732 
    733 void EnableQueryExtractionForTesting() {
    734   CommandLine* cl = CommandLine::ForCurrentProcess();
    735   cl->AppendSwitch(switches::kEnableQueryExtraction);
    736 }
    737 
    738 bool ShouldUseAltInstantURL() {
    739   FieldTrialFlags flags;
    740   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    741       kUseAltInstantURL, false, flags);
    742 }
    743 
    744 bool ShouldUseSearchPathForInstant() {
    745   FieldTrialFlags flags;
    746   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
    747       kUseSearchPathForInstant, false, flags);
    748 }
    749 
    750 }  // namespace chrome
    751