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