| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "webkit/database/database_tracker.h" | 5 #include "webkit/database/database_tracker.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 13 #include "base/message_loop_proxy.h" | 13 #include "base/message_loop_proxy.h" |
| 14 #include "base/platform_file.h" | 14 #include "base/platform_file.h" |
| 15 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
| 16 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
| 17 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" |
| 18 #include "sql/connection.h" | 18 #include "sql/connection.h" |
| 19 #include "sql/meta_table.h" | 19 #include "sql/meta_table.h" |
| 20 #include "sql/transaction.h" | 20 #include "sql/transaction.h" |
| 21 #include "third_party/sqlite/sqlite3.h" | 21 #include "third_party/sqlite/sqlite3.h" |
| 22 #include "webkit/database/database_quota_client.h" | 22 #include "webkit/database/database_quota_client.h" |
| 23 #include "webkit/database/database_util.h" | 23 #include "webkit/database/database_util.h" |
| 24 #include "webkit/database/databases_table.h" | 24 #include "webkit/database/databases_table.h" |
| 25 #include "webkit/quota/quota_manager.h" | 25 #include "webkit/quota/quota_manager.h" |
| 26 #include "webkit/quota/special_storage_policy.h" | 26 #include "webkit/quota/special_storage_policy.h" |
| 27 | 27 |
| 28 namespace webkit_database { | 28 namespace webkit_database { |
| 29 | 29 |
| 30 const FilePath::CharType kDatabaseDirectoryName[] = | 30 const base::FilePath::CharType kDatabaseDirectoryName[] = |
| 31 FILE_PATH_LITERAL("databases"); | 31 FILE_PATH_LITERAL("databases"); |
| 32 const FilePath::CharType kIncognitoDatabaseDirectoryName[] = | 32 const base::FilePath::CharType kIncognitoDatabaseDirectoryName[] = |
| 33 FILE_PATH_LITERAL("databases-incognito"); | 33 FILE_PATH_LITERAL("databases-incognito"); |
| 34 const FilePath::CharType kTrackerDatabaseFileName[] = | 34 const base::FilePath::CharType kTrackerDatabaseFileName[] = |
| 35 FILE_PATH_LITERAL("Databases.db"); | 35 FILE_PATH_LITERAL("Databases.db"); |
| 36 static const int kCurrentVersion = 2; | 36 static const int kCurrentVersion = 2; |
| 37 static const int kCompatibleVersion = 1; | 37 static const int kCompatibleVersion = 1; |
| 38 | 38 |
| 39 const FilePath::CharType kTemporaryDirectoryPrefix[] = | 39 const base::FilePath::CharType kTemporaryDirectoryPrefix[] = |
| 40 FILE_PATH_LITERAL("DeleteMe"); | 40 FILE_PATH_LITERAL("DeleteMe"); |
| 41 const FilePath::CharType kTemporaryDirectoryPattern[] = | 41 const base::FilePath::CharType kTemporaryDirectoryPattern[] = |
| 42 FILE_PATH_LITERAL("DeleteMe*"); | 42 FILE_PATH_LITERAL("DeleteMe*"); |
| 43 | 43 |
| 44 OriginInfo::OriginInfo() | 44 OriginInfo::OriginInfo() |
| 45 : total_size_(0) {} | 45 : total_size_(0) {} |
| 46 | 46 |
| 47 OriginInfo::OriginInfo(const OriginInfo& origin_info) | 47 OriginInfo::OriginInfo(const OriginInfo& origin_info) |
| 48 : origin_(origin_info.origin_), | 48 : origin_(origin_info.origin_), |
| 49 total_size_(origin_info.total_size_), | 49 total_size_(origin_info.total_size_), |
| 50 database_info_(origin_info.database_info_) {} | 50 database_info_(origin_info.database_info_) {} |
| 51 | 51 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 70 DatabaseInfoMap::const_iterator it = database_info_.find(database_name); | 70 DatabaseInfoMap::const_iterator it = database_info_.find(database_name); |
| 71 if (it != database_info_.end()) | 71 if (it != database_info_.end()) |
| 72 return it->second.second; | 72 return it->second.second; |
| 73 return string16(); | 73 return string16(); |
| 74 } | 74 } |
| 75 | 75 |
| 76 OriginInfo::OriginInfo(const string16& origin, int64 total_size) | 76 OriginInfo::OriginInfo(const string16& origin, int64 total_size) |
| 77 : origin_(origin), total_size_(total_size) {} | 77 : origin_(origin), total_size_(total_size) {} |
| 78 | 78 |
| 79 DatabaseTracker::DatabaseTracker( | 79 DatabaseTracker::DatabaseTracker( |
| 80 const FilePath& profile_path, | 80 const base::FilePath& profile_path, |
| 81 bool is_incognito, | 81 bool is_incognito, |
| 82 quota::SpecialStoragePolicy* special_storage_policy, | 82 quota::SpecialStoragePolicy* special_storage_policy, |
| 83 quota::QuotaManagerProxy* quota_manager_proxy, | 83 quota::QuotaManagerProxy* quota_manager_proxy, |
| 84 base::MessageLoopProxy* db_tracker_thread) | 84 base::MessageLoopProxy* db_tracker_thread) |
| 85 : is_initialized_(false), | 85 : is_initialized_(false), |
| 86 is_incognito_(is_incognito), | 86 is_incognito_(is_incognito), |
| 87 force_keep_session_state_(false), | 87 force_keep_session_state_(false), |
| 88 shutting_down_(false), | 88 shutting_down_(false), |
| 89 profile_path_(profile_path), | 89 profile_path_(profile_path), |
| 90 db_dir_(is_incognito_ ? | 90 db_dir_(is_incognito_ ? |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 incognito_origin_directories_.find(origin_identifier); | 273 incognito_origin_directories_.find(origin_identifier); |
| 274 if (it != incognito_origin_directories_.end()) | 274 if (it != incognito_origin_directories_.end()) |
| 275 return it->second; | 275 return it->second; |
| 276 | 276 |
| 277 string16 origin_directory = | 277 string16 origin_directory = |
| 278 base::IntToString16(incognito_origin_directories_generator_++); | 278 base::IntToString16(incognito_origin_directories_generator_++); |
| 279 incognito_origin_directories_[origin_identifier] = origin_directory; | 279 incognito_origin_directories_[origin_identifier] = origin_directory; |
| 280 return origin_directory; | 280 return origin_directory; |
| 281 } | 281 } |
| 282 | 282 |
| 283 FilePath DatabaseTracker::GetFullDBFilePath( | 283 base::FilePath DatabaseTracker::GetFullDBFilePath( |
| 284 const string16& origin_identifier, | 284 const string16& origin_identifier, |
| 285 const string16& database_name) { | 285 const string16& database_name) { |
| 286 DCHECK(!origin_identifier.empty()); | 286 DCHECK(!origin_identifier.empty()); |
| 287 if (!LazyInit()) | 287 if (!LazyInit()) |
| 288 return FilePath(); | 288 return base::FilePath(); |
| 289 | 289 |
| 290 int64 id = databases_table_->GetDatabaseID( | 290 int64 id = databases_table_->GetDatabaseID( |
| 291 origin_identifier, database_name); | 291 origin_identifier, database_name); |
| 292 if (id < 0) | 292 if (id < 0) |
| 293 return FilePath(); | 293 return base::FilePath(); |
| 294 | 294 |
| 295 FilePath file_name = FilePath::FromWStringHack( | 295 base::FilePath file_name = base::FilePath::FromWStringHack( |
| 296 UTF8ToWide(base::Int64ToString(id))); | 296 UTF8ToWide(base::Int64ToString(id))); |
| 297 return db_dir_.Append(FilePath::FromWStringHack( | 297 return db_dir_.Append(base::FilePath::FromWStringHack( |
| 298 UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name); | 298 UTF16ToWide(GetOriginDirectory(origin_identifier)))).Append(file_name); |
| 299 } | 299 } |
| 300 | 300 |
| 301 bool DatabaseTracker::GetOriginInfo(const string16& origin_identifier, | 301 bool DatabaseTracker::GetOriginInfo(const string16& origin_identifier, |
| 302 OriginInfo* info) { | 302 OriginInfo* info) { |
| 303 DCHECK(info); | 303 DCHECK(info); |
| 304 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier); | 304 CachedOriginInfo* cached_info = GetCachedOriginInfo(origin_identifier); |
| 305 if (!cached_info) | 305 if (!cached_info) |
| 306 return false; | 306 return false; |
| 307 *info = OriginInfo(*cached_info); | 307 *info = OriginInfo(*cached_info); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 return false; | 345 return false; |
| 346 | 346 |
| 347 // Check if the database is opened by any renderer. | 347 // Check if the database is opened by any renderer. |
| 348 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) | 348 if (database_connections_.IsDatabaseOpened(origin_identifier, database_name)) |
| 349 return false; | 349 return false; |
| 350 | 350 |
| 351 int64 db_file_size = quota_manager_proxy_ ? | 351 int64 db_file_size = quota_manager_proxy_ ? |
| 352 GetDBFileSize(origin_identifier, database_name) : 0; | 352 GetDBFileSize(origin_identifier, database_name) : 0; |
| 353 | 353 |
| 354 // Try to delete the file on the hard drive. | 354 // Try to delete the file on the hard drive. |
| 355 FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); | 355 base::FilePath db_file = GetFullDBFilePath(origin_identifier, database_name); |
| 356 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) | 356 if (file_util::PathExists(db_file) && !file_util::Delete(db_file, false)) |
| 357 return false; | 357 return false; |
| 358 | 358 |
| 359 // Also delete any orphaned journal file. | 359 // Also delete any orphaned journal file. |
| 360 DCHECK(db_file.Extension().empty()); | 360 DCHECK(db_file.Extension().empty()); |
| 361 file_util::Delete(db_file.InsertBeforeExtensionASCII( | 361 file_util::Delete(db_file.InsertBeforeExtensionASCII( |
| 362 DatabaseUtil::kJournalFileSuffix), false); | 362 DatabaseUtil::kJournalFileSuffix), false); |
| 363 | 363 |
| 364 if (quota_manager_proxy_ && db_file_size) | 364 if (quota_manager_proxy_ && db_file_size) |
| 365 quota_manager_proxy_->NotifyStorageModified( | 365 quota_manager_proxy_->NotifyStorageModified( |
| (...skipping 25 matching lines...) Expand all Loading... |
| 391 return false; | 391 return false; |
| 392 | 392 |
| 393 int64 deleted_size = 0; | 393 int64 deleted_size = 0; |
| 394 if (quota_manager_proxy_) { | 394 if (quota_manager_proxy_) { |
| 395 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); | 395 CachedOriginInfo* origin_info = GetCachedOriginInfo(origin_identifier); |
| 396 if (origin_info) | 396 if (origin_info) |
| 397 deleted_size = origin_info->TotalSize(); | 397 deleted_size = origin_info->TotalSize(); |
| 398 } | 398 } |
| 399 | 399 |
| 400 origins_info_map_.erase(origin_identifier); | 400 origins_info_map_.erase(origin_identifier); |
| 401 FilePath origin_dir = db_dir_.Append(FilePath::FromWStringHack( | 401 base::FilePath origin_dir = db_dir_.Append(base::FilePath::FromWStringHack( |
| 402 UTF16ToWide(origin_identifier))); | 402 UTF16ToWide(origin_identifier))); |
| 403 | 403 |
| 404 // Create a temporary directory to move possibly still existing databases to, | 404 // Create a temporary directory to move possibly still existing databases to, |
| 405 // as we can't delete the origin directory on windows if it contains opened | 405 // as we can't delete the origin directory on windows if it contains opened |
| 406 // files. | 406 // files. |
| 407 FilePath new_origin_dir; | 407 base::FilePath new_origin_dir; |
| 408 file_util::CreateTemporaryDirInDir(db_dir_, | 408 file_util::CreateTemporaryDirInDir(db_dir_, |
| 409 kTemporaryDirectoryPrefix, | 409 kTemporaryDirectoryPrefix, |
| 410 &new_origin_dir); | 410 &new_origin_dir); |
| 411 file_util::FileEnumerator databases( | 411 file_util::FileEnumerator databases( |
| 412 origin_dir, | 412 origin_dir, |
| 413 false, | 413 false, |
| 414 file_util::FileEnumerator::FILES); | 414 file_util::FileEnumerator::FILES); |
| 415 for (FilePath database = databases.Next(); !database.empty(); | 415 for (base::FilePath database = databases.Next(); !database.empty(); |
| 416 database = databases.Next()) { | 416 database = databases.Next()) { |
| 417 FilePath new_file = new_origin_dir.Append(database.BaseName()); | 417 base::FilePath new_file = new_origin_dir.Append(database.BaseName()); |
| 418 file_util::Move(database, new_file); | 418 file_util::Move(database, new_file); |
| 419 } | 419 } |
| 420 file_util::Delete(origin_dir, true); | 420 file_util::Delete(origin_dir, true); |
| 421 file_util::Delete(new_origin_dir, true); // might fail on windows. | 421 file_util::Delete(new_origin_dir, true); // might fail on windows. |
| 422 | 422 |
| 423 databases_table_->DeleteOrigin(origin_identifier); | 423 databases_table_->DeleteOrigin(origin_identifier); |
| 424 | 424 |
| 425 if (quota_manager_proxy_ && deleted_size) { | 425 if (quota_manager_proxy_ && deleted_size) { |
| 426 quota_manager_proxy_->NotifyStorageModified( | 426 quota_manager_proxy_->NotifyStorageModified( |
| 427 quota::QuotaClient::kDatabase, | 427 quota::QuotaClient::kDatabase, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 451 DCHECK(!meta_table_.get()); | 451 DCHECK(!meta_table_.get()); |
| 452 | 452 |
| 453 // If there are left-over directories from failed deletion attempts, clean | 453 // If there are left-over directories from failed deletion attempts, clean |
| 454 // them up. | 454 // them up. |
| 455 if (file_util::DirectoryExists(db_dir_)) { | 455 if (file_util::DirectoryExists(db_dir_)) { |
| 456 file_util::FileEnumerator directories( | 456 file_util::FileEnumerator directories( |
| 457 db_dir_, | 457 db_dir_, |
| 458 false, | 458 false, |
| 459 file_util::FileEnumerator::DIRECTORIES, | 459 file_util::FileEnumerator::DIRECTORIES, |
| 460 kTemporaryDirectoryPattern); | 460 kTemporaryDirectoryPattern); |
| 461 for (FilePath directory = directories.Next(); !directory.empty(); | 461 for (base::FilePath directory = directories.Next(); !directory.empty(); |
| 462 directory = directories.Next()) { | 462 directory = directories.Next()) { |
| 463 file_util::Delete(directory, true); | 463 file_util::Delete(directory, true); |
| 464 } | 464 } |
| 465 } | 465 } |
| 466 | 466 |
| 467 // If the tracker database exists, but it's corrupt or doesn't | 467 // If the tracker database exists, but it's corrupt or doesn't |
| 468 // have a meta table, delete the database directory. | 468 // have a meta table, delete the database directory. |
| 469 const FilePath kTrackerDatabaseFullPath = | 469 const base::FilePath kTrackerDatabaseFullPath = |
| 470 db_dir_.Append(FilePath(kTrackerDatabaseFileName)); | 470 db_dir_.Append(base::FilePath(kTrackerDatabaseFileName)); |
| 471 if (file_util::DirectoryExists(db_dir_) && | 471 if (file_util::DirectoryExists(db_dir_) && |
| 472 file_util::PathExists(kTrackerDatabaseFullPath) && | 472 file_util::PathExists(kTrackerDatabaseFullPath) && |
| 473 (!db_->Open(kTrackerDatabaseFullPath) || | 473 (!db_->Open(kTrackerDatabaseFullPath) || |
| 474 !sql::MetaTable::DoesTableExist(db_.get()))) { | 474 !sql::MetaTable::DoesTableExist(db_.get()))) { |
| 475 db_->Close(); | 475 db_->Close(); |
| 476 if (!file_util::Delete(db_dir_, true)) | 476 if (!file_util::Delete(db_dir_, true)) |
| 477 return false; | 477 return false; |
| 478 } | 478 } |
| 479 | 479 |
| 480 db_->set_error_histogram_name("Sqlite.DatabaseTracker.Error"); | 480 db_->set_error_histogram_name("Sqlite.DatabaseTracker.Error"); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 origin_info.SetDatabaseSize(it->database_name, db_file_size); | 567 origin_info.SetDatabaseSize(it->database_name, db_file_size); |
| 568 origin_info.SetDatabaseDescription(it->database_name, it->description); | 568 origin_info.SetDatabaseDescription(it->database_name, it->description); |
| 569 } | 569 } |
| 570 } | 570 } |
| 571 | 571 |
| 572 return &origins_info_map_[origin_identifier]; | 572 return &origins_info_map_[origin_identifier]; |
| 573 } | 573 } |
| 574 | 574 |
| 575 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, | 575 int64 DatabaseTracker::GetDBFileSize(const string16& origin_identifier, |
| 576 const string16& database_name) { | 576 const string16& database_name) { |
| 577 FilePath db_file_name = GetFullDBFilePath(origin_identifier, database_name); | 577 base::FilePath db_file_name = GetFullDBFilePath(origin_identifier, |
| 578 database_name); |
| 578 int64 db_file_size = 0; | 579 int64 db_file_size = 0; |
| 579 if (!file_util::GetFileSize(db_file_name, &db_file_size)) | 580 if (!file_util::GetFileSize(db_file_name, &db_file_size)) |
| 580 db_file_size = 0; | 581 db_file_size = 0; |
| 581 return db_file_size; | 582 return db_file_size; |
| 582 } | 583 } |
| 583 | 584 |
| 584 int64 DatabaseTracker::SeedOpenDatabaseInfo( | 585 int64 DatabaseTracker::SeedOpenDatabaseInfo( |
| 585 const string16& origin_id, const string16& name, | 586 const string16& origin_id, const string16& name, |
| 586 const string16& description) { | 587 const string16& description) { |
| 587 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name)); | 588 DCHECK(database_connections_.IsDatabaseOpened(origin_id, name)); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 special_storage_policy_->IsStorageProtected( | 684 special_storage_policy_->IsStorageProtected( |
| 684 DatabaseUtil::GetOriginFromIdentifier(*ori))) { | 685 DatabaseUtil::GetOriginFromIdentifier(*ori))) { |
| 685 continue; | 686 continue; |
| 686 } | 687 } |
| 687 | 688 |
| 688 std::vector<DatabaseDetails> details; | 689 std::vector<DatabaseDetails> details; |
| 689 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details)) | 690 if (!databases_table_->GetAllDatabaseDetailsForOrigin(*ori, &details)) |
| 690 rv = net::ERR_FAILED; | 691 rv = net::ERR_FAILED; |
| 691 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); | 692 for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); |
| 692 db != details.end(); ++db) { | 693 db != details.end(); ++db) { |
| 693 FilePath db_file = GetFullDBFilePath(*ori, db->database_name); | 694 base::FilePath db_file = GetFullDBFilePath(*ori, db->database_name); |
| 694 base::PlatformFileInfo file_info; | 695 base::PlatformFileInfo file_info; |
| 695 file_util::GetFileInfo(db_file, &file_info); | 696 file_util::GetFileInfo(db_file, &file_info); |
| 696 if (file_info.last_modified < cutoff) | 697 if (file_info.last_modified < cutoff) |
| 697 continue; | 698 continue; |
| 698 | 699 |
| 699 // Check if the database is opened by any renderer. | 700 // Check if the database is opened by any renderer. |
| 700 if (database_connections_.IsDatabaseOpened(*ori, db->database_name)) | 701 if (database_connections_.IsDatabaseOpened(*ori, db->database_name)) |
| 701 to_be_deleted[*ori].insert(db->database_name); | 702 to_be_deleted[*ori].insert(db->database_name); |
| 702 else | 703 else |
| 703 DeleteClosedDatabase(*ori, db->database_name); | 704 DeleteClosedDatabase(*ori, db->database_name); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 } | 783 } |
| 783 | 784 |
| 784 void DatabaseTracker::DeleteIncognitoDBDirectory() { | 785 void DatabaseTracker::DeleteIncognitoDBDirectory() { |
| 785 shutting_down_ = true; | 786 shutting_down_ = true; |
| 786 is_initialized_ = false; | 787 is_initialized_ = false; |
| 787 | 788 |
| 788 for (FileHandlesMap::iterator it = incognito_file_handles_.begin(); | 789 for (FileHandlesMap::iterator it = incognito_file_handles_.begin(); |
| 789 it != incognito_file_handles_.end(); it++) | 790 it != incognito_file_handles_.end(); it++) |
| 790 base::ClosePlatformFile(it->second); | 791 base::ClosePlatformFile(it->second); |
| 791 | 792 |
| 792 FilePath incognito_db_dir = | 793 base::FilePath incognito_db_dir = |
| 793 profile_path_.Append(kIncognitoDatabaseDirectoryName); | 794 profile_path_.Append(kIncognitoDatabaseDirectoryName); |
| 794 if (file_util::DirectoryExists(incognito_db_dir)) | 795 if (file_util::DirectoryExists(incognito_db_dir)) |
| 795 file_util::Delete(incognito_db_dir, true); | 796 file_util::Delete(incognito_db_dir, true); |
| 796 } | 797 } |
| 797 | 798 |
| 798 void DatabaseTracker::ClearSessionOnlyOrigins() { | 799 void DatabaseTracker::ClearSessionOnlyOrigins() { |
| 799 shutting_down_ = true; | 800 shutting_down_ = true; |
| 800 | 801 |
| 801 bool has_session_only_databases = | 802 bool has_session_only_databases = |
| 802 special_storage_policy_.get() && | 803 special_storage_policy_.get() && |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 if (!db_tracker_thread_->BelongsToCurrentThread()) { | 860 if (!db_tracker_thread_->BelongsToCurrentThread()) { |
| 860 db_tracker_thread_->PostTask( | 861 db_tracker_thread_->PostTask( |
| 861 FROM_HERE, | 862 FROM_HERE, |
| 862 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this)); | 863 base::Bind(&DatabaseTracker::SetForceKeepSessionState, this)); |
| 863 return; | 864 return; |
| 864 } | 865 } |
| 865 force_keep_session_state_ = true; | 866 force_keep_session_state_ = true; |
| 866 } | 867 } |
| 867 | 868 |
| 868 } // namespace webkit_database | 869 } // namespace webkit_database |
| OLD | NEW |