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 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 } | 95 } |
95 | 96 |
96 bool MatchesOrigin(const GURL& my_url, const GURL& other_url) { | 97 bool MatchesOrigin(const GURL& my_url, const GURL& other_url) { |
97 return my_url.host() == other_url.host() && | 98 return my_url.host() == other_url.host() && |
98 my_url.port() == other_url.port() && | 99 my_url.port() == other_url.port() && |
99 (my_url.scheme() == other_url.scheme() || | 100 (my_url.scheme() == other_url.scheme() || |
100 (my_url.SchemeIs(chrome::kHttpsScheme) && | 101 (my_url.SchemeIs(chrome::kHttpsScheme) && |
101 other_url.SchemeIs(chrome::kHttpScheme))); | 102 other_url.SchemeIs(chrome::kHttpScheme))); |
102 } | 103 } |
103 | 104 |
104 bool IsCommandLineInstantURL(const GURL& url) { | |
105 const CommandLine* cl = CommandLine::ForCurrentProcess(); | |
106 const GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL)); | |
107 return instant_url.is_valid() && MatchesOrigin(url, instant_url); | |
108 } | |
109 | |
110 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) { | 105 bool MatchesAnySearchURL(const GURL& url, TemplateURL* template_url) { |
111 GURL search_url = | 106 GURL search_url = |
112 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin); | 107 TemplateURLRefToGURL(template_url->url_ref(), kDisableStartMargin); |
113 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) | 108 if (search_url.is_valid() && MatchesOriginAndPath(url, search_url)) |
114 return true; | 109 return true; |
115 | 110 |
116 // "URLCount() - 1" because we already tested url_ref above. | 111 // "URLCount() - 1" because we already tested url_ref above. |
117 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) { | 112 for (size_t i = 0; i < template_url->URLCount() - 1; ++i) { |
118 TemplateURLRef ref(template_url, i); | 113 TemplateURLRef ref(template_url, i); |
119 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin); | 114 search_url = TemplateURLRefToGURL(ref, kDisableStartMargin); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 return false; | 155 return false; |
161 | 156 |
162 const InstantService* instant_service = | 157 const InstantService* instant_service = |
163 InstantServiceFactory::GetForProfile(profile); | 158 InstantServiceFactory::GetForProfile(profile); |
164 if (!instant_service) | 159 if (!instant_service) |
165 return false; | 160 return false; |
166 | 161 |
167 return instant_service->IsInstantProcess(process_host->GetID()); | 162 return instant_service->IsInstantProcess(process_host->GetID()); |
168 } | 163 } |
169 | 164 |
| 165 // Returns true if |url| passes some basic checks that must succeed for it to be |
| 166 // usable as an instant URL: |
| 167 // (1) It contains the search terms replacement key of |template_url|, which is |
| 168 // expected to be the TemplateURL* for the default search provider. |
| 169 // (2) Either it has a secure scheme, or else the user has manually specified a |
| 170 // --google-base-url and it uses that base URL. (This allows testers to use |
| 171 // --google-base-url to point at non-HTTPS servers, which eases testing.) |
| 172 bool IsSuitableURLForInstant(const GURL& url, const TemplateURL* template_url) { |
| 173 return template_url->HasSearchTermsReplacementKey(url) && |
| 174 (url.SchemeIsSecure() || |
| 175 google_util::StartsWithCommandLineGoogleBaseURL(url)); |
| 176 } |
| 177 |
170 // Returns true if |url| can be used as an Instant URL for |profile|. | 178 // Returns true if |url| can be used as an Instant URL for |profile|. |
171 bool IsInstantURL(const GURL& url, Profile* profile) { | 179 bool IsInstantURL(const GURL& url, Profile* profile) { |
| 180 if (!url.is_valid()) |
| 181 return false; |
| 182 |
172 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 183 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
173 if (!template_url) | 184 if (!template_url) |
174 return false; | 185 return false; |
175 | 186 |
176 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref(); | |
177 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); | 187 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); |
178 GURL effective_url = url; | 188 if (extended_api_enabled && !IsSuitableURLForInstant(url, template_url)) |
179 | |
180 if (IsCommandLineInstantURL(url)) | |
181 effective_url = CoerceCommandLineURLToTemplateURL(url, instant_url_ref, | |
182 kDisableStartMargin); | |
183 | |
184 if (!effective_url.is_valid()) | |
185 return false; | 189 return false; |
186 | 190 |
187 if (extended_api_enabled && !effective_url.SchemeIsSecure()) | 191 const TemplateURLRef& instant_url_ref = template_url->instant_url_ref(); |
188 return false; | |
189 | |
190 if (extended_api_enabled && | |
191 !template_url->HasSearchTermsReplacementKey(effective_url)) | |
192 return false; | |
193 | |
194 const GURL instant_url = | 192 const GURL instant_url = |
195 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin); | 193 TemplateURLRefToGURL(instant_url_ref, kDisableStartMargin); |
196 if (!instant_url.is_valid()) | 194 return instant_url.is_valid() && |
197 return false; | 195 (MatchesOriginAndPath(url, instant_url) || |
198 | 196 (extended_api_enabled && MatchesAnySearchURL(url, template_url))); |
199 if (MatchesOriginAndPath(effective_url, instant_url)) | |
200 return true; | |
201 | |
202 if (extended_api_enabled && MatchesAnySearchURL(effective_url, template_url)) | |
203 return true; | |
204 | |
205 return false; | |
206 } | 197 } |
207 | 198 |
208 string16 GetSearchTermsImpl(const content::WebContents* contents, | 199 string16 GetSearchTermsImpl(const content::WebContents* contents, |
209 const content::NavigationEntry* entry) { | 200 const content::NavigationEntry* entry) { |
210 if (!IsQueryExtractionEnabled()) | 201 if (!IsQueryExtractionEnabled()) |
211 return string16(); | 202 return string16(); |
212 | 203 |
213 // For security reasons, don't extract search terms if the page is not being | 204 // For security reasons, don't extract search terms if the page is not being |
214 // rendered in the privileged Instant renderer process. This is to protect | 205 // rendered in the privileged Instant renderer process. This is to protect |
215 // against a malicious page somehow scripting the search results page and | 206 // against a malicious page somehow scripting the search results page and |
216 // faking search terms in the URL. Random pages can't get into the Instant | 207 // faking search terms in the URL. Random pages can't get into the Instant |
217 // renderer and scripting doesn't work cross-process, so if the page is in | 208 // renderer and scripting doesn't work cross-process, so if the page is in |
218 // the Instant process, we know it isn't being exploited. | 209 // the Instant process, we know it isn't being exploited. |
219 // Since iOS and Android doesn't use the instant framework, these checks are | 210 // Since iOS and Android doesn't use the instant framework, these checks are |
220 // disabled for the two platforms. | 211 // disabled for the two platforms. |
221 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); | 212 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
222 #if !defined(OS_IOS) && !defined(OS_ANDROID) | 213 #if !defined(OS_IOS) && !defined(OS_ANDROID) |
223 if (!IsRenderedInInstantProcess(contents, profile) && | 214 if (!IsRenderedInInstantProcess(contents, profile) && |
224 (contents->GetController().GetLastCommittedEntry() == entry || | 215 ((entry == contents->GetController().GetLastCommittedEntry()) || |
225 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile))) | 216 !ShouldAssignURLToInstantRenderer(entry->GetURL(), profile))) |
226 return string16(); | 217 return string16(); |
227 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) | 218 #endif // !defined(OS_IOS) && !defined(OS_ANDROID) |
228 // Check to see if search terms have already been extracted. | 219 // Check to see if search terms have already been extracted. |
229 string16 search_terms = GetSearchTermsFromNavigationEntry(entry); | 220 string16 search_terms = GetSearchTermsFromNavigationEntry(entry); |
230 if (!search_terms.empty()) | 221 if (!search_terms.empty()) |
231 return search_terms; | 222 return search_terms; |
232 | 223 |
233 // Otherwise, extract from the URL. | 224 // Otherwise, extract from the URL. |
234 return GetSearchTermsFromURL(profile, entry->GetVirtualURL()); | 225 return GetSearchTermsFromURL(profile, entry->GetVirtualURL()); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 | 285 |
295 FieldTrialFlags flags; | 286 FieldTrialFlags flags; |
296 if (GetFieldTrialInfo( | 287 if (GetFieldTrialInfo( |
297 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), | 288 base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName), |
298 &flags, NULL)) { | 289 &flags, NULL)) { |
299 return GetBoolValueForFlagWithDefault(kLocalOnlyFlagName, false, flags); | 290 return GetBoolValueForFlagWithDefault(kLocalOnlyFlagName, false, flags); |
300 } | 291 } |
301 return false; | 292 return false; |
302 } | 293 } |
303 | 294 |
304 string16 GetSearchTermsFromURL(Profile* profile, const GURL& in_url) { | 295 string16 GetSearchTermsFromURL(Profile* profile, const GURL& url) { |
305 GURL url(in_url); | |
306 string16 search_terms; | 296 string16 search_terms; |
307 | |
308 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 297 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
309 if (!template_url) | 298 if (template_url && IsSuitableURLForInstant(url, template_url)) |
310 return string16(); | |
311 | |
312 if (IsCommandLineInstantURL(url)) | |
313 url = CoerceCommandLineURLToTemplateURL(url, template_url->url_ref(), | |
314 kDisableStartMargin); | |
315 | |
316 if (url.SchemeIsSecure() && template_url->HasSearchTermsReplacementKey(url)) | |
317 template_url->ExtractSearchTermsFromURL(url, &search_terms); | 299 template_url->ExtractSearchTermsFromURL(url, &search_terms); |
318 | |
319 return search_terms; | 300 return search_terms; |
320 } | 301 } |
321 | 302 |
322 string16 GetSearchTermsFromNavigationEntry( | 303 string16 GetSearchTermsFromNavigationEntry( |
323 const content::NavigationEntry* entry) { | 304 const content::NavigationEntry* entry) { |
324 string16 search_terms; | 305 string16 search_terms; |
325 if (entry) | 306 if (entry) |
326 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms); | 307 entry->GetExtraData(sessions::kSearchTermsKey, &search_terms); |
327 return search_terms; | 308 return search_terms; |
328 } | 309 } |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_PREDICTION_DISABLED); | 447 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_PREDICTION_DISABLED); |
467 | 448 |
468 DCHECK(IsInstantCheckboxEnabled(profile)); | 449 DCHECK(IsInstantCheckboxEnabled(profile)); |
469 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_ENABLED); | 450 return l10n_util::GetStringUTF16(IDS_INSTANT_CHECKBOX_ENABLED); |
470 } | 451 } |
471 | 452 |
472 GURL GetInstantURL(Profile* profile, int start_margin) { | 453 GURL GetInstantURL(Profile* profile, int start_margin) { |
473 if (!IsInstantCheckboxEnabled(profile)) | 454 if (!IsInstantCheckboxEnabled(profile)) |
474 return GURL(); | 455 return GURL(); |
475 | 456 |
| 457 // In non-extended mode, the checkbox must be checked. |
476 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); | 458 const bool extended_api_enabled = IsInstantExtendedAPIEnabled(); |
477 | |
478 // In non-extended mode, the checkbox must be checked. | |
479 if (!extended_api_enabled && !IsInstantCheckboxChecked(profile)) | 459 if (!extended_api_enabled && !IsInstantCheckboxChecked(profile)) |
480 return GURL(); | 460 return GURL(); |
481 | 461 |
482 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 462 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
483 CommandLine* cl = CommandLine::ForCurrentProcess(); | 463 GURL instant_url = |
484 if (cl->HasSwitch(switches::kInstantURL)) { | 464 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin); |
485 GURL instant_url(cl->GetSwitchValueASCII(switches::kInstantURL)); | 465 |
486 if (extended_api_enabled) { | 466 GURL::Replacements replacements; |
487 // Extended mode won't work if the search terms replacement key is absent. | 467 |
488 GURL coerced_url = CoerceCommandLineURLToTemplateURL( | 468 // Extended mode requires HTTPS. Force it unless the base URL was overridden |
489 instant_url, template_url->instant_url_ref(), start_margin); | 469 // on the command line, in which case we allow HTTP (see comments on |
490 if (!template_url->HasSearchTermsReplacementKey(coerced_url)) | 470 // IsSuitableURLForInstant()). |
491 return GURL(); | 471 const std::string secure_scheme(chrome::kHttpsScheme); |
492 } | 472 if (extended_api_enabled && !instant_url.SchemeIsSecure() && |
493 return instant_url; | 473 !google_util::StartsWithCommandLineGoogleBaseURL(instant_url)) |
| 474 replacements.SetSchemeStr(secure_scheme); |
| 475 |
| 476 // If the user specified additional query params on the command line, add |
| 477 // them. |
| 478 std::string query_params(CommandLine::ForCurrentProcess()-> |
| 479 GetSwitchValueASCII(switches::kExtraSearchQueryParams)); |
| 480 if (!query_params.empty()) { |
| 481 const std::string existing_query_params(instant_url.query()); |
| 482 if (!existing_query_params.empty()) |
| 483 query_params += "&" + existing_query_params; |
| 484 replacements.SetQueryStr(query_params); |
494 } | 485 } |
495 | 486 |
496 GURL instant_url = | 487 return instant_url.ReplaceComponents(replacements); |
497 TemplateURLRefToGURL(template_url->instant_url_ref(), start_margin); | |
498 if (extended_api_enabled && !instant_url.SchemeIsSecure()) { | |
499 // Extended mode requires HTTPS. Force it if necessary. | |
500 const std::string secure_scheme = chrome::kHttpsScheme; | |
501 GURL::Replacements replacements; | |
502 replacements.SetSchemeStr(secure_scheme); | |
503 instant_url = instant_url.ReplaceComponents(replacements); | |
504 } | |
505 | |
506 return instant_url; | |
507 } | 488 } |
508 | 489 |
509 GURL GetLocalInstantURL(Profile* profile) { | 490 GURL GetLocalInstantURL(Profile* profile) { |
510 const TemplateURL* default_provider = | 491 const TemplateURL* default_provider = |
511 GetDefaultSearchProviderTemplateURL(profile); | 492 GetDefaultSearchProviderTemplateURL(profile); |
512 | 493 |
513 if (default_provider && | 494 if (default_provider && |
514 (TemplateURLPrepopulateData::GetEngineType(default_provider->url()) == | 495 (TemplateURLPrepopulateData::GetEngineType(default_provider->url()) == |
515 SEARCH_ENGINE_GOOGLE)) { | 496 SEARCH_ENGINE_GOOGLE)) { |
516 return GURL(chrome::kChromeSearchLocalGoogleNtpUrl); | 497 return GURL(chrome::kChromeSearchLocalGoogleNtpUrl); |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 } | 687 } |
707 | 688 |
708 // Given a FieldTrialFlags object, returns the boolean value of the provided | 689 // Given a FieldTrialFlags object, returns the boolean value of the provided |
709 // flag. | 690 // flag. |
710 bool GetBoolValueForFlagWithDefault(const std::string& flag, | 691 bool GetBoolValueForFlagWithDefault(const std::string& flag, |
711 bool default_value, | 692 bool default_value, |
712 const FieldTrialFlags& flags) { | 693 const FieldTrialFlags& flags) { |
713 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); | 694 return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags); |
714 } | 695 } |
715 | 696 |
716 // Coerces the commandline Instant URL to look like a template URL, so that we | |
717 // can extract search terms from it. | |
718 GURL CoerceCommandLineURLToTemplateURL(const GURL& instant_url, | |
719 const TemplateURLRef& ref, | |
720 int start_margin) { | |
721 GURL search_url = TemplateURLRefToGURL(ref, start_margin); | |
722 | |
723 // NOTE(samarth): GURL returns temporaries which we must save because | |
724 // GURL::Replacements expects the replacements to live until | |
725 // ReplaceComponents is called. | |
726 const std::string search_scheme = chrome::kHttpsScheme; | |
727 const std::string search_host = search_url.host(); | |
728 const std::string search_port = search_url.port(); | |
729 | |
730 GURL::Replacements replacements; | |
731 replacements.SetSchemeStr(search_scheme); | |
732 replacements.SetHostStr(search_host); | |
733 replacements.SetPortStr(search_port); | |
734 return instant_url.ReplaceComponents(replacements); | |
735 } | |
736 | |
737 bool DefaultSearchProviderSupportsInstant(Profile* profile) { | 697 bool DefaultSearchProviderSupportsInstant(Profile* profile) { |
738 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); | 698 TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile); |
739 if (!template_url) | 699 if (!template_url) |
740 return false; | 700 return false; |
741 | 701 |
742 GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref(), | 702 GURL instant_url = TemplateURLRefToGURL(template_url->instant_url_ref(), |
743 kDisableStartMargin); | 703 kDisableStartMargin); |
744 // Extended mode instant requires a search terms replacement key. | 704 // Extended mode instant requires a search terms replacement key. |
745 return instant_url.is_valid() && | 705 return instant_url.is_valid() && |
746 (!IsInstantExtendedAPIEnabled() || | 706 (!IsInstantExtendedAPIEnabled() || |
(...skipping 13 matching lines...) Expand all Loading... |
760 for (size_t i = 0; i < items_b.size(); ++i) { | 720 for (size_t i = 0; i < items_b.size(); ++i) { |
761 if (items_b[i].url != items_a[i].url || | 721 if (items_b[i].url != items_a[i].url || |
762 items_b[i].title != items_a[i].title) { | 722 items_b[i].title != items_a[i].title) { |
763 return false; | 723 return false; |
764 } | 724 } |
765 } | 725 } |
766 return true; | 726 return true; |
767 } | 727 } |
768 | 728 |
769 } // namespace chrome | 729 } // namespace chrome |
OLD | NEW |