Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: content/browser/dom_storage/local_storage_context_mojo.cc

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

Powered by Google App Engine
This is Rietveld 408576698