Home | History | Annotate | Download | only in omnibox
      1 // Copyright 2014 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 #ifndef COMPONENTS_OMNIBOX_SEARCH_SUGGESTION_PARSER_H_
      6 #define COMPONENTS_OMNIBOX_SEARCH_SUGGESTION_PARSER_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/gtest_prod_util.h"
     13 #include "base/strings/string16.h"
     14 #include "components/omnibox/autocomplete_match.h"
     15 #include "components/omnibox/autocomplete_match_type.h"
     16 #include "url/gurl.h"
     17 
     18 class AutocompleteInput;
     19 class AutocompleteSchemeClassifier;
     20 
     21 namespace base {
     22 class DictionaryValue;
     23 class Value;
     24 }
     25 
     26 namespace net {
     27 class URLFetcher;
     28 }
     29 
     30 class SearchSuggestionParser {
     31  public:
     32   // The Result classes are intermediate representations of AutocompleteMatches,
     33   // simply containing relevance-ranked search and navigation suggestions.
     34   // They may be cached to provide some synchronous matches while requests for
     35   // new suggestions from updated input are in flight.
     36   // TODO(msw) Extend these classes to generate their corresponding matches and
     37   //           other requisite data, in order to consolidate and simplify the
     38   //           highly fragmented SearchProvider logic for each Result type.
     39   class Result {
     40    public:
     41     Result(bool from_keyword_provider,
     42            int relevance,
     43            bool relevance_from_server,
     44            AutocompleteMatchType::Type type,
     45            const std::string& deletion_url);
     46     virtual ~Result();
     47 
     48     bool from_keyword_provider() const { return from_keyword_provider_; }
     49 
     50     const base::string16& match_contents() const { return match_contents_; }
     51     const ACMatchClassifications& match_contents_class() const {
     52       return match_contents_class_;
     53     }
     54 
     55     AutocompleteMatchType::Type type() const { return type_; }
     56     int relevance() const { return relevance_; }
     57     void set_relevance(int relevance) { relevance_ = relevance; }
     58     bool received_after_last_keystroke() const {
     59       return received_after_last_keystroke_;
     60     }
     61     void set_received_after_last_keystroke(
     62         bool received_after_last_keystroke) {
     63       received_after_last_keystroke_ = received_after_last_keystroke;
     64     }
     65 
     66     bool relevance_from_server() const { return relevance_from_server_; }
     67     void set_relevance_from_server(bool relevance_from_server) {
     68       relevance_from_server_ = relevance_from_server;
     69     }
     70 
     71     const std::string& deletion_url() const { return deletion_url_; }
     72 
     73     // Returns the default relevance value for this result (which may
     74     // be left over from a previous omnibox input) given the current
     75     // input and whether the current input caused a keyword provider
     76     // to be active.
     77     virtual int CalculateRelevance(const AutocompleteInput& input,
     78                                    bool keyword_provider_requested) const = 0;
     79 
     80    protected:
     81     // The contents to be displayed and its style info.
     82     base::string16 match_contents_;
     83     ACMatchClassifications match_contents_class_;
     84 
     85     // True if the result came from the keyword provider.
     86     bool from_keyword_provider_;
     87 
     88     AutocompleteMatchType::Type type_;
     89 
     90     // The relevance score.
     91     int relevance_;
     92 
     93    private:
     94     // Whether this result's relevance score was fully or partly calculated
     95     // based on server information, and thus is assumed to be more accurate.
     96     // This is ultimately used in
     97     // SearchProvider::ConvertResultsToAutocompleteMatches(), see comments
     98     // there.
     99     bool relevance_from_server_;
    100 
    101     // Whether this result was received asynchronously after the last
    102     // keystroke, otherwise it must have come from prior cached results
    103     // or from a synchronous provider.
    104     bool received_after_last_keystroke_;
    105 
    106     // Optional deletion URL provided with suggestions. Fetching this URL
    107     // should result in some reasonable deletion behaviour on the server,
    108     // e.g. deleting this term out of a user's server-side search history.
    109     std::string deletion_url_;
    110   };
    111 
    112   class SuggestResult : public Result {
    113    public:
    114     SuggestResult(const base::string16& suggestion,
    115                   AutocompleteMatchType::Type type,
    116                   const base::string16& match_contents,
    117                   const base::string16& match_contents_prefix,
    118                   const base::string16& annotation,
    119                   const base::string16& answer_contents,
    120                   const base::string16& answer_type,
    121                   const std::string& suggest_query_params,
    122                   const std::string& deletion_url,
    123                   bool from_keyword_provider,
    124                   int relevance,
    125                   bool relevance_from_server,
    126                   bool should_prefetch,
    127                   const base::string16& input_text);
    128     virtual ~SuggestResult();
    129 
    130     const base::string16& suggestion() const { return suggestion_; }
    131     const base::string16& match_contents_prefix() const {
    132       return match_contents_prefix_;
    133     }
    134     const base::string16& annotation() const { return annotation_; }
    135     const std::string& suggest_query_params() const {
    136       return suggest_query_params_;
    137     }
    138 
    139     const base::string16& answer_contents() const { return answer_contents_; }
    140     const base::string16& answer_type() const { return answer_type_; }
    141 
    142     bool should_prefetch() const { return should_prefetch_; }
    143 
    144     // Fills in |match_contents_class_| to reflect how |match_contents_| should
    145     // be displayed and bolded against the current |input_text|.  If
    146     // |allow_bolding_all| is false and |match_contents_class_| would have all
    147     // of |match_contents_| bolded, do nothing.
    148     void ClassifyMatchContents(const bool allow_bolding_all,
    149                                const base::string16& input_text);
    150 
    151     // Result:
    152     virtual int CalculateRelevance(
    153         const AutocompleteInput& input,
    154         bool keyword_provider_requested) const OVERRIDE;
    155 
    156    private:
    157     // The search terms to be used for this suggestion.
    158     base::string16 suggestion_;
    159 
    160     // The contents to be displayed as prefix of match contents.
    161     // Used for postfix suggestions to display a leading ellipsis (or some
    162     // equivalent character) to indicate omitted text.
    163     // Only used to pass this information to about:omnibox's "Additional Info".
    164     base::string16 match_contents_prefix_;
    165 
    166     // Optional annotation for the |match_contents_| for disambiguation.
    167     // This may be displayed in the autocomplete match contents, but is defined
    168     // separately to facilitate different formatting.
    169     base::string16 annotation_;
    170 
    171     // Optional additional parameters to be added to the search URL.
    172     std::string suggest_query_params_;
    173 
    174     // Optional formatted Answers result.
    175     base::string16 answer_contents_;
    176 
    177     // Type of optional formatted Answers result.
    178     base::string16 answer_type_;
    179 
    180     // Should this result be prefetched?
    181     bool should_prefetch_;
    182   };
    183 
    184   class NavigationResult : public Result {
    185    public:
    186     NavigationResult(const AutocompleteSchemeClassifier& scheme_classifier,
    187                      const GURL& url,
    188                      AutocompleteMatchType::Type type,
    189                      const base::string16& description,
    190                      const std::string& deletion_url,
    191                      bool from_keyword_provider,
    192                      int relevance,
    193                      bool relevance_from_server,
    194                      const base::string16& input_text,
    195                      const std::string& languages);
    196     virtual ~NavigationResult();
    197 
    198     const GURL& url() const { return url_; }
    199     const base::string16& description() const { return description_; }
    200     const base::string16& formatted_url() const { return formatted_url_; }
    201 
    202     // Fills in |match_contents_| and |match_contents_class_| to reflect how
    203     // the URL should be displayed and bolded against the current |input_text|
    204     // and user |languages|.  If |allow_bolding_nothing| is false and
    205     // |match_contents_class_| would result in an entirely unbolded
    206     // |match_contents_|, do nothing.
    207     void CalculateAndClassifyMatchContents(const bool allow_bolding_nothing,
    208                                            const base::string16& input_text,
    209                                            const std::string& languages);
    210 
    211     // Result:
    212     virtual int CalculateRelevance(
    213         const AutocompleteInput& input,
    214         bool keyword_provider_requested) const OVERRIDE;
    215 
    216    private:
    217     // The suggested url for navigation.
    218     GURL url_;
    219 
    220     // The properly formatted ("fixed up") URL string with equivalent meaning
    221     // to the one in |url_|.
    222     base::string16 formatted_url_;
    223 
    224     // The suggested navigational result description; generally the site name.
    225     base::string16 description_;
    226   };
    227 
    228   typedef std::vector<SuggestResult> SuggestResults;
    229   typedef std::vector<NavigationResult> NavigationResults;
    230 
    231   // A simple structure bundling most of the information (including
    232   // both SuggestResults and NavigationResults) returned by a call to
    233   // the suggest server.
    234   //
    235   // This has to be declared after the typedefs since it relies on some of them.
    236   struct Results {
    237     Results();
    238     ~Results();
    239 
    240     // Clears |suggest_results| and |navigation_results| and resets
    241     // |verbatim_relevance| to -1 (implies unset).
    242     void Clear();
    243 
    244     // Returns whether any of the results (including verbatim) have
    245     // server-provided scores.
    246     bool HasServerProvidedScores() const;
    247 
    248     // Query suggestions sorted by relevance score.
    249     SuggestResults suggest_results;
    250 
    251     // Navigational suggestions sorted by relevance score.
    252     NavigationResults navigation_results;
    253 
    254     // The server supplied verbatim relevance scores. Negative values
    255     // indicate that there is no suggested score; a value of 0
    256     // suppresses the verbatim result.
    257     int verbatim_relevance;
    258 
    259     // The JSON metadata associated with this server response.
    260     std::string metadata;
    261 
    262     // If the active suggest field trial (if any) has triggered.
    263     bool field_trial_triggered;
    264 
    265     // If the relevance values of the results are from the server.
    266     bool relevances_from_server;
    267 
    268     // URLs of any images in Answers results.
    269     std::vector<GURL> answers_image_urls;
    270 
    271    private:
    272     DISALLOW_COPY_AND_ASSIGN(Results);
    273   };
    274 
    275   // Extracts JSON data fetched by |source| and converts it to UTF-8.
    276   static std::string ExtractJsonData(const net::URLFetcher* source);
    277 
    278   // Parses JSON response received from the provider, stripping XSSI
    279   // protection if needed. Returns the parsed data if successful, NULL
    280   // otherwise.
    281   static scoped_ptr<base::Value> DeserializeJsonData(std::string json_data);
    282 
    283   // Parses results from the suggest server and updates the appropriate suggest
    284   // and navigation result lists in |results|. |is_keyword_result| indicates
    285   // whether the response was received from the keyword provider.
    286   // Returns whether the appropriate result list members were updated.
    287   static bool ParseSuggestResults(
    288       const base::Value& root_val,
    289       const AutocompleteInput& input,
    290       const AutocompleteSchemeClassifier& scheme_classifier,
    291       int default_result_relevance,
    292       const std::string& languages,
    293       bool is_keyword_result,
    294       Results* results);
    295 
    296  private:
    297   FRIEND_TEST_ALL_PREFIXES(SearchSuggestionParser,
    298                            GetAnswersImageURLsWithoutImagelines);
    299   FRIEND_TEST_ALL_PREFIXES(SearchSuggestionParser,
    300                            GetAnswersImageURLsWithValidImage);
    301 
    302   // Gets URLs of any images in Answers results.
    303   static void GetAnswersImageURLs(const base::DictionaryValue* answer_json,
    304                                   std::vector<GURL>* urls);
    305 
    306   DISALLOW_COPY_AND_ASSIGN(SearchSuggestionParser);
    307 };
    308 
    309 #endif  // COMPONENTS_OMNIBOX_SEARCH_SUGGESTION_PARSER_H_
    310