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
28class AutocompleteProviderClient;
29class AutocompleteProviderListener;
30class AutocompleteResult;
31class SearchProviderTest;
32class TemplateURLService;
33
34namespace history {
35struct KeywordSearchTermVisit;
36}
37
38namespace net {
39class 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.
52class 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