sqlite_persistent_cookie_store.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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::registry_controlled_domains::GetDomainAndRegistry( 645 domain, 646 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); 647 648 std::map<std::string, std::set<std::string> >::iterator it = 649 keys_to_load_.find(key); 650 if (it == keys_to_load_.end()) 651 it = keys_to_load_.insert(std::make_pair 652 (key, std::set<std::string>())).first; 653 it->second.insert(domain); 654 } 655 656 UMA_HISTOGRAM_CUSTOM_TIMES( 657 "Cookie.TimeInitializeDomainMap", 658 base::Time::Now() - start, 659 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 660 50); 661 662 initialized_ = true; 663 return true; 664} 665 666void SQLitePersistentCookieStore::Backend::ChainLoadCookies( 667 const LoadedCallback& loaded_callback) { 668 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 669 IncrementTimeDelta increment(&cookie_load_duration_); 670 671 bool load_success = true; 672 673 if (!db_) { 674 // Close() has been called on this store. 675 load_success = false; 676 } else if (keys_to_load_.size() > 0) { 677 // Load cookies for the first domain key. 678 std::map<std::string, std::set<std::string> >::iterator 679 it = keys_to_load_.begin(); 680 load_success = LoadCookiesForDomains(it->second); 681 keys_to_load_.erase(it); 682 } 683 684 // If load is successful and there are more domain keys to be loaded, 685 // then post a background task to continue chain-load; 686 // Otherwise notify on client runner. 687 if (load_success && keys_to_load_.size() > 0) { 688 PostBackgroundTask(FROM_HERE, base::Bind( 689 &Backend::ChainLoadCookies, this, loaded_callback)); 690 } else { 691 PostClientTask(FROM_HERE, base::Bind( 692 &Backend::CompleteLoadInForeground, this, 693 loaded_callback, load_success)); 694 if (load_success && !restore_old_session_cookies_) 695 DeleteSessionCookiesOnStartup(); 696 } 697} 698 699bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains( 700 const std::set<std::string>& domains) { 701 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 702 703 sql::Statement smt; 704 if (restore_old_session_cookies_) { 705 smt.Assign(db_->GetCachedStatement( 706 SQL_FROM_HERE, 707 "SELECT creation_utc, host_key, name, value, path, expires_utc, " 708 "secure, httponly, last_access_utc, has_expires, persistent, priority " 709 "FROM cookies WHERE host_key = ?")); 710 } else { 711 smt.Assign(db_->GetCachedStatement( 712 SQL_FROM_HERE, 713 "SELECT creation_utc, host_key, name, value, path, expires_utc, " 714 "secure, httponly, last_access_utc, has_expires, persistent, priority " 715 "FROM cookies WHERE host_key = ? AND persistent = 1")); 716 } 717 if (!smt.is_valid()) { 718 smt.Clear(); // Disconnect smt_ref from db_. 719 meta_table_.Reset(); 720 db_.reset(); 721 return false; 722 } 723 724 std::vector<net::CanonicalCookie*> cookies; 725 std::set<std::string>::const_iterator it = domains.begin(); 726 for (; it != domains.end(); ++it) { 727 smt.BindString(0, *it); 728 while (smt.Step()) { 729 scoped_ptr<net::CanonicalCookie> cc(new net::CanonicalCookie( 730 // The "source" URL is not used with persisted cookies. 731 GURL(), // Source 732 smt.ColumnString(2), // name 733 smt.ColumnString(3), // value 734 smt.ColumnString(1), // domain 735 smt.ColumnString(4), // path 736 Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc 737 Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc 738 Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc 739 smt.ColumnInt(6) != 0, // secure 740 smt.ColumnInt(7) != 0, // httponly 741 DBCookiePriorityToCookiePriority( 742 static_cast<DBCookiePriority>(smt.ColumnInt(11))))); // priority 743 DLOG_IF(WARNING, 744 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; 745 cookies_per_origin_[CookieOrigin(cc->Domain(), cc->IsSecure())]++; 746 cookies.push_back(cc.release()); 747 ++num_cookies_read_; 748 } 749 smt.Reset(true); 750 } 751 { 752 base::AutoLock locked(lock_); 753 cookies_.insert(cookies_.end(), cookies.begin(), cookies.end()); 754 } 755 return true; 756} 757 758bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() { 759 // Version check. 760 if (!meta_table_.Init( 761 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 762 return false; 763 } 764 765 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 766 LOG(WARNING) << "Cookie database is too new."; 767 return false; 768 } 769 770 int cur_version = meta_table_.GetVersionNumber(); 771 if (cur_version == 2) { 772 sql::Transaction transaction(db_.get()); 773 if (!transaction.Begin()) 774 return false; 775 if (!db_->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc " 776 "INTEGER DEFAULT 0") || 777 !db_->Execute("UPDATE cookies SET last_access_utc = creation_utc")) { 778 LOG(WARNING) << "Unable to update cookie database to version 3."; 779 return false; 780 } 781 ++cur_version; 782 meta_table_.SetVersionNumber(cur_version); 783 meta_table_.SetCompatibleVersionNumber( 784 std::min(cur_version, kCompatibleVersionNumber)); 785 transaction.Commit(); 786 } 787 788 if (cur_version == 3) { 789 // The time epoch changed for Mac & Linux in this version to match Windows. 790 // This patch came after the main epoch change happened, so some 791 // developers have "good" times for cookies added by the more recent 792 // versions. So we have to be careful to only update times that are under 793 // the old system (which will appear to be from before 1970 in the new 794 // system). The magic number used below is 1970 in our time units. 795 sql::Transaction transaction(db_.get()); 796 transaction.Begin(); 797#if !defined(OS_WIN) 798 ignore_result(db_->Execute( 799 "UPDATE cookies " 800 "SET creation_utc = creation_utc + 11644473600000000 " 801 "WHERE rowid IN " 802 "(SELECT rowid FROM cookies WHERE " 803 "creation_utc > 0 AND creation_utc < 11644473600000000)")); 804 ignore_result(db_->Execute( 805 "UPDATE cookies " 806 "SET expires_utc = expires_utc + 11644473600000000 " 807 "WHERE rowid IN " 808 "(SELECT rowid FROM cookies WHERE " 809 "expires_utc > 0 AND expires_utc < 11644473600000000)")); 810 ignore_result(db_->Execute( 811 "UPDATE cookies " 812 "SET last_access_utc = last_access_utc + 11644473600000000 " 813 "WHERE rowid IN " 814 "(SELECT rowid FROM cookies WHERE " 815 "last_access_utc > 0 AND last_access_utc < 11644473600000000)")); 816#endif 817 ++cur_version; 818 meta_table_.SetVersionNumber(cur_version); 819 transaction.Commit(); 820 } 821 822 if (cur_version == 4) { 823 const base::TimeTicks start_time = base::TimeTicks::Now(); 824 sql::Transaction transaction(db_.get()); 825 if (!transaction.Begin()) 826 return false; 827 if (!db_->Execute("ALTER TABLE cookies " 828 "ADD COLUMN has_expires INTEGER DEFAULT 1") || 829 !db_->Execute("ALTER TABLE cookies " 830 "ADD COLUMN persistent INTEGER DEFAULT 1")) { 831 LOG(WARNING) << "Unable to update cookie database to version 5."; 832 return false; 833 } 834 ++cur_version; 835 meta_table_.SetVersionNumber(cur_version); 836 meta_table_.SetCompatibleVersionNumber( 837 std::min(cur_version, kCompatibleVersionNumber)); 838 transaction.Commit(); 839 UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV5", 840 base::TimeTicks::Now() - start_time); 841 } 842 843 if (cur_version == 5) { 844 const base::TimeTicks start_time = base::TimeTicks::Now(); 845 sql::Transaction transaction(db_.get()); 846 if (!transaction.Begin()) 847 return false; 848 // Alter the table to add the priority column with a default value. 849 std::string stmt(base::StringPrintf( 850 "ALTER TABLE cookies ADD COLUMN priority INTEGER DEFAULT %d", 851 CookiePriorityToDBCookiePriority(net::COOKIE_PRIORITY_DEFAULT))); 852 if (!db_->Execute(stmt.c_str())) { 853 LOG(WARNING) << "Unable to update cookie database to version 6."; 854 return false; 855 } 856 ++cur_version; 857 meta_table_.SetVersionNumber(cur_version); 858 meta_table_.SetCompatibleVersionNumber( 859 std::min(cur_version, kCompatibleVersionNumber)); 860 transaction.Commit(); 861 UMA_HISTOGRAM_TIMES("Cookie.TimeDatabaseMigrationToV6", 862 base::TimeTicks::Now() - start_time); 863 } 864 865 // Put future migration cases here. 866 867 if (cur_version < kCurrentVersionNumber) { 868 UMA_HISTOGRAM_COUNTS_100("Cookie.CorruptMetaTable", 1); 869 870 meta_table_.Reset(); 871 db_.reset(new sql::Connection); 872 if (!file_util::Delete(path_, false) || 873 !db_->Open(path_) || 874 !meta_table_.Init( 875 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 876 UMA_HISTOGRAM_COUNTS_100("Cookie.CorruptMetaTableRecoveryFailed", 1); 877 NOTREACHED() << "Unable to reset the cookie DB."; 878 meta_table_.Reset(); 879 db_.reset(); 880 return false; 881 } 882 } 883 884 return true; 885} 886 887void SQLitePersistentCookieStore::Backend::AddCookie( 888 const net::CanonicalCookie& cc) { 889 BatchOperation(PendingOperation::COOKIE_ADD, cc); 890} 891 892void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime( 893 const net::CanonicalCookie& cc) { 894 BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc); 895} 896 897void SQLitePersistentCookieStore::Backend::DeleteCookie( 898 const net::CanonicalCookie& cc) { 899 BatchOperation(PendingOperation::COOKIE_DELETE, cc); 900} 901 902void SQLitePersistentCookieStore::Backend::BatchOperation( 903 PendingOperation::OperationType op, 904 const net::CanonicalCookie& cc) { 905 // Commit every 30 seconds. 906 static const int kCommitIntervalMs = 30 * 1000; 907 // Commit right away if we have more than 512 outstanding operations. 908 static const size_t kCommitAfterBatchSize = 512; 909 DCHECK(!background_task_runner_->RunsTasksOnCurrentThread()); 910 911 // We do a full copy of the cookie here, and hopefully just here. 912 scoped_ptr<PendingOperation> po(new PendingOperation(op, cc)); 913 914 PendingOperationsList::size_type num_pending; 915 { 916 base::AutoLock locked(lock_); 917 pending_.push_back(po.release()); 918 num_pending = ++num_pending_; 919 } 920 921 if (num_pending == 1) { 922 // We've gotten our first entry for this batch, fire off the timer. 923 if (!background_task_runner_->PostDelayedTask( 924 FROM_HERE, base::Bind(&Backend::Commit, this), 925 base::TimeDelta::FromMilliseconds(kCommitIntervalMs))) { 926 NOTREACHED() << "background_task_runner_ is not running."; 927 } 928 } else if (num_pending == kCommitAfterBatchSize) { 929 // We've reached a big enough batch, fire off a commit now. 930 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::Commit, this)); 931 } 932} 933 934void SQLitePersistentCookieStore::Backend::Commit() { 935 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 936 937 PendingOperationsList ops; 938 { 939 base::AutoLock locked(lock_); 940 pending_.swap(ops); 941 num_pending_ = 0; 942 } 943 944 // Maybe an old timer fired or we are already Close()'ed. 945 if (!db_.get() || ops.empty()) 946 return; 947 948 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, 949 "INSERT INTO cookies (creation_utc, host_key, name, value, path, " 950 "expires_utc, secure, httponly, last_access_utc, has_expires, " 951 "persistent, priority) " 952 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")); 953 if (!add_smt.is_valid()) 954 return; 955 956 sql::Statement update_access_smt(db_->GetCachedStatement(SQL_FROM_HERE, 957 "UPDATE cookies SET last_access_utc=? WHERE creation_utc=?")); 958 if (!update_access_smt.is_valid()) 959 return; 960 961 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, 962 "DELETE FROM cookies WHERE creation_utc=?")); 963 if (!del_smt.is_valid()) 964 return; 965 966 sql::Transaction transaction(db_.get()); 967 if (!transaction.Begin()) 968 return; 969 970 for (PendingOperationsList::iterator it = ops.begin(); 971 it != ops.end(); ++it) { 972 // Free the cookies as we commit them to the database. 973 scoped_ptr<PendingOperation> po(*it); 974 switch (po->op()) { 975 case PendingOperation::COOKIE_ADD: 976 cookies_per_origin_[ 977 CookieOrigin(po->cc().Domain(), po->cc().IsSecure())]++; 978 add_smt.Reset(true); 979 add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 980 add_smt.BindString(1, po->cc().Domain()); 981 add_smt.BindString(2, po->cc().Name()); 982 add_smt.BindString(3, po->cc().Value()); 983 add_smt.BindString(4, po->cc().Path()); 984 add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue()); 985 add_smt.BindInt(6, po->cc().IsSecure()); 986 add_smt.BindInt(7, po->cc().IsHttpOnly()); 987 add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue()); 988 add_smt.BindInt(9, po->cc().IsPersistent()); 989 add_smt.BindInt(10, po->cc().IsPersistent()); 990 add_smt.BindInt( 991 11, CookiePriorityToDBCookiePriority(po->cc().Priority())); 992 if (!add_smt.Run()) 993 NOTREACHED() << "Could not add a cookie to the DB."; 994 break; 995 996 case PendingOperation::COOKIE_UPDATEACCESS: 997 update_access_smt.Reset(true); 998 update_access_smt.BindInt64(0, 999 po->cc().LastAccessDate().ToInternalValue()); 1000 update_access_smt.BindInt64(1, 1001 po->cc().CreationDate().ToInternalValue()); 1002 if (!update_access_smt.Run()) 1003 NOTREACHED() << "Could not update cookie last access time in the DB."; 1004 break; 1005 1006 case PendingOperation::COOKIE_DELETE: 1007 cookies_per_origin_[ 1008 CookieOrigin(po->cc().Domain(), po->cc().IsSecure())]--; 1009 del_smt.Reset(true); 1010 del_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 1011 if (!del_smt.Run()) 1012 NOTREACHED() << "Could not delete a cookie from the DB."; 1013 break; 1014 1015 default: 1016 NOTREACHED(); 1017 break; 1018 } 1019 } 1020 bool succeeded = transaction.Commit(); 1021 UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults", 1022 succeeded ? 0 : 1, 2); 1023} 1024 1025void SQLitePersistentCookieStore::Backend::Flush( 1026 const base::Closure& callback) { 1027 DCHECK(!background_task_runner_->RunsTasksOnCurrentThread()); 1028 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::Commit, this)); 1029 1030 if (!callback.is_null()) { 1031 // We want the completion task to run immediately after Commit() returns. 1032 // Posting it from here means there is less chance of another task getting 1033 // onto the message queue first, than if we posted it from Commit() itself. 1034 PostBackgroundTask(FROM_HERE, callback); 1035 } 1036} 1037 1038// Fire off a close message to the background runner. We could still have a 1039// pending commit timer or Load operations holding references on us, but if/when 1040// this fires we will already have been cleaned up and it will be ignored. 1041void SQLitePersistentCookieStore::Backend::Close() { 1042 if (background_task_runner_->RunsTasksOnCurrentThread()) { 1043 InternalBackgroundClose(); 1044 } else { 1045 // Must close the backend on the background runner. 1046 PostBackgroundTask(FROM_HERE, 1047 base::Bind(&Backend::InternalBackgroundClose, this)); 1048 } 1049} 1050 1051void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { 1052 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1053 // Commit any pending operations 1054 Commit(); 1055 1056 if (!force_keep_session_state_ && special_storage_policy_.get() && 1057 special_storage_policy_->HasSessionOnlyOrigins()) { 1058 DeleteSessionCookiesOnShutdown(); 1059 } 1060 1061 meta_table_.Reset(); 1062 db_.reset(); 1063} 1064 1065void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnShutdown() { 1066 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1067 1068 if (!db_) 1069 return; 1070 1071 if (!special_storage_policy_) 1072 return; 1073 1074 sql::Statement del_smt(db_->GetCachedStatement( 1075 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND secure=?")); 1076 if (!del_smt.is_valid()) { 1077 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1078 return; 1079 } 1080 1081 sql::Transaction transaction(db_.get()); 1082 if (!transaction.Begin()) { 1083 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1084 return; 1085 } 1086 1087 for (CookiesPerOriginMap::iterator it = cookies_per_origin_.begin(); 1088 it != cookies_per_origin_.end(); ++it) { 1089 if (it->second <= 0) { 1090 DCHECK_EQ(0, it->second); 1091 continue; 1092 } 1093 const GURL url(net::cookie_util::CookieOriginToURL(it->first.first, 1094 it->first.second)); 1095 if (!url.is_valid() || !special_storage_policy_->IsStorageSessionOnly(url)) 1096 continue; 1097 1098 del_smt.Reset(true); 1099 del_smt.BindString(0, it->first.first); 1100 del_smt.BindInt(1, it->first.second); 1101 if (!del_smt.Run()) 1102 NOTREACHED() << "Could not delete a cookie from the DB."; 1103 } 1104 1105 if (!transaction.Commit()) 1106 LOG(WARNING) << "Unable to delete cookies on shutdown."; 1107} 1108 1109void SQLitePersistentCookieStore::Backend::ScheduleKillDatabase() { 1110 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1111 1112 corruption_detected_ = true; 1113 1114 // Don't just do the close/delete here, as we are being called by |db| and 1115 // that seems dangerous. 1116 PostBackgroundTask(FROM_HERE, base::Bind(&Backend::KillDatabase, this)); 1117} 1118 1119void SQLitePersistentCookieStore::Backend::KillDatabase() { 1120 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1121 1122 if (db_) { 1123 // This Backend will now be in-memory only. In a future run we will recreate 1124 // the database. Hopefully things go better then! 1125 bool success = db_->RazeAndClose(); 1126 UMA_HISTOGRAM_BOOLEAN("Cookie.KillDatabaseResult", success); 1127 meta_table_.Reset(); 1128 db_.reset(); 1129 } 1130} 1131 1132void SQLitePersistentCookieStore::Backend::SetForceKeepSessionState() { 1133 base::AutoLock locked(lock_); 1134 force_keep_session_state_ = true; 1135} 1136 1137void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() { 1138 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 1139 if (!db_->Execute("DELETE FROM cookies WHERE persistent == 0")) 1140 LOG(WARNING) << "Unable to delete session cookies."; 1141} 1142 1143void SQLitePersistentCookieStore::Backend::PostBackgroundTask( 1144 const tracked_objects::Location& origin, const base::Closure& task) { 1145 if (!background_task_runner_->PostTask(origin, task)) { 1146 LOG(WARNING) << "Failed to post task from " << origin.ToString() 1147 << " to background_task_runner_."; 1148 } 1149} 1150 1151void SQLitePersistentCookieStore::Backend::PostClientTask( 1152 const tracked_objects::Location& origin, const base::Closure& task) { 1153 if (!client_task_runner_->PostTask(origin, task)) { 1154 LOG(WARNING) << "Failed to post task from " << origin.ToString() 1155 << " to client_task_runner_."; 1156 } 1157} 1158 1159SQLitePersistentCookieStore::SQLitePersistentCookieStore( 1160 const base::FilePath& path, 1161 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner, 1162 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, 1163 bool restore_old_session_cookies, 1164 quota::SpecialStoragePolicy* special_storage_policy) 1165 : backend_(new Backend(path, 1166 client_task_runner, 1167 background_task_runner, 1168 restore_old_session_cookies, 1169 special_storage_policy)) { 1170} 1171 1172void SQLitePersistentCookieStore::Load(const LoadedCallback& loaded_callback) { 1173 backend_->Load(loaded_callback); 1174} 1175 1176void SQLitePersistentCookieStore::LoadCookiesForKey( 1177 const std::string& key, 1178 const LoadedCallback& loaded_callback) { 1179 backend_->LoadCookiesForKey(key, loaded_callback); 1180} 1181 1182void SQLitePersistentCookieStore::AddCookie(const net::CanonicalCookie& cc) { 1183 backend_->AddCookie(cc); 1184} 1185 1186void SQLitePersistentCookieStore::UpdateCookieAccessTime( 1187 const net::CanonicalCookie& cc) { 1188 backend_->UpdateCookieAccessTime(cc); 1189} 1190 1191void SQLitePersistentCookieStore::DeleteCookie(const net::CanonicalCookie& cc) { 1192 backend_->DeleteCookie(cc); 1193} 1194 1195void SQLitePersistentCookieStore::SetForceKeepSessionState() { 1196 backend_->SetForceKeepSessionState(); 1197} 1198 1199void SQLitePersistentCookieStore::Flush(const base::Closure& callback) { 1200 backend_->Flush(callback); 1201} 1202 1203SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 1204 backend_->Close(); 1205 // We release our reference to the Backend, though it will probably still have 1206 // a reference if the background runner has not run Close() yet. 1207} 1208 1209net::CookieStore* CreatePersistentCookieStore( 1210 const base::FilePath& path, 1211 bool restore_old_session_cookies, 1212 quota::SpecialStoragePolicy* storage_policy, 1213 net::CookieMonster::Delegate* cookie_monster_delegate) { 1214 SQLitePersistentCookieStore* persistent_store = 1215 new SQLitePersistentCookieStore( 1216 path, 1217 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), 1218 BrowserThread::GetBlockingPool()->GetSequencedTaskRunner( 1219 BrowserThread::GetBlockingPool()->GetSequenceToken()), 1220 restore_old_session_cookies, 1221 storage_policy); 1222 return new net::CookieMonster(persistent_store, cookie_monster_delegate); 1223} 1224 1225} // namespace content 1226