Add support for Chrome Storage Extension API (issue #1947)

- Supports chrome.storage.local and chrome.storage.sync
- chrome.storage.sync behaves identically to chrome.storage.local
This commit is contained in:
Ryan Shetley
2017-09-11 18:42:30 +00:00
committed by Marshall Greenblatt
parent a028976ac4
commit d8a602ed2f
15 changed files with 1159 additions and 5 deletions

View File

@@ -0,0 +1,110 @@
// Copyright 2017 The Chromium Embedded Framework Authors.
// Portions copyright 2016 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 "libcef/browser/extensions/value_store/cef_value_store.h"
#include <utility>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
CefValueStore::CefValueStore() : read_count_(0), write_count_(0) {}
CefValueStore::~CefValueStore() {}
size_t CefValueStore::GetBytesInUse(const std::string& key) {
// Let SettingsStorageQuotaEnforcer implement this.
NOTREACHED();
return 0;
}
size_t CefValueStore::GetBytesInUse(const std::vector<std::string>& keys) {
// Let SettingsStorageQuotaEnforcer implement this.
NOTREACHED();
return 0;
}
size_t CefValueStore::GetBytesInUse() {
// Let SettingsStorageQuotaEnforcer implement this.
NOTREACHED();
return 0;
}
ValueStore::ReadResult CefValueStore::Get(const std::string& key) {
return Get(std::vector<std::string>(1, key));
}
ValueStore::ReadResult CefValueStore::Get(
const std::vector<std::string>& keys) {
read_count_++;
base::DictionaryValue* settings = new base::DictionaryValue();
for (std::vector<std::string>::const_iterator it = keys.begin();
it != keys.end(); ++it) {
base::Value* value = NULL;
if (storage_.GetWithoutPathExpansion(*it, &value)) {
settings->SetWithoutPathExpansion(*it, value->CreateDeepCopy());
}
}
return MakeReadResult(base::WrapUnique(settings), status_);
}
ValueStore::ReadResult CefValueStore::Get() {
read_count_++;
return MakeReadResult(storage_.CreateDeepCopy(), status_);
}
ValueStore::WriteResult CefValueStore::Set(WriteOptions options,
const std::string& key,
const base::Value& value) {
base::DictionaryValue settings;
settings.SetWithoutPathExpansion(key, value.CreateDeepCopy());
return Set(options, settings);
}
ValueStore::WriteResult CefValueStore::Set(
WriteOptions options,
const base::DictionaryValue& settings) {
write_count_++;
std::unique_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
for (base::DictionaryValue::Iterator it(settings); !it.IsAtEnd();
it.Advance()) {
base::Value* old_value = NULL;
if (!storage_.GetWithoutPathExpansion(it.key(), &old_value) ||
!old_value->Equals(&it.value())) {
changes->push_back(ValueStoreChange(
it.key(), old_value ? old_value->CreateDeepCopy() : nullptr,
it.value().CreateDeepCopy()));
storage_.SetWithoutPathExpansion(it.key(), it.value().CreateDeepCopy());
}
}
return MakeWriteResult(std::move(changes), status_);
}
ValueStore::WriteResult CefValueStore::Remove(const std::string& key) {
return Remove(std::vector<std::string>(1, key));
}
ValueStore::WriteResult CefValueStore::Remove(
const std::vector<std::string>& keys) {
write_count_++;
std::unique_ptr<ValueStoreChangeList> changes(new ValueStoreChangeList());
for (std::vector<std::string>::const_iterator it = keys.begin();
it != keys.end(); ++it) {
std::unique_ptr<base::Value> old_value;
if (storage_.RemoveWithoutPathExpansion(*it, &old_value)) {
changes->push_back(ValueStoreChange(*it, std::move(old_value), nullptr));
}
}
return MakeWriteResult(std::move(changes), status_);
}
ValueStore::WriteResult CefValueStore::Clear() {
std::vector<std::string> keys;
for (base::DictionaryValue::Iterator it(storage_); !it.IsAtEnd();
it.Advance()) {
keys.push_back(it.key());
}
return Remove(keys);
}

View File

@@ -0,0 +1,59 @@
// Copyright 2017 The Chromium Embedded Framework Authors.
// Portions copyright 2016 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 CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_
#include <stddef.h>
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "extensions/browser/value_store/value_store.h"
// Implementation Based on TestingValueStore
// ValueStore with an in-memory storage but the ability to
// optionally fail all operations.
class CefValueStore : public ValueStore {
public:
CefValueStore();
~CefValueStore() override;
// Accessors for the number of reads/writes done by this value store. Each
// Get* operation (except for the BytesInUse ones) counts as one read, and
// each Set*/Remove/Clear operation counts as one write. This is useful in
// tests seeking to assert that some number of reads/writes to their
// underlying value store have (or have not) happened.
int read_count() const { return read_count_; }
int write_count() const { return write_count_; }
// ValueStore implementation.
size_t GetBytesInUse(const std::string& key) override;
size_t GetBytesInUse(const std::vector<std::string>& keys) override;
size_t GetBytesInUse() override;
ReadResult Get(const std::string& key) override;
ReadResult Get(const std::vector<std::string>& keys) override;
ReadResult Get() override;
WriteResult Set(WriteOptions options,
const std::string& key,
const base::Value& value) override;
WriteResult Set(WriteOptions options,
const base::DictionaryValue& values) override;
WriteResult Remove(const std::string& key) override;
WriteResult Remove(const std::vector<std::string>& keys) override;
WriteResult Clear() override;
private:
base::DictionaryValue storage_;
int read_count_;
int write_count_;
ValueStore::Status status_;
DISALLOW_COPY_AND_ASSIGN(CefValueStore);
};
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_

View File

@@ -0,0 +1,191 @@
// Copyright 2017 The Chromium Embedded Framework Authors.
// Portions copyright 2016 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 "libcef/browser/extensions/value_store/cef_value_store_factory.h"
#include "base/memory/ptr_util.h"
#include "extensions/browser/value_store/leveldb_value_store.h"
#include "libcef/browser/extensions/value_store/cef_value_store.h"
namespace {
const char kUMAClientName[] = "Cef";
} // namespace
namespace extensions {
using SettingsNamespace = settings_namespace::Namespace;
CefValueStoreFactory::StorageHelper::StorageHelper() = default;
CefValueStoreFactory::StorageHelper::~StorageHelper() = default;
std::set<ExtensionId> CefValueStoreFactory::StorageHelper::GetKnownExtensionIDs(
ModelType model_type) const {
std::set<ExtensionId> ids;
switch (model_type) {
case ValueStoreFactory::ModelType::APP:
for (const auto& key : app_stores_)
ids.insert(key.first);
break;
case ValueStoreFactory::ModelType::EXTENSION:
for (const auto& key : extension_stores_)
ids.insert(key.first);
break;
}
return ids;
}
void CefValueStoreFactory::StorageHelper::Reset() {
app_stores_.clear();
extension_stores_.clear();
}
ValueStore* CefValueStoreFactory::StorageHelper::AddValueStore(
const ExtensionId& extension_id,
ValueStore* value_store,
ModelType model_type) {
if (model_type == ValueStoreFactory::ModelType::APP) {
DCHECK(app_stores_.find(extension_id) == app_stores_.end());
app_stores_[extension_id] = value_store;
} else {
DCHECK(extension_stores_.find(extension_id) == extension_stores_.end());
extension_stores_[extension_id] = value_store;
}
return value_store;
}
void CefValueStoreFactory::StorageHelper::DeleteSettings(
const ExtensionId& extension_id,
ModelType model_type) {
switch (model_type) {
case ValueStoreFactory::ModelType::APP:
app_stores_.erase(extension_id);
break;
case ValueStoreFactory::ModelType::EXTENSION:
extension_stores_.erase(extension_id);
break;
}
}
bool CefValueStoreFactory::StorageHelper::HasSettings(
const ExtensionId& extension_id,
ModelType model_type) const {
switch (model_type) {
case ValueStoreFactory::ModelType::APP:
return app_stores_.find(extension_id) != app_stores_.end();
case ValueStoreFactory::ModelType::EXTENSION:
return extension_stores_.find(extension_id) != extension_stores_.end();
}
NOTREACHED();
return false;
}
ValueStore* CefValueStoreFactory::StorageHelper::GetExisting(
const ExtensionId& extension_id) const {
auto it = app_stores_.find(extension_id);
if (it != app_stores_.end())
return it->second;
it = extension_stores_.find(extension_id);
if (it != extension_stores_.end())
return it->second;
return nullptr;
}
CefValueStoreFactory::CefValueStoreFactory() = default;
CefValueStoreFactory::CefValueStoreFactory(const base::FilePath& db_path)
: db_path_(db_path) {}
CefValueStoreFactory::~CefValueStoreFactory() {}
std::unique_ptr<ValueStore> CefValueStoreFactory::CreateRulesStore() {
if (db_path_.empty())
last_created_store_ = new CefValueStore();
else
last_created_store_ = new LeveldbValueStore(kUMAClientName, db_path_);
return base::WrapUnique(last_created_store_);
}
std::unique_ptr<ValueStore> CefValueStoreFactory::CreateStateStore() {
return CreateRulesStore();
}
CefValueStoreFactory::StorageHelper& CefValueStoreFactory::GetStorageHelper(
SettingsNamespace settings_namespace) {
switch (settings_namespace) {
case settings_namespace::LOCAL:
return local_helper_;
case settings_namespace::SYNC:
return sync_helper_;
case settings_namespace::MANAGED:
return managed_helper_;
case settings_namespace::INVALID:
break;
}
NOTREACHED();
return local_helper_;
}
std::unique_ptr<ValueStore> CefValueStoreFactory::CreateSettingsStore(
SettingsNamespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) {
std::unique_ptr<ValueStore> settings_store(CreateRulesStore());
// Note: This factory is purposely keeping the raw pointers to each ValueStore
// created. Tests using CefValueStoreFactory must be careful to keep
// those ValueStore's alive for the duration of their test.
GetStorageHelper(settings_namespace)
.AddValueStore(extension_id, settings_store.get(), model_type);
return settings_store;
}
ValueStore* CefValueStoreFactory::LastCreatedStore() const {
return last_created_store_;
}
void CefValueStoreFactory::DeleteSettings(SettingsNamespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) {
GetStorageHelper(settings_namespace).DeleteSettings(extension_id, model_type);
}
bool CefValueStoreFactory::HasSettings(SettingsNamespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) {
return GetStorageHelper(settings_namespace)
.HasSettings(extension_id, model_type);
}
std::set<ExtensionId> CefValueStoreFactory::GetKnownExtensionIDs(
SettingsNamespace settings_namespace,
ModelType model_type) const {
return const_cast<CefValueStoreFactory*>(this)
->GetStorageHelper(settings_namespace)
.GetKnownExtensionIDs(model_type);
}
ValueStore* CefValueStoreFactory::GetExisting(
const ExtensionId& extension_id) const {
ValueStore* existing_store = local_helper_.GetExisting(extension_id);
if (existing_store)
return existing_store;
existing_store = sync_helper_.GetExisting(extension_id);
if (existing_store)
return existing_store;
existing_store = managed_helper_.GetExisting(extension_id);
DCHECK(existing_store != nullptr);
return existing_store;
}
void CefValueStoreFactory::Reset() {
last_created_store_ = nullptr;
local_helper_.Reset();
sync_helper_.Reset();
managed_helper_.Reset();
}
} // namespace extensions

View File

@@ -0,0 +1,97 @@
// Copyright 2017 The Chromium Embedded Framework Authors.
// Portions copyright 2016 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 CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_
#define CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_
#include <map>
#include <memory>
#include <set>
#include "base/files/file_path.h"
#include "extensions/browser/value_store/value_store_factory.h"
#include "extensions/common/extension_id.h"
class ValueStore;
namespace extensions {
// Will either open a database on disk (if path provided) returning a
// |LeveldbValueStore|. Otherwise a new |CefValueStore| instance will be
// returned.
class CefValueStoreFactory : public ValueStoreFactory {
public:
CefValueStoreFactory();
explicit CefValueStoreFactory(const base::FilePath& db_path);
// ValueStoreFactory
std::unique_ptr<ValueStore> CreateRulesStore() override;
std::unique_ptr<ValueStore> CreateStateStore() override;
std::unique_ptr<ValueStore> CreateSettingsStore(
settings_namespace::Namespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) override;
void DeleteSettings(settings_namespace::Namespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) override;
bool HasSettings(settings_namespace::Namespace settings_namespace,
ModelType model_type,
const ExtensionId& extension_id) override;
std::set<ExtensionId> GetKnownExtensionIDs(
settings_namespace::Namespace settings_namespace,
ModelType model_type) const override;
// Return the last created |ValueStore|. Use with caution as this may return
// a dangling pointer since the creator now owns the ValueStore which can be
// deleted at any time.
ValueStore* LastCreatedStore() const;
// Return a previously created |ValueStore| for an extension.
ValueStore* GetExisting(const ExtensionId& extension_id) const;
// Reset this class (as if just created).
void Reset();
private:
// Manages a collection of |ValueStore|'s created for an app/extension.
// One of these exists for each setting type.
class StorageHelper {
public:
StorageHelper();
~StorageHelper();
std::set<ExtensionId> GetKnownExtensionIDs(ModelType model_type) const;
ValueStore* AddValueStore(const ExtensionId& extension_id,
ValueStore* value_store,
ModelType model_type);
void DeleteSettings(const ExtensionId& extension_id, ModelType model_type);
bool HasSettings(const ExtensionId& extension_id,
ModelType model_type) const;
void Reset();
ValueStore* GetExisting(const ExtensionId& extension_id) const;
private:
std::map<ExtensionId, ValueStore*> app_stores_;
std::map<ExtensionId, ValueStore*> extension_stores_;
DISALLOW_COPY_AND_ASSIGN(StorageHelper);
};
StorageHelper& GetStorageHelper(
settings_namespace::Namespace settings_namespace);
~CefValueStoreFactory() override;
base::FilePath db_path_;
ValueStore* last_created_store_ = nullptr;
// None of these value stores are owned by this factory, so care must be
// taken when calling GetExisting.
StorageHelper local_helper_;
StorageHelper sync_helper_;
StorageHelper managed_helper_;
DISALLOW_COPY_AND_ASSIGN(CefValueStoreFactory);
};
} // namespace extensions
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_