summaryrefslogtreecommitdiff
path: root/chromium/content/browser/cache_storage/cache_storage_cache.h
blob: 75d0c86fc92cdf0264bae20b7ab1c88ad1f4bab1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_
#define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_

#include <vector>

#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/id_map.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/common/cache_storage/cache_storage_types.h"
#include "content/common/service_worker/service_worker_types.h"
#include "net/disk_cache/disk_cache.h"

namespace net {
class URLRequestContextGetter;
class IOBufferWithSize;
}

namespace storage {
class BlobDataHandle;
class BlobStorageContext;
class QuotaManagerProxy;
}

namespace content {

class CacheStorageBlobToDiskCache;
class CacheMetadata;
class CacheStorageScheduler;
class TestCacheStorageCache;

// Represents a ServiceWorker Cache as seen in
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
// The asynchronous methods are executed serially. Callbacks to the
// public functions will be called so long as the cache object lives.
class CONTENT_EXPORT CacheStorageCache
    : public base::RefCounted<CacheStorageCache> {
 public:
  using ErrorCallback = base::Callback<void(CacheStorageError)>;
  using ResponseCallback =
      base::Callback<void(CacheStorageError,
                          scoped_ptr<ServiceWorkerResponse>,
                          scoped_ptr<storage::BlobDataHandle>)>;
  using Responses = std::vector<ServiceWorkerResponse>;
  using BlobDataHandles = std::vector<storage::BlobDataHandle>;
  using ResponsesCallback = base::Callback<void(CacheStorageError,
                                                scoped_ptr<Responses>,
                                                scoped_ptr<BlobDataHandles>)>;
  using Requests = std::vector<ServiceWorkerFetchRequest>;
  using RequestsCallback =
      base::Callback<void(CacheStorageError, scoped_ptr<Requests>)>;

  static scoped_refptr<CacheStorageCache> CreateMemoryCache(
      const GURL& origin,
      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
      const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
      base::WeakPtr<storage::BlobStorageContext> blob_context);
  static scoped_refptr<CacheStorageCache> CreatePersistentCache(
      const GURL& origin,
      const base::FilePath& path,
      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
      const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
      base::WeakPtr<storage::BlobStorageContext> blob_context);

  // Returns ERROR_TYPE_NOT_FOUND if not found.
  void Match(scoped_ptr<ServiceWorkerFetchRequest> request,
             const ResponseCallback& callback);

  // Returns CACHE_STORAGE_OK and all responses in this cache. If there are no
  // responses, returns CACHE_STORAGE_OK and an empty vector.
  void MatchAll(const ResponsesCallback& callback);

  // Runs given batch operations. This corresponds to the Batch Cache Operations
  // algorithm in the spec.
  //
  // |operations| cannot mix PUT and DELETE operations and cannot contain
  // multiple DELETE operations.
  //
  // In the case of the PUT operation, puts request and response objects in the
  // cache and returns OK when all operations are successfully completed.
  // In the case of the DELETE operation, returns ERROR_NOT_FOUND if a specified
  // entry is not found. Otherwise deletes it and returns OK.
  //
  // TODO(nhiroki): This function should run all operations atomically.
  // http://crbug.com/486637
  void BatchOperation(const std::vector<CacheStorageBatchOperation>& operations,
                      const ErrorCallback& callback);
  void BatchDidOneOperation(const base::Closure& barrier_closure,
                            ErrorCallback* callback,
                            CacheStorageError error);
  void BatchDidAllOperations(scoped_ptr<ErrorCallback> callback);

  // TODO(jkarlin): Have keys take an optional ServiceWorkerFetchRequest.
  // Returns CACHE_STORAGE_OK and a vector of requests if there are no errors.
  void Keys(const RequestsCallback& callback);

  // Closes the backend. Future operations that require the backend
  // will exit early. Close should only be called once per CacheStorageCache.
  void Close(const base::Closure& callback);

  // The size of the cache contents in memory. Returns 0 if the cache backend is
  // not a memory cache backend.
  int64 MemoryBackedSize() const;

  base::FilePath path() const { return path_; }

  base::WeakPtr<CacheStorageCache> AsWeakPtr();

 private:
  friend class base::RefCounted<CacheStorageCache>;
  friend class TestCacheStorageCache;

  struct OpenAllEntriesContext;
  struct MatchAllContext;
  struct KeysContext;
  struct PutContext;

  // The backend progresses from uninitialized, to open, to closed, and cannot
  // reverse direction.  The open step may be skipped.
  enum BackendState {
    BACKEND_UNINITIALIZED,  // No backend, create backend on first operation.
    BACKEND_OPEN,           // Backend can be used.
    BACKEND_CLOSED          // Backend cannot be used.  All ops should fail.
  };

  using Entries = std::vector<disk_cache::Entry*>;
  using ScopedBackendPtr = scoped_ptr<disk_cache::Backend>;
  using BlobToDiskCacheIDMap =
      IDMap<CacheStorageBlobToDiskCache, IDMapOwnPointer>;
  using OpenAllEntriesCallback =
      base::Callback<void(scoped_ptr<OpenAllEntriesContext>,
                          CacheStorageError)>;

  CacheStorageCache(
      const GURL& origin,
      const base::FilePath& path,
      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
      const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
      base::WeakPtr<storage::BlobStorageContext> blob_context);

  // Async operations in progress will cancel and not run their callbacks.
  virtual ~CacheStorageCache();

  // Returns true if the backend is ready to operate.
  bool LazyInitialize();

  // Returns all entries in this cache.
  void OpenAllEntries(const OpenAllEntriesCallback& callback);
  void DidOpenNextEntry(scoped_ptr<OpenAllEntriesContext> entries_context,
                        const OpenAllEntriesCallback& callback,
                        int rv);

  // Match callbacks
  void MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
                 const ResponseCallback& callback);
  void MatchDidOpenEntry(scoped_ptr<ServiceWorkerFetchRequest> request,
                         const ResponseCallback& callback,
                         scoped_ptr<disk_cache::Entry*> entry_ptr,
                         int rv);
  void MatchDidReadMetadata(scoped_ptr<ServiceWorkerFetchRequest> request,
                            const ResponseCallback& callback,
                            disk_cache::ScopedEntryPtr entry,
                            scoped_ptr<CacheMetadata> headers);

  // MatchAll callbacks
  void MatchAllImpl(const ResponsesCallback& callback);
  void MatchAllDidOpenAllEntries(
      const ResponsesCallback& callback,
      scoped_ptr<OpenAllEntriesContext> entries_context,
      CacheStorageError error);
  void MatchAllProcessNextEntry(scoped_ptr<MatchAllContext> context,
                                const Entries::iterator& iter);
  void MatchAllDidReadMetadata(scoped_ptr<MatchAllContext> context,
                               const Entries::iterator& iter,
                               scoped_ptr<CacheMetadata> metadata);

  // Puts the request and response object in the cache. The response body (if
  // present) is stored in the cache, but not the request body. Returns OK on
  // success.
  void Put(const CacheStorageBatchOperation& operation,
           const ErrorCallback& callback);
  void PutImpl(scoped_ptr<PutContext> put_context);
  void PutDidDelete(scoped_ptr<PutContext> put_context,
                    CacheStorageError delete_error);
  void PutDidCreateEntry(scoped_ptr<disk_cache::Entry*> entry_ptr,
                         scoped_ptr<PutContext> put_context,
                         int rv);
  void PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
                          int expected_bytes,
                          int rv);
  void PutDidWriteBlobToCache(scoped_ptr<PutContext> put_context,
                              BlobToDiskCacheIDMap::KeyType blob_to_cache_key,
                              disk_cache::ScopedEntryPtr entry,
                              bool success);

  // Returns ERROR_NOT_FOUND if not found. Otherwise deletes and returns OK.
  void Delete(const CacheStorageBatchOperation& operation,
              const ErrorCallback& callback);
  void DeleteImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
                  const ErrorCallback& callback);
  void DeleteDidOpenEntry(
      const GURL& origin,
      scoped_ptr<ServiceWorkerFetchRequest> request,
      const CacheStorageCache::ErrorCallback& callback,
      scoped_ptr<disk_cache::Entry*> entryptr,
      const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
      int rv);

  // Keys callbacks.
  void KeysImpl(const RequestsCallback& callback);
  void KeysDidOpenAllEntries(const RequestsCallback& callback,
                             scoped_ptr<OpenAllEntriesContext> entries_context,
                             CacheStorageError error);
  void KeysProcessNextEntry(scoped_ptr<KeysContext> keys_context,
                            const Entries::iterator& iter);
  void KeysDidReadMetadata(scoped_ptr<KeysContext> keys_context,
                           const Entries::iterator& iter,
                           scoped_ptr<CacheMetadata> metadata);

  void CloseImpl(const base::Closure& callback);

  // Loads the backend and calls the callback with the result (true for
  // success). The callback will always be called. Virtual for tests.
  virtual void CreateBackend(const ErrorCallback& callback);
  void CreateBackendDidCreate(const CacheStorageCache::ErrorCallback& callback,
                              scoped_ptr<ScopedBackendPtr> backend_ptr,
                              int rv);

  void InitBackend();
  void InitDone(CacheStorageError error);

  void PendingClosure(const base::Closure& callback);
  void PendingErrorCallback(const ErrorCallback& callback,
                            CacheStorageError error);
  void PendingResponseCallback(
      const ResponseCallback& callback,
      CacheStorageError error,
      scoped_ptr<ServiceWorkerResponse> response,
      scoped_ptr<storage::BlobDataHandle> blob_data_handle);
  void PendingResponsesCallback(const ResponsesCallback& callback,
                                CacheStorageError error,
                                scoped_ptr<Responses> responses,
                                scoped_ptr<BlobDataHandles> blob_data_handles);
  void PendingRequestsCallback(const RequestsCallback& callback,
                               CacheStorageError error,
                               scoped_ptr<Requests> requests);

  void PopulateResponseMetadata(const CacheMetadata& metadata,
                                ServiceWorkerResponse* response);
  scoped_ptr<storage::BlobDataHandle> PopulateResponseBody(
      disk_cache::ScopedEntryPtr entry,
      ServiceWorkerResponse* response);

  // Be sure to check |backend_state_| before use.
  scoped_ptr<disk_cache::Backend> backend_;

  GURL origin_;
  base::FilePath path_;
  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
  scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
  base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
  BackendState backend_state_;
  scoped_ptr<CacheStorageScheduler> scheduler_;
  bool initializing_;

  // Owns the elements of the list
  BlobToDiskCacheIDMap active_blob_to_disk_cache_writers_;

  // Whether or not to store data in disk or memory.
  bool memory_only_;

  base::WeakPtrFactory<CacheStorageCache> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(CacheStorageCache);
};

}  // namespace content

#endif  // CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_CACHE_H_