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