Commit 1571d750 authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[DOMStorage] blink::CachedStorageArea for onion souping

As part of onion souping domstorage this adds a couple of new classes
to blink more or less duplicating the content equivalents:

CachedStorageArea matches content::LocalStorageCachedArea (with some
minor API changes, in particular around how it acquires a mojom
StorageArea). Also has improved test coverage compared to the content
version.

MockStorageArea is very similar to content::MockLevelDBWrapper (with
the difference that it doesn't implement StoragePartitionService since
it doesn't need to with the changed API of CachedStorageArea).

Bug: 781870
Change-Id: Ic64b3bf307fe275d9287669743f186c8470847bb
Reviewed-on: https://chromium-review.googlesource.com/1166218Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582334}
parent d30a6822
...@@ -38,6 +38,16 @@ interface StorageAreaGetAllCallback { ...@@ -38,6 +38,16 @@ interface StorageAreaGetAllCallback {
// The mojo interface representing the connection to a single DOMStorage Area. // The mojo interface representing the connection to a single DOMStorage Area.
interface StorageArea { interface StorageArea {
// The quota for each storage area.
// This value is enforced in renderer processes and the browser process.
const uint32 kPerStorageAreaQuota = 10485760; // 10 MiB
// In the browser process we allow some overage to
// accommodate concurrent writes from different renderers
// that were allowed because the limit imposed in the renderer
// wasn't exceeded.
const uint32 kPerStorageAreaOverQuotaAllowance = 102400; // 100 KiB
AddObserver(associated StorageAreaObserver observer); AddObserver(associated StorageAreaObserver observer);
// Set the database entry for |key| to |value|. // Set the database entry for |key| to |value|.
......
include_rules = [ include_rules = [
"+base/atomic_sequence_num.h", "+base/atomic_sequence_num.h",
"+base/memory/scoped_refptr.h", "+base/memory/scoped_refptr.h",
"+mojo/public/cpp/bindings",
"+services/network/public/cpp/shared_url_loader_factory.h", "+services/network/public/cpp/shared_url_loader_factory.h",
"+services/service_manager/public/mojom/interface_provider.mojom-blink.h", "+services/service_manager/public/mojom/interface_provider.mojom-blink.h",
"+third_party/blink/public/common", "+third_party/blink/public/common",
......
...@@ -6,6 +6,8 @@ import("//third_party/blink/renderer/modules/modules.gni") ...@@ -6,6 +6,8 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("storage") { blink_modules_sources("storage") {
sources = [ sources = [
"cached_storage_area.cc",
"cached_storage_area.h",
"dom_window_storage.cc", "dom_window_storage.cc",
"dom_window_storage.h", "dom_window_storage.h",
"dom_window_storage_controller.cc", "dom_window_storage_controller.cc",
...@@ -28,7 +30,11 @@ blink_modules_sources("storage") { ...@@ -28,7 +30,11 @@ blink_modules_sources("storage") {
jumbo_source_set("unit_tests") { jumbo_source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"cached_storage_area_test.cc",
"storage_area_map_test.cc", "storage_area_map_test.cc",
"testing/fake_area_source.h",
"testing/mock_storage_area.cc",
"testing/mock_storage_area.h",
] ]
configs += [ configs += [
......
// 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() {}
virtual KURL GetPageUrl() const = 0;
virtual void 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;
};
static scoped_refptr<CachedStorageArea> CreateForLocalStorage(
scoped_refptr<const SecurityOrigin> origin,
mojo::InterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner);
static scoped_refptr<CachedStorageArea> CreateForSessionStorage(
scoped_refptr<const SecurityOrigin> origin,
mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner);
// 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);
CachedStorageArea(
scoped_refptr<const SecurityOrigin> origin,
mojo::AssociatedInterfacePtr<mojom::blink::StorageArea> area,
scoped_refptr<base::SingleThreadTaskRunner> ipc_runner);
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;
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_;
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_;
PersistentHeapHashMap<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_
// 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_TESTING_FAKE_AREA_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_TESTING_FAKE_AREA_SOURCE_H_
#include "third_party/blink/public/platform/web_scoped_virtual_time_pauser.h"
#include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
class FakeAreaSource : public GarbageCollectedFinalized<FakeAreaSource>,
public CachedStorageArea::Source {
USING_GARBAGE_COLLECTED_MIXIN(FakeAreaSource);
public:
explicit FakeAreaSource(const KURL& page_url) : page_url_(page_url) {}
KURL GetPageUrl() const override { return page_url_; }
void EnqueueStorageEvent(const String& key,
const String& old_value,
const String& new_value,
const String& url) override {
events.push_back(Event{key, old_value, new_value, url});
}
blink::WebScopedVirtualTimePauser CreateWebScopedVirtualTimePauser(
const char* name,
WebScopedVirtualTimePauser::VirtualTaskDuration duration) override {
return blink::WebScopedVirtualTimePauser();
}
struct Event {
String key, old_value, new_value, url;
};
Vector<Event> events;
private:
KURL page_url_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_TESTING_FAKE_AREA_SOURCE_H_
// Copyright 2017 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.
#include "third_party/blink/renderer/modules/storage/testing/mock_storage_area.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
MockStorageArea::MockStorageArea() = default;
MockStorageArea::~MockStorageArea() = default;
mojom::blink::StorageAreaPtr MockStorageArea::GetInterfacePtr() {
mojom::blink::StorageAreaPtr result;
bindings_.AddBinding(this, MakeRequest(&result));
return result;
}
mojom::blink::StorageAreaAssociatedPtr
MockStorageArea::GetAssociatedInterfacePtr() {
mojom::blink::StorageAreaAssociatedPtr result;
associated_bindings_.AddBinding(
this, MakeRequestAssociatedWithDedicatedPipe(&result));
return result;
}
void MockStorageArea::AddObserver(
mojom::blink::StorageAreaObserverAssociatedPtrInfo observer) {
++observer_count_;
}
void MockStorageArea::Put(
const Vector<uint8_t>& key,
const Vector<uint8_t>& value,
const base::Optional<Vector<uint8_t>>& client_old_value,
const String& source,
PutCallback callback) {
observed_put_ = true;
observed_key_ = key;
observed_value_ = value;
observed_source_ = source;
pending_callbacks_.push_back(std::move(callback));
}
void MockStorageArea::Delete(
const Vector<uint8_t>& key,
const base::Optional<Vector<uint8_t>>& client_old_value,
const String& source,
DeleteCallback callback) {
observed_delete_ = true;
observed_key_ = key;
observed_source_ = source;
pending_callbacks_.push_back(std::move(callback));
}
void MockStorageArea::DeleteAll(const String& source,
DeleteAllCallback callback) {
observed_delete_all_ = true;
observed_source_ = source;
pending_callbacks_.push_back(std::move(callback));
}
void MockStorageArea::Get(const Vector<uint8_t>& key, GetCallback callback) {
NOTREACHED();
}
void MockStorageArea::GetAll(
mojom::blink::StorageAreaGetAllCallbackAssociatedPtrInfo complete_callback,
GetAllCallback callback) {
mojom::blink::StorageAreaGetAllCallbackAssociatedPtr complete_ptr;
complete_ptr.Bind(std::move(complete_callback));
pending_callbacks_.push_back(
WTF::Bind(&mojom::blink::StorageAreaGetAllCallback::Complete,
std::move(complete_ptr)));
observed_get_all_ = true;
std::move(callback).Run(true, std::move(get_all_return_values_));
}
} // namespace blink
// Copyright 2017 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_TESTING_MOCK_STORAGE_AREA_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_TESTING_MOCK_STORAGE_AREA_H_
#include "mojo/public/cpp/bindings/associated_binding_set.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/dom_storage/storage_area.mojom-blink.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
namespace blink {
// Mock StorageArea that records all read and write events.
class MockStorageArea : public mojom::blink::StorageArea {
public:
using ResultCallback = base::OnceCallback<void(bool)>;
MockStorageArea();
~MockStorageArea() override;
mojom::blink::StorageAreaPtr GetInterfacePtr();
mojom::blink::StorageAreaAssociatedPtr GetAssociatedInterfacePtr();
// StorageArea implementation:
void AddObserver(
mojom::blink::StorageAreaObserverAssociatedPtrInfo observer) override;
void Put(const Vector<uint8_t>& key,
const Vector<uint8_t>& value,
const base::Optional<Vector<uint8_t>>& client_old_value,
const String& source,
PutCallback callback) override;
void Delete(const Vector<uint8_t>& key,
const base::Optional<Vector<uint8_t>>& client_old_value,
const String& source,
DeleteCallback callback) override;
void DeleteAll(const String& source, DeleteAllCallback callback) override;
void Get(const Vector<uint8_t>& key, GetCallback callback) override;
void GetAll(mojom::blink::StorageAreaGetAllCallbackAssociatedPtrInfo
complete_callback,
GetAllCallback callback) override;
// Methods and members for use by test fixtures.
bool HasBindings() {
return !bindings_.empty() || !associated_bindings_.empty();
}
void ResetObservations() {
observed_get_all_ = false;
observed_put_ = false;
observed_delete_ = false;
observed_delete_all_ = false;
observed_key_.clear();
observed_value_.clear();
observed_source_ = String();
}
void CompleteAllPendingCallbacks() {
while (!pending_callbacks_.empty())
CompleteOnePendingCallback(true);
}
void CompleteOnePendingCallback(bool success) {
ASSERT_TRUE(!pending_callbacks_.empty());
std::move(pending_callbacks_.front()).Run(success);
pending_callbacks_.pop_front();
}
void Flush() {
bindings_.FlushForTesting();
associated_bindings_.FlushForTesting();
}
void CloseAllBindings() {
bindings_.CloseAllBindings();
associated_bindings_.CloseAllBindings();
}
size_t pending_callbacks_count() const { return pending_callbacks_.size(); }
bool observed_get_all() const { return observed_get_all_; }
bool observed_put() const { return observed_put_; }
bool observed_delete() const { return observed_delete_; }
bool observed_delete_all() const { return observed_delete_all_; }
const Vector<uint8_t>& observed_key() const { return observed_key_; }
const Vector<uint8_t>& observed_value() const { return observed_value_; }
const String& observed_source() const { return observed_source_; }
size_t observer_count() const { return observer_count_; }
Vector<mojom::blink::KeyValuePtr>& mutable_get_all_return_values() {
return get_all_return_values_;
}
private:
Deque<ResultCallback> pending_callbacks_;
bool observed_get_all_ = false;
bool observed_put_ = false;
bool observed_delete_ = false;
bool observed_delete_all_ = false;
Vector<uint8_t> observed_key_;
Vector<uint8_t> observed_value_;
String observed_source_;
size_t observer_count_ = 0;
Vector<mojom::blink::KeyValuePtr> get_all_return_values_;
mojo::BindingSet<mojom::blink::StorageArea> bindings_;
mojo::AssociatedBindingSet<mojom::blink::StorageArea> associated_bindings_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_STORAGE_TESTING_MOCK_STORAGE_AREA_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment