1 // Copyright (c) 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 STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
6 #define STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <map>
12 #include <memory>
13 #include <string>
14 #include <vector>
15
16 #include "base/callback_forward.h"
17 #include "base/component_export.h"
18 #include "base/files/file_path.h"
19 #include "base/gtest_prod_util.h"
20 #include "base/macros.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/trace_event/memory_dump_provider.h"
24 #include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
25 #include "mojo/public/cpp/bindings/pending_receiver.h"
26 #include "mojo/public/cpp/bindings/pending_remote.h"
27 #include "mojo/public/cpp/bindings/receiver_set.h"
28 #include "storage/browser/blob/blob_data_handle.h"
29 #include "storage/browser/blob/blob_entry.h"
30 #include "storage/browser/blob/blob_memory_controller.h"
31 #include "storage/browser/blob/blob_storage_constants.h"
32 #include "storage/browser/blob/blob_storage_registry.h"
33 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
34
35 namespace content {
36
37 class ChromeBlobStorageContext;
38 class ShareableBlobDataItem;
39
40 namespace indexed_db_backing_store_unittest {
41 class BlobStorageContextShim;
42 } // namespace indexed_db_backing_store_unittest
43
44 } // namespace content
45
46 namespace storage {
47
48 class BlobDataBuilder;
49 class BlobDataHandle;
50 class BlobDataSnapshot;
51
52 // This class handles the logistics of blob storage within the browser process.
53 // This class is not threadsafe, access on IO thread. In Chromium there is one
54 // instance per profile.
COMPONENT_EXPORT(STORAGE_BROWSER)55 class COMPONENT_EXPORT(STORAGE_BROWSER) BlobStorageContext
56 : public base::trace_event::MemoryDumpProvider,
57 public mojom::BlobStorageContext {
58 public:
59 using TransportAllowedCallback = BlobEntry::TransportAllowedCallback;
60 using BuildAbortedCallback = BlobEntry::BuildAbortedCallback;
61
62 // Initializes the context without disk support.
63 BlobStorageContext();
64 // Disk support is enabled if |file_runner| isn't null.
65 BlobStorageContext(const base::FilePath& profile_directory,
66 const base::FilePath& blob_storage_directory,
67 scoped_refptr<base::TaskRunner> file_runner);
68 ~BlobStorageContext() override;
69
70 // The following three methods all lookup a BlobDataHandle based on some
71 // input. If no blob matching the input exists these methods return null.
72 std::unique_ptr<BlobDataHandle> GetBlobDataFromUUID(const std::string& uuid);
73 // If this BlobStorageContext is deleted before this method finishes, the
74 // callback will still be called with null.
75 void GetBlobDataFromBlobRemote(
76 mojo::PendingRemote<blink::mojom::Blob> blob,
77 base::OnceCallback<void(std::unique_ptr<BlobDataHandle>)> callback);
78
79 // Always returns a handle to a blob. Use BlobStatus::GetBlobStatus() and
80 // BlobStatus::RunOnConstructionComplete(callback) to determine construction
81 // completion and possible errors.
82 std::unique_ptr<BlobDataHandle> AddFinishedBlob(
83 std::unique_ptr<BlobDataBuilder> builder);
84
85 std::unique_ptr<BlobDataHandle> AddFinishedBlob(
86 const std::string& uuid,
87 const std::string& content_type,
88 const std::string& content_disposition,
89 std::vector<scoped_refptr<ShareableBlobDataItem>> items);
90
91 std::unique_ptr<BlobDataHandle> AddBrokenBlob(
92 const std::string& uuid,
93 const std::string& content_type,
94 const std::string& content_disposition,
95 BlobStatus reason);
96
97 size_t blob_count() const { return registry_.blob_count(); }
98
99 const BlobStorageRegistry& registry() { return registry_; }
100
101 // This builds a blob with the given |input_builder| and returns a handle to
102 // the constructed Blob. Blob metadata and data should be accessed through
103 // this handle.
104 // If there is data present that needs further population then we will call
105 // |transport_allowed_callback| when we're ready for the user data to be
106 // populated with the PENDING_DATA_POPULATION status. This can happen
107 // synchronously or asynchronously. Otherwise |transport_allowed_callback|
108 // should be null. In the further population case, the caller must call either
109 // NotifyTransportComplete or CancelBuildingBlob after
110 // |transport_allowed_callback| is called to signify the data is finished
111 // populating or an error occurred (respectively).
112 // If the returned handle is broken, then the possible error cases are:
113 // * OUT_OF_MEMORY if we don't have enough memory to store the blob,
114 // * REFERENCED_BLOB_BROKEN if a referenced blob is broken or we're
115 // referencing ourself.
116 std::unique_ptr<BlobDataHandle> BuildBlob(
117 std::unique_ptr<BlobDataBuilder> input_builder,
118 TransportAllowedCallback transport_allowed_callback);
119
120 // Similar to BuildBlob, but this merely registers a blob that will be built
121 // in the future. The caller must later call either BuildPreregisteredBlob
122 // (to actually start building the blob), or CancelBuildingBlob (if an error
123 // occured).
124 // The returned BlobDataHandle (as well as any handles returned by
125 // GetBlobDataFromUUID before BuildPreregisteredBlob is called) will always
126 // have kUnknownSize for its size. A BlobDataHandle with the correct size is
127 // later returned by BuildPreregisteredBlob.
128 std::unique_ptr<BlobDataHandle> AddFutureBlob(
129 const std::string& uuid,
130 const std::string& content_type,
131 const std::string& content_disposition,
132 BuildAbortedCallback build_aborted_callback);
133
134 // Same as BuildBlob, but for a blob that was previously registered by calling
135 // AddFutureBlob.
136 std::unique_ptr<BlobDataHandle> BuildPreregisteredBlob(
137 std::unique_ptr<BlobDataBuilder> input_builder,
138 TransportAllowedCallback transport_allowed_callback);
139
140 // This breaks a blob that is currently being built by using the BuildBlob
141 // method above. Any callbacks waiting on this blob, including the
142 // |transport_allowed_callback| callback given to BuildBlob, will be called
143 // with this status code.
144 void CancelBuildingBlob(const std::string& uuid, BlobStatus code);
145
146 // After calling BuildBlob above, the caller should call this method to
147 // notify the construction system that the unpopulated data in the given blob
148 // has been. populated. Caller must have all pending items populated in the
149 // original builder |input_builder| given in BuildBlob or we'll check-fail.
150 // If there is no pending data in the |input_builder| for the BuildBlob call,
151 // then this method doesn't need to be called.
152 void NotifyTransportComplete(const std::string& uuid);
153
154 const BlobMemoryController& memory_controller() { return memory_controller_; }
155
156 base::WeakPtr<BlobStorageContext> AsWeakPtr() {
157 return ptr_factory_.GetWeakPtr();
158 }
159
160 void Bind(mojo::PendingReceiver<mojom::BlobStorageContext> receiver);
161
162 void set_limits_for_testing(const BlobStorageLimits& limits) {
163 mutable_memory_controller()->set_limits_for_testing(limits);
164 }
165
166 void DisableFilePagingForTesting() {
167 mutable_memory_controller()->DisableFilePaging(base::File::FILE_OK);
168 }
169
170 protected:
171 friend class content::ChromeBlobStorageContext;
172 friend class BlobBuilderFromStream;
173 friend class BlobDataHandle;
174 friend class BlobDataHandle::BlobDataHandleShared;
175 friend class BlobRegistryImplTest;
176 friend class BlobStorageContextTest;
177 friend class BlobURLTokenImpl;
178 friend class content::indexed_db_backing_store_unittest::
179 BlobStorageContextShim;
180
181 enum class TransportQuotaType { MEMORY, FILE };
182
183 void IncrementBlobRefCount(const std::string& uuid);
184 void DecrementBlobRefCount(const std::string& uuid);
185
186 // This will return an empty snapshot until the blob is complete.
187 // TODO(dmurph): After we make the snapshot method in BlobHandle private, then
188 // make this DCHECK on the blob not being complete.
189 std::unique_ptr<BlobDataSnapshot> CreateSnapshot(const std::string& uuid);
190
191 BlobStatus GetBlobStatus(const std::string& uuid) const;
192
193 // Runs |done| when construction completes with the final status of the blob.
194 void RunOnConstructionComplete(const std::string& uuid,
195 BlobStatusCallback done_callback);
196
197 // Runs |done| when construction begins (when the blob is no longer
198 // PENDING_CONSTRUCTION) with the new status of the blob.
199 void RunOnConstructionBegin(const std::string& uuid,
200 BlobStatusCallback done_callback);
201
202 BlobStorageRegistry* mutable_registry() { return ®istry_; }
203
204 BlobMemoryController* mutable_memory_controller() {
205 return &memory_controller_;
206 }
207
208 private:
209 std::unique_ptr<BlobDataHandle> BuildBlobInternal(
210 BlobEntry* entry,
211 std::unique_ptr<BlobDataBuilder> input_builder,
212 TransportAllowedCallback transport_allowed_callback);
213
214 std::unique_ptr<BlobDataHandle> CreateHandle(const std::string& uuid,
215 BlobEntry* entry);
216
217 void NotifyTransportCompleteInternal(BlobEntry* entry);
218
219 void CancelBuildingBlobInternal(BlobEntry* entry, BlobStatus reason);
220
221 void FinishBuilding(BlobEntry* entry);
222
223 void RequestTransport(
224 BlobEntry* entry,
225 std::vector<BlobMemoryController::FileCreationInfo> files);
226
227 // The files array is empty for memory quota request responses.
228 void OnEnoughSpaceForTransport(
229 const std::string& uuid,
230 std::vector<BlobMemoryController::FileCreationInfo> files,
231 bool can_fit);
232
233 void OnEnoughSpaceForCopies(const std::string& uuid, bool can_fit);
234
235 void OnDependentBlobFinished(const std::string& owning_blob_uuid,
236 BlobStatus reason);
237
238 void ClearAndFreeMemory(BlobEntry* entry);
239
240 // base::trace_event::MemoryDumpProvider implementation.
241 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
242 base::trace_event::ProcessMemoryDump* pmd) override;
243
244 // mojom::BlobStorageContext implementation.
245 void RegisterFromDataItem(mojo::PendingReceiver<blink::mojom::Blob> blob,
246 const std::string& uuid,
247 mojom::BlobDataItemPtr item) override;
248 void RegisterFromMemory(mojo::PendingReceiver<::blink::mojom::Blob> blob,
249 const std::string& uuid,
250 mojo_base::BigBuffer data) override;
251 void WriteBlobToFile(mojo::PendingRemote<::blink::mojom::Blob> blob,
252 const base::FilePath& path,
253 bool flush_on_write,
254 base::Optional<base::Time> last_modified,
255 WriteBlobToFileCallback callback) override;
256
257 base::FilePath profile_directory_;
258 BlobStorageRegistry registry_;
259 BlobMemoryController memory_controller_;
260 mojo::ReceiverSet<mojom::BlobStorageContext> receivers_;
261 base::WeakPtrFactory<BlobStorageContext> ptr_factory_{this};
262
263 DISALLOW_COPY_AND_ASSIGN(BlobStorageContext);
264 };
265
266 } // namespace storage
267
268 #endif // STORAGE_BROWSER_BLOB_BLOB_STORAGE_CONTEXT_H_
269