search_provider.h revision 3f50c38dc070f4bb515c1b64450dae14f316474e
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/autocomplete/autocomplete_match.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 // Marks the instant query as done. If |input_text| is non-empty this changes 56 // the 'search what you typed' results text to |input_text| + |suggest_text|. 57 // |input_text| is the text the user input into the edit. |input_text| differs 58 // from |input_.text()| if the input contained whitespace. 59 // 60 // This method also marks the search provider as no longer needing to wait for 61 // the instant result. 62 void FinalizeInstantQuery(const std::wstring& input_text, 63 const std::wstring& suggest_text); 64 65 // AutocompleteProvider 66 virtual void Start(const AutocompleteInput& input, 67 bool minimal_changes); 68 virtual void Stop(); 69 70 // URLFetcher::Delegate 71 virtual void OnURLFetchComplete(const URLFetcher* source, 72 const GURL& url, 73 const net::URLRequestStatus& status, 74 int response_code, 75 const ResponseCookies& cookies, 76 const std::string& data); 77 78 // ID used in creating URLFetcher for default provider's suggest results. 79 static const int kDefaultProviderURLFetcherID; 80 81 // ID used in creating URLFetcher for keyword provider's suggest results. 82 static const int kKeywordProviderURLFetcherID; 83 84 private: 85 ~SearchProvider(); 86 87 // Manages the providers (TemplateURLs) used by SearchProvider. Two providers 88 // may be used: 89 // . The default provider. This corresponds to the user's default search 90 // engine. This is always used, except for the rare case of no default 91 // engine. 92 // . The keyword provider. This is used if the user has typed in a keyword. 93 class Providers { 94 public: 95 Providers() : default_provider_(NULL), keyword_provider_(NULL) {} 96 97 // Returns true if the specified providers match the two providers managed 98 // by this class. 99 bool equals(const TemplateURL* default_provider, 100 const TemplateURL* keyword_provider) { 101 return (default_provider == default_provider_ && 102 keyword_provider == keyword_provider_); 103 } 104 105 // Resets the providers. 106 void Set(const TemplateURL* default_provider, 107 const TemplateURL* keyword_provider); 108 109 const TemplateURL& default_provider() const { 110 DCHECK(valid_default_provider()); 111 return cached_default_provider_; 112 } 113 114 const TemplateURL& keyword_provider() const { 115 DCHECK(valid_keyword_provider()); 116 return cached_keyword_provider_; 117 } 118 119 // Returns true of the keyword provider is valid. 120 bool valid_keyword_provider() const { return !!keyword_provider_; } 121 122 // Returns true if the keyword provider is valid and has a valid suggest 123 // url. 124 bool valid_suggest_for_keyword_provider() const { 125 return keyword_provider_ && cached_keyword_provider_.suggestions_url(); 126 } 127 128 // Returns true of the default provider is valid. 129 bool valid_default_provider() const { return !!default_provider_; } 130 131 // Returns true if the default provider is valid and has a valid suggest 132 // url. 133 bool valid_suggest_for_default_provider() const { 134 return default_provider_ && cached_default_provider_.suggestions_url(); 135 } 136 137 // Returns true if |from_keyword_provider| is true, or 138 // the keyword provider is not valid. 139 bool is_primary_provider(bool from_keyword_provider) const { 140 return from_keyword_provider || !valid_keyword_provider(); 141 } 142 143 private: 144 // Cached across the life of a query so we behave consistently even if the 145 // user changes their default while the query is running. 146 TemplateURL cached_default_provider_; 147 TemplateURL cached_keyword_provider_; 148 149 // TODO(pkasting): http://b/1162970 We shouldn't need these. 150 const TemplateURL* default_provider_; 151 const TemplateURL* keyword_provider_; 152 }; 153 154 struct NavigationResult { 155 NavigationResult(const GURL& url, const std::wstring& site_name) 156 : url(url), 157 site_name(site_name) { 158 } 159 160 // The URL. 161 GURL url; 162 163 // Name for the site. 164 std::wstring site_name; 165 }; 166 167 typedef std::vector<std::wstring> SuggestResults; 168 typedef std::vector<NavigationResult> NavigationResults; 169 typedef std::vector<history::KeywordSearchTermVisit> HistoryResults; 170 typedef std::map<std::wstring, AutocompleteMatch> MatchMap; 171 172 // Called when timer_ expires. 173 void Run(); 174 175 // Runs the history query, if necessary. The history query is synchronous. 176 // This does not update |done_|. 177 void DoHistoryQuery(bool minimal_changes); 178 179 // Determines whether an asynchronous subcomponent query should run for the 180 // current input. If so, starts it if necessary; otherwise stops it. 181 // NOTE: This function does not update |done_|. Callers must do so. 182 void StartOrStopSuggestQuery(bool minimal_changes); 183 184 // Returns true when the current query can be sent to the Suggest service. 185 // This will be false e.g. when Suggest is disabled, the query contains 186 // potentially private data, etc. 187 bool IsQuerySuitableForSuggest() const; 188 189 // Stops the suggest query. 190 // NOTE: This does not update |done_|. Callers must do so. 191 void StopSuggest(); 192 193 // Creates a URLFetcher requesting suggest results for the specified 194 // TemplateURL. Ownership of the returned URLFetchet passes to the caller. 195 URLFetcher* CreateSuggestFetcher(int id, 196 const TemplateURL& provider, 197 const std::wstring& text); 198 199 // Parses the results from the Suggest server and stores up to kMaxMatches of 200 // them in server_results_. Returns whether parsing succeeded. 201 bool ParseSuggestResults(Value* root_val, 202 bool is_keyword, 203 const std::wstring& input_text, 204 SuggestResults* suggest_results); 205 206 // Converts the parsed server results in server_results_ to a set of 207 // AutocompleteMatches and adds them to |matches_|. This also sets |done_| 208 // correctly. 209 void ConvertResultsToAutocompleteMatches(); 210 211 // Converts the first navigation result in |navigation_results| to an 212 // AutocompleteMatch and adds it to |matches_|. 213 void AddNavigationResultsToMatches( 214 const NavigationResults& navigation_results, 215 bool is_keyword); 216 217 // Adds a match for each result in |results| to |map|. |is_keyword| indicates 218 // whether the results correspond to the keyword provider or default provider. 219 void AddHistoryResultsToMap(const HistoryResults& results, 220 bool is_keyword, 221 int did_not_accept_suggestion, 222 MatchMap* map); 223 224 // Adds a match for each result in |suggest_results| to |map|. |is_keyword| 225 // indicates whether the results correspond to the keyword provider or default 226 // provider. 227 void AddSuggestResultsToMap(const SuggestResults& suggest_results, 228 bool is_keyword, 229 int did_not_accept_suggestion, 230 MatchMap* map); 231 232 // Determines the relevance for a particular match. We use different scoring 233 // algorithms for the different types of matches. 234 int CalculateRelevanceForWhatYouTyped() const; 235 // |time| is the time at which this query was last seen. |is_keyword| is true 236 // if the search is from the keyword provider. 237 int CalculateRelevanceForHistory(const base::Time& time, 238 bool is_keyword) const; 239 // |result_number| is the index of the suggestion in the result set from the 240 // server; the best suggestion is suggestion number 0. |is_keyword| is true 241 // if the search is from the keyword provider. 242 int CalculateRelevanceForSuggestion(size_t num_results, 243 size_t result_number, 244 bool is_keyword) const; 245 // |result_number| is same as above. |is_keyword| is true if the navigation 246 // result was suggested by the keyword provider. 247 int CalculateRelevanceForNavigation(size_t num_results, 248 size_t result_number, 249 bool is_keyword) const; 250 251 // Creates an AutocompleteMatch for "Search <engine> for |query_string|" with 252 // the supplied relevance. Adds this match to |map|; if such a match already 253 // exists, whichever one has lower relevance is eliminated. 254 void AddMatchToMap(const std::wstring& query_string, 255 const std::wstring& input_text, 256 int relevance, 257 AutocompleteMatch::Type type, 258 int accepted_suggestion, 259 bool is_keyword, 260 bool prevent_inline_autocomplete, 261 MatchMap* map); 262 263 // Returns an AutocompleteMatch for a navigational suggestion. 264 AutocompleteMatch NavigationToMatch(const NavigationResult& query_string, 265 int relevance, 266 bool is_keyword); 267 268 // Updates the value of |done_| from the internal state. 269 void UpdateDone(); 270 271 // Updates the description/description_class of the first search match. 272 void UpdateFirstSearchMatchDescription(); 273 274 // Should we query for suggest results immediately? This is normally false, 275 // but may be set to true during testing. 276 static bool query_suggest_immediately_; 277 278 // Maintains the TemplateURLs used. 279 Providers providers_; 280 281 // The user's input. 282 AutocompleteInput input_; 283 284 // Input text when searching against the keyword provider. 285 std::wstring keyword_input_text_; 286 287 // Searches in the user's history that begin with the input text. 288 HistoryResults keyword_history_results_; 289 HistoryResults default_history_results_; 290 291 // Number of suggest results that haven't yet arrived. If greater than 0 it 292 // indicates either |timer_| or one of the URLFetchers is still running. 293 int suggest_results_pending_; 294 295 // A timer to start a query to the suggest server after the user has stopped 296 // typing for long enough. 297 base::OneShotTimer<SearchProvider> timer_; 298 299 // The fetcher that retrieves suggest results for the keyword from the server. 300 scoped_ptr<URLFetcher> keyword_fetcher_; 301 302 // The fetcher that retrieves suggest results for the default engine from the 303 // server. 304 scoped_ptr<URLFetcher> default_fetcher_; 305 306 // Suggestions returned by the Suggest server for the input text. 307 SuggestResults keyword_suggest_results_; 308 SuggestResults default_suggest_results_; 309 310 // Navigational suggestions returned by the server. 311 NavigationResults keyword_navigation_results_; 312 NavigationResults default_navigation_results_; 313 314 // Whether suggest_results_ is valid. 315 bool have_suggest_results_; 316 317 // Has FinalizeInstantQuery been invoked since the last |Start|? 318 bool instant_finalized_; 319 320 DISALLOW_COPY_AND_ASSIGN(SearchProvider); 321}; 322 323#endif // CHROME_BROWSER_AUTOCOMPLETE_SEARCH_PROVIDER_H_ 324