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 "content/browser/leveldb_wrapper_impl.h" | 10 #include "content/browser/leveldb_wrapper_impl.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 // | 24 // |
25 // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key> | 25 // key: "_" + <url::Origin> 'origin'> + '\x00' + <script controlled key> |
26 // value: <script controlled value> | 26 // value: <script controlled value> |
27 | 27 |
28 namespace { | 28 namespace { |
29 const char kVersionKey[] = "VERSION"; | 29 const char kVersionKey[] = "VERSION"; |
30 const char kOriginSeparator = '\x00'; | 30 const char kOriginSeparator = '\x00'; |
31 const char kDataPrefix[] = "_"; | 31 const char kDataPrefix[] = "_"; |
32 const int64_t kMinSchemaVersion = 1; | 32 const int64_t kMinSchemaVersion = 1; |
33 const int64_t kCurrentSchemaVersion = 1; | 33 const int64_t kCurrentSchemaVersion = 1; |
34 | |
35 void NoOpResult(leveldb::mojom::DatabaseError status) {} | |
36 } | 34 } |
37 | 35 |
38 LocalStorageContextMojo::LocalStorageContextMojo( | 36 LocalStorageContextMojo::LocalStorageContextMojo( |
39 service_manager::Connector* connector, | 37 service_manager::Connector* connector, |
40 const base::FilePath& subdirectory) | 38 const base::FilePath& subdirectory) |
41 : connector_(connector), | 39 : connector_(connector), |
42 subdirectory_(subdirectory), | 40 subdirectory_(subdirectory), |
43 weak_ptr_factory_(this) {} | 41 weak_ptr_factory_(this) {} |
44 | 42 |
45 LocalStorageContextMojo::~LocalStorageContextMojo() {} | 43 LocalStorageContextMojo::~LocalStorageContextMojo() {} |
(...skipping 26 matching lines...) Expand all Loading... |
72 file_service_connection_->GetInterface(&leveldb_service_); | 70 file_service_connection_->GetInterface(&leveldb_service_); |
73 leveldb_service_->OpenInMemory( | 71 leveldb_service_->OpenInMemory( |
74 MakeRequest(&database_), | 72 MakeRequest(&database_), |
75 base::Bind(&LocalStorageContextMojo::OnDatabaseOpened, | 73 base::Bind(&LocalStorageContextMojo::OnDatabaseOpened, |
76 weak_ptr_factory_.GetWeakPtr())); | 74 weak_ptr_factory_.GetWeakPtr())); |
77 } | 75 } |
78 } | 76 } |
79 | 77 |
80 if (connection_state_ == CONNECTION_IN_PROGRESS) { | 78 if (connection_state_ == CONNECTION_IN_PROGRESS) { |
81 // Queue this OpenLocalStorage call for when we have a level db pointer. | 79 // Queue this OpenLocalStorage call for when we have a level db pointer. |
82 on_database_opened_callbacks_.push_back(base::Bind( | 80 on_database_opened_callbacks_.push_back(base::BindOnce( |
83 &LocalStorageContextMojo::BindLocalStorage, | 81 &LocalStorageContextMojo::BindLocalStorage, |
84 weak_ptr_factory_.GetWeakPtr(), origin, base::Passed(&request))); | 82 weak_ptr_factory_.GetWeakPtr(), origin, std::move(request))); |
85 return; | 83 return; |
86 } | 84 } |
87 | 85 |
88 BindLocalStorage(origin, std::move(request)); | 86 BindLocalStorage(origin, std::move(request)); |
89 } | 87 } |
90 | 88 |
91 void LocalStorageContextMojo::SetDatabaseForTesting( | 89 void LocalStorageContextMojo::SetDatabaseForTesting( |
92 leveldb::mojom::LevelDBDatabasePtr database) { | 90 leveldb::mojom::LevelDBDatabasePtr database) { |
93 DCHECK_EQ(connection_state_, NO_CONNECTION); | 91 DCHECK_EQ(connection_state_, NO_CONNECTION); |
94 connection_state_ = CONNECTION_IN_PROGRESS; | 92 connection_state_ = CONNECTION_IN_PROGRESS; |
95 database_ = std::move(database); | 93 database_ = std::move(database); |
96 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); | 94 OnDatabaseOpened(leveldb::mojom::DatabaseError::OK); |
97 } | 95 } |
98 | 96 |
99 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( | 97 void LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings( |
100 const url::Origin& origin) { | 98 const url::Origin& origin) { |
101 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); | 99 DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); |
102 level_db_wrappers_.erase(origin); | 100 level_db_wrappers_.erase(origin); |
103 } | 101 } |
104 | 102 |
| 103 std::vector<leveldb::mojom::BatchedOperationPtr> |
| 104 LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit() { |
| 105 std::vector<leveldb::mojom::BatchedOperationPtr> operations; |
| 106 |
| 107 // Write schema version if not already done so before. |
| 108 if (!database_initialized_) { |
| 109 leveldb::mojom::BatchedOperationPtr item = |
| 110 leveldb::mojom::BatchedOperation::New(); |
| 111 item->key = leveldb::StdStringToUint8Vector(kVersionKey); |
| 112 item->value = leveldb::StdStringToUint8Vector( |
| 113 base::Int64ToString(kCurrentSchemaVersion)); |
| 114 operations.push_back(std::move(item)); |
| 115 database_initialized_ = true; |
| 116 } |
| 117 |
| 118 return operations; |
| 119 } |
| 120 |
105 void LocalStorageContextMojo::OnUserServiceConnectionComplete() { | 121 void LocalStorageContextMojo::OnUserServiceConnectionComplete() { |
106 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED, | 122 CHECK_EQ(service_manager::mojom::ConnectResult::SUCCEEDED, |
107 file_service_connection_->GetResult()); | 123 file_service_connection_->GetResult()); |
108 } | 124 } |
109 | 125 |
110 void LocalStorageContextMojo::OnUserServiceConnectionError() { | 126 void LocalStorageContextMojo::OnUserServiceConnectionError() { |
111 CHECK(false); | 127 CHECK(false); |
112 } | 128 } |
113 | 129 |
114 // Part of our asynchronous directory opening called from OpenLocalStorage(). | 130 // Part of our asynchronous directory opening called from OpenLocalStorage(). |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 } | 170 } |
155 | 171 |
156 OnGotDatabaseVersion(leveldb::mojom::DatabaseError::IO_ERROR, | 172 OnGotDatabaseVersion(leveldb::mojom::DatabaseError::IO_ERROR, |
157 std::vector<uint8_t>()); | 173 std::vector<uint8_t>()); |
158 } | 174 } |
159 | 175 |
160 void LocalStorageContextMojo::OnGotDatabaseVersion( | 176 void LocalStorageContextMojo::OnGotDatabaseVersion( |
161 leveldb::mojom::DatabaseError status, | 177 leveldb::mojom::DatabaseError status, |
162 const std::vector<uint8_t>& value) { | 178 const std::vector<uint8_t>& value) { |
163 if (status == leveldb::mojom::DatabaseError::NOT_FOUND) { | 179 if (status == leveldb::mojom::DatabaseError::NOT_FOUND) { |
164 // New database, write current version and continue. | 180 // New database, nothing more to do. Current version will get written |
165 // TODO(mek): Delay writing version until first actual data gets committed. | 181 // when first data is committed. |
166 database_->Put(leveldb::StdStringToUint8Vector(kVersionKey), | |
167 leveldb::StdStringToUint8Vector( | |
168 base::Int64ToString(kCurrentSchemaVersion)), | |
169 base::Bind(&NoOpResult)); | |
170 // new database | |
171 } else if (status == leveldb::mojom::DatabaseError::OK) { | 182 } else if (status == leveldb::mojom::DatabaseError::OK) { |
172 // Existing database, check if version number matches current schema | 183 // Existing database, check if version number matches current schema |
173 // version. | 184 // version. |
174 int64_t db_version; | 185 int64_t db_version; |
175 if (!base::StringToInt64(leveldb::Uint8VectorToStdString(value), | 186 if (!base::StringToInt64(leveldb::Uint8VectorToStdString(value), |
176 &db_version) || | 187 &db_version) || |
177 db_version < kMinSchemaVersion || db_version > kCurrentSchemaVersion) { | 188 db_version < kMinSchemaVersion || db_version > kCurrentSchemaVersion) { |
178 // TODO(mek): delete and recreate database, rather than failing outright. | 189 // TODO(mek): delete and recreate database, rather than failing outright. |
179 database_ = nullptr; | 190 database_ = nullptr; |
180 } | 191 } |
| 192 |
| 193 database_initialized_ = true; |
181 } else { | 194 } else { |
182 // Other read error. Possibly database corruption. | 195 // Other read error. Possibly database corruption. |
183 // TODO(mek): delete and recreate database, rather than failing outright. | 196 // TODO(mek): delete and recreate database, rather than failing outright. |
184 database_ = nullptr; | 197 database_ = nullptr; |
185 } | 198 } |
186 | 199 |
187 // |database_| should be known to either be valid or invalid by now. Run our | 200 // |database_| should be known to either be valid or invalid by now. Run our |
188 // delayed bindings. | 201 // delayed bindings. |
189 connection_state_ = CONNECTION_FINISHED; | 202 connection_state_ = CONNECTION_FINISHED; |
190 for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i) | 203 for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i) |
191 on_database_opened_callbacks_[i].Run(); | 204 std::move(on_database_opened_callbacks_[i]).Run(); |
192 on_database_opened_callbacks_.clear(); | 205 on_database_opened_callbacks_.clear(); |
193 } | 206 } |
194 | 207 |
195 // The (possibly delayed) implementation of OpenLocalStorage(). Can be called | 208 // The (possibly delayed) implementation of OpenLocalStorage(). Can be called |
196 // directly from that function, or through |on_database_open_callbacks_|. | 209 // directly from that function, or through |on_database_open_callbacks_|. |
197 void LocalStorageContextMojo::BindLocalStorage( | 210 void LocalStorageContextMojo::BindLocalStorage( |
198 const url::Origin& origin, | 211 const url::Origin& origin, |
199 mojom::LevelDBWrapperRequest request) { | 212 mojom::LevelDBWrapperRequest request) { |
200 // Delay for a moment after a value is set in anticipation | 213 // Delay for a moment after a value is set in anticipation |
201 // of other values being set, so changes are batched. | 214 // of other values being set, so changes are batched. |
202 const int kCommitDefaultDelaySecs = 5; | 215 const int kCommitDefaultDelaySecs = 5; |
203 | 216 |
204 // To avoid excessive IO we apply limits to the amount of data being written | 217 // To avoid excessive IO we apply limits to the amount of data being written |
205 // and the frequency of writes. | 218 // and the frequency of writes. |
206 const int kMaxBytesPerHour = kPerStorageAreaQuota; | 219 const int kMaxBytesPerHour = kPerStorageAreaQuota; |
207 const int kMaxCommitsPerHour = 60; | 220 const int kMaxCommitsPerHour = 60; |
208 | 221 |
209 auto found = level_db_wrappers_.find(origin); | 222 auto found = level_db_wrappers_.find(origin); |
210 if (found == level_db_wrappers_.end()) { | 223 if (found == level_db_wrappers_.end()) { |
211 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>( | 224 level_db_wrappers_[origin] = base::MakeUnique<LevelDBWrapperImpl>( |
212 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator, | 225 database_.get(), kDataPrefix + origin.Serialize() + kOriginSeparator, |
213 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance, | 226 kPerStorageAreaQuota + kPerStorageAreaOverQuotaAllowance, |
214 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour, | 227 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), kMaxBytesPerHour, |
215 kMaxCommitsPerHour, | 228 kMaxCommitsPerHour, |
216 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, | 229 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperHasNoBindings, |
217 base::Unretained(this), origin)); | 230 base::Unretained(this), origin), |
| 231 base::Bind(&LocalStorageContextMojo::OnLevelDBWrapperPrepareToCommit, |
| 232 base::Unretained(this))); |
218 found = level_db_wrappers_.find(origin); | 233 found = level_db_wrappers_.find(origin); |
219 } | 234 } |
220 | 235 |
221 found->second->Bind(std::move(request)); | 236 found->second->Bind(std::move(request)); |
222 } | 237 } |
223 | 238 |
224 } // namespace content | 239 } // namespace content |
OLD | NEW |