Home | History | Annotate | Download | only in search_provider_logos
      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_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_
      6 #define COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/callback.h"
     12 #include "base/files/file_path.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/observer_list.h"
     16 #include "base/sequenced_task_runner.h"
     17 #include "base/time/clock.h"
     18 #include "base/time/time.h"
     19 #include "components/search_provider_logos/logo_cache.h"
     20 #include "components/search_provider_logos/logo_common.h"
     21 #include "net/url_request/url_fetcher_delegate.h"
     22 #include "url/gurl.h"
     23 
     24 namespace net {
     25 class URLFetcher;
     26 class URLRequestContextGetter;
     27 }
     28 
     29 namespace search_provider_logos {
     30 
     31 // Receives updates when the search provider's logo is available.
     32 class LogoObserver {
     33  public:
     34   virtual ~LogoObserver() {}
     35 
     36   // Called when the cached logo is available and possibly when a freshly
     37   // downloaded logo is available. |logo| will be NULL if no logo is available.
     38   // |from_cache| indicates whether the logo was loaded from the cache.
     39   //
     40   // If the fresh logo is the same as the cached logo, this will not be called
     41   // again.
     42   virtual void OnLogoAvailable(const Logo* logo, bool from_cache) = 0;
     43 
     44   // Called when the LogoTracker will no longer send updates to this
     45   // LogoObserver. For example: after the cached logo is validated, after
     46   // OnFreshLogoAvailable() is called, or when the LogoTracker is destructed.
     47   // This is not called when an observer is removed using
     48   // LogoTracker::RemoveObserver().
     49   virtual void OnObserverRemoved() = 0;
     50 };
     51 
     52 // Provides a LogoTracker with methods it needs to download and cache logos.
     53 class LogoDelegate {
     54  public:
     55   virtual ~LogoDelegate() {}
     56 
     57   // Decodes an untrusted image safely and returns it as an SkBitmap via
     58   // |image_decoded_callback|. If image decoding fails, |image_decoded_callback|
     59   // should be called with NULL. This will be called on the thread that
     60   // LogoTracker lives on and |image_decoded_callback| must be called on the
     61   // same thread.
     62   virtual void DecodeUntrustedImage(
     63       const scoped_refptr<base::RefCountedString>& encoded_image,
     64       base::Callback<void(const SkBitmap&)> image_decoded_callback) = 0;
     65 };
     66 
     67 // Parses the response from the server and returns it as an EncodedLogo. Returns
     68 // NULL if the response is invalid.
     69 typedef base::Callback<
     70     scoped_ptr<EncodedLogo>(const scoped_ptr<std::string>& response,
     71                             base::Time response_time)> ParseLogoResponse;
     72 
     73 // Encodes the fingerprint of the cached logo in the logo URL. This enables the
     74 // server to verify whether the cached logo is up-to-date.
     75 typedef base::Callback<
     76     GURL(const GURL& logo_url, const std::string& fingerprint)>
     77     AppendFingerprintToLogoURL;
     78 
     79 // This class provides the logo for a search provider. Logos are downloaded from
     80 // the search provider's logo URL and cached on disk.
     81 //
     82 // Call SetServerAPI() at least once to specify how to get the logo from the
     83 // server. Then call GetLogo() to trigger retrieval of the logo and receive
     84 // updates once the cached and/or fresh logos are available.
     85 class LogoTracker : public net::URLFetcherDelegate {
     86  public:
     87   // Constructs a LogoTracker with the given LogoDelegate. Takes ownership of
     88   // |delegate|, which will be deleted at the same time as the LogoTracker.
     89   //
     90   // |cached_logo_directory| is the directory in which the cached logo and its
     91   // metadata should be saved.
     92   //
     93   // |file_task_runner| is the SequencedTaskRunner that should be used to run
     94   // file system operations.
     95   //
     96   // |background_task_runner| is the TaskRunner that should be used to for
     97   // CPU-intensive background operations.
     98   //
     99   // |request_context_getter| is the URLRequestContextGetter used to download
    100   // the logo.
    101   explicit LogoTracker(
    102       base::FilePath cached_logo_directory,
    103       scoped_refptr<base::SequencedTaskRunner> file_task_runner,
    104       scoped_refptr<base::TaskRunner> background_task_runner,
    105       scoped_refptr<net::URLRequestContextGetter> request_context_getter,
    106       scoped_ptr<LogoDelegate> delegate);
    107 
    108   virtual ~LogoTracker();
    109 
    110   // Defines the server API for downloading and parsing the logo. This must be
    111   // called at least once before calling GetLogo().
    112   //
    113   // |logo_url| is the URL from which the logo will be downloaded. If |logo_url|
    114   // is different than the current logo URL, any pending LogoObservers will be
    115   // canceled.
    116   //
    117   // |parse_logo_response_func| is a callback that will be used to parse the
    118   // server's response into a EncodedLogo object. |append_fingerprint_func| is a
    119   // callback that will return the URL from which to download the logo if a
    120   // cached logo with a fingerprint is already available. Note:
    121   // |parse_logo_response_func| and |append_fingerprint_func| must be suitable
    122   // for running multiple times, concurrently, and on multiple threads.
    123   void SetServerAPI(const GURL& logo_url,
    124                     const ParseLogoResponse& parse_logo_response_func,
    125                     const AppendFingerprintToLogoURL& append_fingerprint_func);
    126 
    127   // Retrieves the current search provider's logo from the local cache and/or
    128   // over the network, and registers |observer| to be called when the cached
    129   // and/or fresh logos are available.
    130   void GetLogo(LogoObserver* observer);
    131 
    132   // Prevents |observer| from receiving future updates. This is safe to call
    133   // even when the observer is being notified of an update.
    134   void RemoveObserver(LogoObserver* observer);
    135 
    136   // Overrides the cache used to store logos.
    137   void SetLogoCacheForTests(scoped_ptr<LogoCache> cache);
    138 
    139   // Overrides the clock used to check the time.
    140   void SetClockForTests(scoped_ptr<base::Clock> clock);
    141 
    142  private:
    143   // Cancels the current asynchronous operation, if any, and resets all member
    144   // variables that change as the logo is fetched.
    145   void ReturnToIdle();
    146 
    147   // Called when the cached logo has been read from the cache. |cached_logo|
    148   // will be NULL if there wasn't a valid, up-to-date logo in the cache.
    149   void OnCachedLogoRead(scoped_ptr<EncodedLogo> cached_logo);
    150 
    151   // Called when the cached logo has been decoded into an SkBitmap. |image| will
    152   // be NULL if decoding failed.
    153   void OnCachedLogoAvailable(const LogoMetadata& metadata,
    154                              const SkBitmap& image);
    155 
    156   // Stores |logo| in the cache.
    157   void SetCachedLogo(scoped_ptr<EncodedLogo> logo);
    158 
    159   // Updates the metadata for the logo already stored in the cache.
    160   void SetCachedMetadata(const LogoMetadata& metadata);
    161 
    162   // Starts fetching the current logo over the network.
    163   void FetchLogo();
    164 
    165   // Called when the logo has been downloaded and parsed. |logo| will be NULL
    166   // if the server's response was invalid.
    167   void OnFreshLogoParsed(scoped_ptr<EncodedLogo> logo);
    168 
    169   // Called when the fresh logo has been decoded into an SkBitmap. |image| will
    170   // be NULL if decoding failed.
    171   void OnFreshLogoAvailable(scoped_ptr<EncodedLogo> logo,
    172                             const SkBitmap& image);
    173 
    174   // net::URLFetcherDelegate:
    175   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
    176   virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source,
    177                                           int64 current,
    178                                           int64 total) OVERRIDE;
    179 
    180   // The URL from which the logo is fetched.
    181   GURL logo_url_;
    182 
    183   // The function used to parse the logo response from the server.
    184   ParseLogoResponse parse_logo_response_func_;
    185 
    186   // The function used to include the cached logo's fingerprint in the logo URL.
    187   AppendFingerprintToLogoURL append_fingerprint_func_;
    188 
    189   // False if an asynchronous task is currently running.
    190   bool is_idle_;
    191 
    192   // The logo that's been read from the cache, or NULL if the cache is empty.
    193   // Meaningful only if is_cached_logo_valid_ is true; NULL otherwise.
    194   scoped_ptr<Logo> cached_logo_;
    195 
    196   // Whether the value of |cached_logo_| reflects the actual cached logo.
    197   // This will be false if the logo hasn't been read from the cache yet.
    198   // |cached_logo_| may be NULL even if |is_cached_logo_valid_| is true, if no
    199   // logo is cached.
    200   bool is_cached_logo_valid_;
    201 
    202   // The URLFetcher currently fetching the logo. NULL when not fetching.
    203   scoped_ptr<net::URLFetcher> fetcher_;
    204 
    205   // The list of observers to be notified when the logo is available. This
    206   // should be empty when the state is IDLE.
    207   ObserverList<LogoObserver> logo_observers_;
    208 
    209   scoped_ptr<LogoDelegate> logo_delegate_;
    210 
    211   // The cache used to persist the logo on disk. Used only on the file thread.
    212   LogoCache* logo_cache_;
    213 
    214   // Clock used to determine current time. Can be overridden in tests.
    215   scoped_ptr<base::Clock> clock_;
    216 
    217   // The SequencedTaskRunner on which file system operations will be run.
    218   scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
    219 
    220   // The TaskRunner on which the server's response will be parsed.
    221   scoped_refptr<base::TaskRunner> background_task_runner_;
    222 
    223   // The URLRequestContextGetter used for network requests.
    224   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
    225 
    226   base::WeakPtrFactory<LogoTracker> weak_ptr_factory_;
    227 
    228   DISALLOW_COPY_AND_ASSIGN(LogoTracker);
    229 };
    230 
    231 }  // namespace search_provider_logos
    232 
    233 #endif  // COMPONENTS_SEARCH_PROVIDER_LOGOS_LOGO_TRACKER_H_
    234