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