File: cached_storage_area.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (254 lines) | stat: -rw-r--r-- 10,873 bytes parent folder | download | duplicates (2)
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
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_

#include "base/memory/weak_ptr.h"
#include "base/trace_event/memory_dump_provider.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom-blink.h"
#include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/modules/storage/storage_area_map.h"
#include "third_party/blink/renderer/modules/storage/storage_namespace.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class LocalDOMWindow;

// An in-process implementation of LocalStorage using a LevelDB Mojo service.
// Maintains a complete cache of the BlinkStorageKey's Map of key/value pairs
// for fast access. The cache is primed on first access and changes are written
// to the backend through the level db interface pointer. Mutations originating
// in other processes are applied to the cache via mojom::LevelDBObserver
// callbacks.
// There is one CachedStorageArea for potentially many LocalStorageArea
// objects.
class MODULES_EXPORT CachedStorageArea
    : public mojom::blink::StorageAreaObserver,
      public RefCounted<CachedStorageArea>,
      public base::trace_event::MemoryDumpProvider {
 public:
  // Instances of this class are used to identify the "source" of any changes
  // made to this storage area, as well as to dispatch any incoming change
  // events. Change events are not sent back to the source that caused the
  // change. The source passed to the various methods that modify storage
  // should have been registered first by calling RegisterSource.
  class Source : public GarbageCollectedMixin {
   public:
    virtual ~Source() = default;
    virtual KURL GetPageUrl() const = 0;
    // Return 'true' to continue receiving events, and 'false' to stop.
    virtual bool EnqueueStorageEvent(const String& key,
                                     const String& old_value,
                                     const String& new_value,
                                     const String& url) = 0;
    virtual blink::WebScopedVirtualTimePauser CreateWebScopedVirtualTimePauser(
        const char* name,
        WebScopedVirtualTimePauser::VirtualTaskDuration duration) = 0;
    virtual LocalDOMWindow* GetDOMWindow() = 0;
  };

  enum class AreaType {
    kSessionStorage,
    kLocalStorage,
  };

  CachedStorageArea(
      AreaType type,
      const BlinkStorageKey& storage_key,
      LocalDOMWindow* local_dom_window,
      StorageNamespace* storage_namespace,
      bool is_session_storage_for_prerendering,
      mojo::PendingRemote<mojom::blink::StorageArea> storage_area = {});

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

  // These correspond to blink::Storage.
  unsigned GetLength();
  String GetKey(unsigned index);
  String GetItem(const String& key);
  bool SetItem(const String& key, const String& value, Source* source);
  void RemoveItem(const String& key, Source* source);
  void Clear(Source* source);

  // Allow this object to keep track of the Source instances corresponding to
  // it, which is needed for mutation event notifications.
  // Returns the (unique) id allocated for this source for testing purposes.
  String RegisterSource(Source* source);

  size_t quota_used() const { return map_ ? map_->quota_used() : 0; }
  size_t memory_used() const { return map_ ? map_->memory_used() : 0; }

  // Only public to allow tests to parametrize on this type.
  enum class FormatOption {
    kLocalStorageDetectFormat,
    kSessionStorageForceUTF16,
    kSessionStorageForceUTF8
  };

  mojo::Remote<mojom::blink::StorageArea>& RemoteArea() { return remote_area_; }

  // Invoked by the owning StorageNamespace the renderer is told to reset its
  // DOM Storage connections (e.g. to recover from a backend crash). Normally
  // a new StorageArea pipe is bound through the owning StorageNamespace, but
  // |new_area| may be provided by test code instead.
  void ResetConnection(
      mojo::PendingRemote<mojom::blink::StorageArea> new_area = {});

  bool is_session_storage_for_prerendering() const {
    return is_session_storage_for_prerendering_;
  }

  void EvictCachedData();

  void SetRemoteAreaForTesting(
      mojo::PendingRemote<mojom::blink::StorageArea> area) {
    remote_area_.Bind(std::move(area));
  }

 private:
  friend class RefCounted<CachedStorageArea>;
  ~CachedStorageArea() override;

  friend class CachedStorageAreaTest;
  friend class CachedStorageAreaStringFormatTest;
  friend class MockStorageArea;

  // Simple structure used to return information about each locally-initiated
  // mutation on the StorageArea until the mutation is acknowledged by a
  // corresponding StorageAreaObserver event. See |pending_mutations_by_source_|
  // and |pending_mutations_by_key_| below.
  struct PendingMutation {
    String key;
    String new_value;
    String old_value;
  };

  LocalDOMWindow* GetBestCurrentDOMWindow();

  void BindStorageArea(
      mojo::PendingRemote<mojom::blink::StorageArea> new_area = {},
      LocalDOMWindow* local_dom_window = nullptr);

  // mojom::blink::StorageAreaObserver:
  void KeyChanged(const Vector<uint8_t>& key,
                  const Vector<uint8_t>& new_value,
                  const std::optional<Vector<uint8_t>>& old_value,
                  const String& source) override;
  void KeyChangeFailed(const Vector<uint8_t>& key,
                       const String& source) override;
  void KeyDeleted(const Vector<uint8_t>& key,
                  const std::optional<Vector<uint8_t>>& old_value,
                  const String& source) override;
  void AllDeleted(bool was_nonempty, const String& source) override;
  void ShouldSendOldValueOnMutations(bool value) override;

  // base::trace_event::MemoryDumpProvider:
  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                    base::trace_event::ProcessMemoryDump* pmd) override;

  // Enqueues state regarding a locally-initiated storage mutation which will
  // eventually be acknowledged by a StorageAreaObserver event targeting
  // |receiver_|.
  void EnqueuePendingMutation(const String& key,
                              const String& new_value,
                              const String& old_value,
                              const String& source);

  // Dequeues and returns the oldest PendingMutation from the queue for |source|
  // if one exists. If there is no pending mutation queued for |source| this
  // returns null.
  std::unique_ptr<PendingMutation> PopPendingMutation(const String& source);

  void MaybeApplyNonLocalMutationForKey(const String& key,
                                        const String& new_value);

  // Synchronously fetches the areas data if it hasn't been fetched already.
  void EnsureLoaded();

  bool IsSessionStorage() const;
  FormatOption GetKeyFormat() const;
  FormatOption GetValueFormat() const;

  void EnqueueStorageEvent(const String& key,
                           const String& old_value,
                           const String& new_value,
                           const String& url,
                           const String& storage_area_id);

  void EnqueueCheckpointMicrotask(Source* source);
  void NotifyCheckpoint();

  static String Uint8VectorToString(const Vector<uint8_t>& input,
                                    FormatOption format_option);
  static Vector<uint8_t> StringToUint8Vector(const String& input,
                                             FormatOption format_option);

  const AreaType type_;
  const BlinkStorageKey storage_key_;
  const WeakPersistent<StorageNamespace> storage_namespace_;
  // Session storage state for prerendering is initialized by cloning the
  // primary session storage state. It is used locally by the prerendering
  // context, and does not get propagated back to the primary state (i.e., via
  // remote_area_). For more details:
  // https://docs.google.com/document/d/1I5Hr8I20-C1GBr4tAXdm0U8a1RDUKHt4n7WcH4fxiSE/edit?usp=sharing
  const bool is_session_storage_for_prerendering_;

  std::unique_ptr<StorageAreaMap> map_;

  // Queues of local mutations which are pending browser acknowledgement via
  // StorageAreaObserver events. This map is keyed by local source ID and owns
  // the PendingMutation objects.
  //
  // Only used for Local Storage. Session Storage operations are confined to
  // local side-effects and are not acknowledged with StorageAreaObsever events.
  using OwnedPendingMutationQueue = Deque<std::unique_ptr<PendingMutation>>;
  HashMap<String, OwnedPendingMutationQueue> pending_mutations_by_source_;

  // Queues of local mutations indexed per key. Every queued value references a
  // PendingMutation owned by |pending_mutations_by_source_| above.
  //
  // These per-key queues exists for two main reasons:
  //
  // * As long as a key's queue is non-empty, non-local mutations observed for
  //   the key are ignored.
  // * Any time a non-local |AllDeleted| (i.e. script |clear()|) is observed,
  //   the most recent mutation for each key is re-applied locally to the
  //   cleared area, as this improves locally script-observable consistency.
  //
  // Only used for Local Storage. Session Storage operations are confined to
  // local side-effects and are not acknowledged with StorageAreaObsever events.
  HashMap<String, Deque<PendingMutation*>> pending_mutations_by_key_;

  // See ShouldSendOldValueOnMutations().
  bool should_send_old_value_on_mutations_ = true;

  bool checkpoint_queued_ = false;

  // Connection to the backing implementation of this StorageArea. This is
  // always bound.
  mojo::Remote<mojom::blink::StorageArea> remote_area_;

  // Receives StorageAreaObserver events from the StorageArea implementation and
  // dispatches them to this CachedStorageArea.
  mojo::Receiver<mojom::blink::StorageAreaObserver> receiver_{this};

  Persistent<GCedHeapHashMap<WeakMember<Source>, String>> areas_;

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

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_