sqlite_persistent_cookie_store.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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 3// found in the LICENSE file. 4 5#include "content/browser/net/sqlite_persistent_cookie_store.h" 6 7#include <list> 8#include <map> 9#include <set> 10#include <utility> 11 12#include "base/basictypes.h" 13#include "base/bind.h" 14#include "base/callback.h" 15#include "base/file_util.h" 16#include "base/files/file_path.h" 17#include "base/location.h" 18#include "base/logging.h" 19#include "base/memory/ref_counted.h" 20#include "base/memory/scoped_ptr.h" 21#include "base/metrics/histogram.h" 22#include "base/sequenced_task_runner.h" 23#include "base/string_util.h" 24#include "base/stringprintf.h" 25#include "base/synchronization/lock.h" 26#include "base/threading/sequenced_worker_pool.h" 27#include "base/time.h" 28#include "content/public/browser/browser_thread.h" 29#include "content/public/browser/cookie_store_factory.h" 30#include "googleurl/src/gurl.h" 31#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 32#include "net/cookies/canonical_cookie.h" 33#include "net/cookies/cookie_constants.h" 34#include "net/cookies/cookie_util.h" 35#include "sql/error_delegate_util.h" 36#include "sql/meta_table.h" 37#include "sql/statement.h" 38#include "sql/transaction.h" 39#include "third_party/sqlite/sqlite3.h" 40#include "webkit/quota/special_storage_policy.h" 41 42using base::Time; 43 44namespace content { 45 46// This class is designed to be shared between any client thread and the 47// background task runner. It batches operations and commits them on a timer. 48// 49// SQLitePersistentCookieStore::Load is called to load all cookies. It 50// delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread 51// task to the background runner. This task calls Backend::ChainLoadCookies(), 52// which repeatedly posts itself to the BG runner to load each eTLD+1's cookies 53// in separate tasks. When this is complete, Backend::CompleteLoadOnIOThread is 54// posted to the client runner, which notifies the caller of 55// SQLitePersistentCookieStore::Load that the load is complete. 56// 57// If a priority load request is invoked via SQLitePersistentCookieStore:: 58// LoadCookiesForKey, it is delegated to Backend::LoadCookiesForKey, which posts 59// Backend::LoadKeyAndNotifyOnDBThread to the BG runner. That routine loads just 60// that single domain key (eTLD+1)'s cookies, and posts a Backend:: 61// CompleteLoadForKeyOnIOThread to the client runner to notify the caller of 62// SQLitePersistentCookieStore::LoadCookiesForKey that that load is complete. 63// 64// Subsequent to loading, mutations may be queued by any thread using 65// AddCookie, UpdateCookieAccessTime, and DeleteCookie. These are flushed to 66// disk on the BG runner every 30 seconds, 512 operations, or call to Flush(), 67// whichever occurs first. 68class SQLitePersistentCookieStore::Backend 69 : public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> { 70 public: 71 Backend( 72 const base::FilePath& path, 73 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, 74 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, 75 bool restore_old_session_cookies, 76 quota::SpecialStoragePolicy* special_storage_policy) 77 : path_(path), 78 db_(NULL), 79 num_pending_(0), 80 force_keep_session_state_(false), 81 initialized_(false), 82 corruption_detected_(false), 83 restore_old_session_cookies_(restore_old_session_cookies), 84 special_storage_policy_(special_storage_policy), 85 num_cookies_read_(0), 86 client_task_runner_(client_task_runner), 87 background_task_runner_(background_task_runner), 88 num_priority_waiting_(0), 89 total_priority_requests_(0) { 90 } 91 92 // Creates or loads the SQLite database. 93 void Load(const LoadedCallback& loaded_callback); 94 95 // Loads cookies for the domain key (eTLD+1). 96 void LoadCookiesForKey(const std::string& domain, 97 const LoadedCallback& loaded_callback); 98 99 // Batch a cookie addition. 100 void AddCookie(const net::CanonicalCookie& cc); 101 102 // Batch a cookie access time update. 103 void UpdateCookieAccessTime(const net::CanonicalCookie& cc); 104 105 // Batch a cookie deletion. 106 void DeleteCookie(const net::CanonicalCookie& cc); 107 108 // Commit pending operations as soon as possible. 109 void Flush(const base::Closure& callback); 110 111 // Commit any pending operations and close the database. This must be called 112 // before the object is destructed. 113 void Close(); 114 115 void SetForceKeepSessionState(); 116 117 private: 118 friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>; 119 120 class KillDatabaseErrorDelegate : public sql::ErrorDelegate { 121 public: 122 explicit KillDatabaseErrorDelegate(Backend* backend); 123 124 virtual ~KillDatabaseErrorDelegate() {} 125 126 // ErrorDelegate implementation. 127 virtual int OnError(int error, 128 sql::Connection* connection, 129 sql::Statement* stmt) OVERRIDE; 130 131 private: 132 // Do not increment the count on Backend, as that would create a circular 133 // reference (Backend -> Connection -> ErrorDelegate -> Backend). 134 Backend* backend_; 135 136 // True if the delegate has previously attempted to kill the database. 137 bool attempted_to_kill_database_; 138 139 DISALLOW_COPY_AND_ASSIGN(KillDatabaseErrorDelegate); 140 }; 141 142 // You should call Close() before destructing this object. 143 ~Backend() { 144 DCHECK(!db_.get()) << "Close should have already been called."; 145 DCHECK(num_pending_ == 0 && pending_.empty()); 146 } 147 148 // Database upgrade statements. 149 bool EnsureDatabaseVersion(); 150 151 class PendingOperation { 152 public: 153 typedef enum { 154 COOKIE_ADD, 155 COOKIE_UPDATEACCESS, 156 COOKIE_DELETE, 157 } OperationType; 158 159 PendingOperation(OperationType op, const net::CanonicalCookie& cc) 160 : op_(op), cc_(cc) { } 161 162 OperationType op() const { return op_; } 163 const net::CanonicalCookie& cc() const { return cc_; } 164 165 private: 166 OperationType op_; 167 net::CanonicalCookie cc_; 168 }; 169 170 private: 171 // Creates or loads the SQLite database on background runner. 172 void LoadAndNotifyInBackground(const LoadedCallback& loaded_callback, 173 const base::Time& posted_at); 174 175 // Loads cookies for the domain key (eTLD+1) on background runner. 176 void LoadKeyAndNotifyInBackground(const std::string& domains, 177 const LoadedCallback& loaded_callback, 178 const base::Time& posted_at); 179 180 // Notifies the CookieMonster when loading completes for a specific domain key 181 // or for all domain keys. Triggers the callback and passes it all cookies 182 // that have been loaded from DB since last IO notification. 183 void Notify(const LoadedCallback& loaded_callback, bool load_success); 184 185 // Sends notification when the entire store is loaded, and reports metrics 186 // for the total time to load and aggregated results from any priority loads 187 // that occurred. 188 void CompleteLoadInForeground(const LoadedCallback& loaded_callback, 189 bool load_success); 190 191 // Sends notification when a single priority load completes. Updates priority 192 // load metric data. The data is sent only after the final load completes. 193 void CompleteLoadForKeyInForeground(const LoadedCallback& loaded_callback, 194 bool load_success); 195 196 // Sends all metrics, including posting a ReportMetricsInBackground task. 197 // Called after all priority and regular loading is complete. 198 void ReportMetrics(); 199 200 // Sends background-runner owned metrics (i.e., the combined duration of all 201 // BG-runner tasks). 202 void ReportMetricsInBackground(); 203 204 // Initialize the data base. 205 bool InitializeDatabase(); 206 207 // Loads cookies for the next domain key from the DB, then either reschedules 208 // itself or schedules the provided callback to run on the client runner (if 209 // all domains are loaded). 210 void ChainLoadCookies(const LoadedCallback& loaded_callback); 211 212 // Load all cookies for a set of domains/hosts 213 bool LoadCookiesForDomains(const std::set<std::string>& key); 214 215 // Batch a cookie operation (add or delete) 216 void BatchOperation(PendingOperation::OperationType op, 217 const net::CanonicalCookie& cc); 218 // Commit our pending operations to the database. 219 void Commit(); 220 // Close() executed on the background runner. 221 void InternalBackgroundClose(); 222 223 void DeleteSessionCookiesOnStartup(); 224 225 void DeleteSessionCookiesOnShutdown(); 226 227 void KillDatabase(); 228 void ScheduleKillDatabase(); 229 230 void PostBackgroundTask(const tracked_objects::Location& origin, 231 const base::Closure& task); 232 void PostClientTask(const tracked_objects::Location& origin, 233 const base::Closure& task); 234 235 base::FilePath path_; 236 scoped_ptr<sql::Connection> db_; 237 sql::MetaTable meta_table_; 238 239 typedef std::list<PendingOperation*> PendingOperationsList; 240 PendingOperationsList pending_; 241 PendingOperationsList::size_type num_pending_; 242 // True if the persistent store should skip delete on exit rules. 243 bool force_keep_session_state_; 244 // Guard |cookies_|, |pending_|, |num_pending_|, |force_keep_session_state_| 245 base::Lock lock_; 246 247 // Temporary buffer for cookies loaded from DB. Accumulates cookies to reduce 248 // the number of messages sent to the client runner. Sent back in response to 249 // individual load requests for domain keys or when all loading completes. 250 std::vector<net::CanonicalCookie*> cookies_; 251 252 // Map of domain keys(eTLD+1) to domains/hosts that are to be loaded from DB. 253 std::map<std::string, std::set<std::string> > keys_to_load_; 254 255 // Map of (domain keys(eTLD+1), is secure cookie) to number of cookies in the 256 // database. 257 typedef std::pair<std::string, bool> CookieOrigin; 258 typedef std::map<CookieOrigin, int> CookiesPerOriginMap; 259 CookiesPerOriginMap cookies_per_origin_; 260 261 // Indicates if DB has been initialized. 262 bool initialized_; 263 264 // Indicates if the kill-database callback has been scheduled. 265 bool corruption_detected_; 266 267 // If false, we should filter out session cookies when reading the DB. 268 bool restore_old_session_cookies_; 269 270 // Policy defining what data is deleted on shutdown. 271 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; 272 273 // The cumulative time spent loading the cookies on the background runner. 274 // Incremented and reported from the background runner. 275 base::TimeDelta cookie_load_duration_; 276 277 // The total number of cookies read. Incremented and reported on the 278 // background runner. 279 int num_cookies_read_; 280 281 scoped_refptr<base::SequencedTaskRunner> client_task_runner_; 282 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 283 284 // Guards the following metrics-related properties (only accessed when 285 // starting/completing priority loads or completing the total load). 286 base::Lock metrics_lock_; 287 int num_priority_waiting_; 288 // The total number of priority requests. 289 int total_priority_requests_; 290 // The time when |num_priority_waiting_| incremented to 1. 291 base::Time current_priority_wait_start_; 292 // The cumulative duration of time when |num_priority_waiting_| was greater 293 // than 1. 294 base::TimeDelta priority_wait_duration_; 295 296 DISALLOW_COPY_AND_ASSIGN(Backend); 297}; 298 299SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate:: 300KillDatabaseErrorDelegate(Backend* backend) 301 : backend_(backend), 302 attempted_to_kill_database_(false) { 303} 304 305int SQLitePersistentCookieStore::Backend::KillDatabaseErrorDelegate::OnError( 306 int error, sql::Connection* connection, sql::Statement* stmt) { 307 // Do not attempt to kill database more than once. If the first time failed, 308 // it is unlikely that a second time will be successful. 309 if (!attempted_to_kill_database_ && sql::IsErrorCatastrophic(error)) { 310 attempted_to_kill_database_ = true; 311 312 backend_->ScheduleKillDatabase(); 313 } 314 315 return error; 316} 317 318namespace { 319 320// Version number of the database. 321// 322// Version 6 adds cookie priorities. This allows developers to influence the 323// order in which cookies are evicted in order to meet domain cookie limits. 324// 325// Version 5 adds the columns has_expires and is_persistent, so that the 326// database can store session cookies as well as persistent cookies. Databases 327// of version 5 are incompatible with older versions of code. If a database of 328// version 5 is read by older code, session cookies will be treated as normal 329// cookies. Currently, these fields are written, but not read anymore. 330// 331// In version 4, we migrated the time epoch. If you open the DB with an older 332// version on Mac or Linux, the times will look wonky, but the file will likely 333// be usable. On Windows version 3 and 4 are the same. 334// 335// Version 3 updated the database to include the last access time, so we can 336// expire them in decreasing order of use when we've reached the maximum 337// number of cookies. 338const int kCurrentVersionNumber = 6; 339const int kCompatibleVersionNumber = 5; 340 341// Possible values for the 'priority' column. 342enum DBCookiePriority { 343 kCookiePriorityLow = 0, 344 kCookiePriorityMedium = 1, 345 kCookiePriorityHigh = 2, 346}; 347 348DBCookiePriority CookiePriorityToDBCookiePriority(net::CookiePriority value) { 349 switch (value) { 350 case net::COOKIE_PRIORITY_LOW: 351 return kCookiePriorityLow; 352 case net::COOKIE_PRIORITY_MEDIUM: 353 return kCookiePriorityMedium; 354 case net::COOKIE_PRIORITY_HIGH: 355 return kCookiePriorityHigh; 356 } 357 358 NOTREACHED(); 359 return kCookiePriorityMedium; 360} 361 362net::CookiePriority DBCookiePriorityToCookiePriority(DBCookiePriority value) { 363 switch (value) { 364 case kCookiePriorityLow: 365 return net::COOKIE_PRIORITY_LOW; 366 case kCookiePriorityMedium: 367 return net::COOKIE_PRIORITY_MEDIUM; 368 case kCookiePriorityHigh: 369 return net::COOKIE_PRIORITY_HIGH; 370 } 371 372 NOTREACHED(); 373 return net::COOKIE_PRIORITY_DEFAULT; 374} 375 376// Increments a specified TimeDelta by the duration between this object's 377// constructor and destructor. Not thread safe. Multiple instances may be 378// created with the same delta instance as long as their lifetimes are nested. 379// The shortest lived instances have no impact. 380class IncrementTimeDelta { 381 public: 382 explicit IncrementTimeDelta(base::TimeDelta* delta) : 383 delta_(delta), 384 original_value_(*delta), 385 start_(base::Time::Now()) {} 386 387 ~IncrementTimeDelta() { 388 *delta_ = original_value_ + base::Time::Now() - start_; 389 } 390 391 private: 392 base::TimeDelta* delta_; 393 base::TimeDelta original_value_; 394 base::Time start_; 395 396 DISALLOW_COPY_AND_ASSIGN(IncrementTimeDelta); 397}; 398 399// Initializes the cookies table, returning true on success. 400bool InitTable(sql::Connection* db) { 401 if (!db->DoesTableExist("cookies")) { 402 std::string stmt(base::StringPrintf( 403 "CREATE TABLE cookies (" 404 "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY," 405 "host_key TEXT NOT NULL," 406 "name TEXT NOT NULL," 407 "value TEXT NOT NULL," 408 "path TEXT NOT NULL," 409 "expires_utc INTEGER NOT NULL," 410 "secure INTEGER NOT NULL," 411 "httponly INTEGER NOT NULL," 412 "last_access_utc INTEGER NOT NULL, " 413 "has_expires INTEGER NOT NULL DEFAULT 1, " 414 "persistent INTEGER NOT NULL DEFAULT 1," 415 "priority INTEGER NOT NULL DEFAULT %d)", 416 CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT))); 417 if (!db->Execute(stmt.c_str())) 418 return false; 419 } 420 421 // Older code created an index on creation_utc, which is already 422 // primary key for the table. 423 if (!db->Execute("DROP INDEX IF EXISTS cookie_times")) 424 return false; 425 426 if (!db->Execute("CREATE INDEX IF NOT EXISTS domain ON cookies(host_key)")) 427 return false; 428 429 return true; 430} 431 432} // namespace 433 434void SQLitePersistentCookieStore::Backend::Load( 435 const LoadedCallback& loaded_callback) { 436 // This function should be called only once per instance. 437 DCHECK(!db_.get()); 438 PostBackgroundTask(FROM_HERE, base::Bind( 439 &Backend::LoadAndNotifyInBackground, this, 440 loaded_callback, base::Time::Now())); 441} 442 443void SQLitePersistentCookieStore::Backend::LoadCookiesForKey( 444 const std::string& key, 445 const LoadedCallback& loaded_callback) { 446 { 447 base::AutoLock locked(metrics_lock_); 448 if (num_priority_waiting_ == 0) 449 current_priority_wait_start_ = base::Time::Now(); 450 num_priority_waiting_++; 451 total_priority_requests_++; 452 } 453 454 PostBackgroundTask(FROM_HERE, base::Bind( 455 &Backend::LoadKeyAndNotifyInBackground, 456 this, key, loaded_callback, base::Time::Now())); 457} 458 459void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground( 460 const LoadedCallback& loaded_callback, const base::Time& posted_at) { 461 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 462 IncrementTimeDelta increment(&cookie_load_duration_); 463 464 UMA_HISTOGRAM_CUSTOM_TIMES( 465 "Cookie.TimeLoadDBQueueWait", 466 base::Time::Now() - posted_at, 467 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 468 50); 469 470 if (!InitializeDatabase()) { 471 PostClientTask(FROM_HERE, base::Bind( 472 &Backend::CompleteLoadInForeground, this, loaded_callback, false)); 473 } else { 474 ChainLoadCookies(loaded_callback); 475 } 476} 477 478void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyInBackground( 479 const std::string& key, 480 const LoadedCallback& loaded_callback, 481 const base::Time& posted_at) { 482 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 483 IncrementTimeDelta increment(&cookie_load_duration_); 484 485 UMA_HISTOGRAM_CUSTOM_TIMES( 486 "Cookie.TimeKeyLoadDBQueueWait", 487 base::Time::Now() - posted_at, 488 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 489 50); 490 491 bool success = false; 492 if (InitializeDatabase()) { 493 std::map<std::string, std::set<std::string> >::iterator 494 it = keys_to_load_.find(key); 495 if (it != keys_to_load_.end()) { 496 success = LoadCookiesForDomains(it->second); 497 keys_to_load_.erase(it); 498 } else { 499 success = true; 500 } 501 } 502 503 PostClientTask(FROM_HERE, base::Bind( 504 &SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground, 505 this, loaded_callback, success)); 506} 507 508void SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground( 509 const LoadedCallback& loaded_callback, 510 bool load_success) { 511 DCHECK(client_task_runner_->RunsTasksOnCurrentThread()); 512 513 Notify(loaded_callback, load_success); 514 515 { 516 base::AutoLock locked(metrics_lock_); 517 num_priority_waiting_--; 518 if (num_priority_waiting_ == 0) { 519 priority_wait_duration_ += 520 base::Time::Now() - current_priority_wait_start_; 521 } 522 } 523 524} 525 526void SQLitePersistentCookieStore::Backend::ReportMetricsInBackground() { 527 UMA_HISTOGRAM_CUSTOM_TIMES( 528 "Cookie.TimeLoad", 529 cookie_load_duration_, 530 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 531 50); 532} 533 534void SQLitePersistentCookieStore::Backend::ReportMetrics() { 535 PostBackgroundTask(FROM_HERE, base::Bind( 536 &SQLitePersistentCookieStore::Backend::ReportMetricsInBackground, this)); 537 538 { 539 base::AutoLock locked(metrics_lock_); 540 UMA_HISTOGRAM_CUSTOM_TIMES( 541 "Cookie.PriorityBlockingTime", 542 priority_wait_duration_, 543 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 544 50); 545 546 UMA_HISTOGRAM_COUNTS_100( 547 "Cookie.PriorityLoadCount", 548 total_priority_requests_); 549 550 UMA_HISTOGRAM_COUNTS_10000( 551 "Cookie.NumberOfLoadedCookies", 552 num_cookies_read_); 553 } 554} 555 556void SQLitePersistentCookieStore::Backend::CompleteLoadInForeground( 557 const LoadedCallback& loaded_callback, bool load_success) { 558 Notify(loaded_callback, load_success); 559 560 if (load_success) 561 ReportMetrics(); 562} 563 564void SQLitePersistentCookieStore::Backend::Notify( 565 const LoadedCallback& loaded_callback, 566 bool load_success) { 567 DCHECK(client_task_runner_->RunsTasksOnCurrentThread()); 568 569 std::vector<net::CanonicalCookie*> cookies; 570 { 571 base::AutoLock locked(lock_); 572 cookies.swap(cookies_); 573 } 574 575 loaded_callback.Run(cookies); 576} 577 578bool SQLitePersistentCookieStore::Backend::InitializeDatabase() { 579 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 580 581 if (initialized_ || corruption_detected_) { 582 // Return false if we were previously initialized but the DB has since been 583 // closed, or if corruption caused a database reset during initialization. 584 return db_ != NULL; 585 } 586 587 base::Time start = base::Time::Now(); 588 589 const base::FilePath dir = path_.DirName(); 590 if (!file_util::PathExists(dir) && !file_util::CreateDirectory(dir)) { 591 return false; 592 } 593 594 int64 db_size = 0; 595 if (file_util::GetFileSize(path_, &db_size)) 596 UMA_HISTOGRAM_COUNTS("Cookie.DBSizeInKB", db_size / 1024 ); 597 598 db_.reset(new sql::Connection); 599 db_->set_error_histogram_name("Sqlite.Cookie.Error"); 600 db_->set_error_delegate(new KillDatabaseErrorDelegate(this)); 601 602 if (!db_->Open(path_)) { 603 NOTREACHED() << "Unable to open cookie DB."; 604 if (corruption_detected_) 605 db_->Raze(); 606 meta_table_.Reset(); 607 db_.reset(); 608 return false; 609 } 610 611 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 612 NOTREACHED() << "Unable to open cookie DB."; 613 if (corruption_detected_) 614 db_->Raze(); 615 meta_table_.Reset(); 616 db_.reset(); 617 return false; 618 } 619 620 UMA_HISTOGRAM_CUSTOM_TIMES( 621 "Cookie.TimeInitializeDB", 622 base::Time::Now() - start, 623 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 624 50); 625 626 start = base::Time::Now(); 627 628 // Retrieve all the domains 629 sql::Statement smt(db_->GetUniqueStatement( 630 "SELECT DISTINCT host_key FROM cookies")); 631 632 if (!smt.is_valid()) { 633 if (corruption_detected_) 634 db_->Raze(); 635 meta_table_.Reset(); 636 db_.reset(); 637 return false; 638 } 639 640 // Build a map of domain keys (always eTLD+1) to domains. 641 while (smt.Step()) { 642 std::string domain = smt.ColumnString(0); 643 std::string key = 644 net::RegistryControlledDomainService::GetDomainAndRegistry(domain); 645 646 std::map<std::string, std::set<std::string> >::iterator it = 647 keys_to_load_.find(key); 648 if (it == keys_to_load_.end()) 649 it = keys_to_load_.insert(std::make_pair 650 (key, std::set<std::string>())).first; 651 it->second.insert(domain); 652 } 653 654 UMA_HISTOGRAM_CUSTOM_TIMES( 655 "Cookie.TimeInitializeDomainMap", 656 base::Time::Now() - start, 657 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 658 50); 659 660 initialized_ = true; 661 return true; 662} 663 664void SQLitePersistentCookieStore::Backend::ChainLoadCookies( 665 const LoadedCallback& loaded_callback) { 666 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 667 IncrementTimeDelta increment(&cookie_load_duration_); 668 669 bool load_success = true; 670 671 if (!db_) { 672 // Close() has been called on this store. 673 load_success = false; 674 } else if (keys_to_load_.size() > 0) { 675 // Load cookies for the first domain key. 676 std::map<std::string, std::set<std::string> >::iterator 677 it = keys_to_load_.begin(); 678 load_success = LoadCookiesForDomains(it->second); 679 keys_to_load_.erase(it); 680 } 681 682 // If load is successful and there are more domain keys to be loaded, 683 // then post a background task to continue chain-load; 684 // Otherwise notify on client runner. 685 if (load_success && keys_to_load_.size() > 0) { 686 PostBackgroundTask(FROM_HERE, base::Bind( 687 &Backend::ChainLoadCookies, this, loaded_callback)); 688 } else { 689 PostClientTask(FROM_HERE, base::Bind( 690 &Backend::CompleteLoadInForeground, this, 691 loaded_callback, load_success)); 692 if (load_success && !restore_old_session_cookies_) 693 DeleteSessionCookiesOnStartup(); 694 } 695} 696 697bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains( 698 const std::set<std::string>& domains) { 699 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 700 701 sql::Statement smt; 702 if (restore_old_session_cookies_) { 703 smt.Assign(db_->GetCachedStatement( 704 SQL_FROM_HERE, 705 "SELECT creation_utc, host_key, name, value, path, expires_utc, " 706 "secure, httponly, last_access_utc, has_expires, persistent, priority " 707 "FROM cookies WHERE host_key = ?")); 708 } else { 709 smt.Assign(db_->GetCachedStatement( 710 SQL_FROM_HERE, 711 "SELECT creation_utc, host_key, name, value, path, expires_utc, " 712 "secure, httponly, last_access_utc, has_expires, persistent, priority " 713 "FROM cookies WHERE host_key = ? AND persistent = 1")); 714 } 715 if (!smt.is_valid()) { 716 smt.Clear(); // Disconnect smt_ref from db_. 717 meta_table_.Reset(); 718 db_.reset(); 719 return false; 720 } 721 722 std::vector<net::CanonicalCookie*> cookies; 723 std::set<std::string>::const_iterator it = domains.begin(); 724 for (; it != domains.end(); ++it) { 725 smt.BindString(0, *it); 726 while (smt.Step()) { 727 scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie( 728 // The "source" URL is not used with persisted cookies. 729 GURL(), // Source 730 smt.ColumnString(2), // name 731 smt.ColumnString(3), // value 732 smt.ColumnString(1), // domain 733 smt.ColumnString(4), // path 734 Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc 735 Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc 736 Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc 737 smt.ColumnInt(6) != 0, // secure 738 smt.ColumnInt(7) != 0, // httponly 739 DBCookiePriorityToCookiePriority( 740 static_cast<DBCookiePriority>(smt.ColumnInt(11))))); // priority 741 DLOG_IF(WARNING, 742 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; 743 cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++; 744 cookies.push_back(cc.release()); 745 ++num_cookies_read_; 746 } 747 smt.Reset(true); 748 } 749 { 750 base::AutoLock locked(lock_); 751 cookies_.insert(cookies_.end(), cookies.begin(), cookies.end()); 752 } 753 return true; 754} 755 756bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() { 757 // Version check. 758 if (!meta_table_.Init( 759 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 760 return false; 761 } 762 763 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 764 LOG(WARNING) << "Cookie database is too new."; 765 return false; 766 } 767 768 int cur_version = meta_table_.GetVersionNumber(); 769 if (cur_version == 2) { 770 sql::Transaction transaction(db_.get()); 771 if (!transaction.Begin()) 772 return false; 773 if (!db_->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc " 774 "INTEGER DEFAULT 0") || 775 !db_->Execute("UPDATE cookies SET last_access_utc = creation_utc")) { 776 LOG(WARNING) << "Unable to update cookie database to version 3."; 777 return false; 778 } 779 ++cur_version; 780 meta_table_.SetVersionNumber(cur_version); 781 meta_table_.SetCompatibleVersionNumber( 782 std::min(cur_version, kCompatibleVersionNumber)); 783 transaction.Commit(); 784 } 785 786 if (cur_version == 3) { 787 // The time epoch changed for Mac & Linux in this version to match Windows. 788 // This patch came after the main epoch change happened, so some 789 // developers have "good" times for cookies added by the more recent 790 // versions. So we have to be careful to only update times that are under 791 // the old system (which will appear to be from before 1970 in the new 792 // system). The magic number used below is 1970 in our time units. 793 sql::Transaction transaction(db_.get()); 794 transaction.Begin(); 795#if !defined(OS_WIN) 796 ignore_result(db_->Execute( 797 "UPDATE cookies " 798 "SET creation_utc = creation_utc + 11644473600000000 " 799 "WHERE rowid IN " 800 "(SELECT rowid FROM cookies WHERE " 801 "creation_utc > 0 AND creation_utc < 11644473600000000)")); 802 ignore_result(db_->Execute( 803 "UPDATE cookies " 804 "SET expires_utc = expires_utc + 11644473600000000 " 805 "WHERE rowid IN " 806 "(SELECT rowid FROM cookies WHERE " 807 "expires_utc > 0 AND expires_utc < 11644473600000000)")); 808 ignore_result(db_->Execute( 809 "UPDATE cookies " 810 "SET last_access_utc = last_access_utc + 11644473600000000 " 811 "WHERE rowid IN " 812 "(SELECT rowid FROM cookies WHERE " 813 "last_access_utc > 0 AND last_access_utc < 11644473600000000)")); 814#endif 815 ++cur_version; 816 meta_table_.SetVersionNumber(cur_version); 817 transaction.Commit(); 818 } 819 820 if (cur_version == 4) { 821 const base::TimeTicks start_time = base::TimeTicks::Now(); 822 sql::Transaction transaction(db_.get()); 823 if (!transaction.Begin()) 824 return false; 825 if (!db_->Execute("ALTER TABLE cookies " 826 "ADD COLUMN has_expires INTEGER DEFAULT 1") || 827 !db_->Execute("ALTER TABLE cookies " 828 "ADD COLUMN persistent INTEGER DEFAULT 1")) { 829 LOG(WARNING) << "Unable to update cookie database to version 5."; 830 return false; 831 } 832 ++cur_version; 833 meta_table_.SetVersionNumber(cur_version); 834 meta_table_.SetCompatibleVersionNumber( 835 std::min(cur_version, kCompatibleVersionNumber)); 836 transaction.Commit(); 837 UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV5", 838 base::TimeTicks::Now() - start_time); 839 } 840 841 if (cur_version == 5) { 842 const base::TimeTicks start_time = base::TimeTicks::Now(); 843 sql::Transaction transaction(db_.get()); 844 if (!transaction.Begin()) 845 return false; 846 // Alter the table to add the priority column with a default value. 847 std::string stmt(base::StringPrintf( 848 "ALTER TABLE cookies ADD COLUMN priority INTEGER DEFAULT %d", 849 CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT))); 850 if (!db_->Execute(stmt.c_str())) { 851 LOG(WARNING) << "Unable to update cookie database to version 6."; 852 return false; 853 } 854 ++cur_version; 855 meta_table_.SetVersionNumber(cur_version); 856 meta_table_.SetCompatibleVersionNumber( 857 std::min(cur_version, kCompatibleVersionNumber)); 858 transaction.Commit(); 859 UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV6", 860 base::TimeTicks::Now() - start_time); 861 } 862 863 // Put future migration cases here. 864 865 if (cur_version < kCurrentVersionNumber) { 866 UMA_HISTOGRAM_COUNTS_100("Cookie.CorruptMetaTable", 1); 867 868 meta_table_.Reset(); 869 db_.reset(new sql::Connection); 870 if (!file_util::Delete(path_, false) || 871 !db_->Open(path_) || 872 !meta_table_.Init( 873 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 874 UMA_HISTOGRAM_COUNTS_100("Cookie.CorruptMetaTableRecoveryFailed", 1); 875 NOTREACHED() << "Unable to reset the cookie DB."; 876 meta_table_.Reset(); 877 db_.reset(); 878 return false; 879 } 880 } 881 882 return true; 883} 884 885void SQLitePersistentCookieStore::Backend::AddCookie( 886 const net::CanonicalCookie& cc) { 887 BatchOperation(PendingOperation::COOKIE_ADD, cc); 888} 889 890void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime( 891 const net::CanonicalCookie& cc) { 892 BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc); 893} 894 895void SQLitePersistentCookieStore::Backend::DeleteCookie( 896 const net::CanonicalCookie& cc) { 897 BatchOperation(PendingOperation::COOKIE_DELETE, cc); 898} 899 900void SQLitePersistentCookieStore::Backend::BatchOperation( 901 PendingOperation::OperationType op, 902 const net::CanonicalCookie& cc) { 903 // Commit every 30 seconds. 904 static const int kCommitIntervalMs = 30 * 1000; 905 // Commit right away if we have more than 512 outstanding operations. 906 static const size_t kCommitAfterBatchSize = 512; 907 DCHECK(!background_task_runner_->RunsTasksOnCurrentThread()); 908 909 // We do a full copy of the cookie here, and hopefully just here. 910 scoped_ptr<PendingOperation> po(new PendingOperation(op, cc)); 911 912 PendingOperationsList::size_type num_pending; 913 { 914 base::AutoLock locked(lock_); 915 pending_.push_back(po.release()); 916 num_pending = ++num_pending_; 917 } 918 919 if (num_pending == 1) { 920 // We've gotten our first entry for this batch, fire off the timer. 921 if (!background_task_runner_->PostDelayedTask( 922 FROM_HERE, base::Bind(&Backend::Commit, this), 923 base::TimeDelta::FromMilliseconds(kCommitIntervalMs))) { 924 NOTREACHED() << "background_task_runner_ is not running."; 925 } 926 } else if (num_pending == kCommitAfterBatchSize) { 927 // We've reached a big enough batch, fire off a commit now. 928 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::Commit, this)); 929 } 930} 931 932void SQLitePersistentCookieStore::Backend::Commit() { 933 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 934 935 PendingOperationsList ops; 936 { 937 base::AutoLock locked(lock_); 938 pending_.swap(ops); 939 num_pending_ = 0; 940 } 941 942 // Maybe an old timer fired or we are already Close()'ed. 943 if (!db_.get() || ops.empty()) 944 return; 945 946 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, 947 "INSERT INTO cookies (creation_utc, host_key, name, value, path, " 948 "expires_utc, secure, httponly, last_access_utc, has_expires, " 949 "persistent, priority) " 950 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")); 951 if (!add_smt.is_valid()) 952 return; 953 954 sql::Statement update_access_smt(db_->GetCachedStatement(SQL_FROM_HERE, 955 "UPDATE cookies SET last_access_utc=? WHERE creation_utc=?")); 956 if (!update_access_smt.is_valid()) 957 return; 958 959 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, 960 "DELETE FROM cookies WHERE creation_utc=?")); 961 if (!del_smt.is_valid()) 962 return; 963 964 sql::Transaction transaction(db_.get()); 965 if (!transaction.Begin()) 966 return; 967 968 for (PendingOperationsList::iterator it = ops.begin(); 969 it != ops.end(); ++it) { 970 // Free the cookies as we commit them to the database. 971 scoped_ptr<PendingOperation> po(*it); 972 switch (po->op()) { 973 case PendingOperation::COOKIE_ADD: 974 cookies_per_origin_[ 975 CookieOrigin(po->cc().Domain(), po->cc().IsSecure())]++; 976 add_smt.Reset(true); 977 add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 978 add_smt.BindString(1, po->cc().Domain()); 979 add_smt.BindString(2, po->cc().Name()); 980 add_smt.BindString(3, po->cc().Value()); 981 add_smt.BindString(4, po->cc().Path()); 982 add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue()); 983 add_smt.BindInt(6, po->cc().IsSecure()); 984 add_smt.BindInt(7, po->cc().IsHttpOnly()); 985 add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue()); 986 add_smt.BindInt(9, po->cc().IsPersistent()); 987 add_smt.BindInt(10, po->cc().IsPersistent()); 988 add_smt.BindInt( 989 11, CookiePriorityToDBCookiePriority(po->cc().Priority())); 990 if (!add_smt.Run()) 991 NOTREACHED() << "Could not add a cookie to the DB."; 992 break; 993 994 case PendingOperation::COOKIE_UPDATEACCESS: 995 update_access_smt.Reset(true); 996 update_access_smt.BindInt64(0, 997 po->cc().LastAccessDate().ToInternalValue()); 998 update_access_smt.BindInt64(1, 999 po->cc().CreationDate().ToInternalValue()); 1000 if (!update_access_smt.Run()) 1001 NOTREACHED() << "Could not update cookie last access time in the DB."; 1002 break; 1003 1004 case PendingOperation::COOKIE_DELETE: 1005 cookies_per_origin_[ 1006 CookieOrigin(po->cc().Domain(), po->cc().IsSecure())]--; 1007 del_smt.Reset(true); 1008 del_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 1009 if (!del_smt.Run()) 1010 NOTREACHED() << "Could not delete a cookie from the DB."; 1011 break; 1012 1013 default: 1014 NOTREACHED(); 1015 break; 1016 } 1017 } 1018 bool succeeded = transaction.Commit(); 1019 UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults", 1020 succeeded ? 0 : 1, 2); 1021} 1022 1023void SQLitePersistentCookieStore::Backend::Flush( 1024 const base::Closure& callback) { 1025 DCHECK(!background_task_runner_->RunsTasksOnCurrentThread()); 1026 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::Commit, this)); 1027 1028 if (!callback.is_null()) { 1029 // We want the completion task to run immediately after Commit() returns. 1030 // Posting it from here means there is less chance of another task getting 1031 // onto the message queue first, than if we posted it from Commit() itself. 1032 PostBackgroundTask(FROM_HERE, callback); 1033 } 1034} 1035 1036// Fire off a close message to the background runner. We could still have a 1037// pending commit timer or Load operations holding references on us, but if/when 1038// this fires we will already have been cleaned up and it will be ignored. 1039void SQLitePersistentCookieStore::Backend::Close() { 1040 if (background_task_runner_->RunsTasksOnCurrentThread()) { 1041 InternalBackgroundClose(); 1042 } else { 1043 // Must close the backend on the background runner. 1044 PostBackgroundTask(FROM_HERE, 1045 base::Bind(&Backend::InternalBackgroundClose, this)); 1046 } 1047} 1048 1049void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { 1050 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1051 // Commit any pending operations 1052 Commit(); 1053 1054 if (!force_keep_session_state_ && special_storage_policy_.get() && 1055 special_storage_policy_->HasSessionOnlyOrigins()) { 1056 DeleteSessionCookiesOnShutdown(); 1057 } 1058 1059 meta_table_.Reset(); 1060 db_.reset(); 1061} 1062 1063void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() { 1064 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1065 1066 if (!db_) 1067 return; 1068 1069 if (!special_storage_policy_) 1070 return; 1071 1072 sql::Statement del_smt(db_->GetCachedStatement( 1073 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND secure=?")); 1074 if (!del_smt.is_valid()) { 1075 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1076 return; 1077 } 1078 1079 sql::Transaction transaction(db_.get()); 1080 if (!transaction.Begin()) { 1081 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1082 return; 1083 } 1084 1085 for (CookiesPerOriginMap::iterator it = cookies_per_origin_.begin(); 1086 it != cookies_per_origin_.end(); ++it) { 1087 if (it->second <= 0) { 1088 DCHECK_EQ(0, it->second); 1089 continue; 1090 } 1091 const GURL url(net::cookie_util::CookieOriginToURL(it->first.first, 1092 it->first.second)); 1093 if (!url.is_valid() || !special_storage_policy_->IsStorageSessionOnly(url)) 1094 continue; 1095 1096 del_smt.Reset(true); 1097 del_smt.BindString(0, it->first.first); 1098 del_smt.BindInt(1, it->first.second); 1099 if (!del_smt.Run()) 1100 NOTREACHED() << "Could not delete a cookie from the DB."; 1101 } 1102 1103 if (!transaction.Commit()) 1104 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1105} 1106 1107void SQLitePersistentCookieStore::Backend::ScheduleKillDatabase() { 1108 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1109 1110 corruption_detected_ = true; 1111 1112 // Don't just do the close/delete here, as we are being called by |db| and 1113 // that seems dangerous. 1114 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::KillDatabase, this)); 1115} 1116 1117void SQLitePersistentCookieStore::Backend::KillDatabase() { 1118 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1119 1120 if (db_) { 1121 // This Backend will now be in-memory only. In a future run we will recreate 1122 // the database. Hopefully things go better then! 1123 bool success = db_->RazeAndClose(); 1124 UMA_HISTOGRAM_BOOLEAN("Cookie.KillDatabaseResult", success); 1125 meta_table_.Reset(); 1126 db_.reset(); 1127 } 1128} 1129 1130void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() { 1131 base::AutoLock locked(lock_); 1132 force_keep_session_state_ = true; 1133} 1134 1135void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { 1136 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1137 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0")) 1138 LOG(WARNING) << "Unable to delete session cookies."; 1139} 1140 1141void SQLitePersistentCookieStore::Backend::PostBackgroundTask( 1142 const tracked_objects::Location& origin, const base::Closure& task) { 1143 if (!background_task_runner_->PostTask(origin, task)) { 1144 LOG(WARNING) << "Failed to post task from " << origin.ToString() 1145 << " to background_task_runner_."; 1146 } 1147} 1148 1149void SQLitePersistentCookieStore::Backend::PostClientTask( 1150 const tracked_objects::Location& origin, const base::Closure& task) { 1151 if (!client_task_runner_->PostTask(origin, task)) { 1152 LOG(WARNING) << "Failed to post task from " << origin.ToString() 1153 << " to client_task_runner_."; 1154 } 1155} 1156 1157SQLitePersistentCookieStore::SQLitePersistentCookieStore( 1158 const base::FilePath& path, 1159 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, 1160 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, 1161 bool restore_old_session_cookies, 1162 quota::SpecialStoragePolicy* special_storage_policy) 1163 : backend_(new Backend(path, 1164 client_task_runner, 1165 background_task_runner, 1166 restore_old_session_cookies, 1167 special_storage_policy)) { 1168} 1169 1170void SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) { 1171 backend_->Load(loaded_callback); 1172} 1173 1174void SQLitePersistentCookieStore::LoadCookiesForKey( 1175 const std::string& key, 1176 const LoadedCallback& loaded_callback) { 1177 backend_->LoadCookiesForKey(key, loaded_callback); 1178} 1179 1180void SQLitePersistentCookieStore::AddCookie(const net::CanonicalCookie& cc) { 1181 backend_->AddCookie(cc); 1182} 1183 1184void SQLitePersistentCookieStore::UpdateCookieAccessTime( 1185 const net::CanonicalCookie& cc) { 1186 backend_->UpdateCookieAccessTime(cc); 1187} 1188 1189void SQLitePersistentCookieStore::DeleteCookie(const net::CanonicalCookie& cc) { 1190 backend_->DeleteCookie(cc); 1191} 1192 1193void SQLitePersistentCookieStore::SetForceKeepSessionState() { 1194 backend_->SetForceKeepSessionState(); 1195} 1196 1197void SQLitePersistentCookieStore::Flush(const base::Closure& callback) { 1198 backend_->Flush(callback); 1199} 1200 1201SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 1202 backend_->Close(); 1203 // We release our reference to the Backend, though it will probably still have 1204 // a reference if the background runner has not run Close() yet. 1205} 1206 1207net::CookieStore* CreatePersistentCookieStore( 1208 const base::FilePath& path, 1209 bool restore_old_session_cookies, 1210 quota::SpecialStoragePolicy* storage_policy, 1211 net::CookieMonster::Delegate* cookie_monster_delegate) { 1212 SQLitePersistentCookieStore* persistent_store = 1213 new SQLitePersistentCookieStore( 1214 path, 1215 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), 1216 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner( 1217 BrowserThread::GetBlockingPool()->GetSequenceToken()), 1218 restore_old_session_cookies, 1219 storage_policy); 1220 return new net::CookieMonster(persistent_store, cookie_monster_delegate); 1221} 1222 1223} // namespace content 1224