Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / search / search.cc
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