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