• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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