File: active_blob_streamer.h

package info (click to toggle)
chromium 139.0.7258.154-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 6,129,716 kB
  • sloc: cpp: 35,100,894; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,921; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,152; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (133 lines) | stat: -rw-r--r-- 6,118 bytes parent folder | download | duplicates (5)
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
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_ACTIVE_BLOB_STREAMER_H_
#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_ACTIVE_BLOB_STREAMER_H_

#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "content/browser/indexed_db/indexed_db_external_object.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "services/network/public/mojom/data_pipe_getter.mojom.h"
#include "sql/streaming_blob_handle.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"

namespace content::indexed_db::sqlite {

// This class represents an "active" blob, that is, a blob in an IndexedDB
// database which has been vended to one or more clients, and is still connected
// to at least one client. It is owned by a DatabaseConnection and its existence
// is enough to keep the DatabaseConnection alive, since the underlying SQLite
// database connection cannot be closed while any blob is active.
//
// When this class exists, there is a corresponding entry in the
// `blob_references` table.
//
// This class borrows heavily from `indexed_db::BlobReader`, which is used to
// read blobs that are stored as standalone files, and is likely to be
// eventually phased out.
class ActiveBlobStreamer : public blink::mojom::Blob,
                           public network::mojom::DataPipeGetter,
                           public storage::mojom::BlobDataItemReader {
 public:
  ActiveBlobStreamer(const IndexedDBExternalObject& blob_info,
                     sql::StreamingBlobHandle readable_blob_handle,
                     base::OnceClosure on_became_inactive);
  ~ActiveBlobStreamer() override;

  ActiveBlobStreamer(const ActiveBlobStreamer&) = delete;
  ActiveBlobStreamer& operator=(const ActiveBlobStreamer&) = delete;

  // Like Clone(), but called by the DatabaseConnection (which owns `this`).
  void AddReceiver(mojo::PendingReceiver<blink::mojom::Blob> receiver,
                   storage::mojom::BlobStorageContext& blob_registry);

  // blink::mojom::Blob:
  void Clone(mojo::PendingReceiver<blink::mojom::Blob> receiver) override;
  void AsDataPipeGetter(
      mojo::PendingReceiver<network::mojom::DataPipeGetter> receiver) override;
  void ReadRange(
      uint64_t offset,
      uint64_t length,
      mojo::ScopedDataPipeProducerHandle handle,
      mojo::PendingRemote<blink::mojom::BlobReaderClient> client) override;
  void ReadAll(
      mojo::ScopedDataPipeProducerHandle handle,
      mojo::PendingRemote<blink::mojom::BlobReaderClient> client) override;
  void Load(
      mojo::PendingReceiver<network::mojom::URLLoader> loader,
      const std::string& method,
      const net::HttpRequestHeaders& headers,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client) override;
  void ReadSideData(blink::mojom::Blob::ReadSideDataCallback callback) override;
  void CaptureSnapshot(CaptureSnapshotCallback callback) override;
  void GetInternalUUID(GetInternalUUIDCallback callback) override;

  // network::mojom::DataPipeGetter:
  void Clone(
      mojo::PendingReceiver<network::mojom::DataPipeGetter> receiver) override;
  void Read(mojo::ScopedDataPipeProducerHandle pipe,
            network::mojom::DataPipeGetter::ReadCallback callback) override;

  // storage::mojom::BlobDataItemReader:
  void Read(uint64_t offset,
            uint64_t length,
            mojo::ScopedDataPipeProducerHandle pipe,
            storage::mojom::BlobDataItemReader::ReadCallback callback) override;
  void ReadSideData(storage::mojom::BlobDataItemReader::ReadSideDataCallback
                        callback) override;

 private:
  void BindRegistryBlob(storage::mojom::BlobStorageContext& blob_registry);
  void OnMojoDisconnect();

  // Clamps `length` to fit within the blob given the starting position
  // `offset`.
  uint64_t ClampReadLength(uint64_t offset, uint64_t length) const;

  // This UUID is used for both the blob that's served via `blink::mojom::Blob`
  // and the blob in the registry. This is crucial because operations such as
  // copying the blob to a new file do so by identifying the blob to the blob
  // registry using the UUID.
  std::string uuid_;

  // This is the length of the blob, which comes from the SQLite row.
  uint64_t blob_length_;

  // A MIME type.
  std::string content_type_;

  // A handle opened for reading. `this` is owned by the DatabaseConnection, so
  // the handle should remain valid for the lifetime of `this`.
  sql::StreamingBlobHandle readable_blob_handle_;

  // Notes on lifetimes:
  //
  // `receivers_` and `data_pipe_getter_receivers_` correspond to mojo
  // connections to the renderer process. When these are both empty,
  // `registry_blob_` will be reset. This *usually* causes the blob registry
  // to drop the other side of the `BlobDataItemReader` (which is owned by a
  // `ShareableBlobDataItem`), which triggers `this` to be destroyed by running
  // `on_became_inactive`. However, if that `ShareableBlobDataItem` is in fact
  // shared, as is the case with composed blobs, then it will not drop the other
  // side of the `BlobDataItemReader`. When that happens, `this` will continue
  // living. If the renderer looks up the same blob again, `DatabaseConnection`
  // will reuse this object, and `AddReceiver()` will have to re-establish a
  // placeholder with the blob registry, i.e. re-bind `registry_blob_`.
  mojo::ReceiverSet<blink::mojom::Blob> receivers_;
  mojo::ReceiverSet<network::mojom::DataPipeGetter> data_pipe_getter_receivers_;

  mojo::ReceiverSet<storage::mojom::BlobDataItemReader> readers_;
  mojo::Remote<blink::mojom::Blob> registry_blob_;

  base::OnceClosure on_became_inactive_;

  base::WeakPtrFactory<ActiveBlobStreamer> weak_factory_{this};
};

}  // namespace content::indexed_db::sqlite

#endif  // CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_ACTIVE_BLOB_STREAMER_H_