Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/dom_storage/local_storage_context_mojo.h" | 5 #include "content/browser/dom_storage/local_storage_context_mojo.h" |
| 6 | 6 |
| 7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "components/leveldb/public/cpp/util.h" | 9 #include "components/leveldb/public/cpp/util.h" |
| 10 #include "components/leveldb/public/cpp/util.h" | |
|
jam
2016/12/29 16:54:02
nit: remove
| |
| 11 #include "components/leveldb/public/interfaces/leveldb.mojom.h" | |
| 12 #include "content/browser/dom_storage/local_storage_database.pb.h" | |
| 10 #include "content/browser/leveldb_wrapper_impl.h" | 13 #include "content/browser/leveldb_wrapper_impl.h" |
| 11 #include "content/common/dom_storage/dom_storage_types.h" | 14 #include "content/common/dom_storage/dom_storage_types.h" |
| 15 #include "content/public/browser/local_storage_usage_info.h" | |
| 12 #include "services/file/public/interfaces/constants.mojom.h" | 16 #include "services/file/public/interfaces/constants.mojom.h" |
| 13 #include "services/service_manager/public/cpp/connection.h" | 17 #include "services/service_manager/public/cpp/connection.h" |
| 14 #include "services/service_manager/public/cpp/connector.h" | 18 #include "services/service_manager/public/cpp/connector.h" |
| 15 | 19 |
| 16 namespace content { | 20 namespace content { |
| 17 | 21 |
| 18 // LevelDB database schema | 22 // LevelDB database schema |
| 19 // ======================= | 23 // ======================= |
| 20 // | 24 // |
| 21 // Version 1 (in sorted order): | 25 // Version 1 (in sorted order): |
| 22 // key: "VERSION" | 26 // key: "VERSION" |
| 23 // value: "1" | 27 // value: "1" |
| 24 // | 28 // |
| 29 // key: "META:" + <url::Origin 'origin'> | |
| 30 // value: <LocalStorageOriginMetaData serialized as a string> | |
| 31 // | |
| 25 // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key> | 32 // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key> |
| 26 // value: <script controlled value> | 33 // value: <script controlled value> |
| 27 | 34 |
| 28 namespace { | 35 namespace { |
| 36 | |
| 29 const char kVersionKey[] = "VERSION"; | 37 const char kVersionKey[] = "VERSION"; |
| 30 const char kOriginSeparator = '\x00'; | 38 const char kOriginSeparator = '\x00'; |
| 31 const char kDataPrefix[] = "_"; | 39 const char kDataPrefix[] = "_"; |
| 40 const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', ':'}; | |
| 32 const int64_t kMinSchemaVersion = 1; | 41 const int64_t kMinSchemaVersion = 1; |
| 33 const int64_t kCurrentSchemaVersion = 1; | 42 const int64_t kCurrentSchemaVersion = 1; |
| 43 | |
| 44 std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) { | |
| 45 auto serialized_origin = leveldb::StdStringToUint8Vector(origin.Serialize()); | |
| 46 std::vector<uint8_t> key; | |
| 47 key.reserve(arraysize(kMetaPrefix) + serialized_origin.size()); | |
| 48 key.insert(key.end(), kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)); | |
| 49 key.insert(key.end(), serialized_origin.begin(), serialized_origin.end()); | |
| 50 return key; | |
| 51 } | |
| 34 } | 52 } |
| 35 | 53 |
| 36 LocalStorageContextMojo::LocalStorageContextMojo( | 54 LocalStorageContextMojo::LocalStorageContextMojo( |
| 37 service_manager::Connector* connector, | 55 service_manager::Connector* connector, |
| 38 const base::FilePath& subdirectory) | 56 const base::FilePath& subdirectory) |
| 39 : connector_(connector), | 57 : connector_(connector), |
| 40 subdirectory_(subdirectory), | 58 subdirectory_(subdirectory), |
| 41 weak_ptr_factory_(this) {} | 59 weak_ptr_factory_(this) {} |
| 42 | 60 |
| 43 LocalStorageContextMojo::~LocalStorageContextMojo() {} | 61 LocalStorageContextMojo::~LocalStorageContextMojo() {} |
| 44 | 62 |
| 45 void LocalStorageContextMojo::OpenLocalStorage( | 63 void LocalStorageContextMojo::OpenLocalStorage( |
| 46 const url::Origin& origin, | 64 const url::Origin& origin, |
| 47 mojom::LevelDBWrapperRequest request) { | 65 mojom::LevelDBWrapperRequest request) { |
| 66 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, | |
| 67 weak_ptr_factory_.GetWeakPtr(), origin, | |
| 68 std::move(request))); | |
| 69 } | |
| 70 | |
| 71 void LocalStorageContextMojo::GetStorageUsage( | |
| 72 GetStorageUsageCallback callback) { | |
| 73 RunWhenConnected( | |
| 74 base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage, | |
| 75 weak_ptr_factory_.GetWeakPtr(), std::move(callback))); | |
| 76 } | |
| 77 | |
| 78 void LocalStorageContextMojo::SetDatabaseForTesting( | |
| 79 leveldb::mojom::LevelDBDatabasePtr database) { | |
| 80 DCHECK_EQ(connection_state_, NO_CONNECTION); | |
| 81 connection_state_ = CONNECTION_IN_PROGRESS; | |
| 82 database_ = std::move(database); | |
| 83 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); | |
| 84 } | |
| 85 | |
| 86 void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) { | |
| 48 // If we don't have a filesystem_connection_, we'll need to establish one. | 87 // If we don't have a filesystem_connection_, we'll need to establish one. |
| 49 if (connection_state_ == NO_CONNECTION) { | 88 if (connection_state_ == NO_CONNECTION) { |
| 50 CHECK(connector_); | 89 CHECK(connector_); |
| 51 file_service_connection_ = connector_->Connect(file::mojom::kServiceName); | 90 file_service_connection_ = connector_->Connect(file::mojom::kServiceName); |
| 52 connection_state_ = CONNECTION_IN_PROGRESS; | 91 connection_state_ = CONNECTION_IN_PROGRESS; |
| 53 file_service_connection_->AddConnectionCompletedClosure( | 92 file_service_connection_->AddConnectionCompletedClosure( |
| 54 base::Bind(&LocalStorageContextMojo::OnUserServiceConnectionComplete, | 93 base::Bind(&LocalStorageContextMojo::OnUserServiceConnectionComplete, |
| 55 weak_ptr_factory_.GetWeakPtr())); | 94 weak_ptr_factory_.GetWeakPtr())); |
| 56 file_service_connection_->SetConnectionLostClosure( | 95 file_service_connection_->SetConnectionLostClosure( |
| 57 base::Bind(&LocalStorageContextMojo::OnUserServiceConnectionError, | 96 base::Bind(&LocalStorageContextMojo::OnUserServiceConnectionError, |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 70 file_service_connection_->GetInterface(&leveldb_service_); | 109 file_service_connection_->GetInterface(&leveldb_service_); |
| 71 leveldb_service_->OpenInMemory( | 110 leveldb_service_->OpenInMemory( |
| 72 MakeRequest(&database_), | 111 MakeRequest(&database_), |
| 73 base::Bind(&LocalStorageContextMojo::OnDatabaseOpened, | 112 base::Bind(&LocalStorageContextMojo::OnDatabaseOpened, |
| 74 weak_ptr_factory_.GetWeakPtr())); | 113 weak_ptr_factory_.GetWeakPtr())); |
| 75 } | 114 } |
| 76 } | 115 } |
| 77 | 116 |
| 78 if (connection_state_ == CONNECTION_IN_PROGRESS) { | 117 if (connection_state_ == CONNECTION_IN_PROGRESS) { |
| 79 // Queue this OpenLocalStorage call for when we have a level db pointer. | 118 // Queue this OpenLocalStorage call for when we have a level db pointer. |
| 80 on_database_opened_callbacks_.push_back(base::BindOnce( | 119 on_database_opened_callbacks_.push_back(std::move(callback)); |
| 81 &LocalStorageContextMojo::BindLocalStorage, | |
| 82 weak_ptr_factory_.GetWeakPtr(), origin, std::move(request))); | |
| 83 return; | 120 return; |
| 84 } | 121 } |
| 85 | 122 |
| 86 BindLocalStorage(origin, std::move(request)); | 123 std::move(callback).Run(); |
| 87 } | |
| 88 | |
| 89 void LocalStorageContextMojo::SetDatabaseForTesting( | |
| 90 leveldb::mojom::LevelDBDatabasePtr database) { | |
| 91 DCHECK_EQ(connection_state_, NO_CONNECTION); | |
| 92 connection_state_ = CONNECTION_IN_PROGRESS; | |
| 93 database_ = std::move(database); | |
| 94 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); | |
| 95 } | 124 } |
| 96 | 125 |
| 97 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( | 126 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( |
| 98 const url::Origin& origin) { | 127 const url::Origin& origin) { |
| 99 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); | 128 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); |
| 100 level_db_wrappers_.erase(origin); | 129 level_db_wrappers_.erase(origin); |
| 101 } | 130 } |
| 102 | 131 |
| 103 std::vector<leveldb::mojom::BatchedOperationPtr> | 132 std::vector<leveldb::mojom::BatchedOperationPtr> |
| 104 LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit() { | 133 LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit( |
| 134 const url::Origin& origin, | |
| 135 const LevelDBWrapperImpl& wrapper) { | |
| 136 // |wrapper| might not exist in |level_db_wrappers_| anymore at this point, as | |
| 137 // it is possible this commit was triggered by destruction. | |
| 138 | |
| 105 std::vector<leveldb::mojom::BatchedOperationPtr> operations; | 139 std::vector<leveldb::mojom::BatchedOperationPtr> operations; |
| 106 | 140 |
| 107 // Write schema version if not already done so before. | 141 // Write schema version if not already done so before. |
| 108 if (!database_initialized_) { | 142 if (!database_initialized_) { |
| 109 leveldb::mojom::BatchedOperationPtr item = | 143 leveldb::mojom::BatchedOperationPtr item = |
| 110 leveldb::mojom::BatchedOperation::New(); | 144 leveldb::mojom::BatchedOperation::New(); |
| 145 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; | |
| 111 item->key = leveldb::StdStringToUint8Vector(kVersionKey); | 146 item->key = leveldb::StdStringToUint8Vector(kVersionKey); |
| 112 item->value = leveldb::StdStringToUint8Vector( | 147 item->value = leveldb::StdStringToUint8Vector( |
| 113 base::Int64ToString(kCurrentSchemaVersion)); | 148 base::Int64ToString(kCurrentSchemaVersion)); |
| 114 operations.push_back(std::move(item)); | 149 operations.push_back(std::move(item)); |
| 115 database_initialized_ = true; | 150 database_initialized_ = true; |
| 116 } | 151 } |
| 117 | 152 |
| 153 leveldb::mojom::BatchedOperationPtr item = | |
| 154 leveldb::mojom::BatchedOperation::New(); | |
| 155 item->key = CreateMetaDataKey(origin); | |
| 156 if (wrapper.bytes_used() == 0) { | |
| 157 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; | |
| 158 } else { | |
| 159 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; | |
| 160 LocalStorageOriginMetaData data; | |
| 161 data.set_last_modified(base::Time::Now().ToInternalValue()); | |
| 162 data.set_size_bytes(wrapper.bytes_used()); | |
| 163 item->value = leveldb::StdStringToUint8Vector(data.SerializeAsString()); | |
| 164 } | |
| 165 operations.push_back(std::move(item)); | |
| 166 | |
| 118 return operations; | 167 return operations; |
| 119 } | 168 } |
| 120 | 169 |
| 121 void LocalStorageContextMojo::OnUserServiceConnectionComplete() { | 170 void LocalStorageContextMojo::OnUserServiceConnectionComplete() { |
| 122 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED, | 171 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED, |
| 123 file_service_connection_->GetResult()); | 172 file_service_connection_->GetResult()); |
| 124 } | 173 } |
| 125 | 174 |
| 126 void LocalStorageContextMojo::OnUserServiceConnectionError() { | 175 void LocalStorageContextMojo::OnUserServiceConnectionError() { |
| 127 CHECK(false); | 176 CHECK(false); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 auto found = level_db_wrappers_.find(origin); | 274 auto found = level_db_wrappers_.find(origin); |
| 226 if (found == level_db_wrappers_.end()) { | 275 if (found == level_db_wrappers_.end()) { |
| 227 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>( | 276 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>( |
| 228 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator, | 277 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator, |
| 229 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance, | 278 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance, |
| 230 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour, | 279 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour, |
| 231 kMaxCommitsPerHour, | 280 kMaxCommitsPerHour, |
| 232 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, | 281 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, |
| 233 base::Unretained(this), origin), | 282 base::Unretained(this), origin), |
| 234 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit, | 283 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit, |
| 235 base::Unretained(this))); | 284 base::Unretained(this), origin)); |
| 236 found = level_db_wrappers_.find(origin); | 285 found = level_db_wrappers_.find(origin); |
| 237 } | 286 } |
| 238 | 287 |
| 239 found->second->Bind(std::move(request)); | 288 found->second->Bind(std::move(request)); |
| 240 } | 289 } |
| 241 | 290 |
| 291 void LocalStorageContextMojo::RetrieveStorageUsage( | |
| 292 GetStorageUsageCallback callback) { | |
| 293 database_->GetPrefixed( | |
| 294 std::vector<uint8_t>(kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)), | |
| 295 base::Bind(&LocalStorageContextMojo::OnGotMetaData, | |
| 296 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); | |
| 297 } | |
| 298 | |
| 299 void LocalStorageContextMojo::OnGotMetaData( | |
| 300 GetStorageUsageCallback callback, | |
| 301 leveldb::mojom::DatabaseError status, | |
| 302 std::vector<leveldb::mojom::KeyValuePtr> data) { | |
| 303 std::vector<LocalStorageUsageInfo> result; | |
| 304 for (const auto& row : data) { | |
| 305 DCHECK_GT(row->key.size(), arraysize(kMetaPrefix)); | |
| 306 LocalStorageUsageInfo info; | |
| 307 info.origin = GURL(leveldb::Uint8VectorToStdString(row->key).substr( | |
| 308 arraysize(kMetaPrefix))); | |
| 309 if (!info.origin.is_valid()) { | |
| 310 // TODO(mek): Deal with database corruption. | |
| 311 continue; | |
| 312 } | |
| 313 | |
| 314 LocalStorageOriginMetaData data; | |
| 315 if (!data.ParseFromArray(row->value.data(), row->value.size())) { | |
| 316 // TODO(mek): Deal with database corruption. | |
| 317 continue; | |
| 318 } | |
| 319 info.data_size = data.size_bytes(); | |
| 320 info.last_modified = base::Time::FromInternalValue(data.last_modified()); | |
| 321 result.push_back(std::move(info)); | |
| 322 } | |
| 323 std::move(callback).Run(std::move(result)); | |
| 324 } | |
| 325 | |
| 242 } // namespace content | 326 } // namespace content |
| OLD | NEW |