search_provider.h revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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 non-keyword autocomplete entries that start with
7// "Search <engine> for ...", including searching for the current input string,
8// search history, and search suggestions.  An instance of it gets created and
9// managed by the autocomplete controller.
10//
11// For more information on the autocomplete system in general, including how
12// the autocomplete controller and autocomplete providers work, see
13// chrome/browser/autocomplete.h.
14
15#ifndef CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
16#define CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
17#pragma once
18
19#include <map>
20#include <string>
21#include <vector>
22
23#include "base/scoped_ptr.h"
24#include "chrome/browser/autocomplete/autocomplete.h"
25#include "chrome/browser/cancelable_request.h"
26#include "chrome/browser/history/history_types.h"
27#include "chrome/browser/search_engines/template_url.h"
28#include "chrome/browser/search_engines/template_url_id.h"
29#include "chrome/common/net/url_fetcher.h"
30
31class Profile;
32class Value;
33
34// Autocomplete provider for searches and suggestions from a search engine.
35//
36// After construction, the autocomplete controller repeatedly calls Start()
37// with some user input, each time expecting to receive a small set of the best
38// matches (either synchronously or asynchronously).
39//
40// Initially the provider creates a match that searches for the current input
41// text.  It also starts a task to query the Suggest servers.  When that data
42// comes back, the provider creates and returns matches for the best
43// suggestions.
44class SearchProvider : public AutocompleteProvider,
45                       public URLFetcher::Delegate {
46 public:
47  SearchProvider(ACProviderListener* listener, Profile* profile);
48
49#if defined(UNIT_TEST)
50  static void set_query_suggest_immediately(bool value) {
51    query_suggest_immediately_ = value;
52  }
53#endif
54
55  // AutocompleteProvider
56  virtual void Start(const AutocompleteInput& input,
57                     bool minimal_changes);
58  virtual void Stop();
59
60  // URLFetcher::Delegate
61  virtual void OnURLFetchComplete(const URLFetcher* source,
62                                  const GURL& url,
63                                  const URLRequestStatus& status,
64                                  int response_code,
65                                  const ResponseCookies& cookies,
66                                  const std::string& data);
67
68  // ID used in creating URLFetcher for default provider's suggest results.
69  static const int kDefaultProviderURLFetcherID;
70
71  // ID used in creating URLFetcher for keyword provider's suggest results.
72  static const int kKeywordProviderURLFetcherID;
73
74 private:
75  ~SearchProvider();
76
77  // Manages the providers (TemplateURLs) used by SearchProvider. Two providers
78  // may be used:
79  // . The default provider. This corresponds to the user's default search
80  //   engine. This is always used, except for the rare case of no default
81  //   engine.
82  // . The keyword provider. This is used if the user has typed in a keyword.
83  class Providers {
84   public:
85    Providers() : default_provider_(NULL), keyword_provider_(NULL) {}
86
87    // Returns true if the specified providers match the two providers managed
88    // by this class.
89    bool equals(const TemplateURL* default_provider,
90                const TemplateURL* keyword_provider) {
91      return (default_provider == default_provider_ &&
92              keyword_provider == keyword_provider_);
93    }
94
95    // Resets the providers.
96    void Set(const TemplateURL* default_provider,
97             const TemplateURL* keyword_provider);
98
99    const TemplateURL& default_provider() const {
100      DCHECK(valid_default_provider());
101      return cached_default_provider_;
102    }
103
104    const TemplateURL& keyword_provider() const {
105      DCHECK(valid_keyword_provider());
106      return cached_keyword_provider_;
107    }
108
109    // Returns true of the keyword provider is valid.
110    bool valid_keyword_provider() const { return !!keyword_provider_; }
111
112    // Returns true if the keyword provider is valid and has a valid suggest
113    // url.
114    bool valid_suggest_for_keyword_provider() const {
115      return keyword_provider_ && cached_keyword_provider_.suggestions_url();
116    }
117
118    // Returns true of the default provider is valid.
119    bool valid_default_provider() const { return !!default_provider_; }
120
121    // Returns true if the default provider is valid and has a valid suggest
122    // url.
123    bool valid_suggest_for_default_provider() const {
124      return default_provider_ && cached_default_provider_.suggestions_url();
125    }
126
127    // Returns true if |from_keyword_provider| is true, or
128    // the keyword provider is not valid.
129    bool is_primary_provider(bool from_keyword_provider) const {
130      return from_keyword_provider || !valid_keyword_provider();
131    }
132
133   private:
134    // Cached across the life of a query so we behave consistently even if the
135    // user changes their default while the query is running.
136    TemplateURL cached_default_provider_;
137    TemplateURL cached_keyword_provider_;
138
139    // TODO(pkasting): http://b/1162970  We shouldn't need these.
140    const TemplateURL* default_provider_;
141    const TemplateURL* keyword_provider_;
142  };
143
144  struct NavigationResult {
145    NavigationResult(const GURL& url, const std::wstring& site_name)
146        : url(url),
147          site_name(site_name) {
148    }
149
150    // The URL.
151    GURL url;
152
153    // Name for the site.
154    std::wstring site_name;
155  };
156
157  typedef std::vector<std::wstring> SuggestResults;
158  typedef std::vector<NavigationResult> NavigationResults;
159  typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
160  typedef std::map<std::wstring, AutocompleteMatch> MatchMap;
161
162  // Called when timer_ expires.
163  void Run();
164
165  // Determines whether an asynchronous subcomponent query should run for the
166  // current input.  If so, starts it if necessary; otherwise stops it.
167  // NOTE: These functions do not update |done_|.  Callers must do so.
168  void StartOrStopHistoryQuery(bool minimal_changes);
169  void StartOrStopSuggestQuery(bool minimal_changes);
170
171  // Returns true when the current query can be sent to the Suggest service.
172  // This will be false e.g. when Suggest is disabled, the query contains
173  // potentially private data, etc.
174  bool IsQuerySuitableForSuggest() const;
175
176  // Functions to stop the separate asynchronous subcomponents.
177  // NOTE: These functions do not update |done_|.  Callers must do so.
178  void StopHistory();
179  void StopSuggest();
180
181  // Schedules a history query requesting past searches against the engine
182  // whose id is |search_id| and whose text starts with |text|.
183  void ScheduleHistoryQuery(TemplateURLID search_id,
184                            const std::wstring& text);
185
186  // Called back by the history system to return searches that begin with the
187  // input text.
188  void OnGotMostRecentKeywordSearchTerms(
189      CancelableRequestProvider::Handle handle,
190      HistoryResults* results);
191
192  // Creates a URLFetcher requesting suggest results for the specified
193  // TemplateURL. Ownership of the returned URLFetchet passes to the caller.
194  URLFetcher* CreateSuggestFetcher(int id,
195                                   const TemplateURL& provider,
196                                   const std::wstring& text);
197
198  // Parses the results from the Suggest server and stores up to kMaxMatches of
199  // them in server_results_.  Returns whether parsing succeeded.
200  bool ParseSuggestResults(Value* root_val,
201                           bool is_keyword,
202                           const std::wstring& input_text,
203                           SuggestResults* suggest_results);
204
205  // Converts the parsed server results in server_results_ to a set of
206  // AutocompleteMatches and adds them to |matches_|.  This also sets |done_|
207  // correctly.
208  void ConvertResultsToAutocompleteMatches();
209
210  // Converts the first navigation result in |navigation_results| to an
211  // AutocompleteMatch and adds it to |matches_|.
212  void AddNavigationResultsToMatches(
213    const NavigationResults& navigation_results,
214    bool is_keyword);
215
216  // Adds a match for each result in |results| to |map|. |is_keyword| indicates
217  // whether the results correspond to the keyword provider or default provider.
218  void AddHistoryResultsToMap(const HistoryResults& results,
219                              bool is_keyword,
220                              int did_not_accept_suggestion,
221                              MatchMap* map);
222
223  // Adds a match for each result in |suggest_results| to |map|. |is_keyword|
224  // indicates whether the results correspond to the keyword provider or default
225  // provider.
226  void AddSuggestResultsToMap(const SuggestResults& suggest_results,
227                              bool is_keyword,
228                              int did_not_accept_suggestion,
229                              MatchMap* map);
230
231  // Determines the relevance for a particular match.  We use different scoring
232  // algorithms for the different types of matches.
233  int CalculateRelevanceForWhatYouTyped() const;
234  // |time| is the time at which this query was last seen. |is_keyword| is true
235  // if the search is from the keyword provider.
236  int CalculateRelevanceForHistory(const base::Time& time,
237                                   bool is_keyword) const;
238  // |result_number| is the index of the suggestion in the result set from the
239  // server; the best suggestion is suggestion number 0.  |is_keyword| is true
240  // if the search is from the keyword provider.
241  int CalculateRelevanceForSuggestion(size_t num_results,
242                                      size_t result_number,
243                                      bool is_keyword) const;
244  // |result_number| is same as above. |is_keyword| is true if the navigation
245  // result was suggested by the keyword provider.
246  int CalculateRelevanceForNavigation(size_t num_results,
247                                      size_t result_number,
248                                      bool is_keyword) const;
249
250  // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with
251  // the supplied relevance.  Adds this match to |map|; if such a match already
252  // exists, whichever one has lower relevance is eliminated.
253  void AddMatchToMap(const std::wstring& query_string,
254                     int relevance,
255                     AutocompleteMatch::Type type,
256                     int accepted_suggestion,
257                     bool is_keyword,
258                     MatchMap* map);
259  // Returns an AutocompleteMatch for a navigational suggestion.
260  AutocompleteMatch NavigationToMatch(const NavigationResult& query_string,
261                                      int relevance,
262                                      bool is_keyword);
263
264  // Should we query for suggest results immediately? This is normally false,
265  // but may be set to true during testing.
266  static bool query_suggest_immediately_;
267
268  // Maintains the TemplateURLs used.
269  Providers providers_;
270
271  // The user's input.
272  AutocompleteInput input_;
273
274  // Input text when searching against the keyword provider.
275  std::wstring keyword_input_text_;
276
277  // An object we can use to cancel history requests. The client data
278  // corresponds to the id of the search engine and is used in the callback to
279  // determine whether the request corresponds to the keyword of default
280  // provider.
281  CancelableRequestConsumerTSimple<TemplateURLID>
282      history_request_consumer_;
283
284  // Searches in the user's history that begin with the input text.
285  HistoryResults keyword_history_results_;
286  HistoryResults default_history_results_;
287
288  // Whether history_results_ is valid (so we can tell invalid apart from
289  // empty).
290  bool have_history_results_;
291
292  // Whether we are waiting for a history request to finish.
293  bool history_request_pending_;
294
295  // Number of suggest results that haven't yet arrived. If greater than 0 it
296  // indicates either |timer_| or one of the URLFetchers is still running.
297  int suggest_results_pending_;
298
299  // A timer to start a query to the suggest server after the user has stopped
300  // typing for long enough.
301  base::OneShotTimer<SearchProvider> timer_;
302
303  // The fetcher that retrieves suggest results for the keyword from the server.
304  scoped_ptr<URLFetcher> keyword_fetcher_;
305
306  // The fetcher that retrieves suggest results for the default engine from the
307  // server.
308  scoped_ptr<URLFetcher> default_fetcher_;
309
310  // Suggestions returned by the Suggest server for the input text.
311  SuggestResults keyword_suggest_results_;
312  SuggestResults default_suggest_results_;
313
314  // Navigational suggestions returned by the server.
315  NavigationResults keyword_navigation_results_;
316  NavigationResults default_navigation_results_;
317
318  // Whether suggest_results_ is valid.
319  bool have_suggest_results_;
320
321  DISALLOW_COPY_AND_ASSIGN(SearchProvider);
322};
323
324#endif  // CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_
325