1// Copyright 2013 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_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
6#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
7
8#include <deque>
9#include <map>
10#include <set>
11#include <vector>
12
13#include "base/bind.h"
14#include "base/files/file_path.h"
15#include "base/gtest_prod_util.h"
16#include "base/memory/scoped_vector.h"
17#include "base/memory/weak_ptr.h"
18#include "content/browser/service_worker/service_worker_database.h"
19#include "content/browser/service_worker/service_worker_version.h"
20#include "content/common/content_export.h"
21#include "content/common/service_worker/service_worker_status_code.h"
22#include "url/gurl.h"
23
24namespace base {
25class SequencedTaskRunner;
26class SingleThreadTaskRunner;
27}
28
29namespace storage {
30class QuotaManagerProxy;
31}
32
33namespace content {
34
35class ServiceWorkerContextCore;
36class ServiceWorkerDiskCache;
37class ServiceWorkerRegistration;
38class ServiceWorkerRegistrationInfo;
39class ServiceWorkerResponseReader;
40class ServiceWorkerResponseWriter;
41
42// This class provides an interface to store and retrieve ServiceWorker
43// registration data.
44class CONTENT_EXPORT ServiceWorkerStorage
45    : NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
46 public:
47  typedef std::vector<ServiceWorkerDatabase::ResourceRecord> ResourceList;
48  typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
49  typedef base::Callback<void(ServiceWorkerStatusCode status,
50                              const scoped_refptr<ServiceWorkerRegistration>&
51                                  registration)> FindRegistrationCallback;
52  typedef base::Callback<
53      void(const std::vector<ServiceWorkerRegistrationInfo>& registrations)>
54          GetAllRegistrationInfosCallback;
55  typedef base::Callback<
56      void(ServiceWorkerStatusCode status, bool are_equal)>
57          CompareCallback;
58
59  virtual ~ServiceWorkerStorage();
60
61  static scoped_ptr<ServiceWorkerStorage> Create(
62      const base::FilePath& path,
63      base::WeakPtr<ServiceWorkerContextCore> context,
64      const scoped_refptr<base::SequencedTaskRunner>& database_task_runner,
65      const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
66      storage::QuotaManagerProxy* quota_manager_proxy);
67
68  // Used for DeleteAndStartOver. Creates new storage based on |old_storage|.
69  static scoped_ptr<ServiceWorkerStorage> Create(
70      base::WeakPtr<ServiceWorkerContextCore> context,
71      ServiceWorkerStorage* old_storage);
72
73  // Finds registration for |document_url| or |pattern| or |registration_id|.
74  // The Find methods will find stored and initially installing registrations.
75  // Returns SERVICE_WORKER_OK with non-null registration if registration
76  // is found, or returns SERVICE_WORKER_ERROR_NOT_FOUND if no matching
77  // registration is found.  The FindRegistrationForPattern method is
78  // guaranteed to return asynchronously. However, the methods to find
79  // for |document_url| or |registration_id| may complete immediately
80  // (the callback may be called prior to the method returning) or
81  // asynchronously.
82  void FindRegistrationForDocument(const GURL& document_url,
83                                   const FindRegistrationCallback& callback);
84  void FindRegistrationForPattern(const GURL& scope,
85                                  const FindRegistrationCallback& callback);
86  void FindRegistrationForId(int64 registration_id,
87                             const GURL& origin,
88                             const FindRegistrationCallback& callback);
89
90  ServiceWorkerRegistration* GetUninstallingRegistration(const GURL& scope);
91
92  // Returns info about all stored and initially installing registrations.
93  void GetAllRegistrations(const GetAllRegistrationInfosCallback& callback);
94
95  // Commits |registration| with the installed but not activated |version|
96  // to storage, overwritting any pre-existing registration data for the scope.
97  // A pre-existing version's script resources remain available if that version
98  // is live. PurgeResources should be called when it's OK to delete them.
99  void StoreRegistration(
100      ServiceWorkerRegistration* registration,
101      ServiceWorkerVersion* version,
102      const StatusCallback& callback);
103
104  // Updates the state of the registration's stored version to active.
105  void UpdateToActiveState(
106      ServiceWorkerRegistration* registration,
107      const StatusCallback& callback);
108
109  // Updates the stored time to match the value of
110  // registration->last_update_check().
111  void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration);
112
113  // Deletes the registration data for |registration_id|. If the registration's
114  // version is live, its script resources will remain available.
115  // PurgeResources should be called when it's OK to delete them.
116  void DeleteRegistration(int64 registration_id,
117                          const GURL& origin,
118                          const StatusCallback& callback);
119
120  scoped_ptr<ServiceWorkerResponseReader> CreateResponseReader(
121      int64 response_id);
122  scoped_ptr<ServiceWorkerResponseWriter> CreateResponseWriter(
123      int64 response_id);
124
125  // Adds |id| to the set of resources ids that are in the disk
126  // cache but not yet stored with a registration.
127  void StoreUncommittedResponseId(int64 id);
128
129  // Removes |id| from uncommitted list, adds it to the
130  // purgeable list and purges it.
131  void DoomUncommittedResponse(int64 id);
132
133  // Compares only the response bodies.
134  void CompareScriptResources(int64 lhs_id, int64 rhs_id,
135                              const CompareCallback& callback);
136
137  // Deletes the storage and starts over.
138  void DeleteAndStartOver(const StatusCallback& callback);
139
140  // Returns new IDs which are guaranteed to be unique in the storage.
141  int64 NewRegistrationId();
142  int64 NewVersionId();
143  int64 NewResourceId();
144
145  // Intended for use only by ServiceWorkerRegisterJob and
146  // ServiceWorkerRegistration.
147  void NotifyInstallingRegistration(
148      ServiceWorkerRegistration* registration);
149  void NotifyDoneInstallingRegistration(
150      ServiceWorkerRegistration* registration,
151      ServiceWorkerVersion* version,
152      ServiceWorkerStatusCode status);
153  void NotifyUninstallingRegistration(ServiceWorkerRegistration* registration);
154  void NotifyDoneUninstallingRegistration(
155      ServiceWorkerRegistration* registration);
156
157  void Disable();
158  bool IsDisabled() const;
159
160  // |resources| must already be on the purgeable list.
161  void PurgeResources(const ResourceList& resources);
162
163 private:
164  friend class ServiceWorkerResourceStorageTest;
165  friend class ServiceWorkerControlleeRequestHandlerTest;
166  friend class ServiceWorkerContextRequestHandlerTest;
167  friend class ServiceWorkerRequestHandlerTest;
168  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
169                           DeleteRegistration_NoLiveVersion);
170  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
171                           DeleteRegistration_WaitingVersion);
172  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
173                           DeleteRegistration_ActiveVersion);
174  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
175                           UpdateRegistration);
176  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageDiskTest,
177                           CleanupOnRestart);
178
179  struct InitialData {
180    int64 next_registration_id;
181    int64 next_version_id;
182    int64 next_resource_id;
183    std::set<GURL> origins;
184
185    InitialData();
186    ~InitialData();
187  };
188
189  // Because there are too many params for base::Bind to wrap a closure around.
190  struct DidDeleteRegistrationParams {
191    int64 registration_id;
192    GURL origin;
193    StatusCallback callback;
194
195    DidDeleteRegistrationParams();
196    ~DidDeleteRegistrationParams();
197  };
198
199  typedef std::vector<ServiceWorkerDatabase::RegistrationData> RegistrationList;
200  typedef std::map<int64, scoped_refptr<ServiceWorkerRegistration> >
201      RegistrationRefsById;
202  typedef base::Callback<void(
203      InitialData* data,
204      ServiceWorkerDatabase::Status status)> InitializeCallback;
205  typedef base::Callback<
206      void(const GURL& origin,
207           int64 deleted_version_id,
208           const std::vector<int64>& newly_purgeable_resources,
209           ServiceWorkerDatabase::Status status)> WriteRegistrationCallback;
210  typedef base::Callback<
211      void(bool origin_is_deletable,
212           int64 version_id,
213           const std::vector<int64>& newly_purgeable_resources,
214           ServiceWorkerDatabase::Status status)> DeleteRegistrationCallback;
215  typedef base::Callback<void(
216      const ServiceWorkerDatabase::RegistrationData& data,
217      const ResourceList& resources,
218      ServiceWorkerDatabase::Status status)> FindInDBCallback;
219  typedef base::Callback<void(const std::vector<int64>& resource_ids,
220                              ServiceWorkerDatabase::Status status)>
221      GetResourcesCallback;
222
223  ServiceWorkerStorage(
224      const base::FilePath& path,
225      base::WeakPtr<ServiceWorkerContextCore> context,
226      const scoped_refptr<base::SequencedTaskRunner>& database_task_runner,
227      const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
228      storage::QuotaManagerProxy* quota_manager_proxy);
229
230  base::FilePath GetDatabasePath();
231  base::FilePath GetDiskCachePath();
232
233  bool LazyInitialize(
234      const base::Closure& callback);
235  void DidReadInitialData(
236      InitialData* data,
237      ServiceWorkerDatabase::Status status);
238  void DidFindRegistrationForDocument(
239      const GURL& document_url,
240      const FindRegistrationCallback& callback,
241      const ServiceWorkerDatabase::RegistrationData& data,
242      const ResourceList& resources,
243      ServiceWorkerDatabase::Status status);
244  void DidFindRegistrationForPattern(
245      const GURL& scope,
246      const FindRegistrationCallback& callback,
247      const ServiceWorkerDatabase::RegistrationData& data,
248      const ResourceList& resources,
249      ServiceWorkerDatabase::Status status);
250  void DidFindRegistrationForId(
251      const FindRegistrationCallback& callback,
252      const ServiceWorkerDatabase::RegistrationData& data,
253      const ResourceList& resources,
254      ServiceWorkerDatabase::Status status);
255  void DidGetAllRegistrations(
256      const GetAllRegistrationInfosCallback& callback,
257      RegistrationList* registrations,
258      ServiceWorkerDatabase::Status status);
259  void DidStoreRegistration(const StatusCallback& callback,
260                            const GURL& origin,
261                            int64 deleted_version_id,
262                            const std::vector<int64>& newly_purgeable_resources,
263                            ServiceWorkerDatabase::Status status);
264  void DidUpdateToActiveState(
265      const StatusCallback& callback,
266      ServiceWorkerDatabase::Status status);
267  void DidDeleteRegistration(
268      const DidDeleteRegistrationParams& params,
269      bool origin_is_deletable,
270      int64 version_id,
271      const std::vector<int64>& newly_purgeable_resources,
272      ServiceWorkerDatabase::Status status);
273  void ReturnFoundRegistration(
274      const FindRegistrationCallback& callback,
275      const ServiceWorkerDatabase::RegistrationData& data,
276      const ResourceList& resources);
277
278  scoped_refptr<ServiceWorkerRegistration> GetOrCreateRegistration(
279      const ServiceWorkerDatabase::RegistrationData& data,
280      const ResourceList& resources);
281  ServiceWorkerRegistration* FindInstallingRegistrationForDocument(
282      const GURL& document_url);
283  ServiceWorkerRegistration* FindInstallingRegistrationForPattern(
284      const GURL& scope);
285  ServiceWorkerRegistration* FindInstallingRegistrationForId(
286      int64 registration_id);
287
288  // Lazy disk_cache getter.
289  ServiceWorkerDiskCache* disk_cache();
290  void OnDiskCacheInitialized(int rv);
291
292  void StartPurgingResources(const std::vector<int64>& ids);
293  void StartPurgingResources(const ResourceList& resources);
294  void ContinuePurgingResources();
295  void PurgeResource(int64 id);
296  void OnResourcePurged(int64 id, int rv);
297
298  // Deletes purgeable and uncommitted resources left over from the previous
299  // browser session. This must be called once per session before any database
300  // operation that may mutate the purgeable or uncommitted resource lists.
301  void DeleteStaleResources();
302  void DidCollectStaleResources(const std::vector<int64>& stale_resource_ids,
303                                ServiceWorkerDatabase::Status status);
304
305  // Static cross-thread helpers.
306  static void CollectStaleResourcesFromDB(
307      ServiceWorkerDatabase* database,
308      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
309      const GetResourcesCallback& callback);
310  static void ReadInitialDataFromDB(
311      ServiceWorkerDatabase* database,
312      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
313      const InitializeCallback& callback);
314  static void DeleteRegistrationFromDB(
315      ServiceWorkerDatabase* database,
316      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
317      int64 registration_id,
318      const GURL& origin,
319      const DeleteRegistrationCallback& callback);
320  static void WriteRegistrationInDB(
321      ServiceWorkerDatabase* database,
322      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
323      const ServiceWorkerDatabase::RegistrationData& registration,
324      const ResourceList& resources,
325      const WriteRegistrationCallback& callback);
326  static void FindForDocumentInDB(
327      ServiceWorkerDatabase* database,
328      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
329      const GURL& document_url,
330      const FindInDBCallback& callback);
331  static void FindForPatternInDB(
332      ServiceWorkerDatabase* database,
333      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
334      const GURL& scope,
335      const FindInDBCallback& callback);
336  static void FindForIdInDB(
337      ServiceWorkerDatabase* database,
338      scoped_refptr<base::SequencedTaskRunner> original_task_runner,
339      int64 registration_id,
340      const GURL& origin,
341      const FindInDBCallback& callback);
342
343  void ScheduleDeleteAndStartOver();
344  void DidDeleteDatabase(
345      const StatusCallback& callback,
346      ServiceWorkerDatabase::Status status);
347  void DidDeleteDiskCache(
348      const StatusCallback& callback,
349      bool result);
350
351  // For finding registrations being installed or uninstalled.
352  RegistrationRefsById installing_registrations_;
353  RegistrationRefsById uninstalling_registrations_;
354
355  // Origins having registations.
356  std::set<GURL> registered_origins_;
357
358  // Pending database tasks waiting for initialization.
359  std::vector<base::Closure> pending_tasks_;
360
361  int64 next_registration_id_;
362  int64 next_version_id_;
363  int64 next_resource_id_;
364
365  enum State {
366    UNINITIALIZED,
367    INITIALIZING,
368    INITIALIZED,
369    DISABLED,
370  };
371  State state_;
372
373  base::FilePath path_;
374  base::WeakPtr<ServiceWorkerContextCore> context_;
375
376  // Only accessed on |database_task_runner_|.
377  scoped_ptr<ServiceWorkerDatabase> database_;
378
379  scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
380  scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread_;
381  scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
382  scoped_ptr<ServiceWorkerDiskCache> disk_cache_;
383  std::deque<int64> purgeable_resource_ids_;
384  bool is_purge_pending_;
385  bool has_checked_for_stale_resources_;
386  std::set<int64> pending_deletions_;
387
388  base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_;
389
390  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerStorage);
391};
392
393}  // namespace content
394
395#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
396