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