appcache_host.h revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
1// Copyright (c) 2011 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_HOST_H_
6#define WEBKIT_BROWSER_APPCACHE_APPCACHE_HOST_H_
7
8#include "base/callback.h"
9#include "base/gtest_prod_util.h"
10#include "base/memory/ref_counted.h"
11#include "base/observer_list.h"
12#include "url/gurl.h"
13#include "webkit/browser/appcache/appcache_group.h"
14#include "webkit/browser/appcache/appcache_service.h"
15#include "webkit/browser/appcache/appcache_storage.h"
16#include "webkit/browser/webkit_storage_browser_export.h"
17#include "webkit/common/appcache/appcache_interfaces.h"
18#include "webkit/common/resource_type.h"
19
20namespace net {
21class URLRequest;
22}  // namespace net
23
24namespace content {
25class AppCacheStorageImplTest;
26}
27
28namespace appcache {
29
30class AppCache;
31class AppCacheFrontend;
32class AppCacheRequestHandler;
33
34typedef base::Callback<void(Status, void*)> GetStatusCallback;
35typedef base::Callback<void(bool, void*)> StartUpdateCallback;
36typedef base::Callback<void(bool, void*)> SwapCacheCallback;
37
38// Server-side representation of an application cache host.
39class WEBKIT_STORAGE_BROWSER_EXPORT AppCacheHost
40    : public AppCacheStorage::Delegate,
41      public AppCacheGroup::UpdateObserver,
42      public AppCacheService::Observer {
43 public:
44
45  class WEBKIT_STORAGE_BROWSER_EXPORT Observer {
46   public:
47    // Called just after the cache selection algorithm completes.
48    virtual void OnCacheSelectionComplete(AppCacheHost* host) = 0;
49
50    // Called just prior to the instance being deleted.
51    virtual void OnDestructionImminent(AppCacheHost* host) = 0;
52
53    virtual ~Observer() {}
54  };
55
56  AppCacheHost(int host_id, AppCacheFrontend* frontend,
57               AppCacheService* service);
58  virtual ~AppCacheHost();
59
60  // Adds/removes an observer, the AppCacheHost does not take
61  // ownership of the observer.
62  void AddObserver(Observer* observer);
63  void RemoveObserver(Observer* observer);
64
65  // Support for cache selection and scriptable method calls.
66  void SelectCache(const GURL& document_url,
67                   const int64 cache_document_was_loaded_from,
68                   const GURL& manifest_url);
69  void SelectCacheForWorker(int parent_process_id,
70                            int parent_host_id);
71  void SelectCacheForSharedWorker(int64 appcache_id);
72  void MarkAsForeignEntry(const GURL& document_url,
73                          int64 cache_document_was_loaded_from);
74  void GetStatusWithCallback(const GetStatusCallback& callback,
75                             void* callback_param);
76  void StartUpdateWithCallback(const StartUpdateCallback& callback,
77                               void* callback_param);
78  void SwapCacheWithCallback(const SwapCacheCallback& callback,
79                             void* callback_param);
80
81  // Called prior to the main resource load. When the system contains multiple
82  // candidates for a main resource load, the appcache preferred by the host
83  // that created this host is used to break ties.
84  void SetSpawningHostId(int spawning_process_id, int spawning_host_id);
85
86  // May return NULL if the spawning host context has been closed, or if a
87  // spawning host context was never identified.
88  const AppCacheHost* GetSpawningHost() const;
89
90  const GURL& preferred_manifest_url() const {
91    return preferred_manifest_url_;
92  }
93  void set_preferred_manifest_url(const GURL& url) {
94    preferred_manifest_url_ = url;
95  }
96
97  // Support for loading resources out of the appcache.
98  // May return NULL if the request isn't subject to retrieval from an appache.
99  AppCacheRequestHandler* CreateRequestHandler(
100      net::URLRequest* request, ResourceType::Type resource_type);
101
102  // Support for devtools inspecting appcache resources.
103  void GetResourceList(std::vector<AppCacheResourceInfo>* resource_infos);
104
105  // Breaks any existing association between this host and a cache.
106  // 'manifest_url' is sent to DevTools as the manifest url that could have
107  // been associated before or could be associated later with this host.
108  // Associations are broken either thru the cache selection algorithm
109  // implemented in this class, or by the update algorithm (see
110  // AppCacheUpdateJob).
111  void AssociateNoCache(const GURL& manifest_url);
112
113  // Establishes an association between this host and an incomplete cache.
114  // 'manifest_url' is manifest url of the cache group being updated.
115  // Associations with incomplete caches are established by the update algorithm
116  // (see AppCacheUpdateJob).
117  void AssociateIncompleteCache(AppCache* cache, const GURL& manifest_url);
118
119  // Establishes an association between this host and a complete cache.
120  // Associations with complete caches are established either thru the cache
121  // selection algorithm implemented (in this class), or by the update algorithm
122  // (see AppCacheUpdateJob).
123  void AssociateCompleteCache(AppCache* cache);
124
125  // Adds a reference to the newest complete cache in a group, unless it's the
126  // same as the cache that is currently associated with the host.
127  void SetSwappableCache(AppCacheGroup* group);
128
129  // Used to ensure that a loaded appcache survives a frame navigation.
130  void LoadMainResourceCache(int64 cache_id);
131
132  // Used to notify the host that a namespace resource is being delivered as
133  // the main resource of the page and to provide its url.
134  void NotifyMainResourceIsNamespaceEntry(const GURL& namespace_entry_url);
135
136  // Used to notify the host that the main resource was blocked by a policy. To
137  // work properly, this method needs to by invoked prior to cache selection.
138  void NotifyMainResourceBlocked(const GURL& manifest_url);
139
140  // Used by the update job to keep track of which hosts are associated
141  // with which pending master entries.
142  const GURL& pending_master_entry_url() const {
143    return new_master_entry_url_;
144  }
145
146  int host_id() const { return host_id_; }
147  AppCacheService* service() const { return service_; }
148  AppCacheStorage* storage() const { return storage_; }
149  AppCacheFrontend* frontend() const { return frontend_; }
150  AppCache* associated_cache() const { return associated_cache_.get(); }
151
152  bool is_selection_pending() const {
153    return pending_selected_cache_id_ != kNoCacheId ||
154           !pending_selected_manifest_url_.is_empty();
155  }
156
157  const GURL& first_party_url() const { return first_party_url_; }
158
159  // Methods to support cross site navigations.
160  void PrepareForTransfer();
161  void CompleteTransfer(int host_id, AppCacheFrontend* frontend);
162
163 private:
164  Status GetStatus();
165  void LoadSelectedCache(int64 cache_id);
166  void LoadOrCreateGroup(const GURL& manifest_url);
167
168  // See public Associate*Host() methods above.
169  void AssociateCacheHelper(AppCache* cache, const GURL& manifest_url);
170
171  // AppCacheStorage::Delegate impl
172  virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE;
173  virtual void OnGroupLoaded(AppCacheGroup* group,
174                             const GURL& manifest_url) OVERRIDE;
175  // AppCacheService::Observer impl
176  virtual void OnServiceReinitialized(
177      AppCacheStorageReference* old_storage_ref) OVERRIDE;
178
179  void FinishCacheSelection(AppCache* cache, AppCacheGroup* group);
180  void DoPendingGetStatus();
181  void DoPendingStartUpdate();
182  void DoPendingSwapCache();
183
184  void ObserveGroupBeingUpdated(AppCacheGroup* group);
185
186  // AppCacheGroup::UpdateObserver methods.
187  virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE;
188
189  // Returns true if this host is for a dedicated worker context.
190  bool is_for_dedicated_worker() const {
191    return parent_host_id_ != kNoHostId;
192  }
193
194  // Returns the parent context's host instance. This is only valid
195  // to call when this instance is_for_dedicated_worker.
196  AppCacheHost* GetParentAppCacheHost() const;
197
198  // Identifies the corresponding appcache host in the child process.
199  int host_id_;
200
201  // Information about the host that created this one; the manifest
202  // preferred by our creator influences which cache our main resource
203  // should be loaded from.
204  int spawning_host_id_;
205  int spawning_process_id_;
206  GURL preferred_manifest_url_;
207
208  // Hosts for dedicated workers are special cased to shunt
209  // request handling off to the dedicated worker's parent.
210  // The scriptable api is not accessible in dedicated workers
211  // so the other aspects of this class are not relevant for
212  // these special case instances.
213  int parent_host_id_;
214  int parent_process_id_;
215
216  // Defined prior to refs to AppCaches and Groups because destruction
217  // order matters, the disabled_storage_reference_ must outlive those
218  // objects. See additional comments for the storage_ member.
219  scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
220
221  // The cache associated with this host, if any.
222  scoped_refptr<AppCache> associated_cache_;
223
224  // Hold a reference to the newest complete cache (if associated cache is
225  // not the newest) to keep the newest cache in existence while the app cache
226  // group is in use. The newest complete cache may have no associated hosts
227  // holding any references to it and would otherwise be deleted prematurely.
228  scoped_refptr<AppCache> swappable_cache_;
229
230  // Keep a reference to the group being updated until the update completes.
231  scoped_refptr<AppCacheGroup> group_being_updated_;
232
233  // Similarly, keep a reference to the newest cache of the group until the
234  // update completes. When adding a new master entry to a cache that is not
235  // in use in any other host, this reference keeps the cache in  memory.
236  scoped_refptr<AppCache> newest_cache_of_group_being_updated_;
237
238  // Keep a reference to the cache of the main resource so it survives frame
239  // navigations.
240  scoped_refptr<AppCache> main_resource_cache_;
241  int64 pending_main_resource_cache_id_;
242
243  // Cache loading is async, if we're loading a specific cache or group
244  // for the purposes of cache selection, one or the other of these will
245  // indicate which cache or group is being loaded.
246  int64 pending_selected_cache_id_;
247  GURL pending_selected_manifest_url_;
248
249  // A new master entry to be added to the cache, may be empty.
250  GURL new_master_entry_url_;
251
252  // The frontend proxy to deliver notifications to the child process.
253  AppCacheFrontend* frontend_;
254
255  // Our central service object.
256  AppCacheService* service_;
257
258  // And the equally central storage object, with a twist. In some error
259  // conditions the storage object gets recreated and reinitialized. The
260  // disabled_storage_reference_ (defined earlier) allows for cleanup of an
261  // instance that got disabled  after we had latched onto it. In normal
262  // circumstances, disabled_storage_reference_ is expected to be NULL.
263  // When non-NULL both storage_ and disabled_storage_reference_ refer to the
264  // same instance.
265  AppCacheStorage* storage_;
266
267  // Since these are synchronous scriptable API calls in the client, there can
268  // only be one type of callback pending. Also, we have to wait until we have a
269  // cache selection prior to responding to these calls, as cache selection
270  // involves async loading of a cache or a group from storage.
271  GetStatusCallback pending_get_status_callback_;
272  StartUpdateCallback pending_start_update_callback_;
273  SwapCacheCallback pending_swap_cache_callback_;
274  void* pending_callback_param_;
275
276  // True if an intercept or fallback namespace resource was
277  // delivered as the main resource.
278  bool main_resource_was_namespace_entry_;
279  GURL namespace_entry_url_;
280
281  // True if requests for this host were blocked by a policy.
282  bool main_resource_blocked_;
283  GURL blocked_manifest_url_;
284
285  // Tells if info about associated cache is pending. Info is pending
286  // when update job has not returned success yet.
287  bool associated_cache_info_pending_;
288
289  // List of objects observing us.
290  ObserverList<Observer> observers_;
291
292  // Used to inform the QuotaManager of what origins are currently in use.
293  GURL origin_in_use_;
294
295  // First party url to be used in policy checks.
296  GURL first_party_url_;
297
298  friend class content::AppCacheStorageImplTest;
299  friend class AppCacheRequestHandlerTest;
300  friend class AppCacheUpdateJobTest;
301  FRIEND_TEST_ALL_PREFIXES(AppCacheTest, CleanupUnusedCache);
302  FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest, CleanupUnusedGroup);
303  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, Basic);
304  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SelectNoCache);
305  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, ForeignEntry);
306  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, FailedCacheLoad);
307  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, FailedGroupLoad);
308  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SetSwappableCache);
309  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, ForDedicatedWorker);
310  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SelectCacheAllowed);
311  FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SelectCacheBlocked);
312  FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest, QueueUpdate);
313
314  DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
315};
316
317}  // namespace appcache
318
319#endif  // WEBKIT_BROWSER_APPCACHE_APPCACHE_HOST_H_
320