| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/autocomplete/zero_suggest_provider.h" | 5 #include "chrome/browser/autocomplete/zero_suggest_provider.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/i18n/case_conversion.h" | 8 #include "base/i18n/case_conversion.h" |
| 9 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
| 12 #include "base/strings/string16.h" | 12 #include "base/strings/string16.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" | 16 #include "chrome/browser/autocomplete/autocomplete_classifier.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 17 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
| 18 #include "chrome/browser/autocomplete/autocomplete_input.h" | 18 #include "chrome/browser/autocomplete/autocomplete_input.h" |
| 19 #include "chrome/browser/autocomplete/autocomplete_match.h" | 19 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 20 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" | 20 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
| 21 #include "chrome/browser/autocomplete/history_url_provider.h" | 21 #include "chrome/browser/autocomplete/history_url_provider.h" |
| 22 #include "chrome/browser/autocomplete/search_provider.h" | 22 #include "chrome/browser/autocomplete/search_provider.h" |
| 23 #include "chrome/browser/autocomplete/url_prefix.h" | 23 #include "chrome/browser/autocomplete/url_prefix.h" |
| 24 #include "chrome/browser/google/google_util.h" | |
| 25 #include "chrome/browser/history/history_types.h" | 24 #include "chrome/browser/history/history_types.h" |
| 26 #include "chrome/browser/history/top_sites.h" | 25 #include "chrome/browser/history/top_sites.h" |
| 27 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 26 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
| 28 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 27 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
| 29 #include "chrome/browser/profiles/profile.h" | 28 #include "chrome/browser/profiles/profile.h" |
| 30 #include "chrome/browser/search/search.h" | 29 #include "chrome/browser/search/search.h" |
| 31 #include "chrome/browser/search_engines/template_url_service.h" | 30 #include "chrome/browser/search_engines/template_url_service.h" |
| 32 #include "chrome/browser/search_engines/template_url_service_factory.h" | 31 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 33 #include "chrome/browser/sync/profile_sync_service.h" | |
| 34 #include "chrome/browser/sync/profile_sync_service_factory.h" | |
| 35 #include "chrome/common/net/url_fixer_upper.h" | 32 #include "chrome/common/net/url_fixer_upper.h" |
| 36 #include "chrome/common/pref_names.h" | 33 #include "chrome/common/pref_names.h" |
| 37 #include "chrome/common/url_constants.h" | 34 #include "chrome/common/url_constants.h" |
| 38 #include "net/base/escape.h" | 35 #include "net/base/escape.h" |
| 39 #include "net/base/load_flags.h" | 36 #include "net/base/load_flags.h" |
| 40 #include "net/base/net_util.h" | 37 #include "net/base/net_util.h" |
| 41 #include "net/http/http_request_headers.h" | 38 #include "net/http/http_request_headers.h" |
| 42 #include "net/http/http_response_headers.h" | 39 #include "net/http/http_response_headers.h" |
| 43 #include "net/url_request/url_fetcher.h" | 40 #include "net/url_request/url_fetcher.h" |
| 44 #include "net/url_request/url_request_status.h" | 41 #include "net/url_request/url_request_status.h" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 ParseSuggestResults(*data.get()); | 140 ParseSuggestResults(*data.get()); |
| 144 } | 141 } |
| 145 done_ = true; | 142 done_ = true; |
| 146 | 143 |
| 147 ConvertResultsToAutocompleteMatches(); | 144 ConvertResultsToAutocompleteMatches(); |
| 148 if (!matches_.empty()) | 145 if (!matches_.empty()) |
| 149 listener_->OnProviderUpdate(true); | 146 listener_->OnProviderUpdate(true); |
| 150 } | 147 } |
| 151 | 148 |
| 152 void ZeroSuggestProvider::StartZeroSuggest( | 149 void ZeroSuggestProvider::StartZeroSuggest( |
| 153 const GURL& url, | 150 const GURL& current_page_url, |
| 154 AutocompleteInput::PageClassification page_classification, | 151 AutocompleteInput::PageClassification page_classification, |
| 155 const string16& permanent_text) { | 152 const string16& permanent_text) { |
| 156 Stop(true); | 153 Stop(true); |
| 157 field_trial_triggered_ = false; | 154 field_trial_triggered_ = false; |
| 158 field_trial_triggered_in_session_ = false; | 155 field_trial_triggered_in_session_ = false; |
| 159 if (!ShouldRunZeroSuggest(url, page_classification)) | 156 permanent_text_ = permanent_text; |
| 157 current_query_ = current_page_url.spec(); |
| 158 current_page_classification_ = page_classification; |
| 159 current_url_match_ = MatchForCurrentURL(); |
| 160 |
| 161 const TemplateURL* default_provider = |
| 162 template_url_service_->GetDefaultSearchProvider(); |
| 163 string16 prefix; |
| 164 TemplateURLRef::SearchTermsArgs search_term_args(prefix); |
| 165 search_term_args.current_page_url = current_query_; |
| 166 GURL suggest_url(default_provider->suggestions_url_ref(). |
| 167 ReplaceSearchTerms(search_term_args)); |
| 168 if (!SearchProvider::CanSendURL( |
| 169 current_page_url, suggest_url, |
| 170 template_url_service_->GetDefaultSearchProvider(), |
| 171 page_classification, profile_) || |
| 172 !OmniboxFieldTrial::InZeroSuggestFieldTrial()) |
| 160 return; | 173 return; |
| 161 verbatim_relevance_ = kDefaultVerbatimZeroSuggestRelevance; | 174 verbatim_relevance_ = kDefaultVerbatimZeroSuggestRelevance; |
| 162 done_ = false; | 175 done_ = false; |
| 163 permanent_text_ = permanent_text; | |
| 164 current_query_ = url.spec(); | |
| 165 current_page_classification_ = page_classification; | |
| 166 current_url_match_ = MatchForCurrentURL(); | |
| 167 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. | 176 // TODO(jered): Consider adding locally-sourced zero-suggestions here too. |
| 168 // These may be useful on the NTP or more relevant to the user than server | 177 // These may be useful on the NTP or more relevant to the user than server |
| 169 // suggestions, if based on local browsing history. | 178 // suggestions, if based on local browsing history. |
| 170 Run(); | 179 Run(suggest_url); |
| 171 } | 180 } |
| 172 | 181 |
| 173 ZeroSuggestProvider::ZeroSuggestProvider( | 182 ZeroSuggestProvider::ZeroSuggestProvider( |
| 174 AutocompleteProviderListener* listener, | 183 AutocompleteProviderListener* listener, |
| 175 Profile* profile) | 184 Profile* profile) |
| 176 : AutocompleteProvider(listener, profile, | 185 : AutocompleteProvider(listener, profile, |
| 177 AutocompleteProvider::TYPE_ZERO_SUGGEST), | 186 AutocompleteProvider::TYPE_ZERO_SUGGEST), |
| 178 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), | 187 template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)), |
| 179 have_pending_request_(false), | 188 have_pending_request_(false), |
| 180 verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), | 189 verbatim_relevance_(kDefaultVerbatimZeroSuggestRelevance), |
| 181 field_trial_triggered_(false), | 190 field_trial_triggered_(false), |
| 182 field_trial_triggered_in_session_(false), | 191 field_trial_triggered_in_session_(false), |
| 183 weak_ptr_factory_(this) { | 192 weak_ptr_factory_(this) { |
| 184 } | 193 } |
| 185 | 194 |
| 186 ZeroSuggestProvider::~ZeroSuggestProvider() { | 195 ZeroSuggestProvider::~ZeroSuggestProvider() { |
| 187 } | 196 } |
| 188 | 197 |
| 189 bool ZeroSuggestProvider::ShouldRunZeroSuggest( | |
| 190 const GURL& url, | |
| 191 AutocompleteInput::PageClassification page_classification) const { | |
| 192 if (!ShouldSendURL(url, page_classification)) | |
| 193 return false; | |
| 194 | |
| 195 // Don't run if there's no profile or in incognito mode. | |
| 196 if (profile_ == NULL || profile_->IsOffTheRecord()) | |
| 197 return false; | |
| 198 | |
| 199 // Don't run if we can't get preferences or search suggest is not enabled. | |
| 200 PrefService* prefs = profile_->GetPrefs(); | |
| 201 if (prefs == NULL || !prefs->GetBoolean(prefs::kSearchSuggestEnabled)) | |
| 202 return false; | |
| 203 | |
| 204 ProfileSyncService* service = | |
| 205 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); | |
| 206 browser_sync::SyncPrefs sync_prefs(prefs); | |
| 207 | |
| 208 // ZeroSuggest requires sending the current URL to the suggest provider, so we | |
| 209 // only want to enable it if the user is willing to have this data sent. | |
| 210 // Because tab sync involves sending the same data, we currently use | |
| 211 // "tab sync is enabled and tab sync data is unencrypted" as a proxy for | |
| 212 // "the user is OK with sending this data". We might someday want to change | |
| 213 // this to a standalone setting or part of some other explicit general opt-in. | |
| 214 if (!OmniboxFieldTrial::InZeroSuggestFieldTrial() || | |
| 215 service == NULL || | |
| 216 !service->IsSyncEnabledAndLoggedIn() || | |
| 217 !sync_prefs.GetPreferredDataTypes(syncer::UserTypes()).Has( | |
| 218 syncer::PROXY_TABS) || | |
| 219 service->GetEncryptedDataTypes().Has(syncer::SESSIONS)) { | |
| 220 return false; | |
| 221 } | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 bool ZeroSuggestProvider::ShouldSendURL( | |
| 226 const GURL& url, | |
| 227 AutocompleteInput::PageClassification page_classification) const { | |
| 228 if (!url.is_valid()) | |
| 229 return false; | |
| 230 | |
| 231 // TODO(hfung): Show Most Visited on NTP with appropriate verbatim | |
| 232 // description when the user actively focuses on the omnibox as discussed in | |
| 233 // crbug/305366 if Most Visited (or something similar) will launch. | |
| 234 if (page_classification == | |
| 235 AutocompleteInput::INSTANT_NEW_TAB_PAGE_WITH_FAKEBOX_AS_STARTING_FOCUS || | |
| 236 page_classification == | |
| 237 AutocompleteInput::INSTANT_NEW_TAB_PAGE_WITH_OMNIBOX_AS_STARTING_FOCUS) | |
| 238 return false; | |
| 239 | |
| 240 // Only allow HTTP URLs or Google HTTPS URLs (including Google search | |
| 241 // result pages). For the latter case, Google was already sent the HTTPS | |
| 242 // URLs when requesting the page, so the information is just re-sent. | |
| 243 return (url.scheme() == content::kHttpScheme) || | |
| 244 google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN, | |
| 245 google_util::ALLOW_NON_STANDARD_PORTS); | |
| 246 } | |
| 247 | |
| 248 void ZeroSuggestProvider::FillResults( | 198 void ZeroSuggestProvider::FillResults( |
| 249 const Value& root_val, | 199 const Value& root_val, |
| 250 int* verbatim_relevance, | 200 int* verbatim_relevance, |
| 251 SearchProvider::SuggestResults* suggest_results, | 201 SearchProvider::SuggestResults* suggest_results, |
| 252 SearchProvider::NavigationResults* navigation_results) { | 202 SearchProvider::NavigationResults* navigation_results) { |
| 253 string16 query; | 203 string16 query; |
| 254 const ListValue* root_list = NULL; | 204 const ListValue* root_list = NULL; |
| 255 const ListValue* results = NULL; | 205 const ListValue* results = NULL; |
| 256 const ListValue* relevances = NULL; | 206 const ListValue* relevances = NULL; |
| 257 // The response includes the query, which should be empty for ZeroSuggest | 207 // The response includes the query, which should be empty for ZeroSuggest |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 &match.contents_class); | 336 &match.contents_class); |
| 387 | 337 |
| 388 match.description = | 338 match.description = |
| 389 AutocompleteMatch::SanitizeString(navigation.description()); | 339 AutocompleteMatch::SanitizeString(navigation.description()); |
| 390 AutocompleteMatch::ClassifyLocationInString(string16::npos, 0, | 340 AutocompleteMatch::ClassifyLocationInString(string16::npos, 0, |
| 391 match.description.length(), ACMatchClassification::NONE, | 341 match.description.length(), ACMatchClassification::NONE, |
| 392 &match.description_class); | 342 &match.description_class); |
| 393 return match; | 343 return match; |
| 394 } | 344 } |
| 395 | 345 |
| 396 void ZeroSuggestProvider::Run() { | 346 void ZeroSuggestProvider::Run(const GURL& suggest_url) { |
| 397 have_pending_request_ = false; | 347 have_pending_request_ = false; |
| 398 const int kFetcherID = 1; | 348 const int kFetcherID = 1; |
| 399 | |
| 400 const TemplateURL* default_provider = | |
| 401 template_url_service_->GetDefaultSearchProvider(); | |
| 402 // TODO(hfung): Generalize if the default provider supports zero suggest. | |
| 403 // Only make the request if we know that the provider supports zero suggest | |
| 404 // (currently only the prepopulated Google provider). | |
| 405 if (default_provider == NULL || !default_provider->SupportsReplacement() || | |
| 406 default_provider->prepopulate_id() != 1) { | |
| 407 Stop(true); | |
| 408 return; | |
| 409 } | |
| 410 string16 prefix; | |
| 411 TemplateURLRef::SearchTermsArgs search_term_args(prefix); | |
| 412 search_term_args.zero_prefix_url = current_query_; | |
| 413 std::string req_url = default_provider->suggestions_url_ref(). | |
| 414 ReplaceSearchTerms(search_term_args); | |
| 415 GURL suggest_url(req_url); | |
| 416 // Make sure we are sending the suggest request through HTTPS. | |
| 417 if (!suggest_url.SchemeIs(content::kHttpsScheme)) { | |
| 418 Stop(true); | |
| 419 return; | |
| 420 } | |
| 421 | |
| 422 fetcher_.reset( | 349 fetcher_.reset( |
| 423 net::URLFetcher::Create(kFetcherID, | 350 net::URLFetcher::Create(kFetcherID, |
| 424 suggest_url, | 351 suggest_url, |
| 425 net::URLFetcher::GET, this)); | 352 net::URLFetcher::GET, this)); |
| 426 fetcher_->SetRequestContext(profile_->GetRequestContext()); | 353 fetcher_->SetRequestContext(profile_->GetRequestContext()); |
| 427 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | 354 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); |
| 428 // Add Chrome experiment state to the request headers. | 355 // Add Chrome experiment state to the request headers. |
| 429 net::HttpRequestHeaders headers; | 356 net::HttpRequestHeaders headers; |
| 430 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | 357 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( |
| 431 fetcher_->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); | 358 fetcher_->GetOriginalURL(), profile_->IsOffTheRecord(), false, &headers); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 match.is_history_what_you_typed_match = false; | 453 match.is_history_what_you_typed_match = false; |
| 527 match.allowed_to_be_default_match = true; | 454 match.allowed_to_be_default_match = true; |
| 528 | 455 |
| 529 // The placeholder suggestion for the current URL has high relevance so | 456 // The placeholder suggestion for the current URL has high relevance so |
| 530 // that it is in the first suggestion slot and inline autocompleted. It | 457 // that it is in the first suggestion slot and inline autocompleted. It |
| 531 // gets dropped as soon as the user types something. | 458 // gets dropped as soon as the user types something. |
| 532 match.relevance = verbatim_relevance_; | 459 match.relevance = verbatim_relevance_; |
| 533 | 460 |
| 534 return match; | 461 return match; |
| 535 } | 462 } |
| OLD | NEW |