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