mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-02 12:17:15 +01:00
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:
parent
a028976ac4
commit
d8a602ed2f
6
BUILD.gn
6
BUILD.gn
@ -375,6 +375,8 @@ static_library("libcef_static") {
|
||||
"libcef/browser/download_manager_delegate.h",
|
||||
"libcef/browser/extension_impl.cc",
|
||||
"libcef/browser/extension_impl.h",
|
||||
"libcef/browser/extensions/api/storage/sync_value_store_cache.cc",
|
||||
"libcef/browser/extensions/api/storage/sync_value_store_cache.h",
|
||||
"libcef/browser/extensions/api/tabs/tabs_api.cc",
|
||||
"libcef/browser/extensions/api/tabs/tabs_api.h",
|
||||
"libcef/browser/extensions/browser_context_keyed_service_factories.cc",
|
||||
@ -411,6 +413,10 @@ static_library("libcef_static") {
|
||||
"libcef/browser/extensions/pdf_extension_util.h",
|
||||
"libcef/browser/extensions/pdf_web_contents_helper_client.cc",
|
||||
"libcef/browser/extensions/pdf_web_contents_helper_client.h",
|
||||
"libcef/browser/extensions/value_store/cef_value_store.cc",
|
||||
"libcef/browser/extensions/value_store/cef_value_store.h",
|
||||
"libcef/browser/extensions/value_store/cef_value_store_factory.cc",
|
||||
"libcef/browser/extensions/value_store/cef_value_store_factory.h",
|
||||
"libcef/browser/file_dialog_runner.h",
|
||||
"libcef/browser/file_dialog_manager.cc",
|
||||
"libcef/browser/file_dialog_manager.h",
|
||||
|
@ -431,6 +431,7 @@
|
||||
'tests/ceftests/draggable_regions_unittest.cc',
|
||||
'tests/ceftests/extensions/background_unittest.cc',
|
||||
'tests/ceftests/extensions/chrome_alarms_unittest.cc',
|
||||
'tests/ceftests/extensions/chrome_storage_unittest.cc',
|
||||
'tests/ceftests/extensions/chrome_tabs_unittest.cc',
|
||||
'tests/ceftests/extensions/extension_test_handler.cc',
|
||||
'tests/ceftests/extensions/extension_test_handler.h',
|
||||
|
@ -0,0 +1,97 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright 2014 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/api/storage/sync_value_store_cache.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "extensions/browser/api/storage/backend_task_runner.h"
|
||||
#include "extensions/browser/api/storage/weak_unlimited_settings_storage.h"
|
||||
#include "extensions/browser/value_store/value_store_factory.h"
|
||||
#include "extensions/common/api/storage.h"
|
||||
#include "extensions/common/extension.h"
|
||||
#include "extensions/common/permissions/permissions_data.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
namespace cef {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the quota limit for local storage, taken from the schema in
|
||||
// extensions/common/api/storage.json.
|
||||
SettingsStorageQuotaEnforcer::Limits GetLocalQuotaLimits() {
|
||||
SettingsStorageQuotaEnforcer::Limits limits = {
|
||||
static_cast<size_t>(api::storage::local::QUOTA_BYTES),
|
||||
std::numeric_limits<size_t>::max(), std::numeric_limits<size_t>::max()};
|
||||
return limits;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SyncValueStoreCache::SyncValueStoreCache(
|
||||
const scoped_refptr<ValueStoreFactory>& factory)
|
||||
: storage_factory_(factory), quota_(GetLocalQuotaLimits()) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
}
|
||||
|
||||
SyncValueStoreCache::~SyncValueStoreCache() {
|
||||
DCHECK(IsOnBackendSequence());
|
||||
}
|
||||
|
||||
void SyncValueStoreCache::RunWithValueStoreForExtension(
|
||||
const StorageCallback& callback,
|
||||
scoped_refptr<const Extension> extension) {
|
||||
DCHECK(IsOnBackendSequence());
|
||||
|
||||
ValueStore* storage = GetStorage(extension.get());
|
||||
|
||||
// A neat way to implement unlimited storage; if the extension has the
|
||||
// unlimited storage permission, force through all calls to Set().
|
||||
if (extension->permissions_data()->HasAPIPermission(
|
||||
APIPermission::kUnlimitedStorage)) {
|
||||
WeakUnlimitedSettingsStorage unlimited_storage(storage);
|
||||
callback.Run(&unlimited_storage);
|
||||
} else {
|
||||
callback.Run(storage);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncValueStoreCache::DeleteStorageSoon(const std::string& extension_id) {
|
||||
DCHECK(IsOnBackendSequence());
|
||||
storage_map_.erase(extension_id);
|
||||
storage_factory_->DeleteSettings(settings_namespace::SYNC,
|
||||
ValueStoreFactory::ModelType::APP,
|
||||
extension_id);
|
||||
storage_factory_->DeleteSettings(settings_namespace::SYNC,
|
||||
ValueStoreFactory::ModelType::EXTENSION,
|
||||
extension_id);
|
||||
}
|
||||
|
||||
ValueStore* SyncValueStoreCache::GetStorage(const Extension* extension) {
|
||||
StorageMap::iterator iter = storage_map_.find(extension->id());
|
||||
if (iter != storage_map_.end())
|
||||
return iter->second.get();
|
||||
|
||||
ValueStoreFactory::ModelType model_type =
|
||||
extension->is_app() ? ValueStoreFactory::ModelType::APP
|
||||
: ValueStoreFactory::ModelType::EXTENSION;
|
||||
std::unique_ptr<ValueStore> store = storage_factory_->CreateSettingsStore(
|
||||
settings_namespace::SYNC, model_type, extension->id());
|
||||
std::unique_ptr<SettingsStorageQuotaEnforcer> storage(
|
||||
new SettingsStorageQuotaEnforcer(quota_, std::move(store)));
|
||||
DCHECK(storage.get());
|
||||
|
||||
ValueStore* storage_ptr = storage.get();
|
||||
storage_map_[extension->id()] = std::move(storage);
|
||||
return storage_ptr;
|
||||
}
|
||||
} // namespace cef
|
||||
} // namespace extensions
|
@ -0,0 +1,56 @@
|
||||
// Copyright 2017 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright 2014 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_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
|
||||
#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "extensions/browser/api/storage/settings_storage_quota_enforcer.h"
|
||||
#include "extensions/browser/api/storage/value_store_cache.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class ValueStoreFactory;
|
||||
|
||||
namespace cef {
|
||||
|
||||
// Based on LocalValueStoreCache
|
||||
// ValueStoreCache for the SYNC namespace. It owns a backend for apps and
|
||||
// another for extensions. Each backend takes care of persistence.
|
||||
class SyncValueStoreCache : public ValueStoreCache {
|
||||
public:
|
||||
explicit SyncValueStoreCache(const scoped_refptr<ValueStoreFactory>& factory);
|
||||
~SyncValueStoreCache() override;
|
||||
|
||||
// ValueStoreCache implementation:
|
||||
void RunWithValueStoreForExtension(
|
||||
const StorageCallback& callback,
|
||||
scoped_refptr<const Extension> extension) override;
|
||||
void DeleteStorageSoon(const std::string& extension_id) override;
|
||||
|
||||
private:
|
||||
using StorageMap = std::map<std::string, std::unique_ptr<ValueStore>>;
|
||||
|
||||
ValueStore* GetStorage(const Extension* extension);
|
||||
|
||||
// The Factory to use for creating new ValueStores.
|
||||
const scoped_refptr<ValueStoreFactory> storage_factory_;
|
||||
|
||||
// Quota limits (see SettingsStorageQuotaEnforcer).
|
||||
const SettingsStorageQuotaEnforcer::Limits quota_;
|
||||
|
||||
// The collection of ValueStores for local storage.
|
||||
StorageMap storage_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SyncValueStoreCache);
|
||||
};
|
||||
} // namespace cef
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
|
@ -8,6 +8,7 @@
|
||||
#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
|
||||
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
|
||||
#include "extensions/browser/api/alarms/alarm_manager.h"
|
||||
#include "extensions/browser/api/storage/storage_frontend.h"
|
||||
#include "extensions/browser/renderer_startup_helper.h"
|
||||
|
||||
namespace extensions {
|
||||
@ -18,6 +19,7 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
|
||||
CookieSettingsFactory::GetInstance();
|
||||
PrefsTabHelper::GetServiceInstance();
|
||||
RendererStartupHelperFactory::GetInstance();
|
||||
StorageFrontend::GetFactoryInstance();
|
||||
StreamsPrivateAPI::GetFactoryInstance();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "chrome/browser/extensions/api/resources_private/resources_private_api.h"
|
||||
#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
|
||||
#include "extensions/browser/api/alarms/alarms_api.h"
|
||||
#include "extensions/browser/api/storage/storage_api.h"
|
||||
#include "extensions/browser/extension_function_registry.h"
|
||||
|
||||
namespace extensions {
|
||||
@ -36,6 +37,12 @@ const char* const kSupportedAPIs[] = {
|
||||
EXTENSION_FUNCTION_NAME(AlarmsGetAllFunction),
|
||||
EXTENSION_FUNCTION_NAME(AlarmsClearFunction),
|
||||
EXTENSION_FUNCTION_NAME(AlarmsClearAllFunction),
|
||||
"storage",
|
||||
EXTENSION_FUNCTION_NAME(StorageStorageAreaGetFunction),
|
||||
EXTENSION_FUNCTION_NAME(StorageStorageAreaSetFunction),
|
||||
EXTENSION_FUNCTION_NAME(StorageStorageAreaRemoveFunction),
|
||||
EXTENSION_FUNCTION_NAME(StorageStorageAreaClearFunction),
|
||||
EXTENSION_FUNCTION_NAME(StorageStorageAreaGetBytesInUseFunction),
|
||||
"tabs",
|
||||
EXTENSION_FUNCTION_NAME(cefimpl::TabsGetFunction),
|
||||
EXTENSION_FUNCTION_NAME(cefimpl::TabsExecuteScriptFunction),
|
||||
@ -67,6 +74,11 @@ void ChromeFunctionRegistry::RegisterAll(ExtensionFunctionRegistry* registry) {
|
||||
registry->RegisterFunction<AlarmsGetAllFunction>();
|
||||
registry->RegisterFunction<AlarmsClearFunction>();
|
||||
registry->RegisterFunction<AlarmsClearAllFunction>();
|
||||
registry->RegisterFunction<StorageStorageAreaGetFunction>();
|
||||
registry->RegisterFunction<StorageStorageAreaSetFunction>();
|
||||
registry->RegisterFunction<StorageStorageAreaRemoveFunction>();
|
||||
registry->RegisterFunction<StorageStorageAreaClearFunction>();
|
||||
registry->RegisterFunction<StorageStorageAreaGetBytesInUseFunction>();
|
||||
registry->RegisterFunction<cefimpl::TabsExecuteScriptFunction>();
|
||||
registry->RegisterFunction<cefimpl::TabsInsertCSSFunction>();
|
||||
registry->RegisterFunction<cefimpl::TabsGetFunction>();
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "libcef/browser/extension_impl.h"
|
||||
#include "libcef/browser/extensions/pdf_extension_util.h"
|
||||
#include "libcef/browser/extensions/value_store/cef_value_store_factory.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
#include "libcef/common/extensions/extensions_util.h"
|
||||
|
||||
@ -21,6 +22,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/task_scheduler/post_task.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "components/crx_file/id_util.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
@ -40,7 +42,7 @@
|
||||
#include "extensions/browser/renderer_startup_helper.h"
|
||||
#include "extensions/browser/runtime_data.h"
|
||||
#include "extensions/browser/service_worker_manager.h"
|
||||
#include "extensions/browser/value_store/value_store_factory.h"
|
||||
#include "extensions/browser/state_store.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "extensions/common/extension_messages.h"
|
||||
#include "extensions/common/file_util.h"
|
||||
@ -153,7 +155,9 @@ CefExtensionSystem::CefExtensionSystem(BrowserContext* browser_context)
|
||||
renderer_helper_(
|
||||
extensions::RendererStartupHelperFactory::GetForBrowserContext(
|
||||
browser_context)),
|
||||
weak_ptr_factory_(this) {}
|
||||
weak_ptr_factory_(this) {
|
||||
InitPrefs();
|
||||
}
|
||||
|
||||
CefExtensionSystem::~CefExtensionSystem() {}
|
||||
|
||||
@ -384,15 +388,15 @@ SharedUserScriptMaster* CefExtensionSystem::shared_user_script_master() {
|
||||
}
|
||||
|
||||
StateStore* CefExtensionSystem::state_store() {
|
||||
return nullptr;
|
||||
return state_store_.get();
|
||||
}
|
||||
|
||||
StateStore* CefExtensionSystem::rules_store() {
|
||||
return nullptr;
|
||||
return rules_store_.get();
|
||||
}
|
||||
|
||||
scoped_refptr<ValueStoreFactory> CefExtensionSystem::store_factory() {
|
||||
return nullptr;
|
||||
return store_factory_;
|
||||
}
|
||||
|
||||
InfoMap* CefExtensionSystem::info_map() {
|
||||
@ -467,6 +471,21 @@ CefExtensionSystem::ComponentExtensionInfo::ComponentExtensionInfo(
|
||||
}
|
||||
}
|
||||
|
||||
void CefExtensionSystem::InitPrefs() {
|
||||
store_factory_ = new CefValueStoreFactory(browser_context_->GetPath());
|
||||
|
||||
Profile* profile = Profile::FromBrowserContext(browser_context_);
|
||||
|
||||
// Two state stores. The latter, which contains declarative rules, must be
|
||||
// loaded immediately so that the rules are ready before we issue network
|
||||
// requests.
|
||||
state_store_.reset(new StateStore(
|
||||
profile, store_factory_, ValueStoreFrontend::BackendType::STATE, true));
|
||||
|
||||
rules_store_.reset(new StateStore(
|
||||
profile, store_factory_, ValueStoreFrontend::BackendType::RULES, false));
|
||||
}
|
||||
|
||||
// Implementation based on ComponentLoader::CreateExtension.
|
||||
scoped_refptr<const Extension> CefExtensionSystem::CreateExtension(
|
||||
const ComponentExtensionInfo& info,
|
||||
|
@ -116,6 +116,8 @@ class CefExtensionSystem : public ExtensionSystem {
|
||||
bool initialized() const { return initialized_; }
|
||||
|
||||
private:
|
||||
virtual void InitPrefs();
|
||||
|
||||
// Information about a registered component extension.
|
||||
struct ComponentExtensionInfo {
|
||||
ComponentExtensionInfo(const base::DictionaryValue* manifest,
|
||||
@ -169,6 +171,10 @@ class CefExtensionSystem : public ExtensionSystem {
|
||||
std::unique_ptr<QuotaService> quota_service_;
|
||||
std::unique_ptr<AppSorting> app_sorting_;
|
||||
|
||||
std::unique_ptr<StateStore> state_store_;
|
||||
std::unique_ptr<StateStore> rules_store_;
|
||||
scoped_refptr<ValueStoreFactory> store_factory_;
|
||||
|
||||
// Signaled when the extension system has completed its startup tasks.
|
||||
OneShotEvent ready_;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "include/internal/cef_types_wrappers.h"
|
||||
#include "libcef/browser/browser_context_impl.h"
|
||||
#include "libcef/browser/extensions/api/storage/sync_value_store_cache.h"
|
||||
#include "libcef/browser/extensions/extension_web_contents_observer.h"
|
||||
#include "libcef/browser/extensions/mime_handler_view_guest_delegate.h"
|
||||
#include "libcef/browser/extensions/pdf_web_contents_helper_client.h"
|
||||
@ -66,4 +67,17 @@ void CefExtensionsAPIClient::AttachWebContentsHelpers(
|
||||
zoom::ZoomController::CreateForWebContents(web_contents);
|
||||
}
|
||||
|
||||
void CefExtensionsAPIClient::AddAdditionalValueStoreCaches(
|
||||
content::BrowserContext* context,
|
||||
const scoped_refptr<ValueStoreFactory>& factory,
|
||||
const scoped_refptr<base::ObserverListThreadSafe<SettingsObserver>>&
|
||||
observers,
|
||||
std::map<settings_namespace::Namespace, ValueStoreCache*>* caches) {
|
||||
// Add support for chrome.storage.sync.
|
||||
// Because we don't support syncing with Google, we follow the behavior of
|
||||
// chrome.storage.sync as if Chrome were permanently offline, by using a local
|
||||
// store see: https://developer.chrome.com/apps/storage for more information
|
||||
(*caches)[settings_namespace::SYNC] = new cef::SyncValueStoreCache(factory);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
@ -24,6 +24,18 @@ class CefExtensionsAPIClient : public ExtensionsAPIClient {
|
||||
MimeHandlerViewGuest* guest) const override;
|
||||
void AttachWebContentsHelpers(
|
||||
content::WebContents* web_contents) const override;
|
||||
|
||||
// Storage API support.
|
||||
|
||||
// Add any additional value store caches (e.g. for chrome.storage.managed)
|
||||
// to |caches|. By default adds nothing.
|
||||
void AddAdditionalValueStoreCaches(
|
||||
content::BrowserContext* context,
|
||||
const scoped_refptr<ValueStoreFactory>& factory,
|
||||
const scoped_refptr<base::ObserverListThreadSafe<SettingsObserver>>&
|
||||
observers,
|
||||
std::map<settings_namespace::Namespace, ValueStoreCache*>* caches)
|
||||
override;
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
110
libcef/browser/extensions/value_store/cef_value_store.cc
Normal file
110
libcef/browser/extensions/value_store/cef_value_store.cc
Normal 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);
|
||||
}
|
59
libcef/browser/extensions/value_store/cef_value_store.h
Normal file
59
libcef/browser/extensions/value_store/cef_value_store.h
Normal 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_
|
191
libcef/browser/extensions/value_store/cef_value_store_factory.cc
Normal file
191
libcef/browser/extensions/value_store/cef_value_store_factory.cc
Normal 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
|
@ -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_
|
472
tests/ceftests/extensions/chrome_storage_unittest.cc
Normal file
472
tests/ceftests/extensions/chrome_storage_unittest.cc
Normal file
@ -0,0 +1,472 @@
|
||||
// Copyright (c) 2017 The Chromium Embedded Framework 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 "tests/ceftests/extensions/extension_test_handler.h"
|
||||
#include "tests/ceftests/test_util.h"
|
||||
#include "tests/shared/browser/extension_util.h"
|
||||
|
||||
#define STORAGE_TEST_GROUP_ALL(name, test_class) \
|
||||
EXTENSION_TEST_GROUP_ALL(ChromeStorage##name, test_class)
|
||||
#define STORAGE_TEST_GROUP_MINIMAL(name, test_class) \
|
||||
EXTENSION_TEST_GROUP_MINIMAL(ChromeStorage##name, test_class)
|
||||
|
||||
namespace {
|
||||
|
||||
const char kExtensionPath[] = "storage-extension";
|
||||
const char kSuccessMessage[] = "success";
|
||||
|
||||
// Base class for testing chrome.storage methods.
|
||||
// See https://developer.chrome.com/extensions/storage
|
||||
class StorageTestHandler : public ExtensionTestHandler {
|
||||
public:
|
||||
explicit StorageTestHandler(RequestContextType request_context_type)
|
||||
: ExtensionTestHandler(request_context_type) {
|
||||
// Only creating the extension browser.
|
||||
set_create_main_browser(false);
|
||||
}
|
||||
|
||||
// CefExtensionHandler methods:
|
||||
void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
EXPECT_FALSE(got_loaded_);
|
||||
got_loaded_.yes();
|
||||
|
||||
// Verify |extension| contents.
|
||||
EXPECT_FALSE(extension->GetIdentifier().empty());
|
||||
EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
|
||||
client::extension_util::GetInternalExtensionResourcePath(
|
||||
extension->GetPath())
|
||||
.c_str());
|
||||
TestDictionaryEqual(CreateManifest(), extension->GetManifest());
|
||||
|
||||
EXPECT_FALSE(extension_);
|
||||
extension_ = extension;
|
||||
|
||||
CreateBrowserForExtension();
|
||||
}
|
||||
|
||||
void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
EXPECT_TRUE(extension_);
|
||||
EXPECT_TRUE(extension_->IsSame(extension));
|
||||
EXPECT_FALSE(got_unloaded_);
|
||||
got_unloaded_.yes();
|
||||
extension_ = NULL;
|
||||
|
||||
// Execute asynchronously so call stacks have a chance to unwind.
|
||||
// Will close the browser windows.
|
||||
CefPostTask(TID_UI, base::Bind(&StorageTestHandler::DestroyTest, this));
|
||||
}
|
||||
|
||||
// CefLoadHandler methods:
|
||||
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
|
||||
bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) override {
|
||||
CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
|
||||
EXPECT_TRUE(extension);
|
||||
EXPECT_TRUE(extension_->IsSame(extension));
|
||||
|
||||
if (isLoading) {
|
||||
EXPECT_FALSE(extension_browser_);
|
||||
extension_browser_ = browser;
|
||||
} else {
|
||||
EXPECT_TRUE(browser->IsSame(extension_browser_));
|
||||
|
||||
const std::string& url = browser->GetMainFrame()->GetURL();
|
||||
EXPECT_STREQ(extension_url_.c_str(), url.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// CefRequestHandler methods:
|
||||
CefRefPtr<CefResourceHandler> GetResourceHandler(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
EXPECT_TRUE(browser->IsSame(extension_browser_));
|
||||
|
||||
CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
|
||||
EXPECT_TRUE(extension);
|
||||
EXPECT_TRUE(extension_->IsSame(extension));
|
||||
|
||||
const std::string& url = request->GetURL();
|
||||
EXPECT_STREQ(extension_url_.c_str(), url.c_str());
|
||||
|
||||
EXPECT_FALSE(got_url_request_);
|
||||
got_url_request_.yes();
|
||||
|
||||
// Handle the resource request.
|
||||
return RoutingTestHandler::GetResourceHandler(browser, frame, request);
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnLoadExtensions() override {
|
||||
LoadExtension(kExtensionPath, CreateManifest());
|
||||
}
|
||||
|
||||
bool OnMessage(CefRefPtr<CefBrowser> browser,
|
||||
const std::string& message) override {
|
||||
if (message == "extension_onload") {
|
||||
// From body onLoad in the extension browser.
|
||||
EXPECT_TRUE(browser->IsSame(extension_browser_));
|
||||
EXPECT_FALSE(got_body_onload_);
|
||||
got_body_onload_.yes();
|
||||
TriggerStorageApiJSFunction();
|
||||
return true;
|
||||
}
|
||||
EXPECT_TRUE(browser->IsSame(extension_browser_));
|
||||
EXPECT_FALSE(got_success_message_);
|
||||
got_success_message_.yes();
|
||||
EXPECT_STREQ(kSuccessMessage, message.c_str());
|
||||
TriggerDestroyTest();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnDestroyTest() override {
|
||||
extension_browser_ = NULL;
|
||||
|
||||
EXPECT_TRUE(got_loaded_);
|
||||
EXPECT_TRUE(got_url_request_);
|
||||
EXPECT_TRUE(got_body_onload_);
|
||||
EXPECT_TRUE(got_trigger_api_function_);
|
||||
EXPECT_TRUE(got_success_message_);
|
||||
EXPECT_TRUE(got_unloaded_);
|
||||
}
|
||||
|
||||
// Create a manifest that grants access to the storage API.
|
||||
virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
|
||||
ApiPermissionsList api_permissions;
|
||||
api_permissions.push_back("storage");
|
||||
return CreateDefaultManifest(api_permissions);
|
||||
}
|
||||
|
||||
// Add resources in the extension browser.
|
||||
virtual void OnAddExtensionResources(const std::string& origin) {
|
||||
extension_url_ = origin + "extension.html";
|
||||
AddResource(extension_url_, GetExtensionHTML(), "text/html");
|
||||
}
|
||||
|
||||
// Returns the chrome.storage.* JS that is executed in the extension browser
|
||||
// when the triggerStorageApi() JS function is called.
|
||||
virtual std::string GetStorageApiJS() const = 0;
|
||||
|
||||
// Returns the JS that will be loaded in the extension browser. This
|
||||
// implements the triggerStorageApi() JS function called from
|
||||
// TriggerStorageApiJSFunction().
|
||||
virtual std::string GetExtensionJS() const {
|
||||
return "function triggerStorageApi() {" + GetStorageApiJS() + "}";
|
||||
}
|
||||
|
||||
// Returns the HTML that will be loaded in the extension browser.
|
||||
virtual std::string GetExtensionHTML() const {
|
||||
return "<html><head><script>" + GetExtensionJS() +
|
||||
"</script></head><body onLoad=" + GetMessageJS("extension_onload") +
|
||||
">Extension</body></html>";
|
||||
}
|
||||
|
||||
virtual void TriggerDestroyTest() {
|
||||
// Execute asynchronously so call stacks have a chance to unwind.
|
||||
CefPostTask(TID_UI, base::Bind(&StorageTestHandler::UnloadExtension, this,
|
||||
extension_));
|
||||
}
|
||||
|
||||
CefRefPtr<CefExtension> extension() const { return extension_; }
|
||||
std::string extension_url() const { return extension_url_; }
|
||||
CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; }
|
||||
|
||||
bool got_success_message() const { return got_success_message_; }
|
||||
|
||||
private:
|
||||
void CreateBrowserForExtension() {
|
||||
const std::string& identifier = extension_->GetIdentifier();
|
||||
EXPECT_FALSE(identifier.empty());
|
||||
const std::string& origin =
|
||||
client::extension_util::GetExtensionOrigin(identifier);
|
||||
EXPECT_FALSE(origin.empty());
|
||||
|
||||
// Add extension resources.
|
||||
OnAddExtensionResources(origin);
|
||||
|
||||
// Create a browser to host the extension.
|
||||
CreateBrowser(extension_url_, request_context());
|
||||
}
|
||||
|
||||
void TriggerStorageApiJSFunction() {
|
||||
EXPECT_FALSE(got_trigger_api_function_);
|
||||
got_trigger_api_function_.yes();
|
||||
|
||||
extension_browser_->GetMainFrame()->ExecuteJavaScript(
|
||||
"triggerStorageApi();", extension_url_, 0);
|
||||
}
|
||||
|
||||
CefRefPtr<CefExtension> extension_;
|
||||
std::string extension_url_;
|
||||
CefRefPtr<CefBrowser> extension_browser_;
|
||||
|
||||
TrackCallback got_loaded_;
|
||||
TrackCallback got_url_request_;
|
||||
TrackCallback got_body_onload_;
|
||||
TrackCallback got_trigger_api_function_;
|
||||
TrackCallback got_success_message_;
|
||||
TrackCallback got_unloaded_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.local.set(object items, function callback)
|
||||
// and for chrome.storage.local.get(string or array of string or object keys,
|
||||
// function callback)
|
||||
class LocalStorageTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit LocalStorageTestHandler(RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.local.set({\"local_key_1\": \"local_value_1\"}, function() {"
|
||||
"chrome.storage.local.get(\"local_key_1\", function (items) {"
|
||||
"if(items[\"local_key_1\"] == \"local_value_1\") {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}});"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(LocalStorageTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(LocalStorageTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_ALL(LocalStorage, LocalStorageTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.local.getBytesInUse(string or array of string keys,
|
||||
// function callback)
|
||||
class LocalStorageGetBytesInUseTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit LocalStorageGetBytesInUseTestHandler(
|
||||
RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.local.set({\"local_key_2\": \"local_value_2\"}, function() {"
|
||||
"chrome.storage.local.getBytesInUse(\"local_key_2\", function (bytesInUse) {"
|
||||
"if (bytesInUse == 26) {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}});"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(LocalStorageGetBytesInUseTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(LocalStorageGetBytesInUseTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(LocalStorageGetBytesInUse,
|
||||
LocalStorageGetBytesInUseTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.local.remove(string or array of string keys, function
|
||||
// callback)
|
||||
class LocalStorageRemoveTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit LocalStorageRemoveTestHandler(
|
||||
RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.local.set({\"local_key_3\": \"local_value_3\"}, function() {"
|
||||
"chrome.storage.local.remove(\"local_key_3\", function () {"
|
||||
"chrome.storage.local.get(\"local_key_3\", function(items) {"
|
||||
"if (items[\"local_key_3\"] == undefined) {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}})})"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(LocalStorageRemoveTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(LocalStorageRemoveTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(LocalStorageRemove, LocalStorageRemoveTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.local.clear(function callback)
|
||||
class LocalStorageClearTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit LocalStorageClearTestHandler(RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "var value1Cleared = false;"
|
||||
"var value2Cleared = false;"
|
||||
"function checkCleared() {"
|
||||
"if (value1Cleared && value2Cleared) {"
|
||||
+ GetMessageJS(kSuccessMessage) +
|
||||
"}}"
|
||||
"chrome.storage.local.set({\"local_key_4\": \"local_value_4\","
|
||||
"\"local_key_5\": \"local_value_5\"}, function() {"
|
||||
"chrome.storage.local.clear(function () {"
|
||||
|
||||
"chrome.storage.local.get(\"local_key_4\", function(items) {"
|
||||
"if (items[\"local_key_4\"] == undefined) {"
|
||||
"value1Cleared = true;"
|
||||
"checkCleared();"
|
||||
"}});"
|
||||
|
||||
"chrome.storage.local.get(\"local_key_5\", function(items) {"
|
||||
"if (items[\"local_key_5\"] == undefined) {"
|
||||
"value2Cleared = true;"
|
||||
"checkCleared();"
|
||||
"}});"
|
||||
"})});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(LocalStorageClearTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(LocalStorageClearTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(LocalStorageClear, LocalStorageClearTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.sync.set(object items, function callback)
|
||||
// and for chrome.storage.sync.get(string or array of string or object keys,
|
||||
// function callback)
|
||||
class SyncStorageTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit SyncStorageTestHandler(RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.sync.set({\"sync_key_1\": \"sync_value_1\"}, function() {"
|
||||
"chrome.storage.sync.get(\"sync_key_1\", function (items) {"
|
||||
"if (items[\"sync_key_1\"] == \"sync_value_1\") {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}});"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(SyncStorageTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(SyncStorageTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_ALL(SyncStorage, SyncStorageTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.sync.getBytesInUse(string or array of string keys,
|
||||
// function callback)
|
||||
class SyncStorageGetBytesInUseTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit SyncStorageGetBytesInUseTestHandler(
|
||||
RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.sync.set({\"sync_key_2\": \"sync_value_2\"}, function() {"
|
||||
"chrome.storage.sync.getBytesInUse(\"sync_key_2\", function (bytesInUse) {"
|
||||
"if (bytesInUse == 24) {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}});"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(SyncStorageGetBytesInUseTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(SyncStorageGetBytesInUseTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(SyncStorageGetBytesInUse,
|
||||
SyncStorageGetBytesInUseTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.sync.remove(string or array of string keys, function
|
||||
// callback)
|
||||
class SyncStorageRemoveTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit SyncStorageRemoveTestHandler(RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "chrome.storage.sync.set({\"sync_key_3\": \"sync_value_3\"}, function() {"
|
||||
"chrome.storage.sync.remove(\"sync_key_3\", function () {"
|
||||
"chrome.storage.sync.get(\"sync_key_3\", function(items) {"
|
||||
"if (items[\"sync_key_3\"] == undefined) {" +
|
||||
GetMessageJS(kSuccessMessage) +
|
||||
"}})})"
|
||||
"});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(SyncStorageRemoveTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(SyncStorageRemoveTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(SyncStorageRemove, SyncStorageRemoveTestHandler);
|
||||
|
||||
namespace {
|
||||
|
||||
// Test for chrome.storage.sync.clear(function callback)
|
||||
class SyncStorageClearTestHandler : public StorageTestHandler {
|
||||
public:
|
||||
explicit SyncStorageClearTestHandler(RequestContextType request_context_type)
|
||||
: StorageTestHandler(request_context_type) {}
|
||||
|
||||
protected:
|
||||
std::string GetStorageApiJS() const override {
|
||||
return "var value1Cleared = false;"
|
||||
"var value2Cleared = false;"
|
||||
|
||||
"function checkCleared() {"
|
||||
"if (value1Cleared && value2Cleared) {"
|
||||
+ GetMessageJS(kSuccessMessage) +
|
||||
"}}"
|
||||
|
||||
"chrome.storage.sync.set({\"sync_key_4\": \"sync_value_4\","
|
||||
"\"sync_key_5\": \"sync_value_5\"}, function() {"
|
||||
"chrome.storage.sync.clear(function () {"
|
||||
|
||||
"chrome.storage.sync.get(\"sync_key_4\", function(items) {"
|
||||
"if (items[\"sync_key_4\"] == undefined) {"
|
||||
"value1Cleared = true;"
|
||||
"checkCleared();"
|
||||
"}});"
|
||||
|
||||
"chrome.storage.sync.get(\"sync_key_5\", function(items) {"
|
||||
"if (items[\"sync_key_5\"] == undefined) {"
|
||||
"value2Cleared = true;"
|
||||
"checkCleared();"
|
||||
"}});"
|
||||
|
||||
"})});";
|
||||
}
|
||||
|
||||
private:
|
||||
IMPLEMENT_REFCOUNTING(SyncStorageClearTestHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(SyncStorageClearTestHandler);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
STORAGE_TEST_GROUP_MINIMAL(SyncStorageClear, SyncStorageClearTestHandler);
|
Loading…
x
Reference in New Issue
Block a user