Home | History | Annotate | Download | only in search_engines
      1 // Copyright (c) 2011 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 CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
      6 #define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
      7 #pragma once
      8 
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <vector>
     13 
     14 #include "base/gtest_prod_util.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/observer_list.h"
     17 #include "chrome/browser/search_engines/search_host_to_urls_map.h"
     18 #include "chrome/browser/search_engines/template_url_id.h"
     19 #include "chrome/browser/webdata/web_data_service.h"
     20 #include "content/common/notification_observer.h"
     21 #include "content/common/notification_registrar.h"
     22 
     23 class GURL;
     24 class Extension;
     25 class PrefService;
     26 class Profile;
     27 class PrefSetObserver;
     28 class SearchHostToURLsMap;
     29 class SearchTermsData;
     30 class TemplateURLModelObserver;
     31 class TemplateURLRef;
     32 
     33 namespace history {
     34 struct URLVisitedDetails;
     35 }
     36 
     37 // TemplateURLModel is the backend for keywords. It's used by
     38 // KeywordAutocomplete.
     39 //
     40 // TemplateURLModel stores a vector of TemplateURLs. The TemplateURLs are
     41 // persisted to the database maintained by WebDataService. *ALL* mutations
     42 // to the TemplateURLs must funnel through TemplateURLModel. This allows
     43 // TemplateURLModel to notify listeners of changes as well as keep the
     44 // database in sync.
     45 //
     46 // There is a TemplateURLModel per Profile.
     47 //
     48 // TemplateURLModel does not load the vector of TemplateURLs in its
     49 // constructor (except for testing). Use the Load method to trigger a load.
     50 // When TemplateURLModel has completed loading, observers are notified via
     51 // OnTemplateURLModelChanged as well as the TEMPLATE_URL_MODEL_LOADED
     52 // notification message.
     53 //
     54 // TemplateURLModel takes ownership of any TemplateURL passed to it. If there
     55 // is a WebDataService, deletion is handled by WebDataService, otherwise
     56 // TemplateURLModel handles deletion.
     57 
     58 class TemplateURLModel : public WebDataServiceConsumer,
     59                          public NotificationObserver {
     60  public:
     61   typedef std::map<std::string, std::string> QueryTerms;
     62   typedef std::vector<const TemplateURL*> TemplateURLVector;
     63 
     64   // Struct used for initializing the data store with fake data.
     65   // Each initializer is mapped to a TemplateURL.
     66   struct Initializer {
     67     const char* const keyword;
     68     const char* const url;
     69     const char* const content;
     70   };
     71 
     72   explicit TemplateURLModel(Profile* profile);
     73   // The following is for testing.
     74   TemplateURLModel(const Initializer* initializers, const int count);
     75   virtual ~TemplateURLModel();
     76 
     77   // Generates a suitable keyword for the specified url.  Returns an empty
     78   // string if a keyword couldn't be generated.  If |autodetected| is true, we
     79   // don't generate keywords for a variety of situations where we would probably
     80   // not want to auto-add keywords, such as keywords for searches on pages that
     81   // themselves come from form submissions.
     82   static string16 GenerateKeyword(const GURL& url, bool autodetected);
     83 
     84   // Removes any unnecessary characters from a user input keyword.
     85   // This removes the leading scheme, "www." and any trailing slash.
     86   static string16 CleanUserInputKeyword(const string16& keyword);
     87 
     88   // Returns the search url for t_url.  Returns an empty GURL if t_url has no
     89   // url().
     90   static GURL GenerateSearchURL(const TemplateURL* t_url);
     91 
     92   // Just like GenerateSearchURL except that it takes SearchTermsData to supply
     93   // the data for some search terms. Most of the time GenerateSearchURL should
     94   // be called.
     95   static GURL GenerateSearchURLUsingTermsData(
     96       const TemplateURL* t_url,
     97       const SearchTermsData& search_terms_data);
     98 
     99   // Returns true if there is no TemplateURL that conflicts with the
    100   // keyword/url pair, or there is one but it can be replaced. If there is an
    101   // existing keyword that can be replaced and template_url_to_replace is
    102   // non-NULL, template_url_to_replace is set to the keyword to replace.
    103   //
    104   // url gives the url of the search query. The url is used to avoid generating
    105   // a TemplateURL for an existing TemplateURL that shares the same host.
    106   bool CanReplaceKeyword(const string16& keyword,
    107                          const GURL& url,
    108                          const TemplateURL** template_url_to_replace);
    109 
    110   // Returns (in |matches|) all keywords beginning with |prefix|, sorted
    111   // shortest-first. If support_replacement_only is true, only keywords that
    112   // support replacement are returned.
    113   void FindMatchingKeywords(const string16& prefix,
    114                             bool support_replacement_only,
    115                             std::vector<string16>* matches) const;
    116 
    117   // Looks up |keyword| and returns the element it maps to.  Returns NULL if
    118   // the keyword was not found.
    119   // The caller should not try to delete the returned pointer; the data store
    120   // retains ownership of it.
    121   const TemplateURL* GetTemplateURLForKeyword(const string16& keyword) const;
    122 
    123   // Returns the first TemplateURL found with a URL using the specified |host|,
    124   // or NULL if there are no such TemplateURLs
    125   const TemplateURL* GetTemplateURLForHost(const std::string& host) const;
    126 
    127   // Adds a new TemplateURL to this model. TemplateURLModel will own the
    128   // reference, and delete it when the TemplateURL is removed.
    129   void Add(TemplateURL* template_url);
    130 
    131   // Removes the keyword from the model. This deletes the supplied TemplateURL.
    132   // This fails if the supplied template_url is the default search provider.
    133   void Remove(const TemplateURL* template_url);
    134 
    135   // Removes all auto-generated keywords that were created in the specified
    136   // range.
    137   void RemoveAutoGeneratedBetween(base::Time created_after,
    138                                   base::Time created_before);
    139 
    140   // Removes all auto-generated keywords that were created on or after the
    141   // date passed in.
    142   void RemoveAutoGeneratedSince(base::Time created_after);
    143 
    144   // If the given extension has an omnibox keyword, adds a TemplateURL for that
    145   // keyword. Only 1 keyword is allowed for a given extension. If the keyword
    146   // already exists for this extension, does nothing.
    147   void RegisterExtensionKeyword(const Extension* extension);
    148 
    149   // Removes the TemplateURL containing the keyword for the given extension,
    150   // if any.
    151   void UnregisterExtensionKeyword(const Extension* extension);
    152 
    153   // Returns the TemplateURL associated with the keyword for this extension.
    154   // This works by checking the extension ID, not the keyword, so it will work
    155   // even if the user changed the keyword.
    156   const TemplateURL* GetTemplateURLForExtension(
    157       const Extension* extension) const;
    158 
    159   // Returns the set of URLs describing the keywords. The elements are owned
    160   // by TemplateURLModel and should not be deleted.
    161   TemplateURLVector GetTemplateURLs() const;
    162 
    163   // Increment the usage count of a keyword.
    164   // Called when a URL is loaded that was generated from a keyword.
    165   void IncrementUsageCount(const TemplateURL* url);
    166 
    167   // Resets the title, keyword and search url of the specified TemplateURL.
    168   // The TemplateURL is marked as not replaceable.
    169   void ResetTemplateURL(const TemplateURL* url,
    170                         const string16& title,
    171                         const string16& keyword,
    172                         const std::string& search_url);
    173 
    174   // Return true if the given |url| can be made the default.
    175   bool CanMakeDefault(const TemplateURL* url);
    176 
    177   // Set the default search provider.  |url| may be null.
    178   // This will assert if the default search is managed; the UI should not be
    179   // invoking this method in that situation.
    180   void SetDefaultSearchProvider(const TemplateURL* url);
    181 
    182   // Returns the default search provider. If the TemplateURLModel hasn't been
    183   // loaded, the default search provider is pulled from preferences.
    184   //
    185   // NOTE: At least in unittest mode, this may return NULL.
    186   const TemplateURL* GetDefaultSearchProvider();
    187 
    188   // Returns true if the default search is managed through group policy.
    189   bool is_default_search_managed() const { return is_default_search_managed_; }
    190 
    191   // Observers used to listen for changes to the model.
    192   // TemplateURLModel does NOT delete the observers when deleted.
    193   void AddObserver(TemplateURLModelObserver* observer);
    194   void RemoveObserver(TemplateURLModelObserver* observer);
    195 
    196   // Loads the keywords. This has no effect if the keywords have already been
    197   // loaded.
    198   // Observers are notified when loading completes via the method
    199   // OnTemplateURLModelChanged.
    200   void Load();
    201 
    202   // Whether or not the keywords have been loaded.
    203   bool loaded() { return loaded_; }
    204 
    205   // Notification that the keywords have been loaded.
    206   // This is invoked from WebDataService, and should not be directly
    207   // invoked.
    208   virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
    209                                            const WDTypedResult* result);
    210 
    211   // Returns the locale-direction-adjusted short name for the given keyword.
    212   // Also sets the out param to indicate whether the keyword belongs to an
    213   // extension.
    214   string16 GetKeywordShortName(const string16& keyword,
    215                                bool* is_extension_keyword);
    216 
    217   // NotificationObserver method. TemplateURLModel listens for three
    218   // notification types:
    219   // . NOTIFY_HISTORY_URL_VISITED: adds keyword search terms if the visit
    220   //   corresponds to a keyword.
    221   // . NOTIFY_GOOGLE_URL_UPDATED: updates mapping for any keywords containing
    222   //   a google base url replacement term.
    223   // . PREF_CHANGED: checks whether the default search engine has changed.
    224   virtual void Observe(NotificationType type,
    225                        const NotificationSource& source,
    226                        const NotificationDetails& details);
    227 
    228   Profile* profile() const { return profile_; }
    229 
    230   void SetSearchEngineDialogSlot(int slot) {
    231     search_engine_dialog_chosen_slot_ = slot;
    232   }
    233 
    234   int GetSearchEngineDialogSlot() const {
    235     return search_engine_dialog_chosen_slot_;
    236   }
    237 
    238   // Registers the preferences used to save a TemplateURL to prefs.
    239   static void RegisterUserPrefs(PrefService* prefs);
    240 
    241  protected:
    242   // Cover method for the method of the same name on the HistoryService.
    243   // url is the one that was visited with the given search terms.
    244   //
    245   // This exists and is virtual for testing.
    246   virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
    247                                            const GURL& url,
    248                                            const string16& term);
    249 
    250  private:
    251   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, BuildQueryTerms);
    252   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, TestManagedDefaultSearch);
    253   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
    254                            UpdateKeywordSearchTermsForURL);
    255   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest,
    256                            DontUpdateKeywordSearchForNonReplaceable);
    257   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, ChangeGoogleBaseValue);
    258   FRIEND_TEST_ALL_PREFIXES(TemplateURLModelTest, MergeDeletesUnusedProviders);
    259   friend class TemplateURLModelTestUtil;
    260 
    261   typedef std::map<string16, const TemplateURL*> KeywordToTemplateMap;
    262 
    263   // Helper functor for FindMatchingKeywords(), for finding the range of
    264   // keywords which begin with a prefix.
    265   class LessWithPrefix;
    266 
    267   void Init(const Initializer* initializers, int num_initializers);
    268 
    269   void RemoveFromMaps(const TemplateURL* template_url);
    270 
    271   // Removes the supplied template_url from the keyword maps. This searches
    272   // through all entries in the keyword map and does not generate the host or
    273   // keyword. This is used when the cached content of the TemplateURL changes.
    274   void RemoveFromKeywordMapByPointer(const TemplateURL* template_url);
    275 
    276   void AddToMaps(const TemplateURL* template_url);
    277 
    278   // Sets the keywords. This is used once the keywords have been loaded.
    279   // This does NOT notify the delegate or the database.
    280   void SetTemplateURLs(const std::vector<TemplateURL*>& urls);
    281 
    282   // Transitions to the loaded state.
    283   void ChangeToLoadedState();
    284 
    285   // If there is a notification service, sends TEMPLATE_URL_MODEL_LOADED
    286   // notification.
    287   void NotifyLoaded();
    288 
    289   // Saves enough of url to preferences so that it can be loaded from
    290   // preferences on start up.
    291   void SaveDefaultSearchProviderToPrefs(const TemplateURL* url);
    292 
    293   // Creates a TemplateURL that was previously saved to prefs via
    294   // SaveDefaultSearchProviderToPrefs or set via policy.
    295   // Returns true if successful, false otherwise.
    296   // If the user or the policy has opted for no default search, this
    297   // returns true but default_provider is set to NULL.
    298   // |*is_managed| specifies whether the default is managed via policy.
    299   bool LoadDefaultSearchProviderFromPrefs(
    300       scoped_ptr<TemplateURL>* default_provider,
    301       bool* is_managed);
    302 
    303   // Returns true if there is no TemplateURL that has a search url with the
    304   // specified host, or the only TemplateURLs matching the specified host can
    305   // be replaced.
    306   bool CanReplaceKeywordForHost(const std::string& host,
    307                                 const TemplateURL** to_replace);
    308 
    309   // Returns true if the TemplateURL is replaceable. This doesn't look at the
    310   // uniqueness of the keyword or host and is intended to be called after those
    311   // checks have been done. This returns true if the TemplateURL doesn't appear
    312   // in the default list and is marked as safe_for_autoreplace.
    313   bool CanReplace(const TemplateURL* t_url);
    314 
    315   // Updates the information in |existing_turl| using the information from
    316   // |new_values|, but the ID for |existing_turl| is retained.
    317   // Notifying observers is the responsibility of the caller.
    318   void UpdateNoNotify(const TemplateURL* existing_turl,
    319                       const TemplateURL& new_values);
    320 
    321   // Returns the preferences we use.
    322   PrefService* GetPrefs();
    323 
    324   // Iterates through the TemplateURLs to see if one matches the visited url.
    325   // For each TemplateURL whose url matches the visited url
    326   // SetKeywordSearchTermsForURL is invoked.
    327   void UpdateKeywordSearchTermsForURL(
    328       const history::URLVisitedDetails& details);
    329 
    330   // If necessary, generates a visit for the site http:// + t_url.keyword().
    331   void AddTabToSearchVisit(const TemplateURL& t_url);
    332 
    333   // Adds each of the query terms in the specified url whose key and value are
    334   // non-empty to query_terms. If a query key appears multiple times, the value
    335   // is set to an empty string. Returns true if there is at least one key that
    336   // does not occur multiple times.
    337   static bool BuildQueryTerms(
    338       const GURL& url,
    339       std::map<std::string,std::string>* query_terms);
    340 
    341   // Invoked when the Google base URL has changed. Updates the mapping for all
    342   // TemplateURLs that have a replacement term of {google:baseURL} or
    343   // {google:baseSuggestURL}.
    344   void GoogleBaseURLChanged();
    345 
    346   // Update the default search.  Called at initialization or when a managed
    347   // preference has changed.
    348   void UpdateDefaultSearch();
    349 
    350   // Returns the default search specified in the prepopulated data, if it
    351   // exists.  If not, returns first URL in |template_urls_|, or NULL if that's
    352   // empty.
    353   const TemplateURL* FindNewDefaultSearchProvider();
    354 
    355   // Set the default search provider even if it is managed. |url| may be null.
    356   // Caller is responsible for notifying observers.
    357   void SetDefaultSearchProviderNoNotify(const TemplateURL* url);
    358 
    359   // Adds a new TemplateURL to this model. TemplateURLModel will own the
    360   // reference, and delete it when the TemplateURL is removed.
    361   // Caller is responsible for notifying observers.
    362   void AddNoNotify(TemplateURL* template_url);
    363 
    364   // Removes the keyword from the model. This deletes the supplied TemplateURL.
    365   // This fails if the supplied template_url is the default search provider.
    366   // Caller is responsible for notifying observers.
    367   void RemoveNoNotify(const TemplateURL* template_url);
    368 
    369   // Notify the observers that the model has changed.  This is done only if the
    370   // model is loaded.
    371   void NotifyObservers();
    372 
    373   NotificationRegistrar registrar_;
    374 
    375   // Mapping from keyword to the TemplateURL.
    376   KeywordToTemplateMap keyword_to_template_map_;
    377 
    378   TemplateURLVector template_urls_;
    379 
    380   ObserverList<TemplateURLModelObserver> model_observers_;
    381 
    382   // Maps from host to set of TemplateURLs whose search url host is host.
    383   SearchHostToURLsMap provider_map_;
    384 
    385   // Used to obtain the WebDataService.
    386   // When Load is invoked, if we haven't yet loaded, the WebDataService is
    387   // obtained from the Profile. This allows us to lazily access the database.
    388   Profile* profile_;
    389 
    390   // Whether the keywords have been loaded.
    391   bool loaded_;
    392 
    393   // Did loading fail? This is only valid if loaded_ is true.
    394   bool load_failed_;
    395 
    396   // If non-zero, we're waiting on a load.
    397   WebDataService::Handle load_handle_;
    398 
    399   // Service used to store entries.
    400   scoped_refptr<WebDataService> service_;
    401 
    402   // All visits that occurred before we finished loading. Once loaded
    403   // UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
    404   std::vector<history::URLVisitedDetails> visits_to_add_;
    405 
    406   // Once loaded, the default search provider.  This is a pointer to a
    407   // TemplateURL owned by template_urls_.
    408   const TemplateURL* default_search_provider_;
    409 
    410   // Used for UX testing. Gives the slot in the search engine dialog that was
    411   // chosen as the default search engine.
    412   int search_engine_dialog_chosen_slot_;
    413 
    414   // The initial search provider extracted from preferences. This is only valid
    415   // if we haven't been loaded or loading failed.
    416   scoped_ptr<TemplateURL> initial_default_search_provider_;
    417 
    418   // Whether the default search is managed via policy.
    419   bool is_default_search_managed_;
    420 
    421   // The set of preferences observer we use to find if the default search
    422   // preferences have changed.
    423   scoped_ptr<PrefSetObserver> default_search_prefs_;
    424 
    425   // ID assigned to next TemplateURL added to this model. This is an ever
    426   // increasing integer that is initialized from the database.
    427   TemplateURLID next_id_;
    428 
    429   // List of extension IDs waiting for Load to have keywords registered.
    430   std::vector<std::string> pending_extension_ids_;
    431 
    432   DISALLOW_COPY_AND_ASSIGN(TemplateURLModel);
    433 };
    434 
    435 #endif  // CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_MODEL_H_
    436