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