1 // Copyright 2012 The Chromium Authors
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 "net/extras/sqlite/sqlite_persistent_cookie_store.h"
6
7 #include <iterator>
8 #include <map>
9 #include <memory>
10 #include <set>
11 #include <tuple>
12 #include <unordered_set>
13
14 #include "base/feature_list.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/functional/bind.h"
18 #include "base/functional/callback.h"
19 #include "base/location.h"
20 #include "base/logging.h"
21 #include "base/memory/raw_ptr.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/metrics/histogram_functions.h"
24 #include "base/metrics/histogram_macros.h"
25 #include "base/strings/string_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/synchronization/lock.h"
28 #include "base/task/sequenced_task_runner.h"
29 #include "base/thread_annotations.h"
30 #include "base/time/time.h"
31 #include "base/values.h"
32 #include "build/build_config.h"
33 #include "net/cookies/canonical_cookie.h"
34 #include "net/cookies/cookie_constants.h"
35 #include "net/cookies/cookie_util.h"
36 #include "net/extras/sqlite/cookie_crypto_delegate.h"
37 #include "net/extras/sqlite/sqlite_persistent_store_backend_base.h"
38 #include "net/log/net_log.h"
39 #include "net/log/net_log_values.h"
40 #include "sql/error_delegate_util.h"
41 #include "sql/meta_table.h"
42 #include "sql/statement.h"
43 #include "sql/transaction.h"
44 #include "third_party/abseil-cpp/absl/types/optional.h"
45 #include "url/gurl.h"
46 #include "url/third_party/mozilla/url_parse.h"
47
48 using base::Time;
49
50 namespace {
51
CookieKeyedLoadNetLogParams(const std::string & key,net::NetLogCaptureMode capture_mode)52 base::Value::Dict CookieKeyedLoadNetLogParams(
53 const std::string& key,
54 net::NetLogCaptureMode capture_mode) {
55 if (!net::NetLogCaptureIncludesSensitive(capture_mode))
56 return base::Value::Dict();
57 base::Value::Dict dict;
58 dict.Set("key", key);
59 return dict;
60 }
61
62 // Used to populate a histogram for problems when loading cookies.
63 //
64 // Please do not reorder or remove entries. New entries must be added to the
65 // end of the list, just before COOKIE_LOAD_PROBLEM_LAST_ENTRY.
66 enum CookieLoadProblem {
67 COOKIE_LOAD_PROBLEM_DECRYPT_FAILED = 0,
68 // Deprecated 03/2021.
69 // COOKIE_LOAD_PROBLEM_DECRYPT_TIMEOUT = 1,
70 COOKIE_LOAD_PROBLEM_NON_CANONICAL = 2,
71 COOKIE_LOAD_PROBLEM_OPEN_DB = 3,
72 COOKIE_LOAD_PROBLEM_RECOVERY_FAILED = 4,
73 COOKIE_LOAD_DELETE_COOKIE_PARTITION_FAILED = 5,
74 COOKIE_LOAD_PROBLEM_LAST_ENTRY
75 };
76
77 // Used to populate a histogram for problems when committing cookies.
78 //
79 // Please do not reorder or remove entries. New entries must be added to the
80 // end of the list, just before COOKIE_COMMIT_PROBLEM_LAST_ENTRY.
81 enum CookieCommitProblem {
82 COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED = 0,
83 COOKIE_COMMIT_PROBLEM_ADD = 1,
84 COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS = 2,
85 COOKIE_COMMIT_PROBLEM_DELETE = 3,
86 COOKIE_COMMIT_PROBLEM_TRANSACTION_COMMIT = 4,
87 COOKIE_COMMIT_PROBLEM_LAST_ENTRY
88 };
89
RecordCookieLoadProblem(CookieLoadProblem event)90 void RecordCookieLoadProblem(CookieLoadProblem event) {
91 UMA_HISTOGRAM_ENUMERATION("Cookie.LoadProblem", event,
92 COOKIE_LOAD_PROBLEM_LAST_ENTRY);
93 }
94
RecordCookieCommitProblem(CookieCommitProblem event)95 void RecordCookieCommitProblem(CookieCommitProblem event) {
96 UMA_HISTOGRAM_ENUMERATION("Cookie.CommitProblem", event,
97 COOKIE_COMMIT_PROBLEM_LAST_ENTRY);
98 }
99
100 // The persistent cookie store is loaded into memory on eTLD at a time. This
101 // variable controls the delay between loading eTLDs, so as to not overload the
102 // CPU or I/O with these low priority requests immediately after start up.
103 #if BUILDFLAG(IS_IOS)
104 // TODO(ellyjones): This should be 200ms, but currently CookieStoreIOS is
105 // waiting for -FinishedLoadingCookies to be called after all eTLD cookies are
106 // loaded before making any network requests. Changing to 0ms for now.
107 // crbug.com/462593
108 const int kLoadDelayMilliseconds = 0;
109 #else
110 const int kLoadDelayMilliseconds = 0;
111 #endif
112
113 } // namespace
114
115 namespace net {
116
GetCookieStoreBackgroundSequencePriority()117 base::TaskPriority GetCookieStoreBackgroundSequencePriority() {
118 return base::TaskPriority::USER_BLOCKING;
119 }
120
121 namespace {
122
123 // Version number of the database.
124 //
125 // Version 18 - 2022/04/19 - https://crrev.com/c/3594203
126 // Version 17 - 2022/01/25 - https://crrev.com/c/3416230
127 // Version 16 - 2021/09/10 - https://crrev.com/c/3152897
128 // Version 15 - 2021/07/01 - https://crrev.com/c/3001822
129 // Version 14 - 2021/02/23 - https://crrev.com/c/2036899
130 // Version 13 - 2020/10/28 - https://crrev.com/c/2505468
131 // Version 12 - 2019/11/20 - https://crrev.com/c/1898301
132 // Version 11 - 2019/04/17 - https://crrev.com/c/1570416
133 // Version 10 - 2018/02/13 - https://crrev.com/c/906675
134 // Version 9 - 2015/04/17 - https://codereview.chromium.org/1083623003
135 //
136 // Unsupported versions:
137 // Version 8 - 2015/02/23 - https://codereview.chromium.org/876973003
138 // Version 7 - 2013/12/16 - https://codereview.chromium.org/24734007
139 // Version 6 - 2013/04/23 - https://codereview.chromium.org/14208017
140 // Version 5 - 2011/12/05 - https://codereview.chromium.org/8533013
141 // Version 4 - 2009/09/01 - https://codereview.chromium.org/183021
142 //
143 //
144 // Version 18 adds one new field: "last_update_utc" (if not 0 this represents
145 // the last time the cookie was updated). This is distinct from creation_utc
146 // which is carried forward when cookies are updated.
147 //
148 // Version 17 fixes crbug.com/1290841: Bug in V16 migration.
149 //
150 // Version 16 changes the unique constraint's order of columns to have
151 // top_frame_site_key be after host_key. This allows us to use the internal
152 // index created by the UNIQUE keyword without to load cookies by domain
153 // without us needing to supply a top_frame_site_key. This is necessary because
154 // CookieMonster tracks pending cookie loading tasks by host key only.
155 // Version 16 also removes the DEFAULT value from several columns.
156 //
157 // Version 15 adds one new field: "top_frame_site_key" (if not empty then the
158 // string is the scheme and site of the topmost-level frame the cookie was
159 // created in). This field is deserialized into the cookie's partition key.
160 // top_frame_site_key is *NOT* the site-for-cookies when the cookie was created.
161 // In migrating, top_frame_site_key defaults to empty string. This change also
162 // changes the uniqueness constraint on cookies to include the
163 // top_frame_site_key as well.
164 //
165 // Version 14 just reads all encrypted cookies and re-writes them out again to
166 // make sure the new encryption key is in use. This active migration only
167 // happens on Windows, on other OS, this migration is a no-op.
168 //
169 // Version 13 adds two new fields: "source_port" (the port number of the source
170 // origin, and "same_party" (boolean indicating whether the cookie had a
171 // SameParty attribute). In migrating, source_port defaults to -1
172 // (url::PORT_UNSPECIFIED) for old entries for which the source port is unknown,
173 // and same_party defaults to false.
174 //
175 // Version 12 adds a column for "source_scheme" to store whether the
176 // cookie was set from a URL with a cryptographic scheme.
177 //
178 // Version 11 renames the "firstpartyonly" column to "samesite", and changes any
179 // stored values of kCookieSameSiteNoRestriction into
180 // kCookieSameSiteUnspecified to reflect the fact that those cookies were set
181 // without a SameSite attribute specified. Support for a value of
182 // kCookieSameSiteExtended for "samesite" was added, however, that value is now
183 // deprecated and is mapped to CookieSameSite::UNSPECIFIED when loading from the
184 // database.
185 //
186 // Version 10 removes the uniqueness constraint on the creation time (which
187 // was not propagated up the stack and caused problems in
188 // http://crbug.com/800414 and others). It replaces that constraint by a
189 // constraint on (name, domain, path), which is spec-compliant (see
190 // https://tools.ietf.org/html/rfc6265#section-5.3 step 11). Those fields
191 // can then be used in place of the creation time for updating access
192 // time and deleting cookies.
193 // Version 10 also marks all booleans in the store with an "is_" prefix
194 // to indicated their booleanness, as SQLite has no such concept.
195 //
196 // Version 9 adds a partial index to track non-persistent cookies.
197 // Non-persistent cookies sometimes need to be deleted on startup. There are
198 // frequently few or no non-persistent cookies, so the partial index allows the
199 // deletion to be sped up or skipped, without having to page in the DB.
200 //
201 // Version 8 adds "first-party only" cookies.
202 //
203 // Version 7 adds encrypted values. Old values will continue to be used but
204 // all new values written will be encrypted on selected operating systems. New
205 // records read by old clients will simply get an empty cookie value while old
206 // records read by new clients will continue to operate with the unencrypted
207 // version. New and old clients alike will always write/update records with
208 // what they support.
209 //
210 // Version 6 adds cookie priorities. This allows developers to influence the
211 // order in which cookies are evicted in order to meet domain cookie limits.
212 //
213 // Version 5 adds the columns has_expires and is_persistent, so that the
214 // database can store session cookies as well as persistent cookies. Databases
215 // of version 5 are incompatible with older versions of code. If a database of
216 // version 5 is read by older code, session cookies will be treated as normal
217 // cookies. Currently, these fields are written, but not read anymore.
218 //
219 // In version 4, we migrated the time epoch. If you open the DB with an older
220 // version on Mac or Linux, the times will look wonky, but the file will likely
221 // be usable. On Windows version 3 and 4 are the same.
222 //
223 // Version 3 updated the database to include the last access time, so we can
224 // expire them in decreasing order of use when we've reached the maximum
225 // number of cookies.
226 const int kCurrentVersionNumber = 18;
227 const int kCompatibleVersionNumber = 18;
228
229 } // namespace
230
231 // This class is designed to be shared between any client thread and the
232 // background task runner. It batches operations and commits them on a timer.
233 //
234 // SQLitePersistentCookieStore::Load is called to load all cookies. It
235 // delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread
236 // task to the background runner. This task calls Backend::ChainLoadCookies(),
237 // which repeatedly posts itself to the BG runner to load each eTLD+1's cookies
238 // in separate tasks. When this is complete, Backend::CompleteLoadOnIOThread is
239 // posted to the client runner, which notifies the caller of
240 // SQLitePersistentCookieStore::Load that the load is complete.
241 //
242 // If a priority load request is invoked via SQLitePersistentCookieStore::
243 // LoadCookiesForKey, it is delegated to Backend::LoadCookiesForKey, which posts
244 // Backend::LoadKeyAndNotifyOnDBThread to the BG runner. That routine loads just
245 // that single domain key (eTLD+1)'s cookies, and posts a Backend::
246 // CompleteLoadForKeyOnIOThread to the client runner to notify the caller of
247 // SQLitePersistentCookieStore::LoadCookiesForKey that that load is complete.
248 //
249 // Subsequent to loading, mutations may be queued by any thread using
250 // AddCookie, UpdateCookieAccessTime, and DeleteCookie. These are flushed to
251 // disk on the BG runner every 30 seconds, 512 operations, or call to Flush(),
252 // whichever occurs first.
253 class SQLitePersistentCookieStore::Backend
254 : public SQLitePersistentStoreBackendBase {
255 public:
Backend(const base::FilePath & path,scoped_refptr<base::SequencedTaskRunner> client_task_runner,scoped_refptr<base::SequencedTaskRunner> background_task_runner,bool restore_old_session_cookies,CookieCryptoDelegate * crypto_delegate,bool enable_exclusive_access)256 Backend(const base::FilePath& path,
257 scoped_refptr<base::SequencedTaskRunner> client_task_runner,
258 scoped_refptr<base::SequencedTaskRunner> background_task_runner,
259 bool restore_old_session_cookies,
260 CookieCryptoDelegate* crypto_delegate,
261 bool enable_exclusive_access)
262 : SQLitePersistentStoreBackendBase(path,
263 /* histogram_tag = */ "Cookie",
264 kCurrentVersionNumber,
265 kCompatibleVersionNumber,
266 std::move(background_task_runner),
267 std::move(client_task_runner),
268 enable_exclusive_access),
269 restore_old_session_cookies_(restore_old_session_cookies),
270 crypto_(crypto_delegate) {}
271
272 Backend(const Backend&) = delete;
273 Backend& operator=(const Backend&) = delete;
274
275 // Creates or loads the SQLite database.
276 void Load(LoadedCallback loaded_callback);
277
278 // Loads cookies for the domain key (eTLD+1).
279 void LoadCookiesForKey(const std::string& domain,
280 LoadedCallback loaded_callback);
281
282 // Steps through all results of |statement|, makes a cookie from each, and
283 // adds the cookie to |cookies|. Returns true if everything loaded
284 // successfully.
285 bool MakeCookiesFromSQLStatement(
286 std::vector<std::unique_ptr<CanonicalCookie>>& cookies,
287 sql::Statement& statement,
288 std::unordered_set<std::string>& top_frame_site_keys_to_delete);
289
290 // Batch a cookie addition.
291 void AddCookie(const CanonicalCookie& cc);
292
293 // Batch a cookie access time update.
294 void UpdateCookieAccessTime(const CanonicalCookie& cc);
295
296 // Batch a cookie deletion.
297 void DeleteCookie(const CanonicalCookie& cc);
298
299 size_t GetQueueLengthForTesting();
300
301 // Post background delete of all cookies that match |cookies|.
302 void DeleteAllInList(const std::list<CookieOrigin>& cookies);
303
304 private:
305 // You should call Close() before destructing this object.
~Backend()306 ~Backend() override {
307 DCHECK_EQ(0u, num_pending_);
308 DCHECK(pending_.empty());
309 }
310
311 // Database upgrade statements.
312 absl::optional<int> DoMigrateDatabaseSchema() override;
313
314 class PendingOperation {
315 public:
316 enum OperationType {
317 COOKIE_ADD,
318 COOKIE_UPDATEACCESS,
319 COOKIE_DELETE,
320 };
321
PendingOperation(OperationType op,const CanonicalCookie & cc)322 PendingOperation(OperationType op, const CanonicalCookie& cc)
323 : op_(op), cc_(cc) {}
324
op() const325 OperationType op() const { return op_; }
cc() const326 const CanonicalCookie& cc() const { return cc_; }
327
328 private:
329 OperationType op_;
330 CanonicalCookie cc_;
331 };
332
333 private:
334 // Creates or loads the SQLite database on background runner.
335 void LoadAndNotifyInBackground(LoadedCallback loaded_callback);
336
337 // Loads cookies for the domain key (eTLD+1) on background runner.
338 void LoadKeyAndNotifyInBackground(const std::string& domains,
339 LoadedCallback loaded_callback);
340
341 // Notifies the CookieMonster when loading completes for a specific domain key
342 // or for all domain keys. Triggers the callback and passes it all cookies
343 // that have been loaded from DB since last IO notification.
344 void Notify(LoadedCallback loaded_callback, bool load_success);
345
346 // Sends notification when the entire store is loaded, and reports metrics
347 // for the total time to load and aggregated results from any priority loads
348 // that occurred.
349 void CompleteLoadInForeground(LoadedCallback loaded_callback,
350 bool load_success);
351
352 // Sends notification when a single priority load completes. Updates priority
353 // load metric data. The data is sent only after the final load completes.
354 void CompleteLoadForKeyInForeground(LoadedCallback loaded_callback,
355 bool load_success);
356
357 // Initialize the Cookies table.
358 bool CreateDatabaseSchema() override;
359
360 // Initialize the data base.
361 bool DoInitializeDatabase() override;
362
363 // Loads cookies for the next domain key from the DB, then either reschedules
364 // itself or schedules the provided callback to run on the client runner (if
365 // all domains are loaded).
366 void ChainLoadCookies(LoadedCallback loaded_callback);
367
368 // Load all cookies for a set of domains/hosts. The error recovery code
369 // assumes |key| includes all related domains within an eTLD + 1.
370 bool LoadCookiesForDomains(const std::set<std::string>& key);
371
372 void DeleteTopFrameSiteKeys(
373 const std::unordered_set<std::string>& top_frame_site_keys);
374
375 // Batch a cookie operation (add or delete)
376 void BatchOperation(PendingOperation::OperationType op,
377 const CanonicalCookie& cc);
378 // Commit our pending operations to the database.
379 void DoCommit() override;
380
381 void DeleteSessionCookiesOnStartup();
382
383 void BackgroundDeleteAllInList(const std::list<CookieOrigin>& cookies);
384
385 // Shared code between the different load strategies to be used after all
386 // cookies have been loaded.
387 void FinishedLoadingCookies(LoadedCallback loaded_callback, bool success);
388
RecordOpenDBProblem()389 void RecordOpenDBProblem() override {
390 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_OPEN_DB);
391 }
392
RecordDBMigrationProblem()393 void RecordDBMigrationProblem() override {
394 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_OPEN_DB);
395 }
396
397 typedef std::list<std::unique_ptr<PendingOperation>> PendingOperationsForKey;
398 typedef std::map<CanonicalCookie::UniqueCookieKey, PendingOperationsForKey>
399 PendingOperationsMap;
400 PendingOperationsMap pending_ GUARDED_BY(lock_);
401 PendingOperationsMap::size_type num_pending_ GUARDED_BY(lock_) = 0;
402 // Guard |cookies_|, |pending_|, |num_pending_|.
403 base::Lock lock_;
404
405 // Temporary buffer for cookies loaded from DB. Accumulates cookies to reduce
406 // the number of messages sent to the client runner. Sent back in response to
407 // individual load requests for domain keys or when all loading completes.
408 std::vector<std::unique_ptr<CanonicalCookie>> cookies_ GUARDED_BY(lock_);
409
410 // Map of domain keys(eTLD+1) to domains/hosts that are to be loaded from DB.
411 std::map<std::string, std::set<std::string>> keys_to_load_;
412
413 // If false, we should filter out session cookies when reading the DB.
414 bool restore_old_session_cookies_;
415
416 // The cumulative time spent loading the cookies on the background runner.
417 // Incremented and reported from the background runner.
418 base::TimeDelta cookie_load_duration_;
419
420 // Guards the following metrics-related properties (only accessed when
421 // starting/completing priority loads or completing the total load).
422 base::Lock metrics_lock_;
423 int num_priority_waiting_ GUARDED_BY(metrics_lock_) = 0;
424 // The total number of priority requests.
425 int total_priority_requests_ GUARDED_BY(metrics_lock_) = 0;
426 // The time when |num_priority_waiting_| incremented to 1.
427 base::Time current_priority_wait_start_ GUARDED_BY(metrics_lock_);
428 // The cumulative duration of time when |num_priority_waiting_| was greater
429 // than 1.
430 base::TimeDelta priority_wait_duration_ GUARDED_BY(metrics_lock_);
431 // Class with functions that do cryptographic operations (for protecting
432 // cookies stored persistently).
433 //
434 // Not owned.
435 raw_ptr<CookieCryptoDelegate, DanglingUntriaged> crypto_;
436 };
437
438 namespace {
439
440 // Possible values for the 'priority' column.
441 enum DBCookiePriority {
442 kCookiePriorityLow = 0,
443 kCookiePriorityMedium = 1,
444 kCookiePriorityHigh = 2,
445 };
446
CookiePriorityToDBCookiePriority(CookiePriority value)447 DBCookiePriority CookiePriorityToDBCookiePriority(CookiePriority value) {
448 switch (value) {
449 case COOKIE_PRIORITY_LOW:
450 return kCookiePriorityLow;
451 case COOKIE_PRIORITY_MEDIUM:
452 return kCookiePriorityMedium;
453 case COOKIE_PRIORITY_HIGH:
454 return kCookiePriorityHigh;
455 }
456
457 NOTREACHED();
458 return kCookiePriorityMedium;
459 }
460
DBCookiePriorityToCookiePriority(DBCookiePriority value)461 CookiePriority DBCookiePriorityToCookiePriority(DBCookiePriority value) {
462 switch (value) {
463 case kCookiePriorityLow:
464 return COOKIE_PRIORITY_LOW;
465 case kCookiePriorityMedium:
466 return COOKIE_PRIORITY_MEDIUM;
467 case kCookiePriorityHigh:
468 return COOKIE_PRIORITY_HIGH;
469 }
470
471 NOTREACHED();
472 return COOKIE_PRIORITY_DEFAULT;
473 }
474
475 // Possible values for the 'samesite' column
476 enum DBCookieSameSite {
477 kCookieSameSiteUnspecified = -1,
478 kCookieSameSiteNoRestriction = 0,
479 kCookieSameSiteLax = 1,
480 kCookieSameSiteStrict = 2,
481 // Deprecated, mapped to kCookieSameSiteUnspecified.
482 kCookieSameSiteExtended = 3
483 };
484
CookieSameSiteToDBCookieSameSite(CookieSameSite value)485 DBCookieSameSite CookieSameSiteToDBCookieSameSite(CookieSameSite value) {
486 switch (value) {
487 case CookieSameSite::NO_RESTRICTION:
488 return kCookieSameSiteNoRestriction;
489 case CookieSameSite::LAX_MODE:
490 return kCookieSameSiteLax;
491 case CookieSameSite::STRICT_MODE:
492 return kCookieSameSiteStrict;
493 case CookieSameSite::UNSPECIFIED:
494 return kCookieSameSiteUnspecified;
495 }
496 }
497
DBCookieSameSiteToCookieSameSite(DBCookieSameSite value)498 CookieSameSite DBCookieSameSiteToCookieSameSite(DBCookieSameSite value) {
499 CookieSameSite samesite = CookieSameSite::UNSPECIFIED;
500 switch (value) {
501 case kCookieSameSiteNoRestriction:
502 samesite = CookieSameSite::NO_RESTRICTION;
503 break;
504 case kCookieSameSiteLax:
505 samesite = CookieSameSite::LAX_MODE;
506 break;
507 case kCookieSameSiteStrict:
508 samesite = CookieSameSite::STRICT_MODE;
509 break;
510 // SameSite=Extended is deprecated, so we map to UNSPECIFIED.
511 case kCookieSameSiteExtended:
512 case kCookieSameSiteUnspecified:
513 samesite = CookieSameSite::UNSPECIFIED;
514 break;
515 }
516 return samesite;
517 }
518
DBToCookieSourceScheme(int value)519 CookieSourceScheme DBToCookieSourceScheme(int value) {
520 int enum_max_value = static_cast<int>(CookieSourceScheme::kMaxValue);
521
522 if (value < 0 || value > enum_max_value) {
523 DLOG(WARNING) << "DB read of cookie's source scheme is invalid. Resetting "
524 "value to unset.";
525 value = static_cast<int>(
526 CookieSourceScheme::kUnset); // Reset value to a known, useful, state.
527 }
528
529 return static_cast<CookieSourceScheme>(value);
530 }
531
532 // Increments a specified TimeDelta by the duration between this object's
533 // constructor and destructor. Not thread safe. Multiple instances may be
534 // created with the same delta instance as long as their lifetimes are nested.
535 // The shortest lived instances have no impact.
536 class IncrementTimeDelta {
537 public:
IncrementTimeDelta(base::TimeDelta * delta)538 explicit IncrementTimeDelta(base::TimeDelta* delta)
539 : delta_(delta), original_value_(*delta), start_(base::Time::Now()) {}
540
541 IncrementTimeDelta(const IncrementTimeDelta&) = delete;
542 IncrementTimeDelta& operator=(const IncrementTimeDelta&) = delete;
543
~IncrementTimeDelta()544 ~IncrementTimeDelta() {
545 *delta_ = original_value_ + base::Time::Now() - start_;
546 }
547
548 private:
549 raw_ptr<base::TimeDelta> delta_;
550 base::TimeDelta original_value_;
551 base::Time start_;
552 };
553
554 // Initializes the cookies table, returning true on success.
555 // The table cannot exist when calling this function.
CreateV10Schema(sql::Database * db)556 bool CreateV10Schema(sql::Database* db) {
557 DCHECK(!db->DoesTableExist("cookies"));
558
559 std::string stmt(base::StringPrintf(
560 "CREATE TABLE cookies("
561 "creation_utc INTEGER NOT NULL,"
562 "host_key TEXT NOT NULL,"
563 "name TEXT NOT NULL,"
564 "value TEXT NOT NULL,"
565 "path TEXT NOT NULL,"
566 "expires_utc INTEGER NOT NULL,"
567 "is_secure INTEGER NOT NULL,"
568 "is_httponly INTEGER NOT NULL,"
569 "last_access_utc INTEGER NOT NULL,"
570 "has_expires INTEGER NOT NULL DEFAULT 1,"
571 "is_persistent INTEGER NOT NULL DEFAULT 1,"
572 "priority INTEGER NOT NULL DEFAULT %d,"
573 "encrypted_value BLOB DEFAULT '',"
574 "firstpartyonly INTEGER NOT NULL DEFAULT %d,"
575 "UNIQUE (host_key, name, path))",
576 CookiePriorityToDBCookiePriority(COOKIE_PRIORITY_DEFAULT),
577 CookieSameSiteToDBCookieSameSite(CookieSameSite::NO_RESTRICTION)));
578 if (!db->Execute(stmt.c_str()))
579 return false;
580
581 return true;
582 }
583
584 // Initializes the cookies table, returning true on success.
585 // The table cannot exist when calling this function.
CreateV11Schema(sql::Database * db)586 bool CreateV11Schema(sql::Database* db) {
587 DCHECK(!db->DoesTableExist("cookies"));
588
589 std::string stmt(base::StringPrintf(
590 "CREATE TABLE cookies("
591 "creation_utc INTEGER NOT NULL,"
592 "host_key TEXT NOT NULL,"
593 "name TEXT NOT NULL,"
594 "value TEXT NOT NULL,"
595 "path TEXT NOT NULL,"
596 "expires_utc INTEGER NOT NULL,"
597 "is_secure INTEGER NOT NULL,"
598 "is_httponly INTEGER NOT NULL,"
599 "last_access_utc INTEGER NOT NULL,"
600 "has_expires INTEGER NOT NULL DEFAULT 1,"
601 "is_persistent INTEGER NOT NULL DEFAULT 1,"
602 "priority INTEGER NOT NULL DEFAULT %d,"
603 "encrypted_value BLOB DEFAULT '',"
604 "samesite INTEGER NOT NULL DEFAULT %d,"
605 "UNIQUE (host_key, name, path))",
606 CookiePriorityToDBCookiePriority(COOKIE_PRIORITY_DEFAULT),
607 CookieSameSiteToDBCookieSameSite(CookieSameSite::UNSPECIFIED)));
608 if (!db->Execute(stmt.c_str()))
609 return false;
610
611 return true;
612 }
613
614 // Initializes the cookies table, returning true on success.
615 // The table cannot exist when calling this function.
CreateV15Schema(sql::Database * db)616 bool CreateV15Schema(sql::Database* db) {
617 DCHECK(!db->DoesTableExist("cookies"));
618
619 std::string stmt(base::StringPrintf(
620 "CREATE TABLE cookies("
621 "creation_utc INTEGER NOT NULL,"
622 "top_frame_site_key TEXT NOT NULL,"
623 "host_key TEXT NOT NULL,"
624 "name TEXT NOT NULL,"
625 "value TEXT NOT NULL,"
626 "encrypted_value BLOB DEFAULT '',"
627 "path TEXT NOT NULL,"
628 "expires_utc INTEGER NOT NULL,"
629 "is_secure INTEGER NOT NULL,"
630 "is_httponly INTEGER NOT NULL,"
631 "last_access_utc INTEGER NOT NULL,"
632 "has_expires INTEGER NOT NULL DEFAULT 1,"
633 "is_persistent INTEGER NOT NULL DEFAULT 1,"
634 "priority INTEGER NOT NULL DEFAULT %d,"
635 "samesite INTEGER NOT NULL DEFAULT %d,"
636 "source_scheme INTEGER NOT NULL DEFAULT %d,"
637 "source_port INTEGER NOT NULL DEFAULT %d,"
638 "is_same_party INTEGER NOT NULL DEFAULT 0,"
639 "UNIQUE (top_frame_site_key, host_key, name, path))",
640 CookiePriorityToDBCookiePriority(COOKIE_PRIORITY_DEFAULT),
641 CookieSameSiteToDBCookieSameSite(CookieSameSite::UNSPECIFIED),
642 static_cast<int>(CookieSourceScheme::kUnset),
643 SQLitePersistentCookieStore::kDefaultUnknownPort));
644 if (!db->Execute(stmt.c_str()))
645 return false;
646
647 return true;
648 }
649
650 // Initializes the cookies table, returning true on success.
651 // The table cannot exist when calling this function.
CreateV16Schema(sql::Database * db)652 bool CreateV16Schema(sql::Database* db) {
653 DCHECK(!db->DoesTableExist("cookies"));
654
655 const char* kCreateTableQuery =
656 "CREATE TABLE cookies("
657 "creation_utc INTEGER NOT NULL,"
658 "host_key TEXT NOT NULL,"
659 "top_frame_site_key TEXT NOT NULL,"
660 "name TEXT NOT NULL,"
661 "value TEXT NOT NULL,"
662 "encrypted_value BLOB NOT NULL,"
663 "path TEXT NOT NULL,"
664 "expires_utc INTEGER NOT NULL,"
665 "is_secure INTEGER NOT NULL,"
666 "is_httponly INTEGER NOT NULL,"
667 "last_access_utc INTEGER NOT NULL,"
668 "has_expires INTEGER NOT NULL,"
669 "is_persistent INTEGER NOT NULL,"
670 "priority INTEGER NOT NULL,"
671 "samesite INTEGER NOT NULL,"
672 "source_scheme INTEGER NOT NULL,"
673 "source_port INTEGER NOT NULL,"
674 "is_same_party INTEGER NOT NULL);";
675
676 const char* kCreateIndexQuery =
677 "CREATE UNIQUE INDEX cookies_unique_index "
678 "ON cookies(host_key, top_frame_site_key, name, path)";
679
680 if (!db->Execute(kCreateTableQuery))
681 return false;
682 if (!db->Execute(kCreateIndexQuery))
683 return false;
684
685 return true;
686 }
687
688 // Initializes the cookies table, returning true on success.
689 // The table/index cannot exist when calling this function.
CreateV17Schema(sql::Database * db)690 bool CreateV17Schema(sql::Database* db) {
691 return CreateV16Schema(db);
692 }
693
694 // Initializes the cookies table, returning true on success.
695 // The table cannot exist when calling this function.
CreateV18Schema(sql::Database * db)696 bool CreateV18Schema(sql::Database* db) {
697 DCHECK(!db->DoesTableExist("cookies"));
698
699 const char* kCreateTableQuery =
700 "CREATE TABLE cookies("
701 "creation_utc INTEGER NOT NULL,"
702 "host_key TEXT NOT NULL,"
703 "top_frame_site_key TEXT NOT NULL,"
704 "name TEXT NOT NULL,"
705 "value TEXT NOT NULL,"
706 "encrypted_value BLOB NOT NULL,"
707 "path TEXT NOT NULL,"
708 "expires_utc INTEGER NOT NULL,"
709 "is_secure INTEGER NOT NULL,"
710 "is_httponly INTEGER NOT NULL,"
711 "last_access_utc INTEGER NOT NULL,"
712 "has_expires INTEGER NOT NULL,"
713 "is_persistent INTEGER NOT NULL,"
714 "priority INTEGER NOT NULL,"
715 "samesite INTEGER NOT NULL,"
716 "source_scheme INTEGER NOT NULL,"
717 "source_port INTEGER NOT NULL,"
718 "is_same_party INTEGER NOT NULL,"
719 "last_update_utc INTEGER NOT NULL);";
720
721 const char* kCreateIndexQuery =
722 "CREATE UNIQUE INDEX cookies_unique_index "
723 "ON cookies(host_key, top_frame_site_key, name, path)";
724
725 if (!db->Execute(kCreateTableQuery))
726 return false;
727 if (!db->Execute(kCreateIndexQuery))
728 return false;
729
730 return true;
731 }
732
733 } // namespace
734
Load(LoadedCallback loaded_callback)735 void SQLitePersistentCookieStore::Backend::Load(
736 LoadedCallback loaded_callback) {
737 PostBackgroundTask(FROM_HERE,
738 base::BindOnce(&Backend::LoadAndNotifyInBackground, this,
739 std::move(loaded_callback)));
740 }
741
LoadCookiesForKey(const std::string & key,LoadedCallback loaded_callback)742 void SQLitePersistentCookieStore::Backend::LoadCookiesForKey(
743 const std::string& key,
744 LoadedCallback loaded_callback) {
745 {
746 base::AutoLock locked(metrics_lock_);
747 if (num_priority_waiting_ == 0)
748 current_priority_wait_start_ = base::Time::Now();
749 num_priority_waiting_++;
750 total_priority_requests_++;
751 }
752
753 PostBackgroundTask(
754 FROM_HERE, base::BindOnce(&Backend::LoadKeyAndNotifyInBackground, this,
755 key, std::move(loaded_callback)));
756 }
757
LoadAndNotifyInBackground(LoadedCallback loaded_callback)758 void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground(
759 LoadedCallback loaded_callback) {
760 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
761 IncrementTimeDelta increment(&cookie_load_duration_);
762
763 if (!InitializeDatabase()) {
764 PostClientTask(FROM_HERE,
765 base::BindOnce(&Backend::CompleteLoadInForeground, this,
766 std::move(loaded_callback), false));
767 } else {
768 ChainLoadCookies(std::move(loaded_callback));
769 }
770 }
771
LoadKeyAndNotifyInBackground(const std::string & key,LoadedCallback loaded_callback)772 void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyInBackground(
773 const std::string& key,
774 LoadedCallback loaded_callback) {
775 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
776 IncrementTimeDelta increment(&cookie_load_duration_);
777
778 bool success = false;
779 if (InitializeDatabase()) {
780 auto it = keys_to_load_.find(key);
781 if (it != keys_to_load_.end()) {
782 success = LoadCookiesForDomains(it->second);
783 keys_to_load_.erase(it);
784 } else {
785 success = true;
786 }
787 }
788
789 PostClientTask(
790 FROM_HERE,
791 base::BindOnce(
792 &SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground,
793 this, std::move(loaded_callback), success));
794 }
795
CompleteLoadForKeyInForeground(LoadedCallback loaded_callback,bool load_success)796 void SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground(
797 LoadedCallback loaded_callback,
798 bool load_success) {
799 DCHECK(client_task_runner()->RunsTasksInCurrentSequence());
800
801 Notify(std::move(loaded_callback), load_success);
802
803 {
804 base::AutoLock locked(metrics_lock_);
805 num_priority_waiting_--;
806 if (num_priority_waiting_ == 0) {
807 priority_wait_duration_ +=
808 base::Time::Now() - current_priority_wait_start_;
809 }
810 }
811 }
812
CompleteLoadInForeground(LoadedCallback loaded_callback,bool load_success)813 void SQLitePersistentCookieStore::Backend::CompleteLoadInForeground(
814 LoadedCallback loaded_callback,
815 bool load_success) {
816 Notify(std::move(loaded_callback), load_success);
817 }
818
Notify(LoadedCallback loaded_callback,bool load_success)819 void SQLitePersistentCookieStore::Backend::Notify(
820 LoadedCallback loaded_callback,
821 bool load_success) {
822 DCHECK(client_task_runner()->RunsTasksInCurrentSequence());
823
824 std::vector<std::unique_ptr<CanonicalCookie>> cookies;
825 {
826 base::AutoLock locked(lock_);
827 cookies.swap(cookies_);
828 }
829
830 std::move(loaded_callback).Run(std::move(cookies));
831 }
832
CreateDatabaseSchema()833 bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() {
834 DCHECK(db());
835
836 if (db()->DoesTableExist("cookies"))
837 return true;
838
839 return CreateV18Schema(db());
840 }
841
DoInitializeDatabase()842 bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() {
843 DCHECK(db());
844
845 // Retrieve all the domains
846 sql::Statement smt(
847 db()->GetUniqueStatement("SELECT DISTINCT host_key FROM cookies"));
848
849 if (!smt.is_valid()) {
850 Reset();
851 return false;
852 }
853
854 std::vector<std::string> host_keys;
855 while (smt.Step())
856 host_keys.push_back(smt.ColumnString(0));
857
858 // Build a map of domain keys (always eTLD+1) to domains.
859 for (const auto& domain : host_keys) {
860 std::string key = CookieMonster::GetKey(domain);
861 keys_to_load_[key].insert(domain);
862 }
863
864 if (!restore_old_session_cookies_)
865 DeleteSessionCookiesOnStartup();
866
867 return true;
868 }
869
ChainLoadCookies(LoadedCallback loaded_callback)870 void SQLitePersistentCookieStore::Backend::ChainLoadCookies(
871 LoadedCallback loaded_callback) {
872 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
873 IncrementTimeDelta increment(&cookie_load_duration_);
874
875 bool load_success = true;
876
877 if (!db()) {
878 // Close() has been called on this store.
879 load_success = false;
880 } else if (keys_to_load_.size() > 0) {
881 // Load cookies for the first domain key.
882 auto it = keys_to_load_.begin();
883 load_success = LoadCookiesForDomains(it->second);
884 keys_to_load_.erase(it);
885 }
886
887 // If load is successful and there are more domain keys to be loaded,
888 // then post a background task to continue chain-load;
889 // Otherwise notify on client runner.
890 if (load_success && keys_to_load_.size() > 0) {
891 bool success = background_task_runner()->PostDelayedTask(
892 FROM_HERE,
893 base::BindOnce(&Backend::ChainLoadCookies, this,
894 std::move(loaded_callback)),
895 base::Milliseconds(kLoadDelayMilliseconds));
896 if (!success) {
897 LOG(WARNING) << "Failed to post task from " << FROM_HERE.ToString()
898 << " to background_task_runner().";
899 }
900 } else {
901 FinishedLoadingCookies(std::move(loaded_callback), load_success);
902 }
903 }
904
LoadCookiesForDomains(const std::set<std::string> & domains)905 bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
906 const std::set<std::string>& domains) {
907 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
908
909 sql::Statement smt, delete_statement;
910 if (restore_old_session_cookies_) {
911 smt.Assign(db()->GetCachedStatement(
912 SQL_FROM_HERE,
913 "SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
914 "expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
915 "is_persistent, priority, encrypted_value, samesite, source_scheme, "
916 "source_port, is_same_party, last_update_utc FROM cookies WHERE "
917 "host_key = ?"));
918 } else {
919 smt.Assign(db()->GetCachedStatement(
920 SQL_FROM_HERE,
921 "SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
922 "expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
923 "is_persistent, priority, encrypted_value, samesite, source_scheme, "
924 "source_port, is_same_party, last_update_utc FROM cookies WHERE "
925 "host_key = ? AND "
926 "is_persistent = 1"));
927 }
928 delete_statement.Assign(db()->GetCachedStatement(
929 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key = ?"));
930 if (!smt.is_valid() || !delete_statement.is_valid()) {
931 delete_statement.Clear();
932 smt.Clear(); // Disconnect smt_ref from db_.
933 Reset();
934 return false;
935 }
936
937 std::vector<std::unique_ptr<CanonicalCookie>> cookies;
938 std::unordered_set<std::string> top_frame_site_keys_to_delete;
939 auto it = domains.begin();
940 bool ok = true;
941 for (; it != domains.end() && ok; ++it) {
942 smt.BindString(0, *it);
943 ok = MakeCookiesFromSQLStatement(cookies, smt,
944 top_frame_site_keys_to_delete);
945 smt.Reset(true);
946 }
947
948 DeleteTopFrameSiteKeys(std::move(top_frame_site_keys_to_delete));
949
950 if (ok) {
951 base::AutoLock locked(lock_);
952 std::move(cookies.begin(), cookies.end(), std::back_inserter(cookies_));
953 } else {
954 // There were some cookies that were in database but could not be loaded
955 // and handed over to CookieMonster. This is trouble since it means that
956 // if some website tries to send them again, CookieMonster won't know to
957 // issue a delete, and then the addition would violate the uniqueness
958 // constraints and not go through.
959 //
960 // For data consistency, we drop the entire eTLD group.
961 for (const std::string& domain : domains) {
962 delete_statement.BindString(0, domain);
963 if (!delete_statement.Run()) {
964 // TODO(morlovich): Is something more drastic called for here?
965 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_RECOVERY_FAILED);
966 }
967 delete_statement.Reset(true);
968 }
969 }
970 return true;
971 }
972
DeleteTopFrameSiteKeys(const std::unordered_set<std::string> & top_frame_site_keys)973 void SQLitePersistentCookieStore::Backend::DeleteTopFrameSiteKeys(
974 const std::unordered_set<std::string>& top_frame_site_keys) {
975 if (top_frame_site_keys.empty())
976 return;
977
978 sql::Statement delete_statement;
979 delete_statement.Assign(db()->GetCachedStatement(
980 SQL_FROM_HERE, "DELETE FROM cookies WHERE top_frame_site_key = ?"));
981 if (!delete_statement.is_valid())
982 return;
983
984 for (const std::string& key : top_frame_site_keys) {
985 delete_statement.BindString(0, key);
986 if (!delete_statement.Run())
987 RecordCookieLoadProblem(COOKIE_LOAD_DELETE_COOKIE_PARTITION_FAILED);
988 delete_statement.Reset(true);
989 }
990 }
991
MakeCookiesFromSQLStatement(std::vector<std::unique_ptr<CanonicalCookie>> & cookies,sql::Statement & statement,std::unordered_set<std::string> & top_frame_site_keys_to_delete)992 bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
993 std::vector<std::unique_ptr<CanonicalCookie>>& cookies,
994 sql::Statement& statement,
995 std::unordered_set<std::string>& top_frame_site_keys_to_delete) {
996 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
997 bool ok = true;
998 while (statement.Step()) {
999 std::string value;
1000 std::string encrypted_value = statement.ColumnString(13);
1001 if (!encrypted_value.empty() && crypto_) {
1002 bool decrypt_ok = crypto_->DecryptString(encrypted_value, &value);
1003 if (!decrypt_ok) {
1004 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_DECRYPT_FAILED);
1005 ok = false;
1006 continue;
1007 }
1008 } else {
1009 value = statement.ColumnString(4);
1010 }
1011
1012 absl::optional<CookiePartitionKey> cookie_partition_key;
1013 std::string top_frame_site_key = statement.ColumnString(2);
1014 // If we can't deserialize a top_frame_site_key, we delete any cookie with
1015 // that key.
1016 if (!CookiePartitionKey::Deserialize(top_frame_site_key,
1017 cookie_partition_key)) {
1018 top_frame_site_keys_to_delete.insert(std::move(top_frame_site_key));
1019 continue;
1020 }
1021
1022 // Returns nullptr if the resulting cookie is not canonical.
1023 std::unique_ptr<net::CanonicalCookie> cc = CanonicalCookie::FromStorage(
1024 statement.ColumnString(3), // name
1025 value, // value
1026 statement.ColumnString(1), // domain
1027 statement.ColumnString(5), // path
1028 statement.ColumnTime(0), // creation_utc
1029 statement.ColumnTime(6), // expires_utc
1030 statement.ColumnTime(9), // last_access_utc
1031 statement.ColumnTime(18), // last_update_utc
1032 statement.ColumnBool(7), // secure
1033 statement.ColumnBool(8), // http_only
1034 DBCookieSameSiteToCookieSameSite(static_cast<DBCookieSameSite>(
1035 statement.ColumnInt(14))), // samesite
1036 DBCookiePriorityToCookiePriority(static_cast<DBCookiePriority>(
1037 statement.ColumnInt(12))), // priority
1038 statement.ColumnBool(17), // is_same_party
1039 std::move(cookie_partition_key), // top_frame_site_key
1040 DBToCookieSourceScheme(statement.ColumnInt(15)), // source_scheme
1041 statement.ColumnInt(16)); // source_port
1042 if (cc) {
1043 DLOG_IF(WARNING, cc->CreationDate() > Time::Now())
1044 << "CreationDate too recent";
1045 if (!cc->LastUpdateDate().is_null()) {
1046 DLOG_IF(WARNING, cc->LastUpdateDate() > Time::Now())
1047 << "LastUpdateDate too recent";
1048 // In order to anticipate the potential effects of the expiry limit in
1049 // rfc6265bis, we need to check how long it's been since the cookie was
1050 // refreshed (if LastUpdateDate is populated). We use 100 buckets for
1051 // the highest reasonable granularity, set 1 day as the minimum and
1052 // don't track over a 400 max (since these cookies will expire anyway).
1053 UMA_HISTOGRAM_CUSTOM_COUNTS(
1054 "Cookie.DaysSinceRefreshForRetrieval",
1055 (base::Time::Now() - cc->LastUpdateDate()).InDays(), 1, 400, 100);
1056 }
1057 cookies.push_back(std::move(cc));
1058 } else {
1059 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_NON_CANONICAL);
1060 ok = false;
1061 }
1062 }
1063
1064 return ok;
1065 }
1066
1067 absl::optional<int>
DoMigrateDatabaseSchema()1068 SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() {
1069 int cur_version = meta_table()->GetVersionNumber();
1070 if (cur_version == 9) {
1071 sql::Transaction transaction(db());
1072 if (!transaction.Begin())
1073 return absl::nullopt;
1074
1075 if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old"))
1076 return absl::nullopt;
1077 if (!db()->Execute("DROP INDEX IF EXISTS domain"))
1078 return absl::nullopt;
1079 if (!db()->Execute("DROP INDEX IF EXISTS is_transient"))
1080 return absl::nullopt;
1081
1082 if (!CreateV10Schema(db())) {
1083 // Not clear what good a false return here will do since the calling
1084 // code will just init the table.
1085 // TODO(rdsmith): Also, wait, nothing drops the old table and
1086 // InitTable() just returns true if the table exists, so if
1087 // EnsureDatabaseVersion() fails, initting the table won't do any
1088 // further good. Fix?
1089 return absl::nullopt;
1090 }
1091 // If any cookies violate the new uniqueness constraints (no two
1092 // cookies with the same (name, domain, path)), pick the newer version,
1093 // since that's what CookieMonster would do anyway.
1094 if (!db()->Execute(
1095 "INSERT OR REPLACE INTO cookies "
1096 "(creation_utc, host_key, name, value, path, expires_utc, "
1097 "is_secure, is_httponly, last_access_utc, has_expires, "
1098 "is_persistent, priority, encrypted_value, firstpartyonly) "
1099 "SELECT creation_utc, host_key, name, value, path, expires_utc, "
1100 " secure, httponly, last_access_utc, has_expires, "
1101 " persistent, priority, encrypted_value, firstpartyonly "
1102 "FROM cookies_old ORDER BY creation_utc ASC")) {
1103 return absl::nullopt;
1104 }
1105 if (!db()->Execute("DROP TABLE cookies_old"))
1106 return absl::nullopt;
1107 ++cur_version;
1108 if (!meta_table()->SetVersionNumber(cur_version) ||
1109 !meta_table()->SetCompatibleVersionNumber(
1110 std::min(cur_version, kCompatibleVersionNumber)) ||
1111 !transaction.Commit()) {
1112 return absl::nullopt;
1113 }
1114 }
1115
1116 if (cur_version == 10) {
1117 sql::Transaction transaction(db());
1118 if (!transaction.Begin())
1119 return absl::nullopt;
1120
1121 // Copy the data into a new table, renaming the firstpartyonly column to
1122 // samesite.
1123 if (!db()->Execute("DROP TABLE IF EXISTS cookies_old; "
1124 "ALTER TABLE cookies RENAME TO cookies_old"))
1125 return absl::nullopt;
1126 if (!CreateV11Schema(db()))
1127 return absl::nullopt;
1128 if (!db()->Execute(
1129 "INSERT INTO cookies "
1130 "(creation_utc, host_key, name, value, path, expires_utc, "
1131 "is_secure, is_httponly, last_access_utc, has_expires, "
1132 "is_persistent, priority, encrypted_value, samesite) "
1133 "SELECT creation_utc, host_key, name, value, path, expires_utc, "
1134 " is_secure, is_httponly, last_access_utc, has_expires, "
1135 " is_persistent, priority, encrypted_value, firstpartyonly "
1136 "FROM cookies_old")) {
1137 return absl::nullopt;
1138 }
1139 if (!db()->Execute("DROP TABLE cookies_old"))
1140 return absl::nullopt;
1141
1142 // Update stored SameSite values of kCookieSameSiteNoRestriction into
1143 // kCookieSameSiteUnspecified.
1144 std::string update_stmt(base::StringPrintf(
1145 "UPDATE cookies SET samesite=%d WHERE samesite=%d",
1146 CookieSameSiteToDBCookieSameSite(CookieSameSite::UNSPECIFIED),
1147 CookieSameSiteToDBCookieSameSite(CookieSameSite::NO_RESTRICTION)));
1148 if (!db()->Execute(update_stmt.c_str()))
1149 return absl::nullopt;
1150
1151 ++cur_version;
1152 if (!meta_table()->SetVersionNumber(cur_version) ||
1153 !meta_table()->SetCompatibleVersionNumber(
1154 std::min(cur_version, kCompatibleVersionNumber)) ||
1155 !transaction.Commit()) {
1156 return absl::nullopt;
1157 }
1158 }
1159
1160 if (cur_version == 11) {
1161 sql::Transaction transaction(db());
1162 if (!transaction.Begin())
1163 return absl::nullopt;
1164
1165 std::string update_stmt(
1166 base::StringPrintf("ALTER TABLE cookies ADD COLUMN source_scheme "
1167 "INTEGER NOT NULL DEFAULT %d;",
1168 static_cast<int>(CookieSourceScheme::kUnset)));
1169 if (!db()->Execute(update_stmt.c_str()))
1170 return absl::nullopt;
1171
1172 ++cur_version;
1173 if (!meta_table()->SetVersionNumber(cur_version) ||
1174 !meta_table()->SetCompatibleVersionNumber(
1175 std::min(cur_version, kCompatibleVersionNumber)) ||
1176 !transaction.Commit()) {
1177 return absl::nullopt;
1178 }
1179 }
1180
1181 if (cur_version == 12) {
1182 sql::Transaction transaction(db());
1183 if (!transaction.Begin())
1184 return absl::nullopt;
1185
1186 std::string update_stmt(
1187 base::StringPrintf("ALTER TABLE cookies ADD COLUMN source_port "
1188 "INTEGER NOT NULL DEFAULT %d;"
1189 "ALTER TABLE cookies ADD COLUMN is_same_party "
1190 "INTEGER NOT NULL DEFAULT 0;",
1191 kDefaultUnknownPort));
1192 if (!db()->Execute(update_stmt.c_str()))
1193 return absl::nullopt;
1194
1195 ++cur_version;
1196 if (!meta_table()->SetVersionNumber(cur_version) ||
1197 !meta_table()->SetCompatibleVersionNumber(
1198 std::min(cur_version, kCompatibleVersionNumber)) ||
1199 !transaction.Commit()) {
1200 return absl::nullopt;
1201 }
1202 }
1203
1204 if (cur_version == 13) {
1205 sql::Transaction transaction(db());
1206 if (!transaction.Begin())
1207 return absl::nullopt;
1208
1209 #if BUILDFLAG(IS_WIN)
1210 // Migration is only needed on Windows. On other platforms, this is a no-op.
1211 if (crypto_ && crypto_->ShouldEncrypt()) {
1212 sql::Statement select_statement, update_statement;
1213
1214 select_statement.Assign(
1215 db()->GetCachedStatement(SQL_FROM_HERE,
1216 "SELECT rowid, encrypted_value "
1217 "FROM cookies WHERE encrypted_value != ''"));
1218
1219 update_statement.Assign(
1220 db()->GetCachedStatement(SQL_FROM_HERE,
1221 "UPDATE cookies SET encrypted_value=? WHERE "
1222 "rowid=?"));
1223
1224 if (!select_statement.is_valid() || !update_statement.is_valid())
1225 return absl::nullopt;
1226
1227 std::map<int64_t, std::string> encrypted_values;
1228
1229 while (select_statement.Step()) {
1230 int64_t rowid = select_statement.ColumnInt64(0);
1231 std::string encrypted_value = select_statement.ColumnString(1);
1232 DCHECK(!encrypted_value.empty());
1233 std::string decrypted_value;
1234 if (!crypto_->DecryptString(encrypted_value, &decrypted_value)) {
1235 RecordCookieLoadProblem(COOKIE_LOAD_PROBLEM_DECRYPT_FAILED);
1236 continue;
1237 }
1238 std::string new_encrypted_value;
1239 if (!crypto_->EncryptString(decrypted_value, &new_encrypted_value)) {
1240 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED);
1241 continue;
1242 }
1243 encrypted_values[rowid] = new_encrypted_value;
1244 }
1245
1246 for (const auto& entry : encrypted_values) {
1247 update_statement.Reset(true);
1248 update_statement.BindString(0, entry.second);
1249 update_statement.BindInt64(1, entry.first);
1250 if (!update_statement.Run())
1251 return absl::nullopt;
1252 }
1253 }
1254 #endif
1255 ++cur_version;
1256 if (!meta_table()->SetVersionNumber(cur_version) ||
1257 !meta_table()->SetCompatibleVersionNumber(
1258 std::min(cur_version, kCompatibleVersionNumber)) ||
1259 !transaction.Commit()) {
1260 return absl::nullopt;
1261 }
1262 }
1263
1264 if (cur_version == 14) {
1265 sql::Transaction transaction(db());
1266 if (!transaction.Begin())
1267 return absl::nullopt;
1268
1269 if (!db()->Execute("DROP TABLE IF EXISTS cookies_old"))
1270 return absl::nullopt;
1271 if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old"))
1272 return absl::nullopt;
1273
1274 if (!CreateV15Schema(db()))
1275 return absl::nullopt;
1276 std::string insert_cookies_sql = base::StringPrintf(
1277 "INSERT OR REPLACE INTO cookies "
1278 "(creation_utc, top_frame_site_key, host_key, name, value, "
1279 " encrypted_value, path, expires_utc, is_secure, is_httponly, "
1280 " last_access_utc, has_expires, is_persistent, priority, samesite, "
1281 " source_scheme, source_port, is_same_party) "
1282 "SELECT creation_utc, '%s', host_key, name, value, encrypted_value, "
1283 " path, expires_utc, is_secure, is_httponly, last_access_utc, "
1284 " has_expires, is_persistent, priority, samesite, source_scheme, "
1285 " source_port, is_same_party "
1286 "FROM cookies_old ORDER BY creation_utc ASC",
1287 net::kEmptyCookiePartitionKey);
1288 if (!db()->Execute(insert_cookies_sql.c_str()))
1289 return absl::nullopt;
1290 if (!db()->Execute("DROP TABLE cookies_old"))
1291 return absl::nullopt;
1292
1293 ++cur_version;
1294 if (!meta_table()->SetVersionNumber(cur_version) ||
1295 !meta_table()->SetCompatibleVersionNumber(
1296 std::min(cur_version, kCompatibleVersionNumber)) ||
1297 !transaction.Commit()) {
1298 return absl::nullopt;
1299 }
1300 }
1301
1302 if (cur_version == 15) {
1303 sql::Transaction transaction(db());
1304 if (!transaction.Begin())
1305 return absl::nullopt;
1306
1307 if (!db()->Execute("DROP TABLE IF EXISTS cookies_old"))
1308 return absl::nullopt;
1309 if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old"))
1310 return absl::nullopt;
1311
1312 if (!CreateV15Schema(db()))
1313 return absl::nullopt;
1314 std::string insert_cookies_sql = base::StringPrintf(
1315 "INSERT OR REPLACE INTO cookies "
1316 "(creation_utc, host_key, top_frame_site_key, name, value, "
1317 "encrypted_value, path, expires_utc, is_secure, is_httponly, "
1318 "last_access_utc, has_expires, is_persistent, priority, samesite, "
1319 "source_scheme, source_port, is_same_party) "
1320 "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
1321 " encrypted_value, path, expires_utc, is_secure, is_httponly,"
1322 " last_access_utc, has_expires, is_persistent, priority, "
1323 "samesite,"
1324 " source_scheme, source_port, is_same_party "
1325 "FROM cookies_old ORDER BY creation_utc ASC");
1326 if (!db()->Execute(insert_cookies_sql.c_str()))
1327 return absl::nullopt;
1328 if (!db()->Execute("DROP TABLE cookies_old"))
1329 return absl::nullopt;
1330
1331 ++cur_version;
1332 if (!meta_table()->SetVersionNumber(cur_version) ||
1333 !meta_table()->SetCompatibleVersionNumber(
1334 std::min(cur_version, kCompatibleVersionNumber)) ||
1335 !transaction.Commit()) {
1336 return absl::nullopt;
1337 }
1338 }
1339
1340 if (cur_version == 16) {
1341 sql::Transaction transaction(db());
1342 if (!transaction.Begin())
1343 return absl::nullopt;
1344
1345 if (!db()->Execute("DROP TABLE IF EXISTS cookies_old"))
1346 return absl::nullopt;
1347 if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old"))
1348 return absl::nullopt;
1349 if (!db()->Execute("DROP INDEX IF EXISTS cookies_unique_index"))
1350 return absl::nullopt;
1351
1352 if (!CreateV17Schema(db()))
1353 return absl::nullopt;
1354 static constexpr char insert_cookies_sql[] =
1355 "INSERT OR REPLACE INTO cookies "
1356 "(creation_utc, host_key, top_frame_site_key, name, value, "
1357 "encrypted_value, path, expires_utc, is_secure, is_httponly, "
1358 "last_access_utc, has_expires, is_persistent, priority, samesite, "
1359 "source_scheme, source_port, is_same_party) "
1360 "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
1361 " encrypted_value, path, expires_utc, is_secure, is_httponly,"
1362 " last_access_utc, has_expires, is_persistent, priority, "
1363 "samesite,"
1364 " source_scheme, source_port, is_same_party "
1365 "FROM cookies_old ORDER BY creation_utc ASC";
1366 if (!db()->Execute(insert_cookies_sql))
1367 return absl::nullopt;
1368 if (!db()->Execute("DROP TABLE cookies_old"))
1369 return absl::nullopt;
1370
1371 ++cur_version;
1372 if (!meta_table()->SetVersionNumber(cur_version) ||
1373 !meta_table()->SetCompatibleVersionNumber(
1374 std::min(cur_version, kCompatibleVersionNumber)) ||
1375 !transaction.Commit()) {
1376 return absl::nullopt;
1377 }
1378 }
1379
1380 if (cur_version == 17) {
1381 SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeDatabaseMigrationToV18");
1382
1383 sql::Transaction transaction(db());
1384 if (!transaction.Begin())
1385 return absl::nullopt;
1386
1387 if (!db()->Execute("DROP TABLE IF EXISTS cookies_old"))
1388 return absl::nullopt;
1389 if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old"))
1390 return absl::nullopt;
1391 if (!db()->Execute("DROP INDEX IF EXISTS cookies_unique_index"))
1392 return absl::nullopt;
1393
1394 if (!CreateV18Schema(db()))
1395 return absl::nullopt;
1396 static constexpr char insert_cookies_sql[] =
1397 "INSERT OR REPLACE INTO cookies "
1398 "(creation_utc, host_key, top_frame_site_key, name, value, "
1399 "encrypted_value, path, expires_utc, is_secure, is_httponly, "
1400 "last_access_utc, has_expires, is_persistent, priority, samesite, "
1401 "source_scheme, source_port, is_same_party, last_update_utc) "
1402 "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
1403 " encrypted_value, path, expires_utc, is_secure, is_httponly,"
1404 " last_access_utc, has_expires, is_persistent, priority, "
1405 " samesite, source_scheme, source_port, is_same_party, 0 "
1406 "FROM cookies_old ORDER BY creation_utc ASC";
1407 if (!db()->Execute(insert_cookies_sql))
1408 return absl::nullopt;
1409 if (!db()->Execute("DROP TABLE cookies_old"))
1410 return absl::nullopt;
1411
1412 ++cur_version;
1413 if (!meta_table()->SetVersionNumber(cur_version) ||
1414 !meta_table()->SetCompatibleVersionNumber(
1415 std::min(cur_version, kCompatibleVersionNumber)) ||
1416 !transaction.Commit()) {
1417 return absl::nullopt;
1418 }
1419 }
1420
1421 // Put future migration cases here.
1422
1423 return absl::make_optional(cur_version);
1424 }
1425
AddCookie(const CanonicalCookie & cc)1426 void SQLitePersistentCookieStore::Backend::AddCookie(
1427 const CanonicalCookie& cc) {
1428 BatchOperation(PendingOperation::COOKIE_ADD, cc);
1429 }
1430
UpdateCookieAccessTime(const CanonicalCookie & cc)1431 void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime(
1432 const CanonicalCookie& cc) {
1433 BatchOperation(PendingOperation::COOKIE_UPDATEACCESS, cc);
1434 }
1435
DeleteCookie(const CanonicalCookie & cc)1436 void SQLitePersistentCookieStore::Backend::DeleteCookie(
1437 const CanonicalCookie& cc) {
1438 BatchOperation(PendingOperation::COOKIE_DELETE, cc);
1439 }
1440
BatchOperation(PendingOperation::OperationType op,const CanonicalCookie & cc)1441 void SQLitePersistentCookieStore::Backend::BatchOperation(
1442 PendingOperation::OperationType op,
1443 const CanonicalCookie& cc) {
1444 // Commit every 30 seconds.
1445 static const int kCommitIntervalMs = 30 * 1000;
1446 // Commit right away if we have more than 512 outstanding operations.
1447 static const size_t kCommitAfterBatchSize = 512;
1448 DCHECK(!background_task_runner()->RunsTasksInCurrentSequence());
1449
1450 // We do a full copy of the cookie here, and hopefully just here.
1451 auto po = std::make_unique<PendingOperation>(op, cc);
1452
1453 PendingOperationsMap::size_type num_pending;
1454 {
1455 base::AutoLock locked(lock_);
1456 // When queueing the operation, see if it overwrites any already pending
1457 // ones for the same row.
1458 auto key = cc.UniqueKey();
1459 auto iter_and_result =
1460 pending_.insert(std::make_pair(key, PendingOperationsForKey()));
1461 PendingOperationsForKey& ops_for_key = iter_and_result.first->second;
1462 if (!iter_and_result.second) {
1463 // Insert failed -> already have ops.
1464 if (po->op() == PendingOperation::COOKIE_DELETE) {
1465 // A delete op makes all the previous ones irrelevant.
1466 ops_for_key.clear();
1467 } else if (po->op() == PendingOperation::COOKIE_UPDATEACCESS) {
1468 if (!ops_for_key.empty() &&
1469 ops_for_key.back()->op() == PendingOperation::COOKIE_UPDATEACCESS) {
1470 // If access timestamp is updated twice in a row, can dump the earlier
1471 // one.
1472 ops_for_key.pop_back();
1473 }
1474 // At most delete + add before (and no access time updates after above
1475 // conditional).
1476 DCHECK_LE(ops_for_key.size(), 2u);
1477 } else {
1478 // Nothing special is done for adds, since if they're overwriting,
1479 // they'll be preceded by deletes anyway.
1480 DCHECK_LE(ops_for_key.size(), 1u);
1481 }
1482 }
1483 ops_for_key.push_back(std::move(po));
1484 // Note that num_pending_ counts number of calls to BatchOperation(), not
1485 // the current length of the queue; this is intentional to guarantee
1486 // progress, as the length of the queue may decrease in some cases.
1487 num_pending = ++num_pending_;
1488 }
1489
1490 if (num_pending == 1) {
1491 // We've gotten our first entry for this batch, fire off the timer.
1492 if (!background_task_runner()->PostDelayedTask(
1493 FROM_HERE, base::BindOnce(&Backend::Commit, this),
1494 base::Milliseconds(kCommitIntervalMs))) {
1495 NOTREACHED() << "background_task_runner() is not running.";
1496 }
1497 } else if (num_pending == kCommitAfterBatchSize) {
1498 // We've reached a big enough batch, fire off a commit now.
1499 PostBackgroundTask(FROM_HERE, base::BindOnce(&Backend::Commit, this));
1500 }
1501 }
1502
DoCommit()1503 void SQLitePersistentCookieStore::Backend::DoCommit() {
1504 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
1505
1506 PendingOperationsMap ops;
1507 {
1508 base::AutoLock locked(lock_);
1509 pending_.swap(ops);
1510 num_pending_ = 0;
1511 }
1512
1513 // Maybe an old timer fired or we are already Close()'ed.
1514 if (!db() || ops.empty())
1515 return;
1516
1517 sql::Statement add_statement(db()->GetCachedStatement(
1518 SQL_FROM_HERE,
1519 "INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
1520 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
1521 "last_access_utc, has_expires, is_persistent, priority, samesite, "
1522 "source_scheme, source_port, is_same_party, last_update_utc) "
1523 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
1524 if (!add_statement.is_valid())
1525 return;
1526
1527 sql::Statement update_access_statement(db()->GetCachedStatement(
1528 SQL_FROM_HERE,
1529 "UPDATE cookies SET last_access_utc=? WHERE "
1530 "name=? AND host_key=? AND top_frame_site_key=? AND path=?"));
1531 if (!update_access_statement.is_valid())
1532 return;
1533
1534 sql::Statement delete_statement(db()->GetCachedStatement(
1535 SQL_FROM_HERE,
1536 "DELETE FROM cookies WHERE "
1537 "name=? AND host_key=? AND top_frame_site_key=? AND path=?"));
1538 if (!delete_statement.is_valid())
1539 return;
1540
1541 sql::Transaction transaction(db());
1542 if (!transaction.Begin())
1543 return;
1544
1545 for (auto& kv : ops) {
1546 for (std::unique_ptr<PendingOperation>& po_entry : kv.second) {
1547 // Free the cookies as we commit them to the database.
1548 std::unique_ptr<PendingOperation> po(std::move(po_entry));
1549 std::string top_frame_site_key;
1550 if (!CookiePartitionKey::Serialize(po->cc().PartitionKey(),
1551 top_frame_site_key)) {
1552 continue;
1553 }
1554 switch (po->op()) {
1555 case PendingOperation::COOKIE_ADD:
1556 add_statement.Reset(true);
1557 add_statement.BindTime(0, po->cc().CreationDate());
1558 add_statement.BindString(1, po->cc().Domain());
1559 add_statement.BindString(2, top_frame_site_key);
1560 add_statement.BindString(3, po->cc().Name());
1561 if (crypto_ && crypto_->ShouldEncrypt()) {
1562 std::string encrypted_value;
1563 if (!crypto_->EncryptString(po->cc().Value(), &encrypted_value)) {
1564 DLOG(WARNING) << "Could not encrypt a cookie, skipping add.";
1565 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ENCRYPT_FAILED);
1566 continue;
1567 }
1568 add_statement.BindCString(4, ""); // value
1569 // BindBlob() immediately makes an internal copy of the data.
1570 add_statement.BindBlob(5, encrypted_value);
1571 } else {
1572 add_statement.BindString(4, po->cc().Value());
1573 add_statement.BindBlob(5,
1574 base::span<uint8_t>()); // encrypted_value
1575 }
1576 add_statement.BindString(6, po->cc().Path());
1577 add_statement.BindTime(7, po->cc().ExpiryDate());
1578 add_statement.BindBool(8, po->cc().IsSecure());
1579 add_statement.BindBool(9, po->cc().IsHttpOnly());
1580 add_statement.BindTime(10, po->cc().LastAccessDate());
1581 add_statement.BindBool(11, po->cc().IsPersistent());
1582 add_statement.BindBool(12, po->cc().IsPersistent());
1583 add_statement.BindInt(
1584 13, CookiePriorityToDBCookiePriority(po->cc().Priority()));
1585 add_statement.BindInt(
1586 14, CookieSameSiteToDBCookieSameSite(po->cc().SameSite()));
1587 add_statement.BindInt(15, static_cast<int>(po->cc().SourceScheme()));
1588 add_statement.BindInt(16, po->cc().SourcePort());
1589 add_statement.BindBool(17, po->cc().IsSameParty());
1590 add_statement.BindTime(18, po->cc().LastUpdateDate());
1591 if (!add_statement.Run()) {
1592 DLOG(WARNING) << "Could not add a cookie to the DB.";
1593 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ADD);
1594 }
1595 break;
1596
1597 case PendingOperation::COOKIE_UPDATEACCESS:
1598 update_access_statement.Reset(true);
1599 update_access_statement.BindTime(0, po->cc().LastAccessDate());
1600 update_access_statement.BindString(1, po->cc().Name());
1601 update_access_statement.BindString(2, po->cc().Domain());
1602 update_access_statement.BindString(3, top_frame_site_key);
1603 update_access_statement.BindString(4, po->cc().Path());
1604 if (!update_access_statement.Run()) {
1605 DLOG(WARNING)
1606 << "Could not update cookie last access time in the DB.";
1607 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_UPDATE_ACCESS);
1608 }
1609 break;
1610
1611 case PendingOperation::COOKIE_DELETE:
1612 delete_statement.Reset(true);
1613 delete_statement.BindString(0, po->cc().Name());
1614 delete_statement.BindString(1, po->cc().Domain());
1615 delete_statement.BindString(2, top_frame_site_key);
1616 delete_statement.BindString(3, po->cc().Path());
1617 if (!delete_statement.Run()) {
1618 DLOG(WARNING) << "Could not delete a cookie from the DB.";
1619 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_DELETE);
1620 }
1621 break;
1622
1623 default:
1624 NOTREACHED();
1625 break;
1626 }
1627 }
1628 }
1629 bool commit_ok = transaction.Commit();
1630 if (!commit_ok) {
1631 RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_TRANSACTION_COMMIT);
1632 }
1633 }
1634
GetQueueLengthForTesting()1635 size_t SQLitePersistentCookieStore::Backend::GetQueueLengthForTesting() {
1636 DCHECK(client_task_runner()->RunsTasksInCurrentSequence());
1637 size_t total = 0u;
1638 {
1639 base::AutoLock locked(lock_);
1640 for (const auto& key_val : pending_) {
1641 total += key_val.second.size();
1642 }
1643 }
1644 return total;
1645 }
1646
DeleteAllInList(const std::list<CookieOrigin> & cookies)1647 void SQLitePersistentCookieStore::Backend::DeleteAllInList(
1648 const std::list<CookieOrigin>& cookies) {
1649 if (cookies.empty())
1650 return;
1651
1652 if (background_task_runner()->RunsTasksInCurrentSequence()) {
1653 BackgroundDeleteAllInList(cookies);
1654 } else {
1655 // Perform deletion on background task runner.
1656 PostBackgroundTask(
1657 FROM_HERE,
1658 base::BindOnce(&Backend::BackgroundDeleteAllInList, this, cookies));
1659 }
1660 }
1661
DeleteSessionCookiesOnStartup()1662 void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {
1663 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
1664 if (!db()->Execute("DELETE FROM cookies WHERE is_persistent != 1"))
1665 LOG(WARNING) << "Unable to delete session cookies.";
1666 }
1667
1668 // TODO(crbug.com/1225444) Investigate including top_frame_site_key in the WHERE
1669 // clause.
BackgroundDeleteAllInList(const std::list<CookieOrigin> & cookies)1670 void SQLitePersistentCookieStore::Backend::BackgroundDeleteAllInList(
1671 const std::list<CookieOrigin>& cookies) {
1672 DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
1673
1674 if (!db())
1675 return;
1676
1677 // Force a commit of any pending writes before issuing deletes.
1678 // TODO(rohitrao): Remove the need for this Commit() by instead pruning the
1679 // list of pending operations. https://crbug.com/486742.
1680 Commit();
1681
1682 sql::Statement delete_statement(db()->GetCachedStatement(
1683 SQL_FROM_HERE, "DELETE FROM cookies WHERE host_key=? AND is_secure=?"));
1684 if (!delete_statement.is_valid()) {
1685 LOG(WARNING) << "Unable to delete cookies on shutdown.";
1686 return;
1687 }
1688
1689 sql::Transaction transaction(db());
1690 if (!transaction.Begin()) {
1691 LOG(WARNING) << "Unable to delete cookies on shutdown.";
1692 return;
1693 }
1694
1695 for (const auto& cookie : cookies) {
1696 const GURL url(cookie_util::CookieOriginToURL(cookie.first, cookie.second));
1697 if (!url.is_valid())
1698 continue;
1699
1700 delete_statement.Reset(true);
1701 delete_statement.BindString(0, cookie.first);
1702 delete_statement.BindInt(1, cookie.second);
1703 if (!delete_statement.Run())
1704 NOTREACHED() << "Could not delete a cookie from the DB.";
1705 }
1706
1707 if (!transaction.Commit())
1708 LOG(WARNING) << "Unable to delete cookies on shutdown.";
1709 }
1710
FinishedLoadingCookies(LoadedCallback loaded_callback,bool success)1711 void SQLitePersistentCookieStore::Backend::FinishedLoadingCookies(
1712 LoadedCallback loaded_callback,
1713 bool success) {
1714 PostClientTask(FROM_HERE,
1715 base::BindOnce(&Backend::CompleteLoadInForeground, this,
1716 std::move(loaded_callback), success));
1717 }
1718
SQLitePersistentCookieStore(const base::FilePath & path,const scoped_refptr<base::SequencedTaskRunner> & client_task_runner,const scoped_refptr<base::SequencedTaskRunner> & background_task_runner,bool restore_old_session_cookies,CookieCryptoDelegate * crypto_delegate,bool enable_exclusive_access)1719 SQLitePersistentCookieStore::SQLitePersistentCookieStore(
1720 const base::FilePath& path,
1721 const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
1722 const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
1723 bool restore_old_session_cookies,
1724 CookieCryptoDelegate* crypto_delegate,
1725 bool enable_exclusive_access)
1726 : backend_(base::MakeRefCounted<Backend>(path,
1727 client_task_runner,
1728 background_task_runner,
1729 restore_old_session_cookies,
1730 crypto_delegate,
1731 enable_exclusive_access)) {}
1732
DeleteAllInList(const std::list<CookieOrigin> & cookies)1733 void SQLitePersistentCookieStore::DeleteAllInList(
1734 const std::list<CookieOrigin>& cookies) {
1735 backend_->DeleteAllInList(cookies);
1736 }
1737
Load(LoadedCallback loaded_callback,const NetLogWithSource & net_log)1738 void SQLitePersistentCookieStore::Load(LoadedCallback loaded_callback,
1739 const NetLogWithSource& net_log) {
1740 DCHECK(!loaded_callback.is_null());
1741 net_log_ = net_log;
1742 net_log_.BeginEvent(NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD);
1743 // Note that |backend_| keeps |this| alive by keeping a reference count.
1744 // If this class is ever converted over to a WeakPtr<> pattern (as TODO it
1745 // should be) this will need to be replaced by a more complex pattern that
1746 // guarantees |loaded_callback| being called even if the class has been
1747 // destroyed. |backend_| needs to outlive |this| to commit changes to disk.
1748 backend_->Load(base::BindOnce(&SQLitePersistentCookieStore::CompleteLoad,
1749 this, std::move(loaded_callback)));
1750 }
1751
LoadCookiesForKey(const std::string & key,LoadedCallback loaded_callback)1752 void SQLitePersistentCookieStore::LoadCookiesForKey(
1753 const std::string& key,
1754 LoadedCallback loaded_callback) {
1755 DCHECK(!loaded_callback.is_null());
1756 net_log_.AddEvent(NetLogEventType::COOKIE_PERSISTENT_STORE_KEY_LOAD_STARTED,
1757 [&](NetLogCaptureMode capture_mode) {
1758 return CookieKeyedLoadNetLogParams(key, capture_mode);
1759 });
1760 // Note that |backend_| keeps |this| alive by keeping a reference count.
1761 // If this class is ever converted over to a WeakPtr<> pattern (as TODO it
1762 // should be) this will need to be replaced by a more complex pattern that
1763 // guarantees |loaded_callback| being called even if the class has been
1764 // destroyed. |backend_| needs to outlive |this| to commit changes to disk.
1765 backend_->LoadCookiesForKey(
1766 key, base::BindOnce(&SQLitePersistentCookieStore::CompleteKeyedLoad, this,
1767 key, std::move(loaded_callback)));
1768 }
1769
AddCookie(const CanonicalCookie & cc)1770 void SQLitePersistentCookieStore::AddCookie(const CanonicalCookie& cc) {
1771 backend_->AddCookie(cc);
1772 }
1773
UpdateCookieAccessTime(const CanonicalCookie & cc)1774 void SQLitePersistentCookieStore::UpdateCookieAccessTime(
1775 const CanonicalCookie& cc) {
1776 backend_->UpdateCookieAccessTime(cc);
1777 }
1778
DeleteCookie(const CanonicalCookie & cc)1779 void SQLitePersistentCookieStore::DeleteCookie(const CanonicalCookie& cc) {
1780 backend_->DeleteCookie(cc);
1781 }
1782
SetForceKeepSessionState()1783 void SQLitePersistentCookieStore::SetForceKeepSessionState() {
1784 // This store never discards session-only cookies, so this call has no effect.
1785 }
1786
SetBeforeCommitCallback(base::RepeatingClosure callback)1787 void SQLitePersistentCookieStore::SetBeforeCommitCallback(
1788 base::RepeatingClosure callback) {
1789 backend_->SetBeforeCommitCallback(std::move(callback));
1790 }
1791
Flush(base::OnceClosure callback)1792 void SQLitePersistentCookieStore::Flush(base::OnceClosure callback) {
1793 backend_->Flush(std::move(callback));
1794 }
1795
GetQueueLengthForTesting()1796 size_t SQLitePersistentCookieStore::GetQueueLengthForTesting() {
1797 return backend_->GetQueueLengthForTesting();
1798 }
1799
~SQLitePersistentCookieStore()1800 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {
1801 net_log_.AddEventWithStringParams(
1802 NetLogEventType::COOKIE_PERSISTENT_STORE_CLOSED, "type",
1803 "SQLitePersistentCookieStore");
1804 backend_->Close();
1805 }
1806
CompleteLoad(LoadedCallback callback,std::vector<std::unique_ptr<CanonicalCookie>> cookie_list)1807 void SQLitePersistentCookieStore::CompleteLoad(
1808 LoadedCallback callback,
1809 std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) {
1810 net_log_.EndEvent(NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD);
1811 std::move(callback).Run(std::move(cookie_list));
1812 }
1813
CompleteKeyedLoad(const std::string & key,LoadedCallback callback,std::vector<std::unique_ptr<CanonicalCookie>> cookie_list)1814 void SQLitePersistentCookieStore::CompleteKeyedLoad(
1815 const std::string& key,
1816 LoadedCallback callback,
1817 std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) {
1818 net_log_.AddEventWithStringParams(
1819 NetLogEventType::COOKIE_PERSISTENT_STORE_KEY_LOAD_COMPLETED, "domain",
1820 key);
1821 std::move(callback).Run(std::move(cookie_list));
1822 }
1823
1824 } // namespace net
1825