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/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "components/leveldb/public/cpp/util.h" | 10 #include "components/leveldb/public/cpp/util.h" |
11 #include "components/leveldb/public/interfaces/leveldb.mojom.h" | 11 #include "components/leveldb/public/interfaces/leveldb.mojom.h" |
12 #include "content/browser/dom_storage/dom_storage_area.h" | 12 #include "content/browser/dom_storage/dom_storage_area.h" |
13 #include "content/browser/dom_storage/dom_storage_database.h" | 13 #include "content/browser/dom_storage/dom_storage_database.h" |
14 #include "content/browser/dom_storage/dom_storage_task_runner.h" | 14 #include "content/browser/dom_storage/dom_storage_task_runner.h" |
15 #include "content/browser/dom_storage/local_storage_database.pb.h" | 15 #include "content/browser/dom_storage/local_storage_database.pb.h" |
16 #include "content/browser/leveldb_wrapper_impl.h" | 16 #include "content/browser/leveldb_wrapper_impl.h" |
17 #include "content/common/dom_storage/dom_storage_types.h" | 17 #include "content/common/dom_storage/dom_storage_types.h" |
18 #include "content/public/browser/local_storage_usage_info.h" | 18 #include "content/public/browser/local_storage_usage_info.h" |
19 #include "services/file/public/interfaces/constants.mojom.h" | 19 #include "services/file/public/interfaces/constants.mojom.h" |
20 #include "services/service_manager/public/cpp/connector.h" | 20 #include "services/service_manager/public/cpp/connector.h" |
21 #include "sql/connection.h" | 21 #include "sql/connection.h" |
22 #include "storage/browser/quota/special_storage_policy.h" | |
22 #include "third_party/leveldatabase/env_chromium.h" | 23 #include "third_party/leveldatabase/env_chromium.h" |
23 | 24 |
24 namespace content { | 25 namespace content { |
25 | 26 |
26 // LevelDB database schema | 27 // LevelDB database schema |
27 // ======================= | 28 // ======================= |
28 // | 29 // |
29 // Version 1 (in sorted order): | 30 // Version 1 (in sorted order): |
30 // key: "VERSION" | 31 // key: "VERSION" |
31 // value: "1" | 32 // value: "1" |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 // called and need access to the LevelDBWrapperImpl instance. The unique_ptr | 213 // called and need access to the LevelDBWrapperImpl instance. The unique_ptr |
213 // could already be null, but this field should still be valid. | 214 // could already be null, but this field should still be valid. |
214 LevelDBWrapperImpl* level_db_wrapper_ptr_; | 215 LevelDBWrapperImpl* level_db_wrapper_ptr_; |
215 bool deleted_old_data_ = false; | 216 bool deleted_old_data_ = false; |
216 }; | 217 }; |
217 | 218 |
218 LocalStorageContextMojo::LocalStorageContextMojo( | 219 LocalStorageContextMojo::LocalStorageContextMojo( |
219 service_manager::Connector* connector, | 220 service_manager::Connector* connector, |
220 scoped_refptr<DOMStorageTaskRunner> task_runner, | 221 scoped_refptr<DOMStorageTaskRunner> task_runner, |
221 const base::FilePath& old_localstorage_path, | 222 const base::FilePath& old_localstorage_path, |
222 const base::FilePath& subdirectory) | 223 const base::FilePath& subdirectory, |
223 : connector_(connector), | 224 storage::SpecialStoragePolicy* special_storage_policy) |
225 : connector_(connector ? connector->Clone() : nullptr), | |
224 subdirectory_(subdirectory), | 226 subdirectory_(subdirectory), |
227 special_storage_policy_(special_storage_policy), | |
225 task_runner_(std::move(task_runner)), | 228 task_runner_(std::move(task_runner)), |
226 old_localstorage_path_(old_localstorage_path), | 229 old_localstorage_path_(old_localstorage_path), |
227 weak_ptr_factory_(this) {} | 230 weak_ptr_factory_(this) {} |
228 | 231 |
229 LocalStorageContextMojo::~LocalStorageContextMojo() {} | |
230 | |
231 void LocalStorageContextMojo::OpenLocalStorage( | 232 void LocalStorageContextMojo::OpenLocalStorage( |
232 const url::Origin& origin, | 233 const url::Origin& origin, |
233 mojom::LevelDBWrapperRequest request) { | 234 mojom::LevelDBWrapperRequest request) { |
234 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, | 235 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::BindLocalStorage, |
235 weak_ptr_factory_.GetWeakPtr(), origin, | 236 weak_ptr_factory_.GetWeakPtr(), origin, |
236 std::move(request))); | 237 std::move(request))); |
237 } | 238 } |
238 | 239 |
239 void LocalStorageContextMojo::GetStorageUsage( | 240 void LocalStorageContextMojo::GetStorageUsage( |
240 GetStorageUsageCallback callback) { | 241 GetStorageUsageCallback callback) { |
241 RunWhenConnected( | 242 RunWhenConnected( |
242 base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage, | 243 base::BindOnce(&LocalStorageContextMojo::RetrieveStorageUsage, |
243 weak_ptr_factory_.GetWeakPtr(), std::move(callback))); | 244 weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
244 } | 245 } |
245 | 246 |
246 void LocalStorageContextMojo::DeleteStorage(const url::Origin& origin) { | 247 void LocalStorageContextMojo::DeleteStorage(const url::Origin& origin) { |
247 if (connection_state_ != CONNECTION_FINISHED) { | 248 if (connection_state_ != CONNECTION_FINISHED) { |
248 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::DeleteStorage, | 249 RunWhenConnected( |
249 weak_ptr_factory_.GetWeakPtr(), origin)); | 250 base::BindOnce(&LocalStorageContextMojo::DeleteStorage, this, origin)); |
250 return; | 251 return; |
251 } | 252 } |
252 | 253 |
253 LevelDBWrapperImpl* wrapper = GetOrCreateDBWrapper(origin); | 254 LevelDBWrapperImpl* wrapper = GetOrCreateDBWrapper(origin); |
254 // Renderer process expects |source| to always be two newline separated | 255 // Renderer process expects |source| to always be two newline separated |
255 // strings. | 256 // strings. |
256 wrapper->DeleteAll("\n", base::Bind(&NoOpSuccess)); | 257 wrapper->DeleteAll("\n", base::Bind(&NoOpSuccess)); |
257 wrapper->ScheduleImmediateCommit(); | 258 wrapper->ScheduleImmediateCommit(); |
258 } | 259 } |
259 | 260 |
260 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin( | 261 void LocalStorageContextMojo::DeleteStorageForPhysicalOrigin( |
261 const url::Origin& origin) { | 262 const url::Origin& origin) { |
262 GetStorageUsage(base::BindOnce( | 263 GetStorageUsage(base::BindOnce( |
263 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin, | 264 &LocalStorageContextMojo::OnGotStorageUsageForDeletePhysicalOrigin, this, |
264 weak_ptr_factory_.GetWeakPtr(), origin)); | 265 origin)); |
265 } | 266 } |
266 | 267 |
267 void LocalStorageContextMojo::Flush() { | 268 void LocalStorageContextMojo::Flush() { |
268 if (connection_state_ != CONNECTION_FINISHED) { | 269 if (connection_state_ != CONNECTION_FINISHED) { |
269 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Flush, | 270 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Flush, |
270 weak_ptr_factory_.GetWeakPtr())); | 271 weak_ptr_factory_.GetWeakPtr())); |
271 return; | 272 return; |
272 } | 273 } |
273 for (const auto& it : level_db_wrappers_) | 274 for (const auto& it : level_db_wrappers_) |
274 it.second->level_db_wrapper()->ScheduleImmediateCommit(); | 275 it.second->level_db_wrapper()->ScheduleImmediateCommit(); |
275 } | 276 } |
276 | 277 |
278 void LocalStorageContextMojo::Shutdown() { | |
279 DCHECK(!is_shutdown_); | |
280 DCHECK_NE(connection_state_, CONNECTION_SHUTDOWN); | |
281 | |
282 // Nothing to do if no connection to the database was ever made. | |
283 if (connection_state_ == NO_CONNECTION) { | |
284 connection_state_ = CONNECTION_SHUTDOWN; | |
285 is_shutdown_ = true; | |
286 return; | |
287 } | |
288 | |
289 if (connection_state_ != CONNECTION_FINISHED) { | |
michaeln
2017/05/03 21:01:29
Similar to the NO_CONNECTION case, maybe we don't
Marijn Kruisselbrink
2017/05/04 23:03:46
Yeah, agreed that it makes sense to just immediate
| |
290 RunWhenConnected(base::BindOnce(&LocalStorageContextMojo::Shutdown, this)); | |
291 return; | |
292 } | |
293 | |
294 connection_state_ = CONNECTION_SHUTDOWN; | |
295 | |
296 // Flush any uncommitted data. | |
297 for (const auto& it : level_db_wrappers_) | |
298 it.second->level_db_wrapper()->ScheduleImmediateCommit(); | |
299 | |
300 // Respect the content policy settings about what to | |
301 // keep and what to discard. | |
302 if (force_keep_session_state_) { | |
303 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK); | |
304 return; // Keep everything. | |
305 } | |
306 | |
307 bool has_session_only_origins = | |
308 special_storage_policy_.get() && | |
309 special_storage_policy_->HasSessionOnlyOrigins(); | |
310 | |
311 if (has_session_only_origins) { | |
312 RetrieveStorageUsage(base::BindOnce( | |
313 &LocalStorageContextMojo::OnGotStorageUsageForShutdown, this)); | |
314 } else { | |
315 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK); | |
316 } | |
317 } | |
318 | |
277 void LocalStorageContextMojo::PurgeMemory() { | 319 void LocalStorageContextMojo::PurgeMemory() { |
278 for (const auto& it : level_db_wrappers_) | 320 for (const auto& it : level_db_wrappers_) |
279 it.second->level_db_wrapper()->PurgeMemory(); | 321 it.second->level_db_wrapper()->PurgeMemory(); |
280 } | 322 } |
281 | 323 |
282 leveldb::mojom::LevelDBDatabaseAssociatedRequest | 324 leveldb::mojom::LevelDBDatabaseAssociatedRequest |
283 LocalStorageContextMojo::DatabaseRequestForTesting() { | 325 LocalStorageContextMojo::DatabaseRequestForTesting() { |
284 DCHECK_EQ(connection_state_, NO_CONNECTION); | 326 DCHECK_EQ(connection_state_, NO_CONNECTION); |
285 connection_state_ = CONNECTION_IN_PROGRESS; | 327 connection_state_ = CONNECTION_IN_PROGRESS; |
286 leveldb::mojom::LevelDBDatabaseAssociatedRequest request = | 328 leveldb::mojom::LevelDBDatabaseAssociatedRequest request = |
287 MakeIsolatedRequest(&database_); | 329 MakeIsolatedRequest(&database_); |
288 OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK); | 330 OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK); |
289 return request; | 331 return request; |
290 } | 332 } |
291 | 333 |
292 // static | 334 // static |
293 std::vector<uint8_t> LocalStorageContextMojo::MigrateString( | 335 std::vector<uint8_t> LocalStorageContextMojo::MigrateString( |
294 const base::string16& input) { | 336 const base::string16& input) { |
295 static const uint8_t kUTF16Format = 0; | 337 static const uint8_t kUTF16Format = 0; |
296 | 338 |
297 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data()); | 339 const uint8_t* data = reinterpret_cast<const uint8_t*>(input.data()); |
298 std::vector<uint8_t> result; | 340 std::vector<uint8_t> result; |
299 result.reserve(input.size() * sizeof(base::char16) + 1); | 341 result.reserve(input.size() * sizeof(base::char16) + 1); |
300 result.push_back(kUTF16Format); | 342 result.push_back(kUTF16Format); |
301 result.insert(result.end(), data, data + input.size() * sizeof(base::char16)); | 343 result.insert(result.end(), data, data + input.size() * sizeof(base::char16)); |
302 return result; | 344 return result; |
303 } | 345 } |
304 | 346 |
347 LocalStorageContextMojo::~LocalStorageContextMojo() { | |
348 DCHECK(is_shutdown_); | |
349 DCHECK_EQ(connection_state_, CONNECTION_SHUTDOWN); | |
350 } | |
351 | |
305 void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) { | 352 void LocalStorageContextMojo::RunWhenConnected(base::OnceClosure callback) { |
353 DCHECK_NE(connection_state_, CONNECTION_SHUTDOWN); | |
354 | |
306 // If we don't have a filesystem_connection_, we'll need to establish one. | 355 // If we don't have a filesystem_connection_, we'll need to establish one. |
307 if (connection_state_ == NO_CONNECTION) { | 356 if (connection_state_ == NO_CONNECTION) { |
308 connection_state_ = CONNECTION_IN_PROGRESS; | 357 connection_state_ = CONNECTION_IN_PROGRESS; |
309 InitiateConnection(); | 358 InitiateConnection(); |
310 } | 359 } |
311 | 360 |
312 if (connection_state_ == CONNECTION_IN_PROGRESS) { | 361 if (connection_state_ == CONNECTION_IN_PROGRESS) { |
313 // Queue this OpenLocalStorage call for when we have a level db pointer. | 362 // Queue this OpenLocalStorage call for when we have a level db pointer. |
314 on_database_opened_callbacks_.push_back(std::move(callback)); | 363 on_database_opened_callbacks_.push_back(std::move(callback)); |
315 return; | 364 return; |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
577 std::vector<LocalStorageUsageInfo> usage) { | 626 std::vector<LocalStorageUsageInfo> usage) { |
578 for (const auto& info : usage) { | 627 for (const auto& info : usage) { |
579 url::Origin origin_candidate(info.origin); | 628 url::Origin origin_candidate(info.origin); |
580 if (!origin_candidate.IsSameOriginWith(origin) && | 629 if (!origin_candidate.IsSameOriginWith(origin) && |
581 origin_candidate.IsSamePhysicalOriginWith(origin)) | 630 origin_candidate.IsSamePhysicalOriginWith(origin)) |
582 DeleteStorage(origin_candidate); | 631 DeleteStorage(origin_candidate); |
583 } | 632 } |
584 DeleteStorage(origin); | 633 DeleteStorage(origin); |
585 } | 634 } |
586 | 635 |
636 void LocalStorageContextMojo::OnGotStorageUsageForShutdown( | |
637 std::vector<LocalStorageUsageInfo> usage) { | |
638 std::vector<leveldb::mojom::BatchedOperationPtr> operations; | |
639 for (const auto& info : usage) { | |
640 if (special_storage_policy_->IsStorageProtected(info.origin)) | |
641 continue; | |
642 if (!special_storage_policy_->IsStorageSessionOnly(info.origin)) | |
643 continue; | |
644 | |
645 url::Origin origin(info.origin); | |
michaeln
2017/05/03 21:01:29
i see you've copied the behavior for the sqlite im
Marijn Kruisselbrink
2017/05/04 23:03:46
Not sure.. but I imagine properly accounting for s
| |
646 leveldb::mojom::BatchedOperationPtr item = | |
647 leveldb::mojom::BatchedOperation::New(); | |
648 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY; | |
649 item->key = leveldb::StdStringToUint8Vector( | |
650 kDataPrefix + origin.Serialize() + kOriginSeparator); | |
651 operations.push_back(std::move(item)); | |
652 | |
653 item = leveldb::mojom::BatchedOperation::New(); | |
654 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; | |
655 item->key = CreateMetaDataKey(origin); | |
656 operations.push_back(std::move(item)); | |
657 } | |
658 | |
659 if (!operations.empty()) { | |
660 database_->Write( | |
661 std::move(operations), | |
662 base::Bind(&LocalStorageContextMojo::OnShutdownCommitComplete, this)); | |
663 } else { | |
664 OnShutdownCommitComplete(leveldb::mojom::DatabaseError::OK); | |
665 } | |
666 } | |
667 | |
668 void LocalStorageContextMojo::OnShutdownCommitComplete( | |
669 leveldb::mojom::DatabaseError error) { | |
670 is_shutdown_ = true; | |
671 file_system_.reset(); | |
672 directory_.reset(); | |
673 leveldb_service_.reset(); | |
674 level_db_wrappers_.clear(); | |
675 database_.reset(); | |
676 connector_.reset(); | |
677 } | |
678 | |
587 } // namespace content | 679 } // namespace content |
OLD | NEW |