Home | History | Annotate | Download | only in omnibox
      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
      3 // found in the LICENSE file.
      4 //
      5 // This file contains the Search autocomplete provider.  This provider is
      6 // responsible for all autocomplete entries that start with "Search <engine>
      7 // for ...", including searching for the current input string, search
      8 // history, and search suggestions.  An instance of it gets created and
      9 // managed by the autocomplete controller.
     10 
     11 #ifndef COMPONENTS_OMNIBOX_SEARCH_PROVIDER_H_
     12 #define COMPONENTS_OMNIBOX_SEARCH_PROVIDER_H_
     13 
     14 #include <string>
     15 #include <vector>
     16 
     17 #include "base/basictypes.h"
     18 #include "base/compiler_specific.h"
     19 #include "base/memory/scoped_ptr.h"
     20 #include "base/time/time.h"
     21 #include "base/timer/timer.h"
     22 #include "components/metrics/proto/omnibox_input_type.pb.h"
     23 #include "components/omnibox/answers_cache.h"
     24 #include "components/omnibox/base_search_provider.h"
     25 #include "components/search_engines/template_url.h"
     26 #include "net/url_request/url_fetcher_delegate.h"
     27 
     28 class AutocompleteProviderClient;
     29 class AutocompleteProviderListener;
     30 class AutocompleteResult;
     31 class SearchProviderTest;
     32 class TemplateURLService;
     33 
     34 namespace history {
     35 struct KeywordSearchTermVisit;
     36 }
     37 
     38 namespace net {
     39 class URLFetcher;
     40 }
     41 
     42 // Autocomplete provider for searches and suggestions from a search engine.
     43 //
     44 // After construction, the autocomplete controller repeatedly calls Start()
     45 // with some user input, each time expecting to receive a small set of the best
     46 // matches (either synchronously or asynchronously).
     47 //
     48 // Initially the provider creates a match that searches for the current input
     49 // text.  It also starts a task to query the Suggest servers.  When that data
     50 // comes back, the provider creates and returns matches for the best
     51 // suggestions.
     52 class SearchProvider : public BaseSearchProvider,
     53                        public net::URLFetcherDelegate {
     54  public:
     55   SearchProvider(AutocompleteProviderListener* listener,
     56                  TemplateURLService* template_url_service,
     57                  scoped_ptr<AutocompleteProviderClient> client);
     58 
     59   // Extracts the suggest response metadata which SearchProvider previously
     60   // stored for |match|.
     61   static std::string GetSuggestMetadata(const AutocompleteMatch& match);
     62 
     63   // Answers prefetch handling - register displayed answers. Takes the top
     64   // match for Autocomplete and registers the contained answer data, if any.
     65   void RegisterDisplayedAnswers(const AutocompleteResult& result);
     66 
     67   // AutocompleteProvider:
     68   virtual void ResetSession() OVERRIDE;
     69 
     70   // This URL may be sent with suggest requests; see comments on CanSendURL().
     71   void set_current_page_url(const GURL& current_page_url) {
     72     current_page_url_ = current_page_url;
     73   }
     74 
     75  protected:
     76   virtual ~SearchProvider();
     77 
     78  private:
     79   friend class SearchProviderTest;
     80   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, CanSendURL);
     81   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest,
     82                            DontInlineAutocompleteAsynchronously);
     83   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInline);
     84   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineDomainClassify);
     85   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, NavigationInlineSchemeSubstring);
     86   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestRelevanceExperiment);
     87   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, TestDeleteMatch);
     88   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SuggestQueryUsesToken);
     89   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, SessionToken);
     90   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, AnswersCache);
     91   FRIEND_TEST_ALL_PREFIXES(SearchProviderTest, RemoveExtraAnswers);
     92   FRIEND_TEST_ALL_PREFIXES(AutocompleteProviderTest, GetDestinationURL);
     93   FRIEND_TEST_ALL_PREFIXES(InstantExtendedPrefetchTest, ClearPrefetchedResults);
     94   FRIEND_TEST_ALL_PREFIXES(InstantExtendedPrefetchTest, SetPrefetchQuery);
     95 
     96   // Manages the providers (TemplateURLs) used by SearchProvider. Two providers
     97   // may be used:
     98   // . The default provider. This corresponds to the user's default search
     99   //   engine. This is always used, except for the rare case of no default
    100   //   engine.
    101   // . The keyword provider. This is used if the user has typed in a keyword.
    102   class Providers {
    103    public:
    104     explicit Providers(TemplateURLService* template_url_service);
    105 
    106     // Returns true if the specified providers match the two providers cached
    107     // by this class.
    108     bool equal(const base::string16& default_provider,
    109                const base::string16& keyword_provider) const {
    110       return (default_provider == default_provider_) &&
    111           (keyword_provider == keyword_provider_);
    112     }
    113 
    114     // Resets the cached providers.
    115     void set(const base::string16& default_provider,
    116              const base::string16& keyword_provider) {
    117       default_provider_ = default_provider;
    118       keyword_provider_ = keyword_provider;
    119     }
    120 
    121     TemplateURLService* template_url_service() { return template_url_service_; }
    122     const base::string16& default_provider() const { return default_provider_; }
    123     const base::string16& keyword_provider() const { return keyword_provider_; }
    124 
    125     // NOTE: These may return NULL even if the provider members are nonempty!
    126     const TemplateURL* GetDefaultProviderURL() const;
    127     const TemplateURL* GetKeywordProviderURL() const;
    128 
    129     // Returns true if there is a valid keyword provider.
    130     bool has_keyword_provider() const { return !keyword_provider_.empty(); }
    131 
    132    private:
    133     TemplateURLService* template_url_service_;
    134 
    135     // Cached across the life of a query so we behave consistently even if the
    136     // user changes their default while the query is running.
    137     base::string16 default_provider_;
    138     base::string16 keyword_provider_;
    139 
    140     DISALLOW_COPY_AND_ASSIGN(Providers);
    141   };
    142 
    143   class CompareScoredResults;
    144 
    145   typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
    146 
    147   // Calculates the relevance score for the keyword verbatim result (if the
    148   // input matches one of the profile's keyword).
    149   static int CalculateRelevanceForKeywordVerbatim(
    150       metrics::OmniboxInputType::Type type,
    151       bool prefer_keyword);
    152 
    153   // A helper function for UpdateAllOldResults().
    154   static void UpdateOldResults(bool minimal_changes,
    155                                SearchSuggestionParser::Results* results);
    156 
    157   // Returns the first match in |matches| which might be chosen as default.
    158   static ACMatches::iterator FindTopMatch(ACMatches* matches);
    159 
    160   // AutocompleteProvider:
    161   virtual void Start(const AutocompleteInput& input,
    162                      bool minimal_changes) OVERRIDE;
    163   virtual void Stop(bool clear_cached_results) OVERRIDE;
    164 
    165   // BaseSearchProvider:
    166   virtual const TemplateURL* GetTemplateURL(bool is_keyword) const OVERRIDE;
    167   virtual const AutocompleteInput GetInput(bool is_keyword) const OVERRIDE;
    168   virtual bool ShouldAppendExtraParams(
    169       const SearchSuggestionParser::SuggestResult& result) const OVERRIDE;
    170   virtual void RecordDeletionResult(bool success) OVERRIDE;
    171 
    172   // net::URLFetcherDelegate:
    173   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
    174 
    175   // Stops the suggest query.
    176   // NOTE: This does not update |done_|.  Callers must do so.
    177   void StopSuggest();
    178 
    179   // Clears the current results.
    180   void ClearAllResults();
    181 
    182   // Recalculates the match contents class of |results| to better display
    183   // against the current input and user's language.
    184   void UpdateMatchContentsClass(const base::string16& input_text,
    185                                 SearchSuggestionParser::Results* results);
    186 
    187   // Called after ParseSuggestResults to rank the |results|.
    188   void SortResults(bool is_keyword, SearchSuggestionParser::Results* results);
    189 
    190   // Records UMA statistics about a suggest server response.
    191   void LogFetchComplete(bool success, bool is_keyword);
    192 
    193   // Updates |matches_| from the latest results; applies calculated relevances
    194   // if suggested relevances cause undesirable behavior. Updates |done_|.
    195   void UpdateMatches();
    196 
    197   // Called when timer_ expires.
    198   void Run();
    199 
    200   // Runs the history query, if necessary. The history query is synchronous.
    201   // This does not update |done_|.
    202   void DoHistoryQuery(bool minimal_changes);
    203 
    204   // Determines whether an asynchronous subcomponent query should run for the
    205   // current input.  If so, starts it if necessary; otherwise stops it.
    206   // NOTE: This function does not update |done_|.  Callers must do so.
    207   void StartOrStopSuggestQuery(bool minimal_changes);
    208 
    209   // Returns true when the current query can be sent to the Suggest service.
    210   // This will be false e.g. when Suggest is disabled, the query contains
    211   // potentially private data, etc.
    212   bool IsQuerySuitableForSuggest() const;
    213 
    214   // Remove existing keyword results if the user is no longer in keyword mode,
    215   // and, if |minimal_changes| is false, revise the existing results to
    216   // indicate they were received before the last keystroke.
    217   void UpdateAllOldResults(bool minimal_changes);
    218 
    219   // Given new asynchronous results, ensure that we don't clobber the current
    220   // top results, which were determined synchronously on the last keystroke.
    221   void PersistTopSuggestions(SearchSuggestionParser::Results* results);
    222 
    223   // Apply calculated relevance scores to the current results.
    224   void ApplyCalculatedSuggestRelevance(
    225       SearchSuggestionParser::SuggestResults* list);
    226   void ApplyCalculatedNavigationRelevance(
    227       SearchSuggestionParser::NavigationResults* list);
    228 
    229   // Starts a new URLFetcher requesting suggest results from |template_url|;
    230   // callers own the returned URLFetcher, which is NULL for invalid providers.
    231   net::URLFetcher* CreateSuggestFetcher(int id,
    232                                         const TemplateURL* template_url,
    233                                         const AutocompleteInput& input);
    234 
    235   // Converts the parsed results to a set of AutocompleteMatches, |matches_|.
    236   void ConvertResultsToAutocompleteMatches();
    237 
    238   // Remove answer contents from each match in |matches| other than the first
    239   // that appears.
    240   static void RemoveExtraAnswers(ACMatches* matches);
    241 
    242   // Returns an iterator to the first match in |matches_| which might
    243   // be chosen as default.
    244   ACMatches::const_iterator FindTopMatch() const;
    245 
    246   // Checks if suggested relevances violate an expected constraint.
    247   // See UpdateMatches() for the use and explanation of this constraint
    248   // and other constraints enforced without the use of helper functions.
    249   bool IsTopMatchSearchWithURLInput() const;
    250 
    251   // Converts an appropriate number of navigation results in
    252   // |navigation_results| to matches and adds them to |matches|.
    253   void AddNavigationResultsToMatches(
    254       const SearchSuggestionParser::NavigationResults& navigation_results,
    255       ACMatches* matches);
    256 
    257   // Adds a match for each result in |raw_default_history_results_| or
    258   // |raw_keyword_history_results_| to |map|. |is_keyword| indicates
    259   // which one of the two.
    260   void AddRawHistoryResultsToMap(bool is_keyword,
    261                                  int did_not_accept_suggestion,
    262                                  MatchMap* map);
    263 
    264   // Adds a match for each transformed result in |results| to |map|.
    265   void AddTransformedHistoryResultsToMap(
    266       const SearchSuggestionParser::SuggestResults& results,
    267       int did_not_accept_suggestion,
    268       MatchMap* map);
    269 
    270   // Calculates relevance scores for all |results|.
    271   SearchSuggestionParser::SuggestResults ScoreHistoryResultsHelper(
    272       const HistoryResults& results,
    273       bool base_prevent_inline_autocomplete,
    274       bool input_multiple_words,
    275       const base::string16& input_text,
    276       bool is_keyword);
    277 
    278   // Calculates relevance scores for |results|, adjusting for boundary
    279   // conditions around multi-word queries. (See inline comments in function
    280   // definition for more details.)
    281   void ScoreHistoryResults(
    282       const HistoryResults& results,
    283       bool is_keyword,
    284       SearchSuggestionParser::SuggestResults* scored_results);
    285 
    286   // Adds matches for |results| to |map|.
    287   void AddSuggestResultsToMap(
    288       const SearchSuggestionParser::SuggestResults& results,
    289       const std::string& metadata,
    290       MatchMap* map);
    291 
    292   // Gets the relevance score for the verbatim result.  This value may be
    293   // provided by the suggest server or calculated locally; if
    294   // |relevance_from_server| is non-NULL, it will be set to indicate which of
    295   // those is true.
    296   int GetVerbatimRelevance(bool* relevance_from_server) const;
    297 
    298   // Calculates the relevance score for the verbatim result from the
    299   // default search engine.  This version takes into account context:
    300   // i.e., whether the user has entered a keyword-based search or not.
    301   int CalculateRelevanceForVerbatim() const;
    302 
    303   // Calculates the relevance score for the verbatim result from the default
    304   // search engine *ignoring* whether the input is a keyword-based search
    305   // or not.  This function should only be used to determine the minimum
    306   // relevance score that the best result from this provider should have.
    307   // For normal use, prefer the above function.
    308   int CalculateRelevanceForVerbatimIgnoringKeywordModeState() const;
    309 
    310   // Gets the relevance score for the keyword verbatim result.
    311   // |relevance_from_server| is handled as in GetVerbatimRelevance().
    312   // TODO(mpearson): Refactor so this duplication isn't necessary or
    313   // restructure so one static function takes all the parameters it needs
    314   // (rather than looking at internal state).
    315   int GetKeywordVerbatimRelevance(bool* relevance_from_server) const;
    316 
    317   // |time| is the time at which this query was last seen.  |is_keyword|
    318   // indicates whether the results correspond to the keyword provider or default
    319   // provider. |use_aggressive_method| says whether this function can use a
    320   // method that gives high scores (1200+) rather than one that gives lower
    321   // scores.  When using the aggressive method, scores may exceed 1300
    322   // unless |prevent_search_history_inlining| is set.
    323   int CalculateRelevanceForHistory(const base::Time& time,
    324                                    bool is_keyword,
    325                                    bool use_aggressive_method,
    326                                    bool prevent_search_history_inlining) const;
    327 
    328   // Returns an AutocompleteMatch for a navigational suggestion.
    329   AutocompleteMatch NavigationToMatch(
    330       const SearchSuggestionParser::NavigationResult& navigation);
    331 
    332   // Updates the value of |done_| from the internal state.
    333   void UpdateDone();
    334 
    335   // Obtains a session token, regenerating if necessary.
    336   std::string GetSessionToken();
    337 
    338   // Answers prefetch handling - finds the previously displayed answer matching
    339   // the current top-scoring history result. If there is a previous answer,
    340   // returns the query data associated with it. Otherwise, returns an empty
    341   // AnswersQueryData.
    342   AnswersQueryData FindAnswersPrefetchData();
    343 
    344   // The amount of time to wait before sending a new suggest request after the
    345   // previous one.  Non-const because some unittests modify this value.
    346   static int kMinimumTimeBetweenSuggestQueriesMs;
    347 
    348   AutocompleteProviderListener* listener_;
    349 
    350   // The number of suggest results that haven't yet arrived. If it's greater
    351   // than 0, it indicates that one of the URLFetchers is still running.
    352   int suggest_results_pending_;
    353 
    354   // Maintains the TemplateURLs used.
    355   Providers providers_;
    356 
    357   // The user's input.
    358   AutocompleteInput input_;
    359 
    360   // Input when searching against the keyword provider.
    361   AutocompleteInput keyword_input_;
    362 
    363   // Searches in the user's history that begin with the input text.
    364   HistoryResults raw_keyword_history_results_;
    365   HistoryResults raw_default_history_results_;
    366 
    367   // Scored searches in the user's history - based on |keyword_history_results_|
    368   // or |default_history_results_| as appropriate.
    369   SearchSuggestionParser::SuggestResults transformed_keyword_history_results_;
    370   SearchSuggestionParser::SuggestResults transformed_default_history_results_;
    371 
    372   // A timer to start a query to the suggest server after the user has stopped
    373   // typing for long enough.
    374   base::OneShotTimer<SearchProvider> timer_;
    375 
    376   // The time at which we sent a query to the suggest server.
    377   base::TimeTicks time_suggest_request_sent_;
    378 
    379   // Fetchers used to retrieve results for the keyword and default providers.
    380   scoped_ptr<net::URLFetcher> keyword_fetcher_;
    381   scoped_ptr<net::URLFetcher> default_fetcher_;
    382 
    383   // Results from the default and keyword search providers.
    384   SearchSuggestionParser::Results default_results_;
    385   SearchSuggestionParser::Results keyword_results_;
    386 
    387   // The top query suggestion, left blank if none.
    388   base::string16 top_query_suggestion_match_contents_;
    389   // The top navigation suggestion, left blank/invalid if none.
    390   GURL top_navigation_suggestion_;
    391 
    392   GURL current_page_url_;
    393 
    394   // Session token management.
    395   std::string current_token_;
    396   base::TimeTicks token_expiration_time_;
    397 
    398   // Answers prefetch management.
    399   AnswersCache answers_cache_;  // Cache for last answers seen.
    400   AnswersQueryData prefetch_data_;  // Data to use for query prefetching.
    401 
    402   DISALLOW_COPY_AND_ASSIGN(SearchProvider);
    403 };
    404 
    405 #endif  // COMPONENTS_OMNIBOX_SEARCH_PROVIDER_H_
    406