1 // Copyright (c) 2011 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 "chrome/browser/net/sqlite_persistent_cookie_store.h" 6 7 #include <list> 8 9 #include "app/sql/meta_table.h" 10 #include "app/sql/statement.h" 11 #include "app/sql/transaction.h" 12 #include "base/basictypes.h" 13 #include "base/file_path.h" 14 #include "base/file_util.h" 15 #ifdef ANDROID 16 #include "base/lazy_instance.h" 17 #endif 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/string_util.h" 23 #include "base/threading/thread.h" 24 #include "base/threading/thread_restrictions.h" 25 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" 26 #ifndef ANDROID 27 #include "content/browser/browser_thread.h" 28 #endif 29 #include "googleurl/src/gurl.h" 30 31 #ifdef ANDROID 32 namespace { 33 34 class DbThread : public base::Thread { 35 public: 36 DbThread() : base::Thread("android-db") { 37 bool started = Start(); 38 CHECK(started); 39 } 40 }; 41 42 // This class is used by CookieMonster, which is threadsafe, so this class must 43 // be threadsafe too. 44 base::LazyInstance<DbThread> g_db_thread(base::LINKER_INITIALIZED); 45 46 } // namespace 47 #endif 48 49 using base::Time; 50 51 // This class is designed to be shared between any calling threads and the 52 // database thread. It batches operations and commits them on a timer. 53 class SQLitePersistentCookieStore::Backend 54 : public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> { 55 public: 56 explicit Backend(const FilePath& path) 57 : path_(path), 58 db_(NULL), 59 num_pending_(0), 60 clear_local_state_on_exit_(false) 61 #if defined(ANDROID) 62 , cookie_count_(0) 63 #endif 64 { 65 } 66 67 // Creates or load the SQLite database. 68 bool Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies); 69 70 // Batch a cookie addition. 71 void AddCookie(const net::CookieMonster::CanonicalCookie& cc); 72 73 // Batch a cookie access time update. 74 void UpdateCookieAccessTime(const net::CookieMonster::CanonicalCookie& cc); 75 76 // Batch a cookie deletion. 77 void DeleteCookie(const net::CookieMonster::CanonicalCookie& cc); 78 79 // Commit pending operations as soon as possible. 80 void Flush(Task* completion_task); 81 82 // Commit any pending operations and close the database. This must be called 83 // before the object is destructed. 84 void Close(); 85 86 void SetClearLocalStateOnExit(bool clear_local_state); 87 88 #if defined(ANDROID) 89 int get_cookie_count() const { return cookie_count_; } 90 void set_cookie_count(int count) { cookie_count_ = count; } 91 #endif 92 93 private: 94 friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>; 95 96 // You should call Close() before destructing this object. 97 ~Backend() { 98 DCHECK(!db_.get()) << "Close should have already been called."; 99 DCHECK(num_pending_ == 0 && pending_.empty()); 100 } 101 102 // Database upgrade statements. 103 bool EnsureDatabaseVersion(); 104 105 class PendingOperation { 106 public: 107 typedef enum { 108 COOKIE_ADD, 109 COOKIE_UPDATEACCESS, 110 COOKIE_DELETE, 111 } OperationType; 112 113 PendingOperation(OperationType op, 114 const net::CookieMonster::CanonicalCookie& cc) 115 : op_(op), cc_(cc) { } 116 117 OperationType op() const { return op_; } 118 const net::CookieMonster::CanonicalCookie& cc() const { return cc_; } 119 120 private: 121 OperationType op_; 122 net::CookieMonster::CanonicalCookie cc_; 123 }; 124 125 private: 126 // Batch a cookie operation (add or delete) 127 void BatchOperation(PendingOperation::OperationType op, 128 const net::CookieMonster::CanonicalCookie& cc); 129 // Commit our pending operations to the database. 130 #if defined(ANDROID) 131 void Commit(Task* completion_task); 132 #else 133 void Commit(); 134 #endif 135 // Close() executed on the background thread. 136 void InternalBackgroundClose(); 137 138 FilePath path_; 139 scoped_ptr<sql::Connection> db_; 140 sql::MetaTable meta_table_; 141 142 typedef std::list<PendingOperation*> PendingOperationsList; 143 PendingOperationsList pending_; 144 PendingOperationsList::size_type num_pending_; 145 // True if the persistent store should be deleted upon destruction. 146 bool clear_local_state_on_exit_; 147 // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|. 148 base::Lock lock_; 149 150 #if defined(ANDROID) 151 // Number of cookies that have actually been saved. Updated during Commit(). 152 volatile int cookie_count_; 153 #endif 154 155 DISALLOW_COPY_AND_ASSIGN(Backend); 156 }; 157 158 // Version number of the database. In version 4, we migrated the time epoch. 159 // If you open the DB with an older version on Mac or Linux, the times will 160 // look wonky, but the file will likely be usable. On Windows version 3 and 4 161 // are the same. 162 // 163 // Version 3 updated the database to include the last access time, so we can 164 // expire them in decreasing order of use when we've reached the maximum 165 // number of cookies. 166 static const int kCurrentVersionNumber = 4; 167 static const int kCompatibleVersionNumber = 3; 168 169 namespace { 170 171 // Initializes the cookies table, returning true on success. 172 bool InitTable(sql::Connection* db) { 173 if (!db->DoesTableExist("cookies")) { 174 if (!db->Execute("CREATE TABLE cookies (" 175 "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY," 176 "host_key TEXT NOT NULL," 177 "name TEXT NOT NULL," 178 "value TEXT NOT NULL," 179 "path TEXT NOT NULL," 180 #if defined(ANDROID) 181 // On some mobile platforms, we persist session cookies 182 // because the OS can kill the browser during a session. 183 // If so, expires_utc is set to 0. When the field is read 184 // into a Time object, Time::is_null() will return true. 185 #else 186 // We only store persistent, so we know it expires 187 #endif 188 "expires_utc INTEGER NOT NULL," 189 "secure INTEGER NOT NULL," 190 "httponly INTEGER NOT NULL," 191 "last_access_utc INTEGER NOT NULL)")) 192 return false; 193 } 194 195 // Try to create the index every time. Older versions did not have this index, 196 // so we want those people to get it. Ignore errors, since it may exist. 197 db->Execute( 198 "CREATE INDEX IF NOT EXISTS cookie_times ON cookies (creation_utc)"); 199 return true; 200 } 201 202 } // namespace 203 204 bool SQLitePersistentCookieStore::Backend::Load( 205 std::vector<net::CookieMonster::CanonicalCookie*>* cookies) { 206 // This function should be called only once per instance. 207 DCHECK(!db_.get()); 208 209 // Ensure the parent directory for storing cookies is created before reading 210 // from it. We make an exception to allow IO on the UI thread here because 211 // we are going to disk anyway in db_->Open. (This code will be moved to the 212 // DB thread as part of http://crbug.com/52909.) 213 { 214 base::ThreadRestrictions::ScopedAllowIO allow_io; 215 const FilePath dir = path_.DirName(); 216 if (!file_util::PathExists(dir) && !file_util::CreateDirectory(dir)) 217 return false; 218 } 219 220 db_.reset(new sql::Connection); 221 if (!db_->Open(path_)) { 222 NOTREACHED() << "Unable to open cookie DB."; 223 db_.reset(); 224 return false; 225 } 226 227 #ifndef ANDROID 228 // GetErrorHandlerForCookieDb is defined in sqlite_diagnostics.h 229 // which we do not currently include on Android 230 db_->set_error_delegate(GetErrorHandlerForCookieDb()); 231 #endif 232 233 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 234 NOTREACHED() << "Unable to open cookie DB."; 235 db_.reset(); 236 return false; 237 } 238 239 db_->Preload(); 240 241 // Slurp all the cookies into the out-vector. 242 sql::Statement smt(db_->GetUniqueStatement( 243 "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, " 244 "httponly, last_access_utc FROM cookies")); 245 if (!smt) { 246 NOTREACHED() << "select statement prep failed"; 247 db_.reset(); 248 return false; 249 } 250 251 while (smt.Step()) { 252 #if defined(ANDROID) 253 base::Time expires = Time::FromInternalValue(smt.ColumnInt64(5)); 254 #endif 255 scoped_ptr<net::CookieMonster::CanonicalCookie> cc( 256 new net::CookieMonster::CanonicalCookie( 257 // The "source" URL is not used with persisted cookies. 258 GURL(), // Source 259 smt.ColumnString(2), // name 260 smt.ColumnString(3), // value 261 smt.ColumnString(1), // domain 262 smt.ColumnString(4), // path 263 Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc 264 Time::FromInternalValue(smt.ColumnInt64(5)), // expires_utc 265 Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc 266 smt.ColumnInt(6) != 0, // secure 267 smt.ColumnInt(7) != 0, // httponly 268 #if defined(ANDROID) 269 !expires.is_null())); // has_expires 270 #else 271 true)); // has_expires 272 #endif 273 DLOG_IF(WARNING, 274 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; 275 cookies->push_back(cc.release()); 276 } 277 278 #ifdef ANDROID 279 set_cookie_count(cookies->size()); 280 #endif 281 282 return true; 283 } 284 285 bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() { 286 // Version check. 287 if (!meta_table_.Init( 288 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 289 return false; 290 } 291 292 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 293 LOG(WARNING) << "Cookie database is too new."; 294 return false; 295 } 296 297 int cur_version = meta_table_.GetVersionNumber(); 298 if (cur_version == 2) { 299 sql::Transaction transaction(db_.get()); 300 if (!transaction.Begin()) 301 return false; 302 if (!db_->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc " 303 "INTEGER DEFAULT 0") || 304 !db_->Execute("UPDATE cookies SET last_access_utc = creation_utc")) { 305 LOG(WARNING) << "Unable to update cookie database to version 3."; 306 return false; 307 } 308 ++cur_version; 309 meta_table_.SetVersionNumber(cur_version); 310 meta_table_.SetCompatibleVersionNumber( 311 std::min(cur_version, kCompatibleVersionNumber)); 312 transaction.Commit(); 313 } 314 315 if (cur_version == 3) { 316 // The time epoch changed for Mac & Linux in this version to match Windows. 317 // This patch came after the main epoch change happened, so some 318 // developers have "good" times for cookies added by the more recent 319 // versions. So we have to be careful to only update times that are under 320 // the old system (which will appear to be from before 1970 in the new 321 // system). The magic number used below is 1970 in our time units. 322 sql::Transaction transaction(db_.get()); 323 transaction.Begin(); 324 #if !defined(OS_WIN) 325 db_->Execute( 326 "UPDATE cookies " 327 "SET creation_utc = creation_utc + 11644473600000000 " 328 "WHERE rowid IN " 329 "(SELECT rowid FROM cookies WHERE " 330 "creation_utc > 0 AND creation_utc < 11644473600000000)"); 331 db_->Execute( 332 "UPDATE cookies " 333 "SET expires_utc = expires_utc + 11644473600000000 " 334 "WHERE rowid IN " 335 "(SELECT rowid FROM cookies WHERE " 336 "expires_utc > 0 AND expires_utc < 11644473600000000)"); 337 db_->Execute( 338 "UPDATE cookies " 339 "SET last_access_utc = last_access_utc + 11644473600000000 " 340 "WHERE rowid IN " 341 "(SELECT rowid FROM cookies WHERE " 342 "last_access_utc > 0 AND last_access_utc < 11644473600000000)"); 343 #endif 344 ++cur_version; 345 meta_table_.SetVersionNumber(cur_version); 346 transaction.Commit(); 347 } 348 349 // Put future migration cases here. 350 351 // When the version is too old, we just try to continue anyway, there should 352 // not be a released product that makes a database too old for us to handle. 353 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << 354 "Cookie database version " << cur_version << " is too old to handle."; 355 356 return true; 357 } 358 359 void SQLitePersistentCookieStore::Backend::AddCookie( 360 const net::CookieMonster::CanonicalCookie& cc) { 361 BatchOperation(PendingOperation::COOKIE_ADD, cc); 362 } 363 364 void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime( 365 const net::CookieMonster::CanonicalCookie& cc) { 366 BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc); 367 } 368 369 void SQLitePersistentCookieStore::Backend::DeleteCookie( 370 const net::CookieMonster::CanonicalCookie& cc) { 371 BatchOperation(PendingOperation::COOKIE_DELETE, cc); 372 } 373 374 void SQLitePersistentCookieStore::Backend::BatchOperation( 375 PendingOperation::OperationType op, 376 const net::CookieMonster::CanonicalCookie& cc) { 377 // Commit every 30 seconds. 378 static const int kCommitIntervalMs = 30 * 1000; 379 // Commit right away if we have more than 512 outstanding operations. 380 static const size_t kCommitAfterBatchSize = 512; 381 #ifndef ANDROID 382 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 383 #endif 384 385 // We do a full copy of the cookie here, and hopefully just here. 386 scoped_ptr<PendingOperation> po(new PendingOperation(op, cc)); 387 388 PendingOperationsList::size_type num_pending; 389 { 390 base::AutoLock locked(lock_); 391 pending_.push_back(po.release()); 392 num_pending = ++num_pending_; 393 } 394 395 #ifdef ANDROID 396 MessageLoop* loop = g_db_thread.Get().message_loop(); 397 #endif 398 399 if (num_pending == 1) { 400 // We've gotten our first entry for this batch, fire off the timer. 401 #ifdef ANDROID 402 loop->PostDelayedTask(FROM_HERE, NewRunnableMethod( 403 this, &Backend::Commit, static_cast<Task*>(NULL)), kCommitIntervalMs); 404 #else 405 BrowserThread::PostDelayedTask( 406 BrowserThread::DB, FROM_HERE, 407 NewRunnableMethod(this, &Backend::Commit), kCommitIntervalMs); 408 #endif 409 } else if (num_pending == kCommitAfterBatchSize) { 410 // We've reached a big enough batch, fire off a commit now. 411 #ifdef ANDROID 412 loop->PostTask(FROM_HERE, NewRunnableMethod( 413 this, &Backend::Commit, static_cast<Task*>(NULL))); 414 #else 415 BrowserThread::PostTask( 416 BrowserThread::DB, FROM_HERE, 417 NewRunnableMethod(this, &Backend::Commit)); 418 #endif 419 } 420 } 421 422 #if defined(ANDROID) 423 void SQLitePersistentCookieStore::Backend::Commit(Task* completion_task) { 424 #else 425 void SQLitePersistentCookieStore::Backend::Commit() { 426 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 427 #endif 428 429 #if defined(ANDROID) 430 if (completion_task) { 431 // We post this task to the current thread, so it won't run until we exit. 432 MessageLoop::current()->PostTask(FROM_HERE, completion_task); 433 } 434 #endif 435 436 PendingOperationsList ops; 437 { 438 base::AutoLock locked(lock_); 439 pending_.swap(ops); 440 num_pending_ = 0; 441 } 442 443 // Maybe an old timer fired or we are already Close()'ed. 444 if (!db_.get() || ops.empty()) 445 return; 446 447 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, 448 "INSERT INTO cookies (creation_utc, host_key, name, value, path, " 449 "expires_utc, secure, httponly, last_access_utc) " 450 "VALUES (?,?,?,?,?,?,?,?,?)")); 451 if (!add_smt) { 452 NOTREACHED(); 453 return; 454 } 455 456 sql::Statement update_access_smt(db_->GetCachedStatement(SQL_FROM_HERE, 457 "UPDATE cookies SET last_access_utc=? WHERE creation_utc=?")); 458 if (!update_access_smt) { 459 NOTREACHED(); 460 return; 461 } 462 463 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, 464 "DELETE FROM cookies WHERE creation_utc=?")); 465 if (!del_smt) { 466 NOTREACHED(); 467 return; 468 } 469 470 sql::Transaction transaction(db_.get()); 471 if (!transaction.Begin()) { 472 NOTREACHED(); 473 return; 474 } 475 #if defined(ANDROID) 476 int cookie_delta = 0; 477 #endif 478 for (PendingOperationsList::iterator it = ops.begin(); 479 it != ops.end(); ++it) { 480 // Free the cookies as we commit them to the database. 481 scoped_ptr<PendingOperation> po(*it); 482 switch (po->op()) { 483 case PendingOperation::COOKIE_ADD: 484 #if defined(ANDROID) 485 ++cookie_delta; 486 #endif 487 add_smt.Reset(); 488 add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 489 add_smt.BindString(1, po->cc().Domain()); 490 add_smt.BindString(2, po->cc().Name()); 491 add_smt.BindString(3, po->cc().Value()); 492 add_smt.BindString(4, po->cc().Path()); 493 add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue()); 494 add_smt.BindInt(6, po->cc().IsSecure()); 495 add_smt.BindInt(7, po->cc().IsHttpOnly()); 496 add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue()); 497 if (!add_smt.Run()) 498 NOTREACHED() << "Could not add a cookie to the DB."; 499 break; 500 501 case PendingOperation::COOKIE_UPDATEACCESS: 502 update_access_smt.Reset(); 503 update_access_smt.BindInt64(0, 504 po->cc().LastAccessDate().ToInternalValue()); 505 update_access_smt.BindInt64(1, 506 po->cc().CreationDate().ToInternalValue()); 507 if (!update_access_smt.Run()) 508 NOTREACHED() << "Could not update cookie last access time in the DB."; 509 break; 510 511 case PendingOperation::COOKIE_DELETE: 512 #if defined(ANDROID) 513 --cookie_delta; 514 #endif 515 del_smt.Reset(); 516 del_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 517 if (!del_smt.Run()) 518 NOTREACHED() << "Could not delete a cookie from the DB."; 519 break; 520 521 default: 522 NOTREACHED(); 523 break; 524 } 525 } 526 bool succeeded = transaction.Commit(); 527 #if defined(ANDROID) 528 if (succeeded) 529 cookie_count_ += cookie_delta; 530 #endif 531 UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults", 532 succeeded ? 0 : 1, 2); 533 } 534 535 void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) { 536 #if defined(ANDROID) 537 MessageLoop* loop = g_db_thread.Get().message_loop(); 538 loop->PostTask(FROM_HERE, NewRunnableMethod( 539 this, &Backend::Commit, completion_task)); 540 #else 541 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 542 BrowserThread::PostTask( 543 BrowserThread::DB, FROM_HERE, NewRunnableMethod(this, &Backend::Commit)); 544 if (completion_task) { 545 // We want the completion task to run immediately after Commit() returns. 546 // Posting it from here means there is less chance of another task getting 547 // onto the message queue first, than if we posted it from Commit() itself. 548 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, completion_task); 549 } 550 #endif 551 } 552 553 // Fire off a close message to the background thread. We could still have a 554 // pending commit timer that will be holding a reference on us, but if/when 555 // this fires we will already have been cleaned up and it will be ignored. 556 void SQLitePersistentCookieStore::Backend::Close() { 557 #ifndef ANDROID 558 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 559 #endif 560 561 #ifdef ANDROID 562 MessageLoop* loop = g_db_thread.Get().message_loop(); 563 loop->PostTask(FROM_HERE, 564 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); 565 #else 566 // Must close the backend on the background thread. 567 BrowserThread::PostTask( 568 BrowserThread::DB, FROM_HERE, 569 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); 570 #endif 571 } 572 573 void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { 574 #ifndef ANDROID 575 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 576 #endif 577 // Commit any pending operations 578 #if defined(ANDROID) 579 Commit(NULL); 580 #else 581 Commit(); 582 #endif 583 584 db_.reset(); 585 586 if (clear_local_state_on_exit_) 587 file_util::Delete(path_, false); 588 } 589 590 void SQLitePersistentCookieStore::Backend::SetClearLocalStateOnExit( 591 bool clear_local_state) { 592 base::AutoLock locked(lock_); 593 clear_local_state_on_exit_ = clear_local_state; 594 } 595 SQLitePersistentCookieStore::SQLitePersistentCookieStore(const FilePath& path) 596 : backend_(new Backend(path)) { 597 } 598 599 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 600 if (backend_.get()) { 601 backend_->Close(); 602 // Release our reference, it will probably still have a reference if the 603 // background thread has not run Close() yet. 604 backend_ = NULL; 605 } 606 } 607 608 bool SQLitePersistentCookieStore::Load( 609 std::vector<net::CookieMonster::CanonicalCookie*>* cookies) { 610 return backend_->Load(cookies); 611 } 612 613 void SQLitePersistentCookieStore::AddCookie( 614 const net::CookieMonster::CanonicalCookie& cc) { 615 if (backend_.get()) 616 backend_->AddCookie(cc); 617 } 618 619 void SQLitePersistentCookieStore::UpdateCookieAccessTime( 620 const net::CookieMonster::CanonicalCookie& cc) { 621 if (backend_.get()) 622 backend_->UpdateCookieAccessTime(cc); 623 } 624 625 void SQLitePersistentCookieStore::DeleteCookie( 626 const net::CookieMonster::CanonicalCookie& cc) { 627 if (backend_.get()) 628 backend_->DeleteCookie(cc); 629 } 630 631 void SQLitePersistentCookieStore::SetClearLocalStateOnExit( 632 bool clear_local_state) { 633 if (backend_.get()) 634 backend_->SetClearLocalStateOnExit(clear_local_state); 635 } 636 637 void SQLitePersistentCookieStore::Flush(Task* completion_task) { 638 if (backend_.get()) 639 backend_->Flush(completion_task); 640 else if (completion_task) 641 MessageLoop::current()->PostTask(FROM_HERE, completion_task); 642 } 643 644 #if defined(ANDROID) 645 int SQLitePersistentCookieStore::GetCookieCount() { 646 int result = backend_ ? backend_->get_cookie_count() : 0; 647 return result; 648 } 649 #endif 650