| // Copyright (c) 2012 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. |
| // |
| // This file contains the Search autocomplete provider. This provider is |
| // responsible for all autocomplete entries that start with "Search <engine> |
| // for ...", including searching for the current input string, search |
| // history, and search suggestions. An instance of it gets created and |
| // managed by the autocomplete controller. |
| |
| #ifndef COMPONENTS_OMNIBOX_BROWSER_SEARCH_PROVIDER_H_ |
| #define COMPONENTS_OMNIBOX_BROWSER_SEARCH_PROVIDER_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/macros.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "components/omnibox/browser/answers_cache.h" |
| #include "components/omnibox/browser/base_search_provider.h" |
| #include "components/search_engines/template_url.h" |
| #include "components/search_engines/template_url_service_observer.h" |
| #include "third_party/metrics_proto/omnibox_input_type.pb.h" |
| |
| class AutocompleteProviderClient; |
| class AutocompleteProviderListener; |
| class AutocompleteResult; |
| class SearchProviderTest; |
| class TemplateURLService; |
| |
| namespace history { |
| struct KeywordSearchTermVisit; |
| } |
| |
| namespace network { |
| class SimpleURLLoader; |
| } |
| |
| // Autocomplete provider for searches and suggestions from a search engine. |
| // |
| // After construction, the autocomplete controller repeatedly calls Start() |
| // with some user input, each time expecting to receive a small set of the best |
| // matches (either synchronously or asynchronously). |
| // |
| // Initially the provider creates a match that searches for the current input |
| // text. It also starts a task to query the Suggest servers. When that data |
| // comes back, the provider creates and returns matches for the best |
| // suggestions. |
| class SearchProvider : public BaseSearchProvider, |
| public TemplateURLServiceObserver { |
| public: |
| SearchProvider(AutocompleteProviderClient* client, |
| AutocompleteProviderListener* listener); |
| |
| // Extracts the suggest response metadata which SearchProvider previously |
| // stored for |match|. |
| static std::string GetSuggestMetadata(const AutocompleteMatch& match); |
| |
| // Answers prefetch handling - register displayed answers. Takes the top |
| // match for Autocomplete and registers the contained answer data, if any. |
| void RegisterDisplayedAnswers(const AutocompleteResult& result); |
| |
| // Calculates the relevance score for the keyword verbatim result (if the |
| // input matches one of the profile's keywords). If |
| // |allow_exact_keyword_match| is false, the relevance for complete |
| // keywords that support replacements is degraded. |
| static int CalculateRelevanceForKeywordVerbatim( |
| metrics::OmniboxInputType type, |
| bool allow_exact_keyword_match, |
| bool prefer_keyword); |
| |
| // AutocompleteProvider: |
| void ResetSession() override; |
| |
| protected: |
| ~SearchProvider() override; |
| |
| private: |
| friend class AutocompleteProviderTest; |
| friend class SearchProviderTest; |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, CanSendURL); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, |
| DontInlineAutocompleteAsynchronously); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInline); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineDomainClassify); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineSchemeSubstring); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestRelevanceExperiment); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, TestDeleteMatch); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestQueryUsesToken); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SessionToken); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, AnswersCache); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, RemoveExtraAnswers); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, DoesNotProvideOnFocus); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SendsWarmUpRequestOnFocus); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, DoTrimHttpScheme); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, |
| DontTrimHttpSchemeIfInputHasScheme); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, |
| DontTrimHttpsSchemeIfInputHasScheme); |
| FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, DoTrimHttpsScheme); |
| FRIEND_TEST_ALL_PREFIXES(InstantExtendedPrefetchTest, ClearPrefetchedResults); |
| FRIEND_TEST_ALL_PREFIXES(InstantExtendedPrefetchTest, SetPrefetchQuery); |
| |
| // Manages the providers (TemplateURLs) used by SearchProvider. Two providers |
| // may be used: |
| // . The default provider. This corresponds to the user's default search |
| // engine. This is always used, except for the rare case of no default |
| // engine. |
| // . The keyword provider. This is used if the user has typed in a keyword. |
| class Providers { |
| public: |
| explicit Providers(TemplateURLService* template_url_service); |
| |
| // Returns true if the specified providers match the two providers cached |
| // by this class. |
| bool equal(const base::string16& default_provider, |
| const base::string16& keyword_provider) const { |
| return (default_provider == default_provider_) && |
| (keyword_provider == keyword_provider_); |
| } |
| |
| // Resets the cached providers. |
| void set(const base::string16& default_provider, |
| const base::string16& keyword_provider) { |
| default_provider_ = default_provider; |
| keyword_provider_ = keyword_provider; |
| } |
| |
| TemplateURLService* template_url_service() { return template_url_service_; } |
| const base::string16& default_provider() const { return default_provider_; } |
| const base::string16& keyword_provider() const { return keyword_provider_; } |
| |
| // NOTE: These may return NULL even if the provider members are nonempty! |
| const TemplateURL* GetDefaultProviderURL() const; |
| const TemplateURL* GetKeywordProviderURL() const; |
| |
| // Returns true if there is a valid keyword provider. |
| bool has_keyword_provider() const { return !keyword_provider_.empty(); } |
| |
| private: |
| TemplateURLService* template_url_service_; |
| |
| // Cached across the life of a query so we behave consistently even if the |
| // user changes their default while the query is running. |
| base::string16 default_provider_; |
| base::string16 keyword_provider_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Providers); |
| }; |
| |
| class CompareScoredResults; |
| |
| typedef std::vector<history::KeywordSearchTermVisit> HistoryResults; |
| |
| // A helper function for UpdateAllOldResults(). |
| static void UpdateOldResults(bool minimal_changes, |
| SearchSuggestionParser::Results* results); |
| |
| // AutocompleteProvider: |
| void Start(const AutocompleteInput& input, bool minimal_changes) override; |
| void Stop(bool clear_cached_results, |
| bool due_to_user_inactivity) override; |
| |
| // BaseSearchProvider: |
| const TemplateURL* GetTemplateURL(bool is_keyword) const override; |
| const AutocompleteInput GetInput(bool is_keyword) const override; |
| bool ShouldAppendExtraParams( |
| const SearchSuggestionParser::SuggestResult& result) const override; |
| void RecordDeletionResult(bool success) override; |
| |
| // TemplateURLServiceObserver: |
| void OnTemplateURLServiceChanged() override; |
| |
| // Called back from SimpleURLLoader. |
| void OnURLLoadComplete(const network::SimpleURLLoader* source, |
| std::unique_ptr<std::string> response_body); |
| |
| // Stops the suggest query. |
| // NOTE: This does not update |done_|. Callers must do so. |
| void StopSuggest(); |
| |
| // Clears the current results. |
| void ClearAllResults(); |
| |
| // Recalculates the match contents class of |results| to better display |
| // against the current input and user's language. |
| void UpdateMatchContentsClass(const base::string16& input_text, |
| SearchSuggestionParser::Results* results); |
| |
| // Called after ParseSuggestResults to rank the |results|. |
| void SortResults(bool is_keyword, SearchSuggestionParser::Results* results); |
| |
| // Records UMA statistics about a suggest server response. |
| void LogLoadComplete(bool success, bool is_keyword); |
| |
| // Updates |matches_| from the latest results; applies calculated relevances |
| // if suggested relevances cause undesirable behavior. Updates |done_|. |
| void UpdateMatches(); |
| |
| // Checks constraints that may be violated by suggested relevances and |
| // revises/rolls back the suggested relevance scores to make all constraints |
| // hold. |
| void EnforceConstraints(); |
| |
| // Records the top suggestion (if any) for future use. SearchProvider tries |
| // to ensure that an inline autocomplete suggestion does not change |
| // asynchronously. |
| void RecordTopSuggestion(); |
| |
| // Called when |timer_| expires. Sends the suggest requests. |
| // If |query_is_private|, the function doesn't send this query to the default |
| // provider. |
| void Run(bool query_is_private); |
| |
| // Runs the history query, if necessary. The history query is synchronous. |
| // This does not update |done_|. |
| void DoHistoryQuery(bool minimal_changes); |
| |
| // Returns the time to delay before sending the Suggest request. |
| base::TimeDelta GetSuggestQueryDelay() const; |
| |
| // Determines whether an asynchronous subcomponent query should run for the |
| // current input. If so, starts it if necessary; otherwise stops it. |
| // NOTE: This function does not update |done_|. Callers must do so. |
| void StartOrStopSuggestQuery(bool minimal_changes); |
| |
| // Stops |loader| if it's running. This includes resetting the unique_ptr. |
| void CancelLoader(std::unique_ptr<network::SimpleURLLoader>* loader); |
| |
| // Returns true when the current query can be sent to at least one suggest |
| // service. This will be false for example when suggest is disabled. In |
| // the process, calculates whether the query may contain potentially |
| // private data and stores the result in |is_query_private|; such queries |
| // should not be sent to the default search engine. |
| bool IsQuerySuitableForSuggest(bool* query_is_private) const; |
| |
| // Returns true if sending the query to a suggest server may leak sensitive |
| // information (and hence the suggest request shouldn't be sent). In |
| // particular, if the input type might be a URL, we take extra care so that |
| // it isn't sent to the server. |
| bool IsQueryPotentiallyPrivate() const; |
| |
| // Remove existing keyword results if the user is no longer in keyword mode, |
| // and, if |minimal_changes| is false, revise the existing results to |
| // indicate they were received before the last keystroke. |
| void UpdateAllOldResults(bool minimal_changes); |
| |
| // Given new asynchronous results, ensure that we don't clobber the current |
| // top results, which were determined synchronously on the last keystroke. |
| void PersistTopSuggestions(SearchSuggestionParser::Results* results); |
| |
| // Apply calculated relevance scores to the current results. |
| void ApplyCalculatedSuggestRelevance( |
| SearchSuggestionParser::SuggestResults* list); |
| void ApplyCalculatedNavigationRelevance( |
| SearchSuggestionParser::NavigationResults* list); |
| |
| // Starts a new SimpleURLLoader requesting suggest results from |
| // |template_url|; callers own the returned SimpleURLLoader, which is NULL for |
| // invalid providers. |
| std::unique_ptr<network::SimpleURLLoader> CreateSuggestLoader( |
| const TemplateURL* template_url, |
| const AutocompleteInput& input); |
| |
| // Converts the parsed results to a set of AutocompleteMatches, |matches_|. |
| void ConvertResultsToAutocompleteMatches(); |
| |
| // Remove answer contents from each match in |matches| other than the first |
| // that appears. |
| static void RemoveExtraAnswers(ACMatches* matches); |
| |
| // Checks if suggested relevances violate an expected constraint. |
| // See UpdateMatches() for the use and explanation of this constraint |
| // and other constraints enforced without the use of helper functions. |
| bool IsTopMatchSearchWithURLInput() const; |
| |
| // Converts an appropriate number of navigation results in |
| // |navigation_results| to matches and adds them to |matches|. |
| void AddNavigationResultsToMatches( |
| const SearchSuggestionParser::NavigationResults& navigation_results, |
| ACMatches* matches); |
| |
| // Adds a match for each result in |raw_default_history_results_| or |
| // |raw_keyword_history_results_| to |map|. |is_keyword| indicates |
| // which one of the two. |
| void AddRawHistoryResultsToMap(bool is_keyword, |
| int did_not_accept_suggestion, |
| MatchMap* map); |
| |
| // Adds a match for each transformed result in |results| to |map|. |
| void AddTransformedHistoryResultsToMap( |
| const SearchSuggestionParser::SuggestResults& results, |
| int did_not_accept_suggestion, |
| MatchMap* map); |
| |
| // Calculates relevance scores for all |results|. |
| SearchSuggestionParser::SuggestResults ScoreHistoryResultsHelper( |
| const HistoryResults& results, |
| bool base_prevent_inline_autocomplete, |
| bool input_multiple_words, |
| const base::string16& input_text, |
| bool is_keyword); |
| |
| // Calculates relevance scores for |results|, adjusting for boundary |
| // conditions around multi-word queries. (See inline comments in function |
| // definition for more details.) |
| void ScoreHistoryResults( |
| const HistoryResults& results, |
| bool is_keyword, |
| SearchSuggestionParser::SuggestResults* scored_results); |
| |
| // Adds matches for |results| to |map|. |
| void AddSuggestResultsToMap( |
| const SearchSuggestionParser::SuggestResults& results, |
| const std::string& metadata, |
| MatchMap* map); |
| |
| // Gets the relevance score for the verbatim result. This value may be |
| // provided by the suggest server or calculated locally; if |
| // |relevance_from_server| is non-null, it will be set to indicate which of |
| // those is true. |
| int GetVerbatimRelevance(bool* relevance_from_server) const; |
| |
| // Calculates the relevance score for the verbatim result from the |
| // default search engine. This version takes into account context: |
| // i.e., whether the user has entered a keyword-based search or not. |
| int CalculateRelevanceForVerbatim() const; |
| |
| // Calculates the relevance score for the verbatim result from the default |
| // search engine *ignoring* whether the input is a keyword-based search |
| // or not. This function should only be used to determine the minimum |
| // relevance score that the best result from this provider should have. |
| // For normal use, prefer the above function. |
| int CalculateRelevanceForVerbatimIgnoringKeywordModeState() const; |
| |
| // Gets the relevance score for the keyword verbatim result. |
| // |relevance_from_server| is handled as in GetVerbatimRelevance(). |
| // TODO(mpearson): Refactor so this duplication isn't necessary or |
| // restructure so one static function takes all the parameters it needs |
| // (rather than looking at internal state). |
| int GetKeywordVerbatimRelevance(bool* relevance_from_server) const; |
| |
| // |time| is the time at which this query was last seen. |is_keyword| |
| // indicates whether the results correspond to the keyword provider or default |
| // provider. |use_aggressive_method| says whether this function can use a |
| // method that gives high scores (1200+) rather than one that gives lower |
| // scores. When using the aggressive method, scores may exceed 1300 |
| // unless |prevent_search_history_inlining| is set. |
| int CalculateRelevanceForHistory(const base::Time& time, |
| bool is_keyword, |
| bool use_aggressive_method, |
| bool prevent_search_history_inlining) const; |
| |
| // Returns an AutocompleteMatch for a navigational suggestion. |
| AutocompleteMatch NavigationToMatch( |
| const SearchSuggestionParser::NavigationResult& navigation); |
| |
| // Updates the value of |done_| from the internal state. |
| void UpdateDone(); |
| |
| // Obtains a session token, regenerating if necessary. |
| std::string GetSessionToken(); |
| |
| // Answers prefetch handling - finds the previously displayed answer matching |
| // the current top-scoring history result. If there is a previous answer, |
| // returns the query data associated with it. Otherwise, returns an empty |
| // AnswersQueryData. |
| AnswersQueryData FindAnswersPrefetchData(); |
| |
| AutocompleteProviderListener* listener_; |
| |
| // Maintains the TemplateURLs used. |
| Providers providers_; |
| |
| // The user's input. |
| AutocompleteInput input_; |
| |
| // Input when searching against the keyword provider. |
| AutocompleteInput keyword_input_; |
| |
| // Searches in the user's history that begin with the input text. |
| HistoryResults raw_keyword_history_results_; |
| HistoryResults raw_default_history_results_; |
| |
| // Scored searches in the user's history - based on |keyword_history_results_| |
| // or |default_history_results_| as appropriate. |
| SearchSuggestionParser::SuggestResults transformed_keyword_history_results_; |
| SearchSuggestionParser::SuggestResults transformed_default_history_results_; |
| |
| // A timer to start a query to the suggest server after the user has stopped |
| // typing for long enough. |
| base::OneShotTimer timer_; |
| |
| // The time at which we sent a query to the suggest server. |
| base::TimeTicks time_suggest_request_sent_; |
| |
| // Loaders used to retrieve results for the keyword and default providers. |
| // After a loader's results are returned, it gets reset, so a non-null |
| // loader indicates that loader is still in flight. |
| std::unique_ptr<network::SimpleURLLoader> keyword_loader_; |
| std::unique_ptr<network::SimpleURLLoader> default_loader_; |
| |
| // Results from the default and keyword search providers. |
| SearchSuggestionParser::Results default_results_; |
| SearchSuggestionParser::Results keyword_results_; |
| |
| // The top query suggestion, left blank if none. |
| base::string16 top_query_suggestion_match_contents_; |
| // The top navigation suggestion, left blank/invalid if none. |
| GURL top_navigation_suggestion_; |
| |
| // Session token management. |
| std::string current_token_; |
| base::TimeTicks token_expiration_time_; |
| |
| // Answers prefetch management. |
| AnswersCache answers_cache_; // Cache for last answers seen. |
| AnswersQueryData prefetch_data_; // Data to use for query prefetching. |
| |
| DISALLOW_COPY_AND_ASSIGN(SearchProvider); |
| }; |
| |
| #endif // COMPONENTS_OMNIBOX_BROWSER_SEARCH_PROVIDER_H_ |