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 &registry_; }
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