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_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
6 #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <set>
12 #include <vector>
13 
14 #include "base/callback_forward.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequence_checker.h"
17 #include "content/common/content_export.h"
18 #include "net/base/completion_once_callback.h"
19 #include "net/disk_cache/disk_cache.h"
20 
21 namespace content {
22 
23 // TODO(crbug.com/586174): Use disk_cache::EntryResult for better lifetime
24 // management of disk cache entries. Using EntryResult will eliminate allocating
25 // raw pointers and static methods in service worker resource readers/writers.
26 
27 class ServiceWorkerDiskCache;
28 
29 // Thin wrapper around disk_cache::Entry.
30 class CONTENT_EXPORT ServiceWorkerDiskCacheEntry {
31  public:
32   // The newly created entry takes ownership of `disk_cache_entry` and closes it
33   // on destruction. |cache| must outlive the newly created entry.
34   ServiceWorkerDiskCacheEntry(disk_cache::Entry* disk_cache_entry,
35                               ServiceWorkerDiskCache* cache);
36   ~ServiceWorkerDiskCacheEntry();
37 
38   // See `disk_cache::Entry::ReadData()`.
39   int Read(int index,
40            int64_t offset,
41            net::IOBuffer* buf,
42            int buf_len,
43            net::CompletionOnceCallback callback);
44 
45   // See `disk_cache::Entry::WriteData()`.
46   int Write(int index,
47             int64_t offset,
48             net::IOBuffer* buf,
49             int buf_len,
50             net::CompletionOnceCallback callback);
51   int64_t GetSize(int index);
52 
53   // Should only be called by ServiceWorkerDiskCache.
54   void Abandon();
55 
56  private:
57   // The disk_cache::Entry is owned by this entry and closed on destruction.
58   disk_cache::Entry* disk_cache_entry_;
59 
60   // The cache that this entry belongs to.
61   ServiceWorkerDiskCache* const cache_;
62 };
63 
64 // net::DiskCache wrapper for the cache used by service worker resources.
65 //
66 // Provides ways to create/open/doom service worker disk cache entries.
67 class CONTENT_EXPORT ServiceWorkerDiskCache {
68  public:
69   ServiceWorkerDiskCache();
70   ~ServiceWorkerDiskCache();
71 
72   // Initializes the object to use disk backed storage.
73   net::Error InitWithDiskBackend(const base::FilePath& disk_cache_directory,
74                                  bool force,
75                                  base::OnceClosure post_cleanup_callback,
76                                  net::CompletionOnceCallback callback);
77 
78   // Initializes the object to use memory only storage.
79   // This is used for Chrome's incognito browsing.
80   net::Error InitWithMemBackend(int64_t disk_cache_size,
81                                 net::CompletionOnceCallback callback);
82 
83   void Disable();
is_disabled()84   bool is_disabled() const { return is_disabled_; }
85 
86   using EntryCallback =
87       base::OnceCallback<void(int rv,
88                               std::unique_ptr<ServiceWorkerDiskCacheEntry>)>;
89 
90   // Creates/opens/dooms a disk cache entry associated with `key`.
91   void CreateEntry(int64_t key, EntryCallback callback);
92   void OpenEntry(int64_t key, EntryCallback callback);
93   void DoomEntry(int64_t key, net::CompletionOnceCallback callback);
94 
95   base::WeakPtr<ServiceWorkerDiskCache> GetWeakPtr();
96 
set_is_waiting_to_initialize(bool is_waiting_to_initialize)97   void set_is_waiting_to_initialize(bool is_waiting_to_initialize) {
98     is_waiting_to_initialize_ = is_waiting_to_initialize;
99   }
100 
disk_cache()101   disk_cache::Backend* disk_cache() { return disk_cache_.get(); }
102 
103  private:
104   class CreateBackendCallbackShim;
105   friend class ServiceWorkerDiskCacheEntry;
106 
is_initializing_or_waiting_to_initialize()107   bool is_initializing_or_waiting_to_initialize() const {
108     return create_backend_callback_.get() != nullptr ||
109            is_waiting_to_initialize_;
110   }
111 
112   net::Error Init(net::CacheType cache_type,
113                   const base::FilePath& directory,
114                   int64_t cache_size,
115                   bool force,
116                   base::OnceClosure post_cleanup_callback,
117                   net::CompletionOnceCallback callback);
118   void OnCreateBackendComplete(int return_value);
119 
120   uint64_t GetNextCallId();
121 
122   void DidGetEntryResult(uint64_t call_id, disk_cache::EntryResult result);
123   void DidDoomEntry(uint64_t call_id, int net_error);
124 
125   // Called by ServiceWorkerDiskCacheEntry constructor.
126   void AddOpenEntry(ServiceWorkerDiskCacheEntry* entry);
127   // Called by ServiceWorkerDiskCacheEntry destructor.
128   void RemoveOpenEntry(ServiceWorkerDiskCacheEntry* entry);
129 
130   bool is_disabled_ = false;
131   bool is_waiting_to_initialize_ = false;
132   net::CompletionOnceCallback init_callback_;
133   scoped_refptr<CreateBackendCallbackShim> create_backend_callback_;
134   std::vector<base::OnceClosure> pending_calls_;
135   uint64_t next_call_id_ = 0;
136   std::map</*call_id=*/uint64_t, EntryCallback> active_entry_calls_;
137   std::map</*call_id=*/uint64_t, net::CompletionOnceCallback>
138       active_doom_calls_;
139   std::set<ServiceWorkerDiskCacheEntry*> open_entries_;
140   std::unique_ptr<disk_cache::Backend> disk_cache_;
141 
142   SEQUENCE_CHECKER(sequence_checker_);
143 
144   base::WeakPtrFactory<ServiceWorkerDiskCache> weak_factory_{this};
145 };
146 
147 }  // namespace content
148 
149 #endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
150