• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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().
set_current_page_url(const GURL & current_page_url)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.
equal(const base::string16 & default_provider,const base::string16 & keyword_provider)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.
set(const base::string16 & default_provider,const base::string16 & keyword_provider)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 
template_url_service()121     TemplateURLService* template_url_service() { return template_url_service_; }
default_provider()122     const base::string16& default_provider() const { return default_provider_; }
keyword_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.
has_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