sqlite_persistent_cookie_store.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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#include "base/logging.h" 16#include "base/metrics/histogram.h" 17#include "base/ref_counted.h" 18#include "base/scoped_ptr.h" 19#include "base/string_util.h" 20#include "base/thread.h" 21#ifndef ANDROID 22#include "chrome/browser/browser_thread.h" 23#include "chrome/browser/diagnostics/sqlite_diagnostics.h" 24#endif 25 26#ifdef ANDROID 27base::Thread* getDbThread() 28{ 29 static base::Thread* dbThread = NULL; 30 if (dbThread && dbThread->IsRunning()) 31 return dbThread; 32 33 if (!dbThread) 34 dbThread = new base::Thread("db"); 35 36 if (!dbThread) 37 return NULL; 38 39 base::Thread::Options options; 40 options.message_loop_type = MessageLoop::TYPE_DEFAULT; 41 if (!dbThread->StartWithOptions(options)) { 42 delete dbThread; 43 dbThread = NULL; 44 } 45 return dbThread; 46} 47#endif 48 49using 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. 53class SQLitePersistentCookieStore::Backend 54 : public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> { 55 public: 56<<<<<<< HEAD 57 // The passed database pointer must be already-initialized. This object will 58 // take ownership. 59 explicit Backend(sql::Connection* db) 60 : db_(db) 61 , num_pending_(0) 62#if defined(ANDROID) 63 , cookie_count_(0) 64#endif 65 { 66 DCHECK(db_) << "Database must exist."; 67======= 68 explicit Backend(const FilePath& path) 69 : path_(path), 70 db_(NULL), 71 num_pending_(0), 72 clear_local_state_on_exit_(false) { 73>>>>>>> chromium.org at r10.0.621.0 74 } 75 76 // Creates or load the SQLite database. 77 bool Load(std::vector<net::CookieMonster::CanonicalCookie*>* cookies); 78 79 // Batch a cookie addition. 80 void AddCookie(const net::CookieMonster::CanonicalCookie& cc); 81 82 // Batch a cookie access time update. 83 void UpdateCookieAccessTime(const net::CookieMonster::CanonicalCookie& cc); 84 85 // Batch a cookie deletion. 86 void DeleteCookie(const net::CookieMonster::CanonicalCookie& cc); 87 88<<<<<<< HEAD 89#if defined(ANDROID) 90 // Commit pending operations as soon as possible. 91 void Flush(Task* completion_task); 92#endif 93======= 94 // Commit pending operations as soon as possible. 95 void Flush(Task* completion_task); 96>>>>>>> chromium.org at r10.0.621.0 97 98 // Commit any pending operations and close the database. This must be called 99 // before the object is destructed. 100 void Close(); 101 102<<<<<<< HEAD 103#if defined(ANDROID) 104 int get_cookie_count() const { return cookie_count_; } 105 void set_cookie_count(int count) { cookie_count_ = count; } 106#endif 107======= 108 void SetClearLocalStateOnExit(bool clear_local_state); 109>>>>>>> chromium.org at r10.0.621.0 110 111 private: 112 friend class base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend>; 113 114 // You should call Close() before destructing this object. 115 ~Backend() { 116 DCHECK(!db_.get()) << "Close should have already been called."; 117 DCHECK(num_pending_ == 0 && pending_.empty()); 118 } 119 120 // Database upgrade statements. 121 bool EnsureDatabaseVersion(); 122 123 class PendingOperation { 124 public: 125 typedef enum { 126 COOKIE_ADD, 127 COOKIE_UPDATEACCESS, 128 COOKIE_DELETE, 129 } OperationType; 130 131 PendingOperation(OperationType op, 132 const net::CookieMonster::CanonicalCookie& cc) 133 : op_(op), cc_(cc) { } 134 135 OperationType op() const { return op_; } 136 const net::CookieMonster::CanonicalCookie& cc() const { return cc_; } 137 138 private: 139 OperationType op_; 140 net::CookieMonster::CanonicalCookie cc_; 141 }; 142 143 private: 144 // Batch a cookie operation (add or delete) 145 void BatchOperation(PendingOperation::OperationType op, 146 const net::CookieMonster::CanonicalCookie& cc); 147 // Commit our pending operations to the database. 148#if defined(ANDROID) 149 void Commit(Task* completion_task); 150#else 151 void Commit(); 152#endif 153 // Close() executed on the background thread. 154 void InternalBackgroundClose(); 155 156 FilePath path_; 157 scoped_ptr<sql::Connection> db_; 158 sql::MetaTable meta_table_; 159 160 typedef std::list<PendingOperation*> PendingOperationsList; 161 PendingOperationsList pending_; 162 PendingOperationsList::size_type num_pending_; 163 // True if the persistent store should be deleted upon destruction. 164 bool clear_local_state_on_exit_; 165 // Guard |pending_|, |num_pending_| and |clear_local_state_on_exit_|. 166 Lock lock_; 167 168#if defined(ANDROID) 169 // Number of cookies that have actually been saved. Updated during Commit(). 170 volatile int cookie_count_; 171#endif 172 173 DISALLOW_COPY_AND_ASSIGN(Backend); 174}; 175 176// Version number of the database. In version 4, we migrated the time epoch. 177// If you open the DB with an older version on Mac or Linux, the times will 178// look wonky, but the file will likely be usable. On Windows version 3 and 4 179// are the same. 180// 181// Version 3 updated the database to include the last access time, so we can 182// expire them in decreasing order of use when we've reached the maximum 183// number of cookies. 184static const int kCurrentVersionNumber = 4; 185static const int kCompatibleVersionNumber = 3; 186 187namespace { 188 189// Initializes the cookies table, returning true on success. 190bool InitTable(sql::Connection* db) { 191 if (!db->DoesTableExist("cookies")) { 192 if (!db->Execute("CREATE TABLE cookies (" 193 "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY," 194 "host_key TEXT NOT NULL," 195 "name TEXT NOT NULL," 196 "value TEXT NOT NULL," 197 "path TEXT NOT NULL," 198 // We only store persistent, so we know it expires 199 "expires_utc INTEGER NOT NULL," 200 "secure INTEGER NOT NULL," 201 "httponly INTEGER NOT NULL," 202 "last_access_utc INTEGER NOT NULL)")) 203 return false; 204 } 205 206 // Try to create the index every time. Older versions did not have this index, 207 // so we want those people to get it. Ignore errors, since it may exist. 208 db->Execute("CREATE INDEX cookie_times ON cookies (creation_utc)"); 209 return true; 210} 211 212} // namespace 213 214bool SQLitePersistentCookieStore::Backend::Load( 215 std::vector<net::CookieMonster::CanonicalCookie*>* cookies) { 216 // This function should be called only once per instance. 217 DCHECK(!db_.get()); 218 219 db_.reset(new sql::Connection); 220 if (!db_->Open(path_)) { 221 NOTREACHED() << "Unable to open cookie DB."; 222 db_.reset(); 223 return false; 224 } 225 226 db_->set_error_delegate(GetErrorHandlerForCookieDb()); 227 228 if (!EnsureDatabaseVersion() || !InitTable(db_.get())) { 229 NOTREACHED() << "Unable to open cookie DB."; 230 db_.reset(); 231 return false; 232 } 233 234 db_->Preload(); 235 236 // Slurp all the cookies into the out-vector. 237 sql::Statement smt(db_->GetUniqueStatement( 238 "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, " 239 "httponly, last_access_utc FROM cookies")); 240 if (!smt) { 241 NOTREACHED() << "select statement prep failed"; 242 db_.reset(); 243 return false; 244 } 245 246 while (smt.Step()) { 247 scoped_ptr<net::CookieMonster::CanonicalCookie> cc( 248 new net::CookieMonster::CanonicalCookie( 249 smt.ColumnString(2), // name 250 smt.ColumnString(3), // value 251 smt.ColumnString(1), // domain 252 smt.ColumnString(4), // path 253 smt.ColumnInt(6) != 0, // secure 254 smt.ColumnInt(7) != 0, // httponly 255 Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc 256 Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc 257 true, // has_expires 258 Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc 259 DLOG_IF(WARNING, 260 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; 261 cookies->push_back(cc.release()); 262 } 263 264 return true; 265} 266 267bool SQLitePersistentCookieStore::Backend::EnsureDatabaseVersion() { 268 // Version check. 269 if (!meta_table_.Init( 270 db_.get(), kCurrentVersionNumber, kCompatibleVersionNumber)) { 271 return false; 272 } 273 274 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 275 LOG(WARNING) << "Cookie database is too new."; 276 return false; 277 } 278 279 int cur_version = meta_table_.GetVersionNumber(); 280 if (cur_version == 2) { 281 sql::Transaction transaction(db_.get()); 282 if (!transaction.Begin()) 283 return false; 284 if (!db_->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc " 285 "INTEGER DEFAULT 0") || 286 !db_->Execute("UPDATE cookies SET last_access_utc = creation_utc")) { 287 LOG(WARNING) << "Unable to update cookie database to version 3."; 288 return false; 289 } 290 ++cur_version; 291 meta_table_.SetVersionNumber(cur_version); 292 meta_table_.SetCompatibleVersionNumber( 293 std::min(cur_version, kCompatibleVersionNumber)); 294 transaction.Commit(); 295 } 296 297 if (cur_version == 3) { 298 // The time epoch changed for Mac & Linux in this version to match Windows. 299 // This patch came after the main epoch change happened, so some 300 // developers have "good" times for cookies added by the more recent 301 // versions. So we have to be careful to only update times that are under 302 // the old system (which will appear to be from before 1970 in the new 303 // system). The magic number used below is 1970 in our time units. 304 sql::Transaction transaction(db_.get()); 305 transaction.Begin(); 306#if !defined(OS_WIN) 307 db_->Execute( 308 "UPDATE cookies " 309 "SET creation_utc = creation_utc + 11644473600000000 " 310 "WHERE rowid IN " 311 "(SELECT rowid FROM cookies WHERE " 312 "creation_utc > 0 AND creation_utc < 11644473600000000)"); 313 db_->Execute( 314 "UPDATE cookies " 315 "SET expires_utc = expires_utc + 11644473600000000 " 316 "WHERE rowid IN " 317 "(SELECT rowid FROM cookies WHERE " 318 "expires_utc > 0 AND expires_utc < 11644473600000000)"); 319 db_->Execute( 320 "UPDATE cookies " 321 "SET last_access_utc = last_access_utc + 11644473600000000 " 322 "WHERE rowid IN " 323 "(SELECT rowid FROM cookies WHERE " 324 "last_access_utc > 0 AND last_access_utc < 11644473600000000)"); 325#endif 326 ++cur_version; 327 meta_table_.SetVersionNumber(cur_version); 328 transaction.Commit(); 329 } 330 331 // Put future migration cases here. 332 333 // When the version is too old, we just try to continue anyway, there should 334 // not be a released product that makes a database too old for us to handle. 335 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << 336 "Cookie database version " << cur_version << " is too old to handle."; 337 338 return true; 339} 340 341void SQLitePersistentCookieStore::Backend::AddCookie( 342 const net::CookieMonster::CanonicalCookie& cc) { 343 BatchOperation(PendingOperation::COOKIE_ADD, cc); 344} 345 346void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime( 347 const net::CookieMonster::CanonicalCookie& cc) { 348 BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc); 349} 350 351void SQLitePersistentCookieStore::Backend::DeleteCookie( 352 const net::CookieMonster::CanonicalCookie& cc) { 353 BatchOperation(PendingOperation::COOKIE_DELETE, cc); 354} 355 356void SQLitePersistentCookieStore::Backend::BatchOperation( 357 PendingOperation::OperationType op, 358 const net::CookieMonster::CanonicalCookie& cc) { 359 // Commit every 30 seconds. 360 static const int kCommitIntervalMs = 30 * 1000; 361 // Commit right away if we have more than 512 outstanding operations. 362 static const size_t kCommitAfterBatchSize = 512; 363#ifndef ANDROID 364 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 365#endif 366 367 // We do a full copy of the cookie here, and hopefully just here. 368 scoped_ptr<PendingOperation> po(new PendingOperation(op, cc)); 369 370 PendingOperationsList::size_type num_pending; 371 { 372 AutoLock locked(lock_); 373 pending_.push_back(po.release()); 374 num_pending = ++num_pending_; 375 } 376 377#ifdef ANDROID 378 if (!getDbThread()) 379 return; 380 MessageLoop* loop = getDbThread()->message_loop(); 381#endif 382 383 if (num_pending == 1) { 384 // We've gotten our first entry for this batch, fire off the timer. 385#ifdef ANDROID 386 loop->PostDelayedTask(FROM_HERE, NewRunnableMethod( 387 this, &Backend::Commit, static_cast<Task*>(NULL)), kCommitIntervalMs); 388#else 389 BrowserThread::PostDelayedTask( 390 BrowserThread::DB, FROM_HERE, 391 NewRunnableMethod(this, &Backend::Commit), kCommitIntervalMs); 392#endif 393 } else if (num_pending == kCommitAfterBatchSize) { 394 // We've reached a big enough batch, fire off a commit now. 395#ifdef ANDROID 396 loop->PostTask(FROM_HERE, NewRunnableMethod( 397 this, &Backend::Commit, static_cast<Task*>(NULL))); 398#else 399 BrowserThread::PostTask( 400 BrowserThread::DB, FROM_HERE, 401 NewRunnableMethod(this, &Backend::Commit)); 402#endif 403 } 404} 405 406#if defined(ANDROID) 407void SQLitePersistentCookieStore::Backend::Commit(Task* completion_task) { 408#else 409void SQLitePersistentCookieStore::Backend::Commit() { 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 411<<<<<<< HEAD 412#endif 413 414#if defined(ANDROID) 415 if (completion_task) { 416 // We post this task to the current thread, so it won't run until we exit. 417 MessageLoop::current()->PostTask(FROM_HERE, completion_task); 418 } 419#endif 420======= 421>>>>>>> chromium.org at r10.0.621.0 422 423 PendingOperationsList ops; 424 { 425 AutoLock locked(lock_); 426 pending_.swap(ops); 427 num_pending_ = 0; 428 } 429 430 // Maybe an old timer fired or we are already Close()'ed. 431 if (!db_.get() || ops.empty()) 432 return; 433 434 sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE, 435 "INSERT INTO cookies (creation_utc, host_key, name, value, path, " 436 "expires_utc, secure, httponly, last_access_utc) " 437 "VALUES (?,?,?,?,?,?,?,?,?)")); 438 if (!add_smt) { 439 NOTREACHED(); 440 return; 441 } 442 443 sql::Statement update_access_smt(db_->GetCachedStatement(SQL_FROM_HERE, 444 "UPDATE cookies SET last_access_utc=? WHERE creation_utc=?")); 445 if (!update_access_smt) { 446 NOTREACHED(); 447 return; 448 } 449 450 sql::Statement del_smt(db_->GetCachedStatement(SQL_FROM_HERE, 451 "DELETE FROM cookies WHERE creation_utc=?")); 452 if (!del_smt) { 453 NOTREACHED(); 454 return; 455 } 456 457 sql::Transaction transaction(db_.get()); 458 if (!transaction.Begin()) { 459 NOTREACHED(); 460 return; 461 } 462#if defined(ANDROID) 463 int cookie_delta = 0; 464#endif 465 for (PendingOperationsList::iterator it = ops.begin(); 466 it != ops.end(); ++it) { 467 // Free the cookies as we commit them to the database. 468 scoped_ptr<PendingOperation> po(*it); 469 switch (po->op()) { 470 case PendingOperation::COOKIE_ADD: 471#if defined(ANDROID) 472 ++cookie_delta; 473#endif 474 add_smt.Reset(); 475 add_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 476 add_smt.BindString(1, po->cc().Domain()); 477 add_smt.BindString(2, po->cc().Name()); 478 add_smt.BindString(3, po->cc().Value()); 479 add_smt.BindString(4, po->cc().Path()); 480 add_smt.BindInt64(5, po->cc().ExpiryDate().ToInternalValue()); 481 add_smt.BindInt(6, po->cc().IsSecure()); 482 add_smt.BindInt(7, po->cc().IsHttpOnly()); 483 add_smt.BindInt64(8, po->cc().LastAccessDate().ToInternalValue()); 484 if (!add_smt.Run()) 485 NOTREACHED() << "Could not add a cookie to the DB."; 486 break; 487 488 case PendingOperation::COOKIE_UPDATEACCESS: 489 update_access_smt.Reset(); 490 update_access_smt.BindInt64(0, 491 po->cc().LastAccessDate().ToInternalValue()); 492 update_access_smt.BindInt64(1, 493 po->cc().CreationDate().ToInternalValue()); 494 if (!update_access_smt.Run()) 495 NOTREACHED() << "Could not update cookie last access time in the DB."; 496 break; 497 498 case PendingOperation::COOKIE_DELETE: 499#if defined(ANDROID) 500 --cookie_delta; 501#endif 502 del_smt.Reset(); 503 del_smt.BindInt64(0, po->cc().CreationDate().ToInternalValue()); 504 if (!del_smt.Run()) 505 NOTREACHED() << "Could not delete a cookie from the DB."; 506 break; 507 508 default: 509 NOTREACHED(); 510 break; 511 } 512 } 513 bool succeeded = transaction.Commit(); 514#if defined(ANDROID) 515 if (succeeded) 516 cookie_count_ += cookie_delta; 517#endif 518 UMA_HISTOGRAM_ENUMERATION("Cookie.BackingStoreUpdateResults", 519 succeeded ? 0 : 1, 2); 520} 521 522<<<<<<< HEAD 523#if defined(ANDROID) 524void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) { 525// Keep this #ifdef when upstreaming to Chromium. 526#if defined(ANDROID) 527 if (!getDbThread()) { 528 if (completion_task) 529 MessageLoop::current()->PostTask(FROM_HERE, completion_task); 530 return; 531 } 532 533 MessageLoop* loop = getDbThread()->message_loop(); 534 loop->PostTask(FROM_HERE, NewRunnableMethod( 535 this, &Backend::Commit, completion_task)); 536#else 537 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 538 BrowserThread::PostTask( 539 BrowserThread::DB, FROM_HERE, NewRunnableMethod( 540 this, &Backend::Commit, completion_task)); 541#endif 542} 543#endif 544======= 545void SQLitePersistentCookieStore::Backend::Flush(Task* completion_task) { 546 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 547 BrowserThread::PostTask( 548 BrowserThread::DB, FROM_HERE, NewRunnableMethod(this, &Backend::Commit)); 549 if (completion_task) { 550 // We want the completion task to run immediately after Commit() returns. 551 // Posting it from here means there is less chance of another task getting 552 // onto the message queue first, than if we posted it from Commit() itself. 553 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, completion_task); 554 } 555} 556>>>>>>> chromium.org at r10.0.621.0 557 558// Fire off a close message to the background thread. We could still have a 559// pending commit timer that will be holding a reference on us, but if/when 560// this fires we will already have been cleaned up and it will be ignored. 561void SQLitePersistentCookieStore::Backend::Close() { 562#ifndef ANDROID 563 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::DB)); 564#endif 565 566#ifdef ANDROID 567 if (!getDbThread()) 568 return; 569 570 MessageLoop* loop = getDbThread()->message_loop(); 571 loop->PostTask(FROM_HERE, 572 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); 573#else 574 // Must close the backend on the background thread. 575 BrowserThread::PostTask( 576 BrowserThread::DB, FROM_HERE, 577 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); 578#endif 579} 580 581void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { 582#ifndef ANDROID 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 584#endif 585 // Commit any pending operations 586#if defined(ANDROID) 587 Commit(NULL); 588#else 589 Commit(); 590<<<<<<< HEAD 591#endif 592 delete db_; 593 db_ = NULL; 594======= 595 596 db_.reset(); 597 598 if (clear_local_state_on_exit_) 599 file_util::Delete(path_, false); 600>>>>>>> chromium.org at r10.0.621.0 601} 602 603void SQLitePersistentCookieStore::Backend::SetClearLocalStateOnExit( 604 bool clear_local_state) { 605 AutoLock locked(lock_); 606 clear_local_state_on_exit_ = clear_local_state; 607} 608SQLitePersistentCookieStore::SQLitePersistentCookieStore(const FilePath& path) 609 : backend_(new Backend(path)) { 610} 611 612SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { 613 if (backend_.get()) { 614 backend_->Close(); 615 // Release our reference, it will probably still have a reference if the 616 // background thread has not run Close() yet. 617 backend_ = NULL; 618 } 619} 620 621<<<<<<< HEAD 622// Version number of the database. In version 4, we migrated the time epoch. 623// If you open the DB with an older version on Mac or Linux, the times will 624// look wonky, but the file will likely be usable. On Windows version 3 and 4 625// are the same. 626// 627// Version 3 updated the database to include the last access time, so we can 628// expire them in decreasing order of use when we've reached the maximum 629// number of cookies. 630static const int kCurrentVersionNumber = 4; 631static const int kCompatibleVersionNumber = 3; 632 633namespace { 634 635// Initializes the cookies table, returning true on success. 636bool InitTable(sql::Connection* db) { 637 if (!db->DoesTableExist("cookies")) { 638 if (!db->Execute("CREATE TABLE cookies (" 639 "creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY," 640 "host_key TEXT NOT NULL," 641 "name TEXT NOT NULL," 642 "value TEXT NOT NULL," 643 "path TEXT NOT NULL," 644#if defined(ANDROID) 645 // On some mobile platforms, we persist session cookies 646 // because the OS can kill the browser during a session. 647 // If so, expires_utc is set to 0. When the field is read 648 // into a Time object, Time::is_null() will return true. 649#else 650 // We only store persistent, so we know it expires 651#endif 652 "expires_utc INTEGER NOT NULL," 653 "secure INTEGER NOT NULL," 654 "httponly INTEGER NOT NULL," 655 "last_access_utc INTEGER NOT NULL)")) 656 return false; 657 } 658 659 // Try to create the index every time. Older versions did not have this index, 660 // so we want those people to get it. Ignore errors, since it may exist. 661#ifdef ANDROID 662 db->Execute("CREATE INDEX IF NOT EXISTS cookie_times ON cookies (creation_utc)"); 663#else 664 db->Execute("CREATE INDEX cookie_times ON cookies (creation_utc)"); 665#endif 666 return true; 667} 668 669} // namespace 670 671bool SQLitePersistentCookieStore::Load( 672 std::vector<net::CookieMonster::CanonicalCookie*>* cookies) { 673 scoped_ptr<sql::Connection> db(new sql::Connection); 674 if (!db->Open(path_)) { 675 NOTREACHED() << "Unable to open cookie DB."; 676 return false; 677 } 678 679#ifndef ANDROID 680 // GetErrorHandlerForCookieDb is defined in sqlite_diagnostics.h 681 // which we do not currently include on Android 682 db->set_error_delegate(GetErrorHandlerForCookieDb()); 683#endif 684 685 if (!EnsureDatabaseVersion(db.get()) || !InitTable(db.get())) { 686 NOTREACHED() << "Unable to initialize cookie DB."; 687 return false; 688 } 689 690 db->Preload(); 691 692 // Slurp all the cookies into the out-vector. 693 sql::Statement smt(db->GetUniqueStatement( 694 "SELECT creation_utc, host_key, name, value, path, expires_utc, secure, " 695 "httponly, last_access_utc FROM cookies")); 696 if (!smt) { 697 NOTREACHED() << "select statement prep failed"; 698 return false; 699 } 700 701 while (smt.Step()) { 702#if defined(ANDROID) 703 base::Time expires = Time::FromInternalValue(smt.ColumnInt64(5)); 704#endif 705 scoped_ptr<net::CookieMonster::CanonicalCookie> cc( 706 new net::CookieMonster::CanonicalCookie( 707 smt.ColumnString(2), // name 708 smt.ColumnString(3), // value 709 smt.ColumnString(1), // domain 710 smt.ColumnString(4), // path 711 smt.ColumnInt(6) != 0, // secure 712 smt.ColumnInt(7) != 0, // httponly 713 Time::FromInternalValue(smt.ColumnInt64(0)), // creation_utc 714 Time::FromInternalValue(smt.ColumnInt64(8)), // last_access_utc 715#if defined(ANDROID) 716 !expires.is_null(), // has_expires 717 expires)); // expires_utc 718#else 719 true, // has_expires 720 Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc 721#endif 722 DLOG_IF(WARNING, 723 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; 724 cookies->push_back(cc.release()); 725 } 726 727 // Create the backend, this will take ownership of the db pointer. 728 backend_ = new Backend(db.release()); 729#if defined(ANDROID) 730 backend_->set_cookie_count(cookies->size()); 731#endif 732 return true; 733} 734 735bool SQLitePersistentCookieStore::EnsureDatabaseVersion(sql::Connection* db) { 736 // Version check. 737 if (!meta_table_.Init(db, kCurrentVersionNumber, kCompatibleVersionNumber)) 738 return false; 739 740 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { 741 LOG(WARNING) << "Cookie database is too new."; 742 return false; 743 } 744 745 int cur_version = meta_table_.GetVersionNumber(); 746 if (cur_version == 2) { 747 sql::Transaction transaction(db); 748 if (!transaction.Begin()) 749 return false; 750 if (!db->Execute("ALTER TABLE cookies ADD COLUMN last_access_utc " 751 "INTEGER DEFAULT 0") || 752 !db->Execute("UPDATE cookies SET last_access_utc = creation_utc")) { 753 LOG(WARNING) << "Unable to update cookie database to version 3."; 754 return false; 755 } 756 ++cur_version; 757 meta_table_.SetVersionNumber(cur_version); 758 meta_table_.SetCompatibleVersionNumber( 759 std::min(cur_version, kCompatibleVersionNumber)); 760 transaction.Commit(); 761 } 762 763 if (cur_version == 3) { 764 // The time epoch changed for Mac & Linux in this version to match Windows. 765 // This patch came after the main epoch change happened, so some 766 // developers have "good" times for cookies added by the more recent 767 // versions. So we have to be careful to only update times that are under 768 // the old system (which will appear to be from before 1970 in the new 769 // system). The magic number used below is 1970 in our time units. 770 sql::Transaction transaction(db); 771 transaction.Begin(); 772#if !defined(OS_WIN) 773 db->Execute( 774 "UPDATE cookies " 775 "SET creation_utc = creation_utc + 11644473600000000 " 776 "WHERE rowid IN " 777 "(SELECT rowid FROM cookies WHERE " 778 "creation_utc > 0 AND creation_utc < 11644473600000000)"); 779 db->Execute( 780 "UPDATE cookies " 781 "SET expires_utc = expires_utc + 11644473600000000 " 782 "WHERE rowid IN " 783 "(SELECT rowid FROM cookies WHERE " 784 "expires_utc > 0 AND expires_utc < 11644473600000000)"); 785 db->Execute( 786 "UPDATE cookies " 787 "SET last_access_utc = last_access_utc + 11644473600000000 " 788 "WHERE rowid IN " 789 "(SELECT rowid FROM cookies WHERE " 790 "last_access_utc > 0 AND last_access_utc < 11644473600000000)"); 791#endif 792 ++cur_version; 793 meta_table_.SetVersionNumber(cur_version); 794 transaction.Commit(); 795 } 796 797 // Put future migration cases here. 798 799 // When the version is too old, we just try to continue anyway, there should 800 // not be a released product that makes a database too old for us to handle. 801 LOG_IF(WARNING, cur_version < kCurrentVersionNumber) << 802 "Cookie database version " << cur_version << " is too old to handle."; 803 804 return true; 805======= 806bool SQLitePersistentCookieStore::Load( 807 std::vector<net::CookieMonster::CanonicalCookie*>* cookies) { 808 return backend_->Load(cookies); 809>>>>>>> chromium.org at r10.0.621.0 810} 811 812void SQLitePersistentCookieStore::AddCookie( 813 const net::CookieMonster::CanonicalCookie& cc) { 814 if (backend_.get()) 815 backend_->AddCookie(cc); 816} 817 818void SQLitePersistentCookieStore::UpdateCookieAccessTime( 819 const net::CookieMonster::CanonicalCookie& cc) { 820 if (backend_.get()) 821 backend_->UpdateCookieAccessTime(cc); 822} 823 824void SQLitePersistentCookieStore::DeleteCookie( 825 const net::CookieMonster::CanonicalCookie& cc) { 826 if (backend_.get()) 827 backend_->DeleteCookie(cc); 828} 829 830<<<<<<< HEAD 831#if defined(ANDROID) 832void SQLitePersistentCookieStore::Flush(Task* completion_callback) { 833 if (backend_.get()) 834 backend_->Flush(completion_callback); 835 else { 836 if (completion_callback) 837 MessageLoop::current()->PostTask(FROM_HERE, completion_callback); 838 } 839} 840#endif 841 842#if defined(ANDROID) 843int SQLitePersistentCookieStore::GetCookieCount() { 844 int result = backend_ ? backend_->get_cookie_count() : 0; 845 return result; 846} 847#endif 848 849// static 850void SQLitePersistentCookieStore::ClearLocalState( 851 const FilePath& path) { 852 file_util::Delete(path, false); 853======= 854void SQLitePersistentCookieStore::SetClearLocalStateOnExit( 855 bool clear_local_state) { 856 if (backend_.get()) 857 backend_->SetClearLocalStateOnExit(clear_local_state); 858} 859 860void SQLitePersistentCookieStore::Flush(Task* completion_task) { 861 if (backend_.get()) 862 backend_->Flush(completion_task); 863 else if (completion_task) 864 MessageLoop::current()->PostTask(FROM_HERE, completion_task); 865>>>>>>> chromium.org at r10.0.621.0 866} 867