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 #ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_ 6 #define CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <memory> 12 #include <vector> 13 14 #include "base/compiler_specific.h" 15 #include "base/gtest_prod_util.h" 16 #include "base/macros.h" 17 #include "base/memory/ref_counted.h" 18 #include "base/memory/weak_ptr.h" 19 #include "content/browser/appcache/appcache_working_set.h" 20 #include "content/common/content_export.h" 21 #include "url/origin.h" 22 23 class GURL; 24 25 namespace content { 26 27 namespace appcache_storage_unittest { 28 class AppCacheStorageTest; 29 FORWARD_DECLARE_TEST(AppCacheStorageTest, DelegateReferences); 30 FORWARD_DECLARE_TEST(AppCacheStorageTest, UsageMap); 31 } // namespace appcache_storage_unittest 32 33 class AppCache; 34 class AppCacheEntry; 35 class AppCacheGroup; 36 class AppCacheQuotaClientTest; 37 class AppCacheResponseMetadataWriter; 38 class AppCacheResponseReader; 39 class AppCacheResponseTest; 40 class AppCacheResponseWriter; 41 class AppCacheServiceImpl; 42 struct AppCacheInfoCollection; 43 struct HttpResponseInfoIOBuffer; 44 45 class CONTENT_EXPORT AppCacheStorage { 46 public: 47 class CONTENT_EXPORT Delegate { 48 public: 49 Delegate(const Delegate&) = delete; 50 Delegate& operator=(const Delegate&) = delete; 51 52 // If retrieval fails, |collection| will be null. OnAllInfo(AppCacheInfoCollection * collection)53 virtual void OnAllInfo(AppCacheInfoCollection* collection) {} 54 55 // If the load fails, |cache| will be null. OnCacheLoaded(AppCache * cache,int64_t cache_id)56 virtual void OnCacheLoaded(AppCache* cache, int64_t cache_id) {} 57 58 // If the load fails, |group| will be null. OnGroupLoaded(AppCacheGroup * group,const GURL & manifest_url)59 virtual void OnGroupLoaded( 60 AppCacheGroup* group, const GURL& manifest_url) {} 61 62 // If successfully stored, |success| will be true. OnGroupAndNewestCacheStored(AppCacheGroup * group,AppCache * newest_cache,bool success,bool would_exceed_quota)63 virtual void OnGroupAndNewestCacheStored( 64 AppCacheGroup* group, AppCache* newest_cache, bool success, 65 bool would_exceed_quota) {} 66 67 // If the operation fails, |success| will be false. OnGroupMadeObsolete(AppCacheGroup * group,bool success,int response_code)68 virtual void OnGroupMadeObsolete(AppCacheGroup* group, 69 bool success, 70 int response_code) {} 71 72 // If a load fails, |response_info| will be null. OnResponseInfoLoaded(AppCacheResponseInfo * response_info,int64_t response_id)73 virtual void OnResponseInfoLoaded(AppCacheResponseInfo* response_info, 74 int64_t response_id) {} 75 76 // If no response is found, |entry|'s response_id() and |fallback_entry|'s 77 // response_id() will be kAppCacheNoResponseId. 78 // 79 // If the response is the entry for an intercept or fallback namespace, 80 // |namespace_entry_url| refers to the entry. Otherwise, it is empty. 81 // 82 // If a response is found, |cache_id|, |group_id|, and |manifest_url| 83 // identify the cache containing the response. OnMainResponseFound(const GURL & url,const AppCacheEntry & entry,const GURL & namespace_entry_url,const AppCacheEntry & fallback_entry,int64_t cache_id,int64_t group_id,const GURL & mainfest_url)84 virtual void OnMainResponseFound(const GURL& url, 85 const AppCacheEntry& entry, 86 const GURL& namespace_entry_url, 87 const AppCacheEntry& fallback_entry, 88 int64_t cache_id, 89 int64_t group_id, 90 const GURL& mainfest_url) {} 91 92 protected: 93 // The constructor and destructor exist to facilitate subclassing, and 94 // should not be called directly. 95 Delegate() noexcept = default; 96 virtual ~Delegate() = default; 97 }; 98 99 explicit AppCacheStorage(AppCacheServiceImpl* service); 100 virtual ~AppCacheStorage(); 101 102 // Schedules a task to retrieve basic info about all groups and caches 103 // stored in the system. Upon completion the delegate will be called 104 // with the results. 105 virtual void GetAllInfo(Delegate* delegate) = 0; 106 107 // Schedules a cache to be loaded from storage. Upon load completion 108 // the delegate will be called back. If the cache already resides in 109 // memory, the delegate will be called back immediately without returning 110 // to the message loop. If the load fails, the delegate will be called 111 // back with a NULL cache pointer. 112 virtual void LoadCache(int64_t id, Delegate* delegate) = 0; 113 114 // Schedules a group and its newest cache, if any, to be loaded from storage. 115 // Upon load completion the delegate will be called back. If the group 116 // and newest cache already reside in memory, the delegate will be called 117 // back immediately without returning to the message loop. If the load fails, 118 // the delegate will be called back with a NULL group pointer. 119 virtual void LoadOrCreateGroup( 120 const GURL& manifest_url, Delegate* delegate) = 0; 121 122 // Schedules response info to be loaded from storage. 123 // Upon load completion the delegate will be called back. If the data 124 // already resides in memory, the delegate will be called back 125 // immediately without returning to the message loop. If the load fails, 126 // the delegate will be called back with a NULL pointer. 127 virtual void LoadResponseInfo(const GURL& manifest_url, 128 int64_t response_id, 129 Delegate* delegate); 130 131 // Schedules a group and its newest complete cache to be initially stored or 132 // incrementally updated with new changes. Upon completion the delegate 133 // will be called back. A group without a newest cache cannot be stored. 134 // It's a programming error to call this method without a newest cache. A 135 // side effect of storing a new newest cache is the removal of the group's 136 // old caches and responses from persistent storage (although they may still 137 // linger in the in-memory working set until no longer needed). The new 138 // cache will be added as the group's newest complete cache only if storage 139 // succeeds. 140 virtual void StoreGroupAndNewestCache( 141 AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) = 0; 142 143 // Schedules a query to identify a response for a main request. Upon 144 // completion the delegate will be called back. 145 virtual void FindResponseForMainRequest( 146 const GURL& url, 147 const GURL& preferred_manifest_url, 148 Delegate* delegate) = 0; 149 150 // Performs an immediate lookup of the in-memory cache to 151 // identify a response for a sub resource request. 152 virtual void FindResponseForSubRequest( 153 AppCache* cache, const GURL& url, 154 AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry, 155 bool* found_network_namespace) = 0; 156 157 // Immediately updates in-memory storage, if the cache is in memory, 158 // and schedules a task to update persistent storage. If the cache is 159 // already scheduled to be loaded, upon loading completion the entry 160 // will be marked. There is no delegate completion callback. 161 virtual void MarkEntryAsForeign(const GURL& entry_url, int64_t cache_id) = 0; 162 163 // Schedules a task to update persistent storage and doom the group and all 164 // related caches and responses for deletion. Upon completion the in-memory 165 // instance is marked as obsolete and the delegate callback is called. 166 virtual void MakeGroupObsolete(AppCacheGroup* group, 167 Delegate* delegate, 168 int response_code) = 0; 169 170 // Schedules a task to update persistent storage with the times of the first 171 // evictable error and last successful full update check. 172 virtual void StoreEvictionTimes(AppCacheGroup* group) = 0; 173 174 // Cancels all pending callbacks for the delegate. The delegate callbacks 175 // will not be invoked after, however any scheduled operations will still 176 // take place. The callbacks for subsequently scheduled operations are 177 // unaffected. CancelDelegateCallbacks(Delegate * delegate)178 void CancelDelegateCallbacks(Delegate* delegate) { 179 DelegateReference* delegate_reference = GetDelegateReference(delegate); 180 if (delegate_reference) 181 delegate_reference->CancelReference(); 182 } 183 184 // Creates a reader to read a response from storage. 185 virtual std::unique_ptr<AppCacheResponseReader> CreateResponseReader( 186 const GURL& manifest_url, 187 int64_t response_id) = 0; 188 189 // Creates a writer to write a new response to storage. This call 190 // establishes a new response id. 191 virtual std::unique_ptr<AppCacheResponseWriter> CreateResponseWriter( 192 const GURL& manifest_url) = 0; 193 194 // Creates a metadata writer to write metadata of response to storage. 195 virtual std::unique_ptr<AppCacheResponseMetadataWriter> 196 CreateResponseMetadataWriter(int64_t response_id) = 0; 197 198 // Schedules the lazy deletion of responses and saves the ids 199 // persistently such that the responses will be deleted upon restart 200 // if they aren't deleted prior to shutdown. 201 virtual void DoomResponses(const GURL& manifest_url, 202 const std::vector<int64_t>& response_ids) = 0; 203 204 // Schedules the lazy deletion of responses without persistently saving 205 // the response ids. 206 virtual void DeleteResponses(const GURL& manifest_url, 207 const std::vector<int64_t>& response_ids) = 0; 208 209 // Returns true if the AppCacheStorage instance is initialized. 210 virtual bool IsInitialized() = 0; 211 212 // Generates unique storage ids for different object types. NewCacheId()213 int64_t NewCacheId() { return ++last_cache_id_; } NewGroupId()214 int64_t NewGroupId() { return ++last_group_id_; } 215 216 // The working set of object instances currently in memory. working_set()217 AppCacheWorkingSet* working_set() { return &working_set_; } 218 219 // A map of origins to usage. usage_map()220 const std::map<url::Origin, int64_t>& usage_map() const { return usage_map_; } 221 222 // Simple ptr back to the service object that owns us. service()223 AppCacheServiceImpl* service() { return service_; } 224 225 // Returns a weak pointer reference to the AppCacheStorage instance. 226 base::WeakPtr<AppCacheStorage> GetWeakPtr(); 227 228 protected: 229 friend class content::AppCacheQuotaClientTest; 230 friend class content::AppCacheResponseTest; 231 friend class content::appcache_storage_unittest::AppCacheStorageTest; 232 233 // Helper used to manage multiple references to a 'delegate' and to 234 // allow all pending callbacks to that delegate to be easily cancelled. 235 struct CONTENT_EXPORT DelegateReference : 236 public base::RefCounted<DelegateReference> { 237 Delegate* delegate; 238 AppCacheStorage* storage; 239 240 DelegateReference(Delegate* delegate, AppCacheStorage* storage); 241 CancelReferenceDelegateReference242 void CancelReference() { 243 storage->delegate_references_.erase(delegate); 244 storage = nullptr; 245 delegate = nullptr; 246 } 247 248 private: 249 friend class base::RefCounted<DelegateReference>; 250 ~DelegateReference(); 251 }; 252 253 // Helper for calling a function on a collection of delegates. 254 // 255 // ForEachCallable: (AppCacheStorage::Delegate*) -> void 256 template <typename ForEachCallable> ForEachDelegate(const std::vector<scoped_refptr<DelegateReference>> & delegates,const ForEachCallable & callable)257 static void ForEachDelegate( 258 const std::vector<scoped_refptr<DelegateReference>>& delegates, 259 const ForEachCallable& callable) { 260 for (const scoped_refptr<DelegateReference>& delegate_ref : delegates) { 261 Delegate* delegate = delegate_ref->delegate; 262 if (delegate != nullptr) 263 callable(delegate); 264 } 265 } 266 267 // Helper used to manage an async LoadResponseInfo calls on behalf of 268 // multiple callers. 269 class ResponseInfoLoadTask { 270 public: 271 ResponseInfoLoadTask(const GURL& manifest_url, 272 int64_t response_id, 273 AppCacheStorage* storage); 274 ~ResponseInfoLoadTask(); 275 response_id()276 int64_t response_id() const { return response_id_; } manifest_url()277 const GURL& manifest_url() const { return manifest_url_; } 278 AddDelegate(DelegateReference * delegate_reference)279 void AddDelegate(DelegateReference* delegate_reference) { 280 delegates_.push_back(delegate_reference); 281 } 282 283 void StartIfNeeded(); 284 285 private: 286 void OnReadComplete(int result); 287 288 AppCacheStorage* storage_; 289 GURL manifest_url_; 290 int64_t response_id_; 291 std::unique_ptr<AppCacheResponseReader> reader_; 292 std::vector<scoped_refptr<DelegateReference>> delegates_; 293 scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_; 294 }; 295 GetDelegateReference(Delegate * delegate)296 DelegateReference* GetDelegateReference(Delegate* delegate) { 297 std::map<Delegate*, DelegateReference*>::iterator iter = 298 delegate_references_.find(delegate); 299 if (iter != delegate_references_.end()) 300 return iter->second; 301 return nullptr; 302 } 303 GetOrCreateDelegateReference(Delegate * delegate)304 DelegateReference* GetOrCreateDelegateReference(Delegate* delegate) { 305 DelegateReference* reference = GetDelegateReference(delegate); 306 if (reference) 307 return reference; 308 return new DelegateReference(delegate, this); 309 } 310 GetOrCreateResponseInfoLoadTask(const GURL & manifest_url,int64_t response_id)311 ResponseInfoLoadTask* GetOrCreateResponseInfoLoadTask( 312 const GURL& manifest_url, 313 int64_t response_id) { 314 auto iter = pending_info_loads_.find(response_id); 315 if (iter != pending_info_loads_.end()) 316 return iter->second.get(); 317 return new ResponseInfoLoadTask(manifest_url, response_id, this); 318 } 319 320 // Should only be called when creating a new response writer. NewResponseId()321 int64_t NewResponseId() { return ++last_response_id_; } 322 323 // Helpers to query and notify the QuotaManager. 324 void UpdateUsageMapAndNotify(const url::Origin& origin, int64_t new_usage); 325 void ClearUsageMapAndNotify(); 326 void NotifyStorageAccessed(const url::Origin& origin); 327 328 // The last storage id used for different object types. 329 int64_t last_cache_id_; 330 int64_t last_group_id_; 331 int64_t last_response_id_; 332 333 // Maps origin to padded usage. 334 std::map<url::Origin, int64_t> usage_map_; 335 AppCacheWorkingSet working_set_; 336 AppCacheServiceImpl* service_; 337 std::map<Delegate*, DelegateReference*> delegate_references_; 338 339 // Note that the ResponseInfoLoadTask items add themselves to this map. 340 std::map<int64_t, std::unique_ptr<ResponseInfoLoadTask>> pending_info_loads_; 341 342 // The set of last ids must be retrieved from storage prior to being used. 343 static const int64_t kUnitializedId; 344 345 FRIEND_TEST_ALL_PREFIXES( 346 content::appcache_storage_unittest::AppCacheStorageTest, 347 DelegateReferences); 348 FRIEND_TEST_ALL_PREFIXES( 349 content::appcache_storage_unittest::AppCacheStorageTest, 350 UsageMap); 351 352 // The WeakPtrFactory below must occur last in the class definition so they 353 // get destroyed last. 354 base::WeakPtrFactory<AppCacheStorage> weak_factory_{this}; 355 356 DISALLOW_COPY_AND_ASSIGN(AppCacheStorage); 357 }; 358 359 } // namespace content 360 361 #endif // CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_ 362