Chromium Code Reviews| Index: content/browser/dom_storage/local_storage_context_mojo.cc |
| diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc |
| index fa68355acc9aff1da5c02d93014a3a40695257dc..b449ced9849a3211f79442bdeb150afa197bb019 100644 |
| --- a/content/browser/dom_storage/local_storage_context_mojo.cc |
| +++ b/content/browser/dom_storage/local_storage_context_mojo.cc |
| @@ -7,8 +7,12 @@ |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "components/leveldb/public/cpp/util.h" |
| +#include "components/leveldb/public/cpp/util.h" |
|
jam
2016/12/29 16:54:02
nit: remove
|
| +#include "components/leveldb/public/interfaces/leveldb.mojom.h" |
| +#include "content/browser/dom_storage/local_storage_database.pb.h" |
| #include "content/browser/leveldb_wrapper_impl.h" |
| #include "content/common/dom_storage/dom_storage_types.h" |
| +#include "content/public/browser/local_storage_usage_info.h" |
| #include "services/file/public/interfaces/constants.mojom.h" |
| #include "services/service_manager/public/cpp/connection.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| @@ -22,15 +26,29 @@ namespace content { |
| // key: "VERSION" |
| // value: "1" |
| // |
| +// key: "META:" + <url::Origin 'origin'> |
| +// value: <LocalStorageOriginMetaData serialized as a string> |
| +// |
| // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key> |
| // value: <script controlled value> |
| namespace { |
| + |
| const char kVersionKey[] = "VERSION"; |
| const char kOriginSeparator = '\x00'; |
| const char kDataPrefix[] = "_"; |
| +const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', ':'}; |
| const int64_t kMinSchemaVersion = 1; |
| const int64_t kCurrentSchemaVersion = 1; |
| + |
| +std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) { |
| + auto serialized_origin = leveldb::StdStringToUint8Vector(origin.Serialize()); |
| + std::vector<uint8_t> key; |
| + key.reserve(arraysize(kMetaPrefix) + serialized_origin.size()); |
| + key.insert(key.end(), kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)); |
| + key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); |
| + return key; |
| +} |
| } |
| LocalStorageContextMojo::LocalStorageContextMojo( |
| @@ -45,6 +63,27 @@ LocalStorageContextMojo::~LocalStorageContextMojo() {} |
| void LocalStorageContextMojo::OpenLocalStorage( |
| const url::Origin& origin, |
| mojom::LevelDBWrapperRequest request) { |
| + RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, |
| + weak_ptr_factory_.GetWeakPtr(), origin, |
| + std::move(request))); |
| +} |
| + |
| +void LocalStorageContextMojo::GetStorageUsage( |
| + GetStorageUsageCallback callback) { |
| + RunWhenConnected( |
| + base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage, |
| + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| +} |
| + |
| +void LocalStorageContextMojo::SetDatabaseForTesting( |
| + leveldb::mojom::LevelDBDatabasePtr database) { |
| + DCHECK_EQ(connection_state_, NO_CONNECTION); |
| + connection_state_ = CONNECTION_IN_PROGRESS; |
| + database_ = std::move(database); |
| + OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); |
| +} |
| + |
| +void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) { |
| // If we don't have a filesystem_connection_, we'll need to establish one. |
| if (connection_state_ == NO_CONNECTION) { |
| CHECK(connector_); |
| @@ -77,21 +116,11 @@ void LocalStorageContextMojo::OpenLocalStorage( |
| if (connection_state_ == CONNECTION_IN_PROGRESS) { |
| // Queue this OpenLocalStorage call for when we have a level db pointer. |
| - on_database_opened_callbacks_.push_back(base::BindOnce( |
| - &LocalStorageContextMojo::BindLocalStorage, |
| - weak_ptr_factory_.GetWeakPtr(), origin, std::move(request))); |
| + on_database_opened_callbacks_.push_back(std::move(callback)); |
| return; |
| } |
| - BindLocalStorage(origin, std::move(request)); |
| -} |
| - |
| -void LocalStorageContextMojo::SetDatabaseForTesting( |
| - leveldb::mojom::LevelDBDatabasePtr database) { |
| - DCHECK_EQ(connection_state_, NO_CONNECTION); |
| - connection_state_ = CONNECTION_IN_PROGRESS; |
| - database_ = std::move(database); |
| - OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); |
| + std::move(callback).Run(); |
| } |
| void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( |
| @@ -101,13 +130,19 @@ void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( |
| } |
| std::vector<leveldb::mojom::BatchedOperationPtr> |
| -LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit() { |
| +LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit( |
| + const url::Origin& origin, |
| + const LevelDBWrapperImpl& wrapper) { |
| + // |wrapper| might not exist in |level_db_wrappers_| anymore at this point, as |
| + // it is possible this commit was triggered by destruction. |
| + |
| std::vector<leveldb::mojom::BatchedOperationPtr> operations; |
| // Write schema version if not already done so before. |
| if (!database_initialized_) { |
| leveldb::mojom::BatchedOperationPtr item = |
| leveldb::mojom::BatchedOperation::New(); |
| + item->type = leveldb::mojom::BatchOperationType::PUT_KEY; |
| item->key = leveldb::StdStringToUint8Vector(kVersionKey); |
| item->value = leveldb::StdStringToUint8Vector( |
| base::Int64ToString(kCurrentSchemaVersion)); |
| @@ -115,6 +150,20 @@ LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit() { |
| database_initialized_ = true; |
| } |
| + leveldb::mojom::BatchedOperationPtr item = |
| + leveldb::mojom::BatchedOperation::New(); |
| + item->key = CreateMetaDataKey(origin); |
| + if (wrapper.bytes_used() == 0) { |
| + item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; |
| + } else { |
| + item->type = leveldb::mojom::BatchOperationType::PUT_KEY; |
| + LocalStorageOriginMetaData data; |
| + data.set_last_modified(base::Time::Now().ToInternalValue()); |
| + data.set_size_bytes(wrapper.bytes_used()); |
| + item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString()); |
| + } |
| + operations.push_back(std::move(item)); |
| + |
| return operations; |
| } |
| @@ -232,11 +281,46 @@ void LocalStorageContextMojo::BindLocalStorage( |
| base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, |
| base::Unretained(this), origin), |
| base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit, |
| - base::Unretained(this))); |
| + base::Unretained(this), origin)); |
| found = level_db_wrappers_.find(origin); |
| } |
| found->second->Bind(std::move(request)); |
| } |
| +void LocalStorageContextMojo::RetrieveStorageUsage( |
| + GetStorageUsageCallback callback) { |
| + database_->GetPrefixed( |
| + std::vector<uint8_t>(kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)), |
| + base::Bind(&LocalStorageContextMojo::OnGotMetaData, |
| + weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); |
| +} |
| + |
| +void LocalStorageContextMojo::OnGotMetaData( |
| + GetStorageUsageCallback callback, |
| + leveldb::mojom::DatabaseError status, |
| + std::vector<leveldb::mojom::KeyValuePtr> data) { |
| + std::vector<LocalStorageUsageInfo> result; |
| + for (const auto& row : data) { |
| + DCHECK_GT(row->key.size(), arraysize(kMetaPrefix)); |
| + LocalStorageUsageInfo info; |
| + info.origin = GURL(leveldb::Uint8VectorToStdString(row->key).substr( |
| + arraysize(kMetaPrefix))); |
| + if (!info.origin.is_valid()) { |
| + // TODO(mek): Deal with database corruption. |
| + continue; |
| + } |
| + |
| + LocalStorageOriginMetaData data; |
| + if (!data.ParseFromArray(row->value.data(), row->value.size())) { |
| + // TODO(mek): Deal with database corruption. |
| + continue; |
| + } |
| + info.data_size = data.size_bytes(); |
| + info.last_modified = base::Time::FromInternalValue(data.last_modified()); |
| + result.push_back(std::move(info)); |
| + } |
| + std::move(callback).Run(std::move(result)); |
| +} |
| + |
| } // namespace content |