Index: chrome/browser/autocomplete/base_search_provider.cc |
diff --git a/chrome/browser/autocomplete/base_search_provider.cc b/chrome/browser/autocomplete/base_search_provider.cc |
deleted file mode 100644 |
index 71a7049af8c21744fdcd2e55b9e3f581494bf4dc..0000000000000000000000000000000000000000 |
--- a/chrome/browser/autocomplete/base_search_provider.cc |
+++ /dev/null |
@@ -1,463 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/autocomplete/base_search_provider.h" |
- |
-#include "base/i18n/case_conversion.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "components/metrics/proto/omnibox_event.pb.h" |
-#include "components/metrics/proto/omnibox_input_type.pb.h" |
-#include "components/omnibox/autocomplete_provider_delegate.h" |
-#include "components/omnibox/autocomplete_provider_listener.h" |
-#include "components/omnibox/omnibox_field_trial.h" |
-#include "components/search_engines/template_url.h" |
-#include "components/search_engines/template_url_prepopulate_data.h" |
-#include "components/search_engines/template_url_service.h" |
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
-#include "net/url_request/url_fetcher.h" |
-#include "net/url_request/url_fetcher_delegate.h" |
-#include "url/gurl.h" |
- |
-using metrics::OmniboxEventProto; |
- |
-// SuggestionDeletionHandler ------------------------------------------------- |
- |
-// This class handles making requests to the server in order to delete |
-// personalized suggestions. |
-class SuggestionDeletionHandler : public net::URLFetcherDelegate { |
- public: |
- typedef base::Callback<void(bool, SuggestionDeletionHandler*)> |
- DeletionCompletedCallback; |
- |
- SuggestionDeletionHandler( |
- const std::string& deletion_url, |
- net::URLRequestContextGetter* request_context, |
- const DeletionCompletedCallback& callback); |
- |
- virtual ~SuggestionDeletionHandler(); |
- |
- private: |
- // net::URLFetcherDelegate: |
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; |
- |
- scoped_ptr<net::URLFetcher> deletion_fetcher_; |
- DeletionCompletedCallback callback_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SuggestionDeletionHandler); |
-}; |
- |
-SuggestionDeletionHandler::SuggestionDeletionHandler( |
- const std::string& deletion_url, |
- net::URLRequestContextGetter* request_context, |
- const DeletionCompletedCallback& callback) : callback_(callback) { |
- GURL url(deletion_url); |
- DCHECK(url.is_valid()); |
- |
- deletion_fetcher_.reset(net::URLFetcher::Create( |
- BaseSearchProvider::kDeletionURLFetcherID, |
- url, |
- net::URLFetcher::GET, |
- this)); |
- deletion_fetcher_->SetRequestContext(request_context); |
- deletion_fetcher_->Start(); |
-} |
- |
-SuggestionDeletionHandler::~SuggestionDeletionHandler() { |
-} |
- |
-void SuggestionDeletionHandler::OnURLFetchComplete( |
- const net::URLFetcher* source) { |
- DCHECK(source == deletion_fetcher_.get()); |
- callback_.Run( |
- source->GetStatus().is_success() && (source->GetResponseCode() == 200), |
- this); |
-} |
- |
-// BaseSearchProvider --------------------------------------------------------- |
- |
-// static |
-const int BaseSearchProvider::kDefaultProviderURLFetcherID = 1; |
-const int BaseSearchProvider::kKeywordProviderURLFetcherID = 2; |
-const int BaseSearchProvider::kDeletionURLFetcherID = 3; |
- |
-BaseSearchProvider::BaseSearchProvider( |
- TemplateURLService* template_url_service, |
- scoped_ptr<AutocompleteProviderDelegate> delegate, |
- AutocompleteProvider::Type type) |
- : AutocompleteProvider(type), |
- template_url_service_(template_url_service), |
- delegate_(delegate.Pass()), |
- field_trial_triggered_(false), |
- field_trial_triggered_in_session_(false) { |
-} |
- |
-// static |
-bool BaseSearchProvider::ShouldPrefetch(const AutocompleteMatch& match) { |
- return match.GetAdditionalInfo(kShouldPrefetchKey) == kTrue; |
-} |
- |
-// static |
-AutocompleteMatch BaseSearchProvider::CreateSearchSuggestion( |
- const base::string16& suggestion, |
- AutocompleteMatchType::Type type, |
- bool from_keyword_provider, |
- const TemplateURL* template_url, |
- const SearchTermsData& search_terms_data) { |
- // This call uses a number of default values. For instance, it assumes that |
- // if this match is from a keyword provider than the user is in keyword mode. |
- return CreateSearchSuggestion( |
- NULL, AutocompleteInput(), from_keyword_provider, |
- SearchSuggestionParser::SuggestResult( |
- suggestion, type, suggestion, base::string16(), base::string16(), |
- base::string16(), base::string16(), std::string(), std::string(), |
- from_keyword_provider, 0, false, false, base::string16()), |
- template_url, search_terms_data, 0, false); |
-} |
- |
-void BaseSearchProvider::DeleteMatch(const AutocompleteMatch& match) { |
- DCHECK(match.deletable); |
- if (!match.GetAdditionalInfo(BaseSearchProvider::kDeletionUrlKey).empty()) { |
- deletion_handlers_.push_back(new SuggestionDeletionHandler( |
- match.GetAdditionalInfo(BaseSearchProvider::kDeletionUrlKey), |
- delegate_->RequestContext(), |
- base::Bind(&BaseSearchProvider::OnDeletionComplete, |
- base::Unretained(this)))); |
- } |
- |
- TemplateURL* template_url = |
- match.GetTemplateURL(template_url_service_, false); |
- // This may be NULL if the template corresponding to the keyword has been |
- // deleted or there is no keyword set. |
- if (template_url != NULL) { |
- delegate_->DeleteMatchingURLsForKeywordFromHistory(template_url->id(), |
- match.contents); |
- } |
- |
- // Immediately update the list of matches to show the match was deleted, |
- // regardless of whether the server request actually succeeds. |
- DeleteMatchFromMatches(match); |
-} |
- |
-void BaseSearchProvider::AddProviderInfo(ProvidersInfo* provider_info) const { |
- provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo()); |
- metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back(); |
- new_entry.set_provider(AsOmniboxEventProviderType()); |
- new_entry.set_provider_done(done_); |
- std::vector<uint32> field_trial_hashes; |
- OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes); |
- for (size_t i = 0; i < field_trial_hashes.size(); ++i) { |
- if (field_trial_triggered_) |
- new_entry.mutable_field_trial_triggered()->Add(field_trial_hashes[i]); |
- if (field_trial_triggered_in_session_) { |
- new_entry.mutable_field_trial_triggered_in_session()->Add( |
- field_trial_hashes[i]); |
- } |
- } |
-} |
- |
-// static |
-const char BaseSearchProvider::kRelevanceFromServerKey[] = |
- "relevance_from_server"; |
-const char BaseSearchProvider::kShouldPrefetchKey[] = "should_prefetch"; |
-const char BaseSearchProvider::kSuggestMetadataKey[] = "suggest_metadata"; |
-const char BaseSearchProvider::kDeletionUrlKey[] = "deletion_url"; |
-const char BaseSearchProvider::kTrue[] = "true"; |
-const char BaseSearchProvider::kFalse[] = "false"; |
- |
-BaseSearchProvider::~BaseSearchProvider() {} |
- |
-void BaseSearchProvider::SetDeletionURL(const std::string& deletion_url, |
- AutocompleteMatch* match) { |
- if (deletion_url.empty()) |
- return; |
- if (!template_url_service_) |
- return; |
- GURL url = |
- template_url_service_->GetDefaultSearchProvider()->GenerateSearchURL( |
- template_url_service_->search_terms_data()); |
- url = url.GetOrigin().Resolve(deletion_url); |
- if (url.is_valid()) { |
- match->RecordAdditionalInfo(BaseSearchProvider::kDeletionUrlKey, |
- url.spec()); |
- match->deletable = true; |
- } |
-} |
- |
-// static |
-AutocompleteMatch BaseSearchProvider::CreateSearchSuggestion( |
- AutocompleteProvider* autocomplete_provider, |
- const AutocompleteInput& input, |
- const bool in_keyword_mode, |
- const SearchSuggestionParser::SuggestResult& suggestion, |
- const TemplateURL* template_url, |
- const SearchTermsData& search_terms_data, |
- int accepted_suggestion, |
- bool append_extra_query_params) { |
- AutocompleteMatch match(autocomplete_provider, suggestion.relevance(), false, |
- suggestion.type()); |
- |
- if (!template_url) |
- return match; |
- match.keyword = template_url->keyword(); |
- match.contents = suggestion.match_contents(); |
- match.contents_class = suggestion.match_contents_class(); |
- match.answer_contents = suggestion.answer_contents(); |
- match.answer_type = suggestion.answer_type(); |
- if (suggestion.type() == AutocompleteMatchType::SEARCH_SUGGEST_INFINITE) { |
- match.RecordAdditionalInfo( |
- kACMatchPropertyInputText, base::UTF16ToUTF8(input.text())); |
- match.RecordAdditionalInfo( |
- kACMatchPropertyContentsPrefix, |
- base::UTF16ToUTF8(suggestion.match_contents_prefix())); |
- match.RecordAdditionalInfo( |
- kACMatchPropertyContentsStartIndex, |
- static_cast<int>( |
- suggestion.suggestion().length() - match.contents.length())); |
- } |
- |
- if (!suggestion.annotation().empty()) |
- match.description = suggestion.annotation(); |
- |
- // suggestion.match_contents() should have already been collapsed. |
- match.allowed_to_be_default_match = |
- (!in_keyword_mode || suggestion.from_keyword_provider()) && |
- (base::CollapseWhitespace(input.text(), false) == |
- suggestion.match_contents()); |
- |
- // When the user forced a query, we need to make sure all the fill_into_edit |
- // values preserve that property. Otherwise, if the user starts editing a |
- // suggestion, non-Search results will suddenly appear. |
- if (input.type() == metrics::OmniboxInputType::FORCED_QUERY) |
- match.fill_into_edit.assign(base::ASCIIToUTF16("?")); |
- if (suggestion.from_keyword_provider()) |
- match.fill_into_edit.append(match.keyword + base::char16(' ')); |
- if (!input.prevent_inline_autocomplete() && |
- (!in_keyword_mode || suggestion.from_keyword_provider()) && |
- StartsWith(suggestion.suggestion(), input.text(), false)) { |
- match.inline_autocompletion = |
- suggestion.suggestion().substr(input.text().length()); |
- match.allowed_to_be_default_match = true; |
- } |
- match.fill_into_edit.append(suggestion.suggestion()); |
- |
- const TemplateURLRef& search_url = template_url->url_ref(); |
- DCHECK(search_url.SupportsReplacement(search_terms_data)); |
- match.search_terms_args.reset( |
- new TemplateURLRef::SearchTermsArgs(suggestion.suggestion())); |
- match.search_terms_args->original_query = input.text(); |
- match.search_terms_args->accepted_suggestion = accepted_suggestion; |
- match.search_terms_args->enable_omnibox_start_margin = true; |
- match.search_terms_args->suggest_query_params = |
- suggestion.suggest_query_params(); |
- match.search_terms_args->append_extra_query_params = |
- append_extra_query_params; |
- // This is the destination URL sans assisted query stats. This must be set |
- // so the AutocompleteController can properly de-dupe; the controller will |
- // eventually overwrite it before it reaches the user. |
- match.destination_url = |
- GURL(search_url.ReplaceSearchTerms(*match.search_terms_args.get(), |
- search_terms_data)); |
- |
- // Search results don't look like URLs. |
- match.transition = suggestion.from_keyword_provider() ? |
- content::PAGE_TRANSITION_KEYWORD : content::PAGE_TRANSITION_GENERATED; |
- |
- return match; |
-} |
- |
-// static |
-bool BaseSearchProvider::ZeroSuggestEnabled( |
- const GURL& suggest_url, |
- const TemplateURL* template_url, |
- OmniboxEventProto::PageClassification page_classification, |
- const SearchTermsData& search_terms_data, |
- AutocompleteProviderDelegate* delegate) { |
- if (!OmniboxFieldTrial::InZeroSuggestFieldTrial()) |
- return false; |
- |
- // Make sure we are sending the suggest request through HTTPS to prevent |
- // exposing the current page URL or personalized results without encryption. |
- if (!suggest_url.SchemeIs(url::kHttpsScheme)) |
- return false; |
- |
- // Don't show zero suggest on the NTP. |
- // TODO(hfung): Experiment with showing MostVisited zero suggest on NTP |
- // under the conditions described in crbug.com/305366. |
- if ((page_classification == |
- OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS) || |
- (page_classification == |
- OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS)) |
- return false; |
- |
- // Don't run if in incognito mode. |
- if (delegate->IsOffTheRecord()) |
- return false; |
- |
- // Don't run if we can't get preferences or search suggest is not enabled. |
- if (!delegate->SearchSuggestEnabled()) |
- return false; |
- |
- // Only make the request if we know that the provider supports zero suggest |
- // (currently only the prepopulated Google provider). |
- if (template_url == NULL || |
- !template_url->SupportsReplacement(search_terms_data) || |
- TemplateURLPrepopulateData::GetEngineType( |
- *template_url, search_terms_data) != SEARCH_ENGINE_GOOGLE) |
- return false; |
- |
- return true; |
-} |
- |
-// static |
-bool BaseSearchProvider::CanSendURL( |
- const GURL& current_page_url, |
- const GURL& suggest_url, |
- const TemplateURL* template_url, |
- OmniboxEventProto::PageClassification page_classification, |
- const SearchTermsData& search_terms_data, |
- AutocompleteProviderDelegate* delegate) { |
- if (!ZeroSuggestEnabled(suggest_url, template_url, page_classification, |
- search_terms_data, delegate)) |
- return false; |
- |
- if (!current_page_url.is_valid()) |
- return false; |
- |
- // Only allow HTTP URLs or HTTPS URLs for the same domain as the search |
- // provider. |
- if ((current_page_url.scheme() != url::kHttpScheme) && |
- ((current_page_url.scheme() != url::kHttpsScheme) || |
- !net::registry_controlled_domains::SameDomainOrHost( |
- current_page_url, suggest_url, |
- net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES))) |
- return false; |
- |
- if (!delegate->TabSyncEnabledAndUnencrypted()) |
- return false; |
- |
- return true; |
-} |
- |
-void BaseSearchProvider::AddMatchToMap( |
- const SearchSuggestionParser::SuggestResult& result, |
- const std::string& metadata, |
- int accepted_suggestion, |
- bool mark_as_deletable, |
- bool in_keyword_mode, |
- MatchMap* map) { |
- AutocompleteMatch match = CreateSearchSuggestion( |
- this, GetInput(result.from_keyword_provider()), in_keyword_mode, result, |
- GetTemplateURL(result.from_keyword_provider()), |
- template_url_service_->search_terms_data(), accepted_suggestion, |
- ShouldAppendExtraParams(result)); |
- if (!match.destination_url.is_valid()) |
- return; |
- match.search_terms_args->bookmark_bar_pinned = delegate_->ShowBookmarkBar(); |
- match.RecordAdditionalInfo(kRelevanceFromServerKey, |
- result.relevance_from_server() ? kTrue : kFalse); |
- match.RecordAdditionalInfo(kShouldPrefetchKey, |
- result.should_prefetch() ? kTrue : kFalse); |
- SetDeletionURL(result.deletion_url(), &match); |
- if (mark_as_deletable) |
- match.deletable = true; |
- // Metadata is needed only for prefetching queries. |
- if (result.should_prefetch()) |
- match.RecordAdditionalInfo(kSuggestMetadataKey, metadata); |
- |
- // Try to add |match| to |map|. If a match for this suggestion is |
- // already in |map|, replace it if |match| is more relevant. |
- // NOTE: Keep this ToLower() call in sync with url_database.cc. |
- MatchKey match_key( |
- std::make_pair(base::i18n::ToLower(result.suggestion()), |
- match.search_terms_args->suggest_query_params)); |
- const std::pair<MatchMap::iterator, bool> i( |
- map->insert(std::make_pair(match_key, match))); |
- |
- bool should_prefetch = result.should_prefetch(); |
- if (!i.second) { |
- // NOTE: We purposefully do a direct relevance comparison here instead of |
- // using AutocompleteMatch::MoreRelevant(), so that we'll prefer "items |
- // added first" rather than "items alphabetically first" when the scores |
- // are equal. The only case this matters is when a user has results with |
- // the same score that differ only by capitalization; because the history |
- // system returns results sorted by recency, this means we'll pick the most |
- // recent such result even if the precision of our relevance score is too |
- // low to distinguish the two. |
- if (match.relevance > i.first->second.relevance) { |
- match.duplicate_matches.insert(match.duplicate_matches.end(), |
- i.first->second.duplicate_matches.begin(), |
- i.first->second.duplicate_matches.end()); |
- i.first->second.duplicate_matches.clear(); |
- match.duplicate_matches.push_back(i.first->second); |
- i.first->second = match; |
- } else { |
- i.first->second.duplicate_matches.push_back(match); |
- if (match.keyword == i.first->second.keyword) { |
- // Old and new matches are from the same search provider. It is okay to |
- // record one match's prefetch data onto a different match (for the same |
- // query string) for the following reasons: |
- // 1. Because the suggest server only sends down a query string from |
- // which we construct a URL, rather than sending a full URL, and because |
- // we construct URLs from query strings in the same way every time, the |
- // URLs for the two matches will be the same. Therefore, we won't end up |
- // prefetching something the server didn't intend. |
- // 2. Presumably the server sets the prefetch bit on a match it things |
- // is sufficiently relevant that the user is likely to choose it. |
- // Surely setting the prefetch bit on a match of even higher relevance |
- // won't violate this assumption. |
- should_prefetch |= ShouldPrefetch(i.first->second); |
- i.first->second.RecordAdditionalInfo(kShouldPrefetchKey, |
- should_prefetch ? kTrue : kFalse); |
- if (should_prefetch) |
- i.first->second.RecordAdditionalInfo(kSuggestMetadataKey, metadata); |
- } |
- } |
- } |
-} |
- |
-bool BaseSearchProvider::ParseSuggestResults( |
- const base::Value& root_val, |
- int default_result_relevance, |
- bool is_keyword_result, |
- SearchSuggestionParser::Results* results) { |
- if (!SearchSuggestionParser::ParseSuggestResults( |
- root_val, GetInput(is_keyword_result), |
- delegate_->SchemeClassifier(), default_result_relevance, |
- delegate_->AcceptLanguages(), is_keyword_result, results)) |
- return false; |
- |
- for (std::vector<GURL>::const_iterator it = |
- results->answers_image_urls.begin(); |
- it != results->answers_image_urls.end(); ++it) |
- delegate_->PrefetchImage(*it); |
- |
- field_trial_triggered_ |= results->field_trial_triggered; |
- field_trial_triggered_in_session_ |= results->field_trial_triggered; |
- return true; |
-} |
- |
-void BaseSearchProvider::DeleteMatchFromMatches( |
- const AutocompleteMatch& match) { |
- for (ACMatches::iterator i(matches_.begin()); i != matches_.end(); ++i) { |
- // Find the desired match to delete by checking the type and contents. |
- // We can't check the destination URL, because the autocomplete controller |
- // may have reformulated that. Not that while checking for matching |
- // contents works for personalized suggestions, if more match types gain |
- // deletion support, this algorithm may need to be re-examined. |
- if (i->contents == match.contents && i->type == match.type) { |
- matches_.erase(i); |
- break; |
- } |
- } |
-} |
- |
-void BaseSearchProvider::OnDeletionComplete( |
- bool success, SuggestionDeletionHandler* handler) { |
- RecordDeletionResult(success); |
- SuggestionDeletionHandlers::iterator it = std::find( |
- deletion_handlers_.begin(), deletion_handlers_.end(), handler); |
- DCHECK(it != deletion_handlers_.end()); |
- deletion_handlers_.erase(it); |
-} |