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: ~LogoObserver()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: ~LogoDelegate()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