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
StringToInstantSupportState(const base::string16 & value)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
InstantSupportStateToString(InstantSupportState state)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
GetDefaultSearchProviderTemplateURL(Profile * profile)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
TemplateURLRefToGURL(const TemplateURLRef & ref,const SearchTermsData & search_terms_data,bool append_extra_query_params,bool force_instant_results)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
MatchesAnySearchURL(const GURL & url,TemplateURL * template_url,const SearchTermsData & search_terms_data)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.)
IsSuitableURLForInstant(const GURL & url,const TemplateURL * template_url)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|.
IsInstantURL(const GURL & url,Profile * 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
GetSearchTermsImpl(const content::WebContents * contents,const content::NavigationEntry * entry)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
IsURLAllowedForSupervisedUser(const GURL & url,Profile * profile)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.
IsValidNewTabURL(Profile * profile,const GURL & new_tab_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 {
NewTabURLDetailschrome::__anone9e7a3d10111::NewTabURLDetails279 NewTabURLDetails(const GURL& url, NewTabURLState state)
280 : url(url), state(state) {}
281
ForProfilechrome::__anone9e7a3d10111::NewTabURLDetails282 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
InstantExtendedEnabledParam(bool for_search)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
ForceInstantResultsParam(bool for_prerender)321 std::string ForceInstantResultsParam(bool for_prerender) {
322 return (for_prerender || !IsInstantExtendedAPIEnabled()) ?
323 "ion=1&" : std::string();
324 }
325
IsQueryExtractionEnabled()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
ExtractSearchTermsFromURL(Profile * profile,const GURL & url)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
IsQueryExtractionAllowedForURL(Profile * profile,const GURL & url)363 bool IsQueryExtractionAllowedForURL(Profile* profile, const GURL& url) {
364 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
365 return template_url && IsSuitableURLForInstant(url, template_url);
366 }
367
GetSearchTermsFromNavigationEntry(const content::NavigationEntry * entry)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
GetSearchTerms(const content::WebContents * contents)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
ShouldAssignURLToInstantRenderer(const GURL & url,Profile * profile)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
IsRenderedInInstantProcess(const content::WebContents * contents,Profile * profile)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
ShouldUseProcessPerSiteForInstantURL(const GURL & url,Profile * profile)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
IsNTPURL(const GURL & url,Profile * profile)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
IsInstantNTP(const content::WebContents * contents)437 bool IsInstantNTP(const content::WebContents* contents) {
438 if (!contents)
439 return false;
440
441 return NavEntryIsInstantNTP(contents,
442 contents->GetController().GetVisibleEntry());
443 }
444
NavEntryIsInstantNTP(const content::WebContents * contents,const content::NavigationEntry * entry)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
IsSuggestPrefEnabled(Profile * profile)462 bool IsSuggestPrefEnabled(Profile* profile) {
463 return profile && !profile->IsOffTheRecord() && profile->GetPrefs() &&
464 profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
465 }
466
GetInstantURL(Profile * profile,bool force_instant_results)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|.
GetSearchURLs(Profile * 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
GetNewTabPageURL(Profile * profile)524 GURL GetNewTabPageURL(Profile* profile) {
525 return NewTabURLDetails::ForProfile(profile).url;
526 }
527
GetSearchResultPrefetchBaseURL(Profile * profile)528 GURL GetSearchResultPrefetchBaseURL(Profile* profile) {
529 return ShouldPrefetchSearchResults() ? GetInstantURL(profile, true) : GURL();
530 }
531
ShouldPrefetchSearchResults()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
ShouldAllowPrefetchNonDefaultMatch()550 bool ShouldAllowPrefetchNonDefaultMatch() {
551 if (!ShouldPrefetchSearchResults())
552 return false;
553
554 FieldTrialFlags flags;
555 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
556 kAllowPrefetchNonDefaultMatch, false, flags);
557 }
558
ShouldPrerenderInstantUrlOnOmniboxFocus()559 bool ShouldPrerenderInstantUrlOnOmniboxFocus() {
560 if (!ShouldPrefetchSearchResults())
561 return false;
562
563 FieldTrialFlags flags;
564 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
565 kPrerenderInstantUrlOnOmniboxFocus, false, flags);
566 }
567
ShouldReuseInstantSearchBasePage()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
GetLocalInstantURL(Profile * profile)581 GURL GetLocalInstantURL(Profile* profile) {
582 return GURL(chrome::kChromeSearchLocalNtpUrl);
583 }
584
GetDisplaySearchButtonConditions()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
ShouldDisplayOriginChip()606 bool ShouldDisplayOriginChip() {
607 return GetOriginChipCondition() != ORIGIN_CHIP_DISABLED;
608 }
609
GetOriginChipCondition()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
ShouldShowGoogleLocalNTP()628 bool ShouldShowGoogleLocalNTP() {
629 FieldTrialFlags flags;
630 return !GetFieldTrialInfo(&flags) || GetBoolValueForFlagWithDefault(
631 kShouldShowGoogleLocalNTPFlagName, true, flags);
632 }
633
GetEffectiveURLForInstant(const GURL & url,Profile * profile)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
HandleNewTabURLRewrite(GURL * url,content::BrowserContext * browser_context)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
HandleNewTabURLReverseRewrite(GURL * url,content::BrowserContext * browser_context)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
SetInstantSupportStateInNavigationEntry(InstantSupportState state,content::NavigationEntry * entry)709 void SetInstantSupportStateInNavigationEntry(InstantSupportState state,
710 content::NavigationEntry* entry) {
711 if (!entry)
712 return;
713
714 entry->SetExtraData(kInstantSupportStateKey,
715 InstantSupportStateToString(state));
716 }
717
GetInstantSupportStateFromNavigationEntry(const content::NavigationEntry & entry)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
ShouldPrefetchSearchResultsOnSRP()727 bool ShouldPrefetchSearchResultsOnSRP() {
728 FieldTrialFlags flags;
729 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
730 kPrefetchSearchResultsOnSRP, false, flags);
731 }
732
EnableQueryExtractionForTesting()733 void EnableQueryExtractionForTesting() {
734 CommandLine* cl = CommandLine::ForCurrentProcess();
735 cl->AppendSwitch(switches::kEnableQueryExtraction);
736 }
737
ShouldUseAltInstantURL()738 bool ShouldUseAltInstantURL() {
739 FieldTrialFlags flags;
740 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
741 kUseAltInstantURL, false, flags);
742 }
743
ShouldUseSearchPathForInstant()744 bool ShouldUseSearchPathForInstant() {
745 FieldTrialFlags flags;
746 return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
747 kUseSearchPathForInstant, false, flags);
748 }
749
750 } // namespace chrome
751