 Chromium Code Reviews
 Chromium Code Reviews Issue 2861473002:
  Clear up session only storage on localstorage shutdown  (Closed)
    
  
    Issue 2861473002:
  Clear up session only storage on localstorage shutdown  (Closed) 
  | 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 |