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 |