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