blob: fcf1110f69e098c0f5acb9e1bd6545ec7d38b208 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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 "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom-blink.h"
#include "third_party/blink/public/platform/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/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
// An in-process implementation of LocalStorage using a LevelDB Mojo service.
// Maintains a complete cache of the origin'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:
// 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;
};
// Used to send events to the InspectorDOMStorageAgent.
class InspectorEventListener {
public:
virtual ~InspectorEventListener() = default;
virtual void DidDispatchStorageEvent(const SecurityOrigin* origin,
const String& key,
const String& old_value,
const String& new_value) = 0;
};
static scoped_refptr<CachedStorageArea> CreateForLocalStorage(
scoped_refptr<const SecurityOrigin> origin,
mojo::InterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
InspectorEventListener* listener);
static scoped_refptr<CachedStorageArea> CreateForSessionStorage(
scoped_refptr<const SecurityOrigin> origin,
mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
InspectorEventListener* listener);
// 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 memory_used() const { return map_ ? map_->quota_used() : 0; }
// Only public to allow tests to parametrize on this type.
enum class FormatOption {
kLocalStorageDetectFormat,
kSessionStorageForceUTF16,
kSessionStorageForceUTF8
};
private:
CachedStorageArea(scoped_refptr<const SecurityOrigin> origin,
mojo::InterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
InspectorEventListener* listener);
CachedStorageArea(
scoped_refptr<const SecurityOrigin> origin,
mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
InspectorEventListener* listener);
friend class RefCounted<CachedStorageArea>;
~CachedStorageArea() override;
friend class CachedStorageAreaTest;
friend class CachedStorageAreaStringFormatTest;
// StorageAreaObserver:
void KeyAdded(const Vector<uint8_t>& key,
const Vector<uint8_t>& value,
const String& source) override;
void KeyChanged(const Vector<uint8_t>& key,
const Vector<uint8_t>& new_value,
const Vector<uint8_t>& old_value,
const String& source) override;
void KeyDeleted(const Vector<uint8_t>& key,
const Vector<uint8_t>& old_value,
const String& source) override;
void AllDeleted(const String& source) override;
void ShouldSendOldValueOnMutations(bool value) override;
// Common helper for KeyAdded() and KeyChanged()
void KeyAddedOrChanged(const Vector<uint8_t>& key,
const Vector<uint8_t>& new_value,
const String& old_value,
const String& source);
void OnSetItemComplete(const String& key,
WebScopedVirtualTimePauser,
bool success);
void OnRemoveItemComplete(const String& key,
WebScopedVirtualTimePauser,
bool success);
void OnClearComplete(WebScopedVirtualTimePauser, bool success);
void OnGetAllComplete(bool success);
// Synchronously fetches the areas data if it hasn't been fetched already.
void EnsureLoaded();
// Resets the object back to its newly constructed state.
void Reset();
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);
static String Uint8VectorToString(const Vector<uint8_t>& input,
FormatOption format_option);
static Vector<uint8_t> StringToUint8Vector(const String& input,
FormatOption format_option);
scoped_refptr<const SecurityOrigin> origin_;
InspectorEventListener* inspector_event_listener_;
std::unique_ptr<StorageAreaMap> map_;
HashMap<String, int> ignore_key_mutations_;
bool ignore_all_mutations_ = false;
// See ShouldSendOldValueOnMutations().
bool should_send_old_value_on_mutations_ = true;
// Depending on if this is a session storage or local storage area only one of
// |mojo_area_ptr_| and |mojo_area_associated_ptr_| will be non-null. Either
// way |mojo_area_| will be equal to the non-null one.
mojom::blink::StorageArea* mojo_area_;
mojo::InterfacePtr<mojom::blink::StorageArea> mojo_area_ptr_;
mojo::AssociatedInterfacePtr<mojom::blink::StorageArea>
mojo_area_associated_ptr_;
mojo::AssociatedBinding<mojom::blink::StorageAreaObserver> binding_;
Persistent<HeapHashMap<WeakMember<Source>, String>> areas_;
base::WeakPtrFactory<CachedStorageArea> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CachedStorageArea);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_CACHED_STORAGE_AREA_H_