OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/search/search.h" | 5 #include "chrome/browser/search/search.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
11 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
| 14 #include "chrome/browser/google/google_util.h" |
14 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/browser/search/instant_service.h" | 16 #include "chrome/browser/search/instant_service.h" |
16 #include "chrome/browser/search/instant_service_factory.h" | 17 #include "chrome/browser/search/instant_service_factory.h" |
17 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" | 18 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" |
18 #include "chrome/browser/search_engines/template_url_service.h" | 19 #include "chrome/browser/search_engines/template_url_service.h" |
19 #include "chrome/browser/search_engines/template_url_service_factory.h" | 20 #include "chrome/browser/search_engines/template_url_service_factory.h" |
20 #include "chrome/browser/ui/browser.h" | 21 #include "chrome/browser/ui/browser.h" |
21 #include "chrome/browser/ui/browser_instant_controller.h" | 22 #include "chrome/browser/ui/browser_instant_controller.h" |
22 #include "chrome/browser/ui/browser_iterator.h" | 23 #include "chrome/browser/ui/browser_iterator.h" |
23 #include "chrome/common/chrome_switches.h" | 24 #include "chrome/common/chrome_switches.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 bool instant_extended_opt_in_state_gate = false; | 81 bool instant_extended_opt_in_state_gate = false; |
81 | 82 |
82 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) { | 83 TemplateURL* GetDefaultSearchProviderTemplateURL(Profile* profile) { |
83 TemplateURLService* template_url_service = | 84 TemplateURLService* template_url_service = |
84 TemplateURLServiceFactory::GetForProfile(profile); | 85 TemplateURLServiceFactory::GetForProfile(profile); |
85 if (template_url_service) | 86 if (template_url_service) |
86 return template_url_service->GetDefaultSearchProvider(); | 87 return template_url_service->GetDefaultSearchProvider(); |
87 return NULL; | 88 return NULL; |
88 } | 89 } |
89 | 90 |
90 GURL TemplateURLRefToGURL(const TemplateURLRef& ref, int start_margin) { | 91 GURL TemplateURLRefToGURL(const TemplateURLRef& ref, |
| 92 int start_margin, |
| 93 bool append_extra_query_params) { |
91 TemplateURLRef::SearchTermsArgs search_terms_args = | 94 TemplateURLRef::SearchTermsArgs search_terms_args = |
92 TemplateURLRef::SearchTermsArgs(string16()); | 95 TemplateURLRef::SearchTermsArgs(string16()); |
93 search_terms_args.omnibox_start_margin = start_margin; | 96 search_terms_args.omnibox_start_margin = start_margin; |
| 97 search_terms_args.append_extra_query_params = append_extra_query_params; |
94 return GURL(ref.ReplaceSearchTerms(search_terms_args)); | 98 return GURL(ref.ReplaceSearchTerms(search_terms_args)); |
95 } | 99 } |
96 | 100 |
97 bool MatchesOrigin(const GURL& my_url, const GURL& other_url) { | 101 bool MatchesOrigin(const GURL& my_url, const GURL& other_url) { |
98 return my_url.host() == other_url.host() && | 102 return my_url.host() == other_url.host() && |
99 my_url.port() == other_url.port() && | 103 my_url.port() == other_url.port() && |
100 (my_url.scheme() == other_url.scheme() || | 104 (my_url.scheme() == other_url.scheme() || |
101 (my_url.SchemeIs(chrome::kHttpsScheme) && | 105 (my_url.SchemeIs(chrome::kHttpsScheme) && |
102 other_url.SchemeIs(chrome::kHttpScheme))); | 106 other_url.SchemeIs(chrome::kHttpScheme))); |
103 } | 107 } |
104 | 108 |
105 bool IsCommandLineInstantURL(const GURL& url) { | |
106 const CommandLine* cl = CommandLine::ForCurrentProcess(); | |
107 const GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL)); | |
108 return instant_url.is_valid() && MatchesOrigin(url, instant_url); | |
109 } | |
110 | |
111 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) { | 109 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) { |
112 GURL search_url = | 110 GURL search_url = |
113 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin); | 111 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin, false); |
114 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) | 112 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) |
115 return true; | 113 return true; |
116 | 114 |
117 // "URLCount() - 1" because we already tested url_ref above. | 115 // "URLCount() - 1" because we already tested url_ref above. |
118 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) { | 116 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) { |
119 TemplateURLRef ref(template_url, i); | 117 TemplateURLRef ref(template_url, i); |
120 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin); | 118 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin, false); |
121 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) | 119 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) |
122 return true; | 120 return true; |
123 } | 121 } |
124 | 122 |
125 return false; | 123 return false; |
126 } | 124 } |
127 | 125 |
128 void RecordInstantExtendedOptInState() { | 126 void RecordInstantExtendedOptInState() { |
129 if (!instant_extended_opt_in_state_gate) { | 127 if (!instant_extended_opt_in_state_gate) { |
130 instant_extended_opt_in_state_gate = true; | 128 instant_extended_opt_in_state_gate = true; |
(...skipping 30 matching lines...) Expand all Loading... |
161 return false; | 159 return false; |
162 | 160 |
163 const InstantService* instant_service = | 161 const InstantService* instant_service = |
164 InstantServiceFactory::GetForProfile(profile); | 162 InstantServiceFactory::GetForProfile(profile); |
165 if (!instant_service) | 163 if (!instant_service) |
166 return false; | 164 return false; |
167 | 165 |
168 return instant_service->IsInstantProcess(process_host->GetID()); | 166 return instant_service->IsInstantProcess(process_host->GetID()); |
169 } | 167 } |
170 | 168 |
| 169 // Returns true if |url| passes some basic checks that must succeed for it to be |
| 170 // usable as an instant URL: |
| 171 // (1) It contains the search terms replacement key of |template_url|, which is |
| 172 // expected to be the TemplateURL* for the default search provider. |
| 173 // (2) Either it has a secure scheme, or else the user has manually specified a |
| 174 // --google-base-url and it uses that base URL. (This allows testers to use |
| 175 // --google-base-url to point at non-HTTPS servers, which eases testing.) |
| 176 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) { |
| 177 return template_url->HasSearchTermsReplacementKey(url) && |
| 178 (url.SchemeIsSecure() || |
| 179 google_util::StartsWithCommandLineGoogleBaseURL(url)); |
| 180 } |
| 181 |
171 // Returns true if |url| can be used as an Instant URL for |profile|. | 182 // Returns true if |url| can be used as an Instant URL for |profile|. |
172 bool IsInstantURL(const GURL& url, Profile* profile) { | 183 bool IsInstantURL(const GURL& url, Profile* profile) { |
| 184 if (!url.is_valid()) |
| 185 return false; |
| 186 |
173 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 187 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
174 if (!template_url) | 188 if (!template_url) |
175 return false; | 189 return false; |
176 | 190 |
177 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref(); | |
178 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); | 191 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); |
179 GURL effective_url = url; | 192 if (extended_api_enabled && !IsSuitableURLForInstant(url, template_url)) |
180 | |
181 if (IsCommandLineInstantURL(url)) | |
182 effective_url = CoerceCommandLineURLToTemplateURL(url, instant_url_ref, | |
183 kDisableStartMargin); | |
184 | |
185 if (!effective_url.is_valid()) | |
186 return false; | 193 return false; |
187 | 194 |
188 if (extended_api_enabled && !effective_url.SchemeIsSecure()) | 195 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref(); |
189 return false; | |
190 | |
191 if (extended_api_enabled && | |
192 !template_url->HasSearchTermsReplacementKey(effective_url)) | |
193 return false; | |
194 | |
195 const GURL instant_url = | 196 const GURL instant_url = |
196 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin); | 197 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin, false); |
197 if (!instant_url.is_valid()) | 198 return instant_url.is_valid() && |
198 return false; | 199 (MatchesOriginAndPath(url, instant_url) || |
199 | 200 (extended_api_enabled && MatchesAnySearchURL(url, template_url))); |
200 if (MatchesOriginAndPath(effective_url, instant_url)) | |
201 return true; | |
202 | |
203 if (extended_api_enabled && MatchesAnySearchURL(effective_url, template_url)) | |
204 return true; | |
205 | |
206 return false; | |
207 } | 201 } |
208 | 202 |
209 string16 GetSearchTermsImpl(const content::WebContents* contents, | 203 string16 GetSearchTermsImpl(const content::WebContents* contents, |
210 const content::NavigationEntry* entry) { | 204 const content::NavigationEntry* entry) { |
211 if (!IsQueryExtractionEnabled()) | 205 if (!IsQueryExtractionEnabled()) |
212 return string16(); | 206 return string16(); |
213 | 207 |
214 // For security reasons, don't extract search terms if the page is not being | 208 // For security reasons, don't extract search terms if the page is not being |
215 // rendered in the privileged Instant renderer process. This is to protect | 209 // rendered in the privileged Instant renderer process. This is to protect |
216 // against a malicious page somehow scripting the search results page and | 210 // against a malicious page somehow scripting the search results page and |
217 // faking search terms in the URL. Random pages can't get into the Instant | 211 // faking search terms in the URL. Random pages can't get into the Instant |
218 // renderer and scripting doesn't work cross-process, so if the page is in | 212 // renderer and scripting doesn't work cross-process, so if the page is in |
219 // the Instant process, we know it isn't being exploited. | 213 // the Instant process, we know it isn't being exploited. |
220 // Since iOS and Android doesn't use the instant framework, these checks are | 214 // Since iOS and Android doesn't use the instant framework, these checks are |
221 // disabled for the two platforms. | 215 // disabled for the two platforms. |
222 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | 216 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
223 #if !defined(OS_IOS) && !defined(OS_ANDROID) | 217 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
224 if (!IsRenderedInInstantProcess(contents, profile) && | 218 if (!IsRenderedInInstantProcess(contents, profile) && |
225 (contents->GetController().GetLastCommittedEntry() == entry || | 219 ((entry == contents->GetController().GetLastCommittedEntry()) || |
226 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile))) | 220 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile))) |
227 return string16(); | 221 return string16(); |
228 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) | 222 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) |
229 // Check to see if search terms have already been extracted. | 223 // Check to see if search terms have already been extracted. |
230 string16 search_terms = GetSearchTermsFromNavigationEntry(entry); | 224 string16 search_terms = GetSearchTermsFromNavigationEntry(entry); |
231 if (!search_terms.empty()) | 225 if (!search_terms.empty()) |
232 return search_terms; | 226 return search_terms; |
233 | 227 |
234 // Otherwise, extract from the URL. | 228 // Otherwise, extract from the URL. |
235 return GetSearchTermsFromURL(profile, entry->GetVirtualURL()); | 229 return GetSearchTermsFromURL(profile, entry->GetVirtualURL()); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 | 289 |
296 FieldTrialFlags flags; | 290 FieldTrialFlags flags; |
297 if (GetFieldTrialInfo( | 291 if (GetFieldTrialInfo( |
298 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), | 292 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), |
299 &flags, NULL)) { | 293 &flags, NULL)) { |
300 return GetBoolValueForFlagWithDefault(kLocalOnlyFlagName, false, flags); | 294 return GetBoolValueForFlagWithDefault(kLocalOnlyFlagName, false, flags); |
301 } | 295 } |
302 return false; | 296 return false; |
303 } | 297 } |
304 | 298 |
305 string16 GetSearchTermsFromURL(Profile* profile, const GURL& in_url) { | 299 string16 GetSearchTermsFromURL(Profile* profile, const GURL& url) { |
306 GURL url(in_url); | |
307 string16 search_terms; | 300 string16 search_terms; |
308 | |
309 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 301 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
310 if (!template_url) | 302 if (template_url && IsSuitableURLForInstant(url, template_url)) |
311 return string16(); | |
312 | |
313 if (IsCommandLineInstantURL(url)) | |
314 url = CoerceCommandLineURLToTemplateURL(url, template_url->url_ref(), | |
315 kDisableStartMargin); | |
316 | |
317 if (url.SchemeIsSecure() && template_url->HasSearchTermsReplacementKey(url)) | |
318 template_url->ExtractSearchTermsFromURL(url, &search_terms); | 303 template_url->ExtractSearchTermsFromURL(url, &search_terms); |
319 | |
320 return search_terms; | 304 return search_terms; |
321 } | 305 } |
322 | 306 |
323 string16 GetSearchTermsFromNavigationEntry( | 307 string16 GetSearchTermsFromNavigationEntry( |
324 const content::NavigationEntry* entry) { | 308 const content::NavigationEntry* entry) { |
325 string16 search_terms; | 309 string16 search_terms; |
326 if (entry) | 310 if (entry) |
327 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms); | 311 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms); |
328 return search_terms; | 312 return search_terms; |
329 } | 313 } |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_PREDICTION_DISABLED); | 451 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_PREDICTION_DISABLED); |
468 | 452 |
469 DCHECK(IsInstantCheckboxEnabled(profile)); | 453 DCHECK(IsInstantCheckboxEnabled(profile)); |
470 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_ENABLED); | 454 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_ENABLED); |
471 } | 455 } |
472 | 456 |
473 GURL GetInstantURL(Profile* profile, int start_margin) { | 457 GURL GetInstantURL(Profile* profile, int start_margin) { |
474 if (!IsInstantCheckboxEnabled(profile)) | 458 if (!IsInstantCheckboxEnabled(profile)) |
475 return GURL(); | 459 return GURL(); |
476 | 460 |
| 461 // In non-extended mode, the checkbox must be checked. |
477 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); | 462 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); |
478 | |
479 // In non-extended mode, the checkbox must be checked. | |
480 if (!extended_api_enabled && !IsInstantCheckboxChecked(profile)) | 463 if (!extended_api_enabled && !IsInstantCheckboxChecked(profile)) |
481 return GURL(); | 464 return GURL(); |
482 | 465 |
483 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 466 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
484 CommandLine* cl = CommandLine::ForCurrentProcess(); | 467 GURL instant_url = |
485 if (cl->HasSwitch(switches::kInstantURL)) { | 468 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin, true); |
486 GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL)); | 469 |
487 if (extended_api_enabled) { | 470 // Extended mode requires HTTPS. Force it unless the base URL was overridden |
488 // Extended mode won't work if the search terms replacement key is absent. | 471 // on the command line, in which case we allow HTTP (see comments on |
489 GURL coerced_url = CoerceCommandLineURLToTemplateURL( | 472 // IsSuitableURLForInstant()). |
490 instant_url, template_url->instant_url_ref(), start_margin); | 473 if (!extended_api_enabled || instant_url.SchemeIsSecure() || |
491 if (!template_url->HasSearchTermsReplacementKey(coerced_url)) | 474 google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) |
492 return GURL(); | |
493 } | |
494 return instant_url; | 475 return instant_url; |
495 } | |
496 | 476 |
497 GURL instant_url = | 477 GURL::Replacements replacements; |
498 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin); | 478 const std::string secure_scheme(chrome::kHttpsScheme); |
499 if (extended_api_enabled && !instant_url.SchemeIsSecure()) { | 479 replacements.SetSchemeStr(secure_scheme); |
500 // Extended mode requires HTTPS. Force it if necessary. | 480 return instant_url.ReplaceComponents(replacements); |
501 const std::string secure_scheme = chrome::kHttpsScheme; | |
502 GURL::Replacements replacements; | |
503 replacements.SetSchemeStr(secure_scheme); | |
504 instant_url = instant_url.ReplaceComponents(replacements); | |
505 } | |
506 | |
507 return instant_url; | |
508 } | 481 } |
509 | 482 |
510 GURL GetLocalInstantURL(Profile* profile) { | 483 GURL GetLocalInstantURL(Profile* profile) { |
511 const TemplateURL* default_provider = | 484 const TemplateURL* default_provider = |
512 GetDefaultSearchProviderTemplateURL(profile); | 485 GetDefaultSearchProviderTemplateURL(profile); |
513 | 486 |
514 if (default_provider && | 487 if (default_provider && |
515 (TemplateURLPrepopulateData::GetEngineType(default_provider->url()) == | 488 (TemplateURLPrepopulateData::GetEngineType(default_provider->url()) == |
516 SEARCH_ENGINE_GOOGLE)) { | 489 SEARCH_ENGINE_GOOGLE)) { |
517 return GURL(chrome::kChromeSearchLocalGoogleNtpUrl); | 490 return GURL(chrome::kChromeSearchLocalGoogleNtpUrl); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 } | 692 } |
720 | 693 |
721 // Given a FieldTrialFlags object, returns the boolean value of the provided | 694 // Given a FieldTrialFlags object, returns the boolean value of the provided |
722 // flag. | 695 // flag. |
723 bool GetBoolValueForFlagWithDefault(const std::string& flag, | 696 bool GetBoolValueForFlagWithDefault(const std::string& flag, |
724 bool default_value, | 697 bool default_value, |
725 const FieldTrialFlags& flags) { | 698 const FieldTrialFlags& flags) { |
726 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); | 699 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); |
727 } | 700 } |
728 | 701 |
729 // Coerces the commandline Instant URL to look like a template URL, so that we | |
730 // can extract search terms from it. | |
731 GURL CoerceCommandLineURLToTemplateURL(const GURL& instant_url, | |
732 const TemplateURLRef& ref, | |
733 int start_margin) { | |
734 GURL search_url = TemplateURLRefToGURL(ref, start_margin); | |
735 | |
736 // NOTE(samarth): GURL returns temporaries which we must save because | |
737 // GURL::Replacements expects the replacements to live until | |
738 // ReplaceComponents is called. | |
739 const std::string search_scheme = chrome::kHttpsScheme; | |
740 const std::string search_host = search_url.host(); | |
741 const std::string search_port = search_url.port(); | |
742 | |
743 GURL::Replacements replacements; | |
744 replacements.SetSchemeStr(search_scheme); | |
745 replacements.SetHostStr(search_host); | |
746 replacements.SetPortStr(search_port); | |
747 return instant_url.ReplaceComponents(replacements); | |
748 } | |
749 | |
750 bool DefaultSearchProviderSupportsInstant(Profile* profile) { | 702 bool DefaultSearchProviderSupportsInstant(Profile* profile) { |
751 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 703 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
752 if (!template_url) | 704 if (!template_url) |
753 return false; | 705 return false; |
754 | 706 |
755 GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref(), | 707 GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref(), |
756 kDisableStartMargin); | 708 kDisableStartMargin, false); |
757 // Extended mode instant requires a search terms replacement key. | 709 // Extended mode instant requires a search terms replacement key. |
758 return instant_url.is_valid() && | 710 return instant_url.is_valid() && |
759 (!IsInstantExtendedAPIEnabled() || | 711 (!IsInstantExtendedAPIEnabled() || |
760 template_url->HasSearchTermsReplacementKey(instant_url)); | 712 template_url->HasSearchTermsReplacementKey(instant_url)); |
761 } | 713 } |
762 | 714 |
763 void ResetInstantExtendedOptInStateGateForTest() { | 715 void ResetInstantExtendedOptInStateGateForTest() { |
764 instant_extended_opt_in_state_gate = false; | 716 instant_extended_opt_in_state_gate = false; |
765 } | 717 } |
766 | 718 |
767 } // namespace chrome | 719 } // namespace chrome |
OLD | NEW |