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