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