Upstream version 5.34.92.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/prefs/pref_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/google/google_util.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.h"
20 #include "chrome/browser/search_engines/template_url_service_factory.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/sessions/serialized_navigation_entry.h"
30 #include "components/user_prefs/pref_registry_syncable.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "grit/generated_resources.h"
35 #include "ui/base/l10n/l10n_util.h"
36
37 #if defined(ENABLE_MANAGED_USERS)
38 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
39 #include "chrome/browser/managed_mode/managed_user_service.h"
40 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
41 #endif
42
43 namespace chrome {
44
45 namespace {
46
47 // Configuration options for Embedded Search.
48 // EmbeddedSearch field trials are named in such a way that we can parse out
49 // the experiment configuration from the trial's group name in order to give
50 // us maximum flexability in running experiments.
51 // Field trial groups should be named things like "Group7 espv:2 instant:1".
52 // The first token is always GroupN for some integer N, followed by a
53 // space-delimited list of key:value pairs which correspond to these flags:
54 const char kEmbeddedPageVersionFlagName[] = "espv";
55 #if defined(OS_IOS) || defined(OS_ANDROID)
56 const uint64 kEmbeddedPageVersionDefault = 1;
57 #else
58 const uint64 kEmbeddedPageVersionDefault = 2;
59 #endif
60
61 const char kHideVerbatimFlagName[] = "hide_verbatim";
62 const char kPrefetchSearchResultsFlagName[] = "prefetch_results";
63 const char kPrefetchSearchResultsOnSRP[] = "prefetch_results_srp";
64
65 // Controls whether to reuse prerendered Instant Search base page to commit any
66 // search query.
67 const char kReuseInstantSearchBasePage[] = "reuse_instant_search_base_page";
68
69 const char kDisplaySearchButtonFlagName[] = "display_search_button";
70 const char kOriginChipFlagName[] = "origin_chip";
71 #if !defined(OS_IOS) && !defined(OS_ANDROID)
72 const char kEnableQueryExtractionFlagName[] = "query_extraction";
73 #endif
74
75 // Constants for the field trial name and group prefix.
76 // Note in M30 and below this field trial was named "InstantExtended" and in
77 // M31 was renamed to EmbeddedSearch for clarity and cleanliness.  Since we
78 // can't easilly sync up Finch configs with the pushing of this change to
79 // Dev & Canary, for now the code accepts both names.
80 // TODO(dcblack): Remove the InstantExtended name once M31 hits the Beta
81 // channel.
82 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
83 const char kEmbeddedSearchFieldTrialName[] = "EmbeddedSearch";
84
85 // If the field trial's group name ends with this string its configuration will
86 // be ignored and Instant Extended will not be enabled by default.
87 const char kDisablingSuffix[] = "DISABLED";
88
89 // Used to set the Instant support state of the Navigation entry.
90 const char kInstantSupportStateKey[] = "instant_support_state";
91
92 const char kInstantSupportEnabled[] = "Instant support enabled";
93 const char kInstantSupportDisabled[] = "Instant support disabled";
94 const char kInstantSupportUnknown[] = "Instant support unknown";
95
96 InstantSupportState StringToInstantSupportState(const base::string16& value) {
97   if (value == base::ASCIIToUTF16(kInstantSupportEnabled))
98     return INSTANT_SUPPORT_YES;
99   else if (value == base::ASCIIToUTF16(kInstantSupportDisabled))
100     return INSTANT_SUPPORT_NO;
101   else
102     return INSTANT_SUPPORT_UNKNOWN;
103 }
104
105 base::string16 InstantSupportStateToString(InstantSupportState state) {
106   switch (state) {
107     case INSTANT_SUPPORT_NO:
108       return base::ASCIIToUTF16(kInstantSupportDisabled);
109     case INSTANT_SUPPORT_YES:
110       return base::ASCIIToUTF16(kInstantSupportEnabled);
111     case INSTANT_SUPPORT_UNKNOWN:
112       return base::ASCIIToUTF16(kInstantSupportUnknown);
113   }
114   return base::ASCIIToUTF16(kInstantSupportUnknown);
115 }
116
117 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) {
118   TemplateURLService* template_url_service =
119       TemplateURLServiceFactory::GetForProfile(profile);
120   if (template_url_service)
121     return template_url_service->GetDefaultSearchProvider();
122   return NULL;
123 }
124
125 GURL TemplateURLRefToGURL(const TemplateURLRef& ref,
126                           int start_margin,
127                           bool append_extra_query_params,
128                           bool force_instant_results) {
129   TemplateURLRef::SearchTermsArgs search_terms_args =
130       TemplateURLRef::SearchTermsArgs(base::string16());
131   search_terms_args.omnibox_start_margin = start_margin;
132   search_terms_args.append_extra_query_params = append_extra_query_params;
133   search_terms_args.force_instant_results = force_instant_results;
134   return GURL(ref.ReplaceSearchTerms(search_terms_args));
135 }
136
137 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) {
138   GURL search_url =
139       TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false,
140                            false);
141   if (search_url.is_valid() &&
142       search::MatchesOriginAndPath(url, search_url))
143     return true;
144
145   // "URLCount() - 1" because we already tested url_ref above.
146   for (size_t i = 0; i < template_url->URLCount() - 1; ++i) {
147     TemplateURLRef ref(template_url, i);
148     search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false, false);
149     if (search_url.is_valid() &&
150         search::MatchesOriginAndPath(url, search_url))
151       return true;
152   }
153
154   return false;
155 }
156
157 // Returns true if |contents| is rendered inside the Instant process for
158 // |profile|.
159 bool IsRenderedInInstantProcess(const content::WebContents* contents,
160                                 Profile* profile) {
161   const content::RenderProcessHost* process_host =
162       contents->GetRenderProcessHost();
163   if (!process_host)
164     return false;
165
166   const InstantService* instant_service =
167       InstantServiceFactory::GetForProfile(profile);
168   if (!instant_service)
169     return false;
170
171   return instant_service->IsInstantProcess(process_host->GetID());
172 }
173
174 // Returns true if |url| passes some basic checks that must succeed for it to be
175 // usable as an instant URL:
176 // (1) It contains the search terms replacement key of |template_url|, which is
177 //     expected to be the TemplateURL* for the default search provider.
178 // (2) Either it has a secure scheme, or else the user has manually specified a
179 //     --google-base-url and it uses that base URL.  (This allows testers to use
180 //     --google-base-url to point at non-HTTPS servers, which eases testing.)
181 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) {
182   return template_url->HasSearchTermsReplacementKey(url) &&
183       (url.SchemeIsSecure() ||
184        google_util::StartsWithCommandLineGoogleBaseURL(url));
185 }
186
187 // Returns true if |url| can be used as an Instant URL for |profile|.
188 bool IsInstantURL(const GURL& url, Profile* profile) {
189   if (!IsInstantExtendedAPIEnabled())
190     return false;
191
192   if (!url.is_valid())
193     return false;
194
195   const GURL new_tab_url(GetNewTabPageURL(profile));
196   if (new_tab_url.is_valid() &&
197       search::MatchesOriginAndPath(url, new_tab_url))
198     return true;
199
200   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
201   if (!template_url)
202     return false;
203
204   if (!IsSuitableURLForInstant(url, template_url))
205     return false;
206
207   const TemplateURLRef& instant_url_ref = template_url->instant_url_ref();
208   const GURL instant_url =
209       TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false, false);
210   if (!instant_url.is_valid())
211     return false;
212
213   if (search::MatchesOriginAndPath(url, instant_url))
214     return true;
215
216   return IsQueryExtractionEnabled() && MatchesAnySearchURL(url, template_url);
217 }
218
219 base::string16 GetSearchTermsImpl(const content::WebContents* contents,
220                                   const content::NavigationEntry* entry) {
221   if (!contents || !IsQueryExtractionEnabled())
222     return base::string16();
223
224   // For security reasons, don't extract search terms if the page is not being
225   // rendered in the privileged Instant renderer process. This is to protect
226   // against a malicious page somehow scripting the search results page and
227   // faking search terms in the URL. Random pages can't get into the Instant
228   // renderer and scripting doesn't work cross-process, so if the page is in
229   // the Instant process, we know it isn't being exploited.
230   // Since iOS and Android doesn't use the instant framework, these checks are
231   // disabled for the two platforms.
232   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
233 #if !defined(OS_IOS) && !defined(OS_ANDROID)
234   if (!IsRenderedInInstantProcess(contents, profile) &&
235       ((entry == contents->GetController().GetLastCommittedEntry()) ||
236        !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile)))
237     return base::string16();
238 #endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
239   // Check to see if search terms have already been extracted.
240   base::string16 search_terms = GetSearchTermsFromNavigationEntry(entry);
241   if (!search_terms.empty())
242     return search_terms;
243
244   // Otherwise, extract from the URL.
245   return GetSearchTermsFromURL(profile, entry->GetVirtualURL());
246 }
247
248 bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) {
249 #if defined(ENABLE_MANAGED_USERS)
250   ManagedUserService* managed_user_service =
251       ManagedUserServiceFactory::GetForProfile(profile);
252   ManagedModeURLFilter* url_filter =
253       managed_user_service->GetURLFilterForUIThread();
254   if (url_filter->GetFilteringBehaviorForURL(url) ==
255           ManagedModeURLFilter::BLOCK) {
256     return false;
257   }
258 #endif
259   return true;
260 }
261
262 }  // namespace
263
264 // Negative start-margin values prevent the "es_sm" parameter from being used.
265 const int kDisableStartMargin = -1;
266
267 bool IsInstantExtendedAPIEnabled() {
268 #if defined(OS_IOS) || defined(OS_ANDROID)
269   return false;
270 #else
271   return true;
272 #endif  // defined(OS_IOS) || defined(OS_ANDROID)
273 }
274
275 // Determine what embedded search page version to request from the user's
276 // default search provider. If 0, the embedded search UI should not be enabled.
277 uint64 EmbeddedSearchPageVersion() {
278   FieldTrialFlags flags;
279   if (GetFieldTrialInfo(&flags)) {
280     return GetUInt64ValueForFlagWithDefault(kEmbeddedPageVersionFlagName,
281                                             kEmbeddedPageVersionDefault,
282                                             flags);
283   }
284   return kEmbeddedPageVersionDefault;
285 }
286
287 bool IsQueryExtractionEnabled() {
288 #if defined(OS_IOS) || defined(OS_ANDROID)
289   return true;
290 #else
291   if (!IsInstantExtendedAPIEnabled())
292     return false;
293
294   const CommandLine* command_line = CommandLine::ForCurrentProcess();
295   if (command_line->HasSwitch(switches::kEnableQueryExtraction))
296     return true;
297
298   FieldTrialFlags flags;
299   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
300       kEnableQueryExtractionFlagName, false, flags);
301 #endif  // defined(OS_IOS) || defined(OS_ANDROID)
302 }
303
304 base::string16 GetSearchTermsFromURL(Profile* profile, const GURL& url) {
305   if (url.is_valid() && url == GetSearchResultPrefetchBaseURL(profile)) {
306     // InstantSearchPrerenderer has the search query for the Instant search base
307     // page.
308     InstantSearchPrerenderer* prerenderer =
309         InstantSearchPrerenderer::GetForProfile(profile);
310     DCHECK(prerenderer);
311     return prerenderer->get_last_query();
312   }
313
314   base::string16 search_terms;
315   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
316   if (template_url && IsSuitableURLForInstant(url, template_url))
317     template_url->ExtractSearchTermsFromURL(url, &search_terms);
318   return search_terms;
319 }
320
321 base::string16 GetSearchTermsFromNavigationEntry(
322     const content::NavigationEntry* entry) {
323   base::string16 search_terms;
324   if (entry)
325     entry->GetExtraData(sessions::kSearchTermsKey, &search_terms);
326   return search_terms;
327 }
328
329 base::string16 GetSearchTerms(const content::WebContents* contents) {
330   if (!contents)
331     return base::string16();
332
333   const content::NavigationEntry* entry =
334       contents->GetController().GetVisibleEntry();
335   if (!entry)
336     return base::string16();
337
338 #if !defined(OS_IOS) && !defined(OS_ANDROID)
339   // iOS and Android doesn't use the Instant framework, disable this check for
340   // the two platforms.
341   InstantSupportState state = GetInstantSupportStateFromNavigationEntry(*entry);
342   if (state == INSTANT_SUPPORT_NO)
343     return base::string16();
344 #endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
345
346   return GetSearchTermsImpl(contents, entry);
347 }
348
349 bool ShouldAssignURLToInstantRenderer(const GURL& url, Profile* profile) {
350   return url.is_valid() &&
351          profile &&
352          IsInstantExtendedAPIEnabled() &&
353          (url.SchemeIs(chrome::kChromeSearchScheme) ||
354           IsInstantURL(url, profile));
355 }
356
357 bool ShouldUseProcessPerSiteForInstantURL(const GURL& url, Profile* profile) {
358   return ShouldAssignURLToInstantRenderer(url, profile) &&
359       (url.host() == chrome::kChromeSearchLocalNtpHost ||
360        url.host() == chrome::kChromeSearchOnlineNtpHost);
361 }
362
363 bool IsNTPURL(const GURL& url, Profile* profile) {
364   if (!url.is_valid())
365     return false;
366
367   if (!IsInstantExtendedAPIEnabled())
368     return url == GURL(chrome::kChromeUINewTabURL);
369
370   return profile &&
371       ((IsInstantURL(url, profile) &&
372         GetSearchTermsFromURL(profile, url).empty()) ||
373        url == GURL(chrome::kChromeSearchLocalNtpUrl));
374 }
375
376 bool IsInstantNTP(const content::WebContents* contents) {
377   if (!contents)
378     return false;
379
380   return NavEntryIsInstantNTP(contents,
381                               contents->GetController().GetVisibleEntry());
382 }
383
384 bool NavEntryIsInstantNTP(const content::WebContents* contents,
385                           const content::NavigationEntry* entry) {
386   if (!contents || !entry || !IsInstantExtendedAPIEnabled())
387     return false;
388
389   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
390   if (!IsRenderedInInstantProcess(contents, profile))
391     return false;
392
393   if (entry->GetURL() == GetLocalInstantURL(profile))
394     return true;
395
396   GURL new_tab_url(GetNewTabPageURL(profile));
397   return new_tab_url.is_valid() &&
398       search::MatchesOriginAndPath(entry->GetURL(), new_tab_url);
399 }
400
401 bool IsSuggestPrefEnabled(Profile* profile) {
402   return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
403          profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
404 }
405
406 GURL GetInstantURL(Profile* profile, int start_margin,
407                    bool force_instant_results) {
408   if (!IsInstantExtendedAPIEnabled() || !IsSuggestPrefEnabled(profile))
409     return GURL();
410
411   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
412   if (!template_url)
413     return GURL();
414
415   GURL instant_url =
416       TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true,
417                            force_instant_results);
418   if (!instant_url.is_valid() ||
419       !template_url->HasSearchTermsReplacementKey(instant_url))
420     return GURL();
421
422   // Extended mode requires HTTPS.  Force it unless the base URL was overridden
423   // on the command line, in which case we allow HTTP (see comments on
424   // IsSuitableURLForInstant()).
425   if (!instant_url.SchemeIsSecure() &&
426       !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) {
427     GURL::Replacements replacements;
428     const std::string secure_scheme(content::kHttpsScheme);
429     replacements.SetSchemeStr(secure_scheme);
430     instant_url = instant_url.ReplaceComponents(replacements);
431   }
432
433   if (!IsURLAllowedForSupervisedUser(instant_url, profile))
434     return GURL();
435
436   return instant_url;
437 }
438
439 // Returns URLs associated with the default search engine for |profile|.
440 std::vector<GURL> GetSearchURLs(Profile* profile) {
441   std::vector<GURL> result;
442   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
443   if (!template_url)
444     return result;
445   for (size_t i = 0; i < template_url->URLCount(); ++i) {
446     TemplateURLRef ref(template_url, i);
447     result.push_back(TemplateURLRefToGURL(ref, kDisableStartMargin, false,
448                                           false));
449   }
450   return result;
451 }
452
453 GURL GetNewTabPageURL(Profile* profile) {
454   if (!profile || profile->IsOffTheRecord())
455     return GURL();
456
457   if (!IsSuggestPrefEnabled(profile))
458     return GURL(chrome::kChromeSearchLocalNtpUrl);
459
460   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
461   if (!template_url)
462     return GURL(chrome::kChromeSearchLocalNtpUrl);
463
464   GURL url(TemplateURLRefToGURL(template_url->new_tab_url_ref(),
465                                 kDisableStartMargin, false, false));
466   if (!url.is_valid() || !url.SchemeIsSecure())
467     return GURL(chrome::kChromeSearchLocalNtpUrl);
468
469   if (!IsURLAllowedForSupervisedUser(url, profile))
470     return GURL(chrome::kChromeSearchLocalNtpUrl);
471
472   return url;
473 }
474
475 GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
476   return ShouldPrefetchSearchResults() ?
477       GetInstantURL(profile, kDisableStartMargin, true) : GURL();
478 }
479
480 bool ShouldPrefetchSearchResults() {
481   FieldTrialFlags flags;
482   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
483       kPrefetchSearchResultsFlagName, false, flags);
484 }
485
486 bool ShouldReuseInstantSearchBasePage() {
487   if (!ShouldPrefetchSearchResults())
488     return false;
489
490   FieldTrialFlags flags;
491   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
492       kReuseInstantSearchBasePage, false, flags);
493 }
494
495 GURL GetLocalInstantURL(Profile* profile) {
496   return GURL(chrome::kChromeSearchLocalNtpUrl);
497 }
498
499 bool ShouldHideTopVerbatimMatch() {
500   FieldTrialFlags flags;
501   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
502       kHideVerbatimFlagName, false, flags);
503 }
504
505 DisplaySearchButtonConditions GetDisplaySearchButtonConditions() {
506   const CommandLine* cl = CommandLine::ForCurrentProcess();
507   if (cl->HasSwitch(switches::kDisableSearchButtonInOmnibox)) {
508     return DISPLAY_SEARCH_BUTTON_NEVER;
509   } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStr)) {
510     return DISPLAY_SEARCH_BUTTON_FOR_STR;
511   } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxForStrOrIip)) {
512     return DISPLAY_SEARCH_BUTTON_FOR_STR_OR_IIP;
513   } else if (cl->HasSwitch(switches::kEnableSearchButtonInOmniboxAlways)) {
514     return DISPLAY_SEARCH_BUTTON_ALWAYS;
515   }
516
517   FieldTrialFlags flags;
518   if (!GetFieldTrialInfo(&flags))
519     return DISPLAY_SEARCH_BUTTON_NEVER;
520   uint64 value =
521       GetUInt64ValueForFlagWithDefault(kDisplaySearchButtonFlagName, 0, flags);
522   return (value < DISPLAY_SEARCH_BUTTON_NUM_VALUES) ?
523       static_cast<DisplaySearchButtonConditions>(value) :
524       DISPLAY_SEARCH_BUTTON_NEVER;
525 }
526
527 bool ShouldDisplayOriginChip() {
528   return GetOriginChipPosition() != ORIGIN_CHIP_DISABLED;
529 }
530
531 OriginChipPosition GetOriginChipPosition() {
532   const CommandLine* cl = CommandLine::ForCurrentProcess();
533   if (cl->HasSwitch(switches::kDisableOriginChip)) {
534     return ORIGIN_CHIP_DISABLED;
535   } else if (cl->HasSwitch(switches::kEnableOriginChipLeadingLocationBar)) {
536     return ORIGIN_CHIP_LEADING_LOCATION_BAR;
537   } else if (cl->HasSwitch(switches::kEnableOriginChip) ||
538              cl->HasSwitch(switches::kEnableOriginChipTrailingLocationBar)) {
539     return ORIGIN_CHIP_TRAILING_LOCATION_BAR;
540   } else if (cl->HasSwitch(switches::kEnableOriginChipLeadingMenuButton)) {
541     return ORIGIN_CHIP_LEADING_MENU_BUTTON;
542   }
543
544   FieldTrialFlags flags;
545   if (!GetFieldTrialInfo(&flags))
546     return ORIGIN_CHIP_DISABLED;
547   uint64 value =
548       GetUInt64ValueForFlagWithDefault(kOriginChipFlagName, 0, flags);
549   return (value < ORIGIN_CHIP_NUM_VALUES) ?
550       static_cast<OriginChipPosition>(value) :
551       ORIGIN_CHIP_DISABLED;
552 }
553
554 GURL GetEffectiveURLForInstant(const GURL& url, Profile* profile) {
555   CHECK(ShouldAssignURLToInstantRenderer(url, profile))
556       << "Error granting Instant access.";
557
558   if (url.SchemeIs(chrome::kChromeSearchScheme))
559     return url;
560
561   GURL effective_url(url);
562
563   // Replace the scheme with "chrome-search:".
564   url_canon::Replacements<char> replacements;
565   std::string search_scheme(chrome::kChromeSearchScheme);
566   replacements.SetScheme(search_scheme.data(),
567                          url_parse::Component(0, search_scheme.length()));
568
569   // If the URL corresponds to an online NTP, replace the host with
570   // "online-ntp".
571   std::string online_ntp_host(chrome::kChromeSearchOnlineNtpHost);
572   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
573   if (template_url) {
574     const GURL instant_url = TemplateURLRefToGURL(
575         template_url->instant_url_ref(), kDisableStartMargin, false, false);
576     if (instant_url.is_valid() &&
577         search::MatchesOriginAndPath(url, instant_url)) {
578       replacements.SetHost(online_ntp_host.c_str(),
579                            url_parse::Component(0, online_ntp_host.length()));
580     }
581   }
582
583   effective_url = effective_url.ReplaceComponents(replacements);
584   return effective_url;
585 }
586
587 bool HandleNewTabURLRewrite(GURL* url,
588                             content::BrowserContext* browser_context) {
589   if (!IsInstantExtendedAPIEnabled())
590     return false;
591
592   if (!url->SchemeIs(chrome::kChromeUIScheme) ||
593       url->host() != chrome::kChromeUINewTabHost)
594     return false;
595
596   Profile* profile = Profile::FromBrowserContext(browser_context);
597   GURL new_tab_url(GetNewTabPageURL(profile));
598   if (!new_tab_url.is_valid())
599     return false;
600
601   *url = new_tab_url;
602   return true;
603 }
604
605 bool HandleNewTabURLReverseRewrite(GURL* url,
606                                    content::BrowserContext* browser_context) {
607   if (!IsInstantExtendedAPIEnabled())
608     return false;
609
610   Profile* profile = Profile::FromBrowserContext(browser_context);
611   GURL new_tab_url(GetNewTabPageURL(profile));
612   if (!new_tab_url.is_valid() ||
613       !search::MatchesOriginAndPath(new_tab_url, *url))
614     return false;
615
616   *url = GURL(chrome::kChromeUINewTabURL);
617   return true;
618 }
619
620 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
621                                              content::NavigationEntry* entry) {
622   if (!entry)
623     return;
624
625   entry->SetExtraData(kInstantSupportStateKey,
626                       InstantSupportStateToString(state));
627 }
628
629 InstantSupportState GetInstantSupportStateFromNavigationEntry(
630     const content::NavigationEntry& entry) {
631   base::string16 value;
632   if (!entry.GetExtraData(kInstantSupportStateKey, &value))
633     return INSTANT_SUPPORT_UNKNOWN;
634
635   return StringToInstantSupportState(value);
636 }
637
638 bool ShouldPrefetchSearchResultsOnSRP() {
639   FieldTrialFlags flags;
640   return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
641       kPrefetchSearchResultsOnSRP, false, flags);
642 }
643
644 void EnableQueryExtractionForTesting() {
645   CommandLine* cl = CommandLine::ForCurrentProcess();
646   cl->AppendSwitch(switches::kEnableQueryExtraction);
647 }
648
649 bool GetFieldTrialInfo(FieldTrialFlags* flags) {
650   // Get the group name.  If the EmbeddedSearch trial doesn't exist, look for
651   // the older InstantExtended name.
652   std::string group_name = base::FieldTrialList::FindFullName(
653       kEmbeddedSearchFieldTrialName);
654   if (group_name.empty()) {
655     group_name = base::FieldTrialList::FindFullName(
656         kInstantExtendedFieldTrialName);
657   }
658
659   if (EndsWith(group_name, kDisablingSuffix, true))
660     return false;
661
662   // We have a valid trial that isn't disabled. Extract the flags.
663   std::string group_prefix(group_name);
664   size_t first_space = group_name.find(" ");
665   if (first_space != std::string::npos) {
666     // There is a flags section of the group name. Split that out and parse it.
667     group_prefix = group_name.substr(0, first_space);
668     if (!base::SplitStringIntoKeyValuePairs(group_name.substr(first_space),
669                                             ':', ' ', flags)) {
670       // Failed to parse the flags section. Assume the whole group name is
671       // invalid.
672       return false;
673     }
674   }
675   return true;
676 }
677
678 // Given a FieldTrialFlags object, returns the string value of the provided
679 // flag.
680 std::string GetStringValueForFlagWithDefault(const std::string& flag,
681                                              const std::string& default_value,
682                                              const FieldTrialFlags& flags) {
683   FieldTrialFlags::const_iterator i;
684   for (i = flags.begin(); i != flags.end(); i++) {
685     if (i->first == flag)
686       return i->second;
687   }
688   return default_value;
689 }
690
691 // Given a FieldTrialFlags object, returns the uint64 value of the provided
692 // flag.
693 uint64 GetUInt64ValueForFlagWithDefault(const std::string& flag,
694                                         uint64 default_value,
695                                         const FieldTrialFlags& flags) {
696   uint64 value;
697   std::string str_value =
698       GetStringValueForFlagWithDefault(flag, std::string(), flags);
699   if (base::StringToUint64(str_value, &value))
700     return value;
701   return default_value;
702 }
703
704 // Given a FieldTrialFlags object, returns the boolean value of the provided
705 // flag.
706 bool GetBoolValueForFlagWithDefault(const std::string& flag,
707                                     bool default_value,
708                                     const FieldTrialFlags& flags) {
709   return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
710 }
711
712 }  // namespace chrome