1// Copyright 2014 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_SERVICE_IMPL_H_
6#define CONTENT_BROWSER_APPCACHE_APPCACHE_SERVICE_IMPL_H_
7
8#include <map>
9#include <set>
10
11#include "base/gtest_prod_util.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/observer_list.h"
15#include "base/time/time.h"
16#include "base/timer/timer.h"
17#include "content/common/appcache_interfaces.h"
18#include "content/common/content_export.h"
19#include "content/public/browser/appcache_service.h"
20#include "net/base/completion_callback.h"
21#include "net/base/net_errors.h"
22#include "storage/browser/quota/quota_manager_proxy.h"
23
24namespace base {
25class FilePath;
26class SingleThreadTaskRunner;
27}  // namespace base
28
29namespace net {
30class URLRequestContext;
31}  // namespace net
32
33namespace storage {
34class SpecialStoragePolicy;
35}  // namespace storage
36
37namespace content {
38FORWARD_DECLARE_TEST(AppCacheServiceImplTest, ScheduleReinitialize);
39class AppCacheBackendImpl;
40class AppCacheExecutableHandlerFactory;
41class AppCacheQuotaClient;
42class AppCachePolicy;
43class AppCacheServiceImplTest;
44class AppCacheStorageImplTest;
45class AppCacheStorage;
46
47// Refcounted container to manage the lifetime of the old storage instance
48// during Reinitialization.
49class CONTENT_EXPORT AppCacheStorageReference
50    : public base::RefCounted<AppCacheStorageReference> {
51public:
52  AppCacheStorage* storage() const { return storage_.get(); }
53private:
54  friend class AppCacheServiceImpl;
55  friend class base::RefCounted<AppCacheStorageReference>;
56  AppCacheStorageReference(scoped_ptr<AppCacheStorage> storage);
57  ~AppCacheStorageReference();
58
59  scoped_ptr<AppCacheStorage> storage_;
60};
61
62// Class that manages the application cache service. Sends notifications
63// to many frontends.  One instance per user-profile. Each instance has
64// exclusive access to its cache_directory on disk.
65class CONTENT_EXPORT AppCacheServiceImpl
66    : public AppCacheService {
67 public:
68
69  class CONTENT_EXPORT Observer {
70   public:
71    // An observer method to inform consumers of reinitialzation. Managing
72    // the lifetime of the old storage instance is a delicate process.
73    // Consumers can keep the old disabled instance alive by hanging on to the
74    // ref provided.
75    virtual void OnServiceReinitialized(
76        AppCacheStorageReference* old_storage_ref) = 0;
77    virtual ~Observer() {}
78  };
79
80  // If not using quota management, the proxy may be NULL.
81  explicit AppCacheServiceImpl(storage::QuotaManagerProxy* quota_manager_proxy);
82  virtual ~AppCacheServiceImpl();
83
84  void Initialize(
85      const base::FilePath& cache_directory,
86      const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
87      const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread);
88
89  void AddObserver(Observer* observer) {
90    observers_.AddObserver(observer);
91  }
92
93  void RemoveObserver(Observer* observer) {
94    observers_.RemoveObserver(observer);
95  }
96
97  // For use in catastrophic failure modes to reboot the appcache system
98  // without relaunching the browser.
99  void ScheduleReinitialize();
100
101  // AppCacheService implementation:
102  virtual void CanHandleMainResourceOffline(
103      const GURL& url,
104      const GURL& first_party,
105      const net::CompletionCallback& callback) OVERRIDE;
106  virtual void GetAllAppCacheInfo(
107      AppCacheInfoCollection* collection,
108      const net::CompletionCallback& callback) OVERRIDE;
109  virtual void DeleteAppCacheGroup(
110      const GURL& manifest_url,
111      const net::CompletionCallback& callback) OVERRIDE;
112
113  // Deletes all appcaches for the origin, 'callback' is invoked upon
114  // completion. This method always completes asynchronously.
115  // (virtual for unit testing)
116  virtual void DeleteAppCachesForOrigin(
117      const GURL& origin, const net::CompletionCallback& callback);
118
119  // Checks the integrity of 'response_id' by reading the headers and data.
120  // If it cannot be read, the cache group for 'manifest_url' is deleted.
121  void CheckAppCacheResponse(const GURL& manifest_url, int64 cache_id,
122                             int64 response_id);
123
124  // Context for use during cache updates, should only be accessed
125  // on the IO thread. We do NOT add a reference to the request context,
126  // it is the callers responsibility to ensure that the pointer
127  // remains valid while set.
128  net::URLRequestContext* request_context() const { return request_context_; }
129  void set_request_context(net::URLRequestContext* context) {
130    request_context_ = context;
131  }
132
133  // The appcache policy, may be null, in which case access is always allowed.
134  // The service does NOT assume ownership of the policy, it is the callers
135  // responsibility to ensure that the pointer remains valid while set.
136  AppCachePolicy* appcache_policy() const { return appcache_policy_; }
137  void set_appcache_policy(AppCachePolicy* policy) {
138    appcache_policy_ = policy;
139  }
140
141  // The factory may be null, in which case invocations of exe handlers
142  // will result in an error response.
143  // The service does NOT assume ownership of the factory, it is the callers
144  // responsibility to ensure that the pointer remains valid while set.
145  AppCacheExecutableHandlerFactory* handler_factory() const {
146    return handler_factory_;
147  }
148  void set_handler_factory(
149      AppCacheExecutableHandlerFactory* factory) {
150    handler_factory_ = factory;
151  }
152
153  storage::SpecialStoragePolicy* special_storage_policy() const {
154    return special_storage_policy_.get();
155  }
156  void set_special_storage_policy(storage::SpecialStoragePolicy* policy);
157
158  storage::QuotaManagerProxy* quota_manager_proxy() const {
159    return quota_manager_proxy_.get();
160  }
161
162  AppCacheQuotaClient* quota_client() const {
163    return quota_client_;
164  }
165
166  // Each child process in chrome uses a distinct backend instance.
167  // See chrome/browser/AppCacheDispatcherHost.
168  void RegisterBackend(AppCacheBackendImpl* backend_impl);
169  void UnregisterBackend(AppCacheBackendImpl* backend_impl);
170  AppCacheBackendImpl* GetBackend(int id) const {
171    BackendMap::const_iterator it = backends_.find(id);
172    return (it != backends_.end()) ? it->second : NULL;
173  }
174
175  AppCacheStorage* storage() const { return storage_.get(); }
176
177  // Disables the exit-time deletion of session-only data.
178  void set_force_keep_session_state() { force_keep_session_state_ = true; }
179  bool force_keep_session_state() const { return force_keep_session_state_; }
180
181 protected:
182  friend class content::AppCacheServiceImplTest;
183  friend class content::AppCacheStorageImplTest;
184  FRIEND_TEST_ALL_PREFIXES(content::AppCacheServiceImplTest,
185      ScheduleReinitialize);
186
187  class AsyncHelper;
188  class CanHandleOfflineHelper;
189  class DeleteHelper;
190  class DeleteOriginHelper;
191  class GetInfoHelper;
192  class CheckResponseHelper;
193
194  typedef std::set<AsyncHelper*> PendingAsyncHelpers;
195  typedef std::map<int, AppCacheBackendImpl*> BackendMap;
196
197  void Reinitialize();
198
199  base::FilePath cache_directory_;
200  scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
201  scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
202  AppCachePolicy* appcache_policy_;
203  AppCacheQuotaClient* quota_client_;
204  AppCacheExecutableHandlerFactory* handler_factory_;
205  scoped_ptr<AppCacheStorage> storage_;
206  scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
207  scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
208  PendingAsyncHelpers pending_helpers_;
209  BackendMap backends_;  // One 'backend' per child process.
210  // Context for use during cache updates.
211  net::URLRequestContext* request_context_;
212  // If true, nothing (not even session-only data) should be deleted on exit.
213  bool force_keep_session_state_;
214  base::Time last_reinit_time_;
215  base::TimeDelta next_reinit_delay_;
216  base::OneShotTimer<AppCacheServiceImpl> reinit_timer_;
217  ObserverList<Observer> observers_;
218
219  DISALLOW_COPY_AND_ASSIGN(AppCacheServiceImpl);
220};
221
222}  // namespace content
223
224#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_SERVICE_IMPL_H_
225