chromium/net/extras/sqlite/sqlite_persistent_cookie_store.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"

#include <iterator>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <tuple>
#include <unordered_set>

#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "base/types/optional_ref.h"
#include "base/values.h"
#include "build/build_config.h"
#include "crypto/sha2.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_util.h"
#include "net/extras/sqlite/cookie_crypto_delegate.h"
#include "net/extras/sqlite/sqlite_persistent_store_backend_base.h"
#include "net/log/net_log.h"
#include "net/log/net_log_values.h"
#include "sql/error_delegate_util.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "url/gurl.h"
#include "url/third_party/mozilla/url_parse.h"

Time;

namespace {

static constexpr int kHoursInOneWeek =;
static constexpr int kHoursInOneYear =;

base::Value::Dict CookieKeyedLoadNetLogParams(
    const std::string& key,
    net::NetLogCaptureMode capture_mode) {}

// Used to populate a histogram for problems when loading cookies.
//
// Please do not reorder or remove entries. New entries must be added to the
// end of the list, just before COOKIE_LOAD_PROBLEM_LAST_ENTRY.
enum CookieLoadProblem {};

// Used to populate a histogram for problems when committing cookies.
//
// Please do not reorder or remove entries. New entries must be added to the
// end of the list, just before COOKIE_COMMIT_PROBLEM_LAST_ENTRY.
enum CookieCommitProblem {};

void RecordCookieLoadProblem(CookieLoadProblem event) {}

void RecordCookieCommitProblem(CookieCommitProblem event) {}

// Records metrics around the age in hours of a cookie loaded from the store via
// MakeCookiesFromSQLStatement for use by some browser context.
void HistogramCookieAge(const net::CanonicalCookie& cookie) {}

}  // namespace

namespace net {

base::TaskPriority GetCookieStoreBackgroundSequencePriority() {}

namespace {

// Version number of the database.
//
// Version 24 - 2024/08/15 - https://crrev.com/c/5792044
// Version 23 - 2024/04/10 - https://crrev.com/c/5169630
// Version 22 - 2024/03/22 - https://crrev.com/c/5378176
// Version 21 - 2023/11/22 - https://crrev.com/c/5049032
// Version 20 - 2023/11/14 - https://crrev.com/c/5030577
// Version 19 - 2023/09/22 - https://crrev.com/c/4704672
// Version 18 - 2022/04/19 - https://crrev.com/c/3594203
//
// Versions older than two years should be removed and marked as unsupported.
// This was last done in February 2024. https://crrev.com/c/5300252
// Be sure to update SQLitePersistentCookieStoreTest.TestInvalidVersionRecovery
// to test the latest unsupported version number.
//
// Unsupported versions:
// Version 17 - 2022/01/25 - https://crrev.com/c/3416230
// Version 16 - 2021/09/10 - https://crrev.com/c/3152897
// Version 15 - 2021/07/01 - https://crrev.com/c/3001822
// Version 14 - 2021/02/23 - https://crrev.com/c/2036899
// Version 13 - 2020/10/28 - https://crrev.com/c/2505468
// Version 12 - 2019/11/20 - https://crrev.com/c/1898301
// Version 11 - 2019/04/17 - https://crrev.com/c/1570416
// Version 10 - 2018/02/13 - https://crrev.com/c/906675
// Version 9  - 2015/04/17 - https://codereview.chromium.org/1083623003
// Version 8  - 2015/02/23 - https://codereview.chromium.org/876973003
// Version 7  - 2013/12/16 - https://codereview.chromium.org/24734007
// Version 6  - 2013/04/23 - https://codereview.chromium.org/14208017
// Version 5  - 2011/12/05 - https://codereview.chromium.org/8533013
// Version 4  - 2009/09/01 - https://codereview.chromium.org/183021
//

// Version 24 adds a SHA256 hash of the domain value to front of the the
// encrypted_value.
//
// Version 23 adds the value for has_cross_site_ancestor and updates any
// preexisting cookies with a source_scheme value of kUnset and a is_secure of
// true to have a source_scheme value of kSecure.
//
// Version 22 adds one new field: "source_type". This reflects the source of
// the last set/update to the cookie (unknown, http, script, other). Existing
// cookies in the DB default to "unknown".
//
// Version 21 removes the is_same_party column.
//
// Version 20 changes the UNIQUE constraint to include the source_scheme and
// source_port and begins to insert, update, and delete cookies based on their
// source_scheme and source_port.
//
// Version 19 caps expires_utc to no more than 400 days in the future for all
// stored cookies with has_expires. This is in compliance with section 7.2 of
// draft-ietf-httpbis-rfc6265bis-12.
//
// Version 18 adds one new field: "last_update_utc" (if not 0 this represents
// the last time the cookie was updated). This is distinct from creation_utc
// which is carried forward when cookies are updated.
//
// Version 17 fixes crbug.com/1290841: Bug in V16 migration.
//
// Version 16 changes the unique constraint's order of columns to have
// top_frame_site_key be after host_key. This allows us to use the internal
// index created by the UNIQUE keyword without to load cookies by domain
// without us needing to supply a top_frame_site_key. This is necessary because
// CookieMonster tracks pending cookie loading tasks by host key only.
// Version 16 also removes the DEFAULT value from several columns.
//
// Version 15 adds one new field: "top_frame_site_key" (if not empty then the
// string is the scheme and site of the topmost-level frame the cookie was
// created in). This field is deserialized into the cookie's partition key.
// top_frame_site_key is *NOT* the site-for-cookies when the cookie was created.
// In migrating, top_frame_site_key defaults to empty string. This change also
// changes the uniqueness constraint on cookies to include the
// top_frame_site_key as well.
//
// Version 14 just reads all encrypted cookies and re-writes them out again to
// make sure the new encryption key is in use. This active migration only
// happens on Windows, on other OS, this migration is a no-op.
//
// Version 13 adds two new fields: "source_port" (the port number of the source
// origin, and "is_same_party" (boolean indicating whether the cookie had a
// SameParty attribute). In migrating, source_port defaults to -1
// (url::PORT_UNSPECIFIED) for old entries for which the source port is unknown,
// and is_same_party defaults to false.
//
// Version 12 adds a column for "source_scheme" to store whether the
// cookie was set from a URL with a cryptographic scheme.
//
// Version 11 renames the "firstpartyonly" column to "samesite", and changes any
// stored values of kCookieSameSiteNoRestriction into
// kCookieSameSiteUnspecified to reflect the fact that those cookies were set
// without a SameSite attribute specified. Support for a value of
// kCookieSameSiteExtended for "samesite" was added, however, that value is now
// deprecated and is mapped to CookieSameSite::UNSPECIFIED when loading from the
// database.
//
// Version 10 removes the uniqueness constraint on the creation time (which
// was not propagated up the stack and caused problems in
// http://crbug.com/800414 and others).  It replaces that constraint by a
// constraint on (name, domain, path), which is spec-compliant (see
// https://tools.ietf.org/html/rfc6265#section-5.3 step 11).  Those fields
// can then be used in place of the creation time for updating access
// time and deleting cookies.
// Version 10 also marks all booleans in the store with an "is_" prefix
// to indicated their booleanness, as SQLite has no such concept.
//
// Version 9 adds a partial index to track non-persistent cookies.
// Non-persistent cookies sometimes need to be deleted on startup. There are
// frequently few or no non-persistent cookies, so the partial index allows the
// deletion to be sped up or skipped, without having to page in the DB.
//
// Version 8 adds "first-party only" cookies.
//
// Version 7 adds encrypted values.  Old values will continue to be used but
// all new values written will be encrypted on selected operating systems.  New
// records read by old clients will simply get an empty cookie value while old
// records read by new clients will continue to operate with the unencrypted
// version.  New and old clients alike will always write/update records with
// what they support.
//
// Version 6 adds cookie priorities. This allows developers to influence the
// order in which cookies are evicted in order to meet domain cookie limits.
//
// Version 5 adds the columns has_expires and is_persistent, so that the
// database can store session cookies as well as persistent cookies. Databases
// of version 5 are incompatible with older versions of code. If a database of
// version 5 is read by older code, session cookies will be treated as normal
// cookies. Currently, these fields are written, but not read anymore.
//
// In version 4, we migrated the time epoch.  If you open the DB with an older
// version on Mac or Linux, the times will look wonky, but the file will likely
// be usable. On Windows version 3 and 4 are the same.
//
// Version 3 updated the database to include the last access time, so we can
// expire them in decreasing order of use when we've reached the maximum
// number of cookies.
const int kCurrentVersionNumber =;
const int kCompatibleVersionNumber =;

}  // namespace

// This class is designed to be shared between any client thread and the
// background task runner. It batches operations and commits them on a timer.
//
// SQLitePersistentCookieStore::Load is called to load all cookies.  It
// delegates to Backend::Load, which posts a Backend::LoadAndNotifyOnDBThread
// task to the background runner.  This task calls Backend::ChainLoadCookies(),
// which repeatedly posts itself to the BG runner to load each eTLD+1's cookies
// in separate tasks.  When this is complete, Backend::CompleteLoadOnIOThread is
// posted to the client runner, which notifies the caller of
// SQLitePersistentCookieStore::Load that the load is complete.
//
// If a priority load request is invoked via SQLitePersistentCookieStore::
// LoadCookiesForKey, it is delegated to Backend::LoadCookiesForKey, which posts
// Backend::LoadKeyAndNotifyOnDBThread to the BG runner. That routine loads just
// that single domain key (eTLD+1)'s cookies, and posts a Backend::
// CompleteLoadForKeyOnIOThread to the client runner to notify the caller of
// SQLitePersistentCookieStore::LoadCookiesForKey that that load is complete.
//
// Subsequent to loading, mutations may be queued by any thread using
// AddCookie, UpdateCookieAccessTime, and DeleteCookie. These are flushed to
// disk on the BG runner every 30 seconds, 512 operations, or call to Flush(),
// whichever occurs first.
class SQLitePersistentCookieStore::Backend
    : public SQLitePersistentStoreBackendBase {};

namespace {

// Possible values for the 'priority' column.
enum DBCookiePriority {};

DBCookiePriority CookiePriorityToDBCookiePriority(CookiePriority value) {}

CookiePriority DBCookiePriorityToCookiePriority(DBCookiePriority value) {}

// Possible values for the 'samesite' column
enum DBCookieSameSite {};

DBCookieSameSite CookieSameSiteToDBCookieSameSite(CookieSameSite value) {}

CookieSameSite DBCookieSameSiteToCookieSameSite(DBCookieSameSite value) {}

// Possible values for the `source` column
enum DBCookieSourceType {};

DBCookieSourceType CookieSourceTypeToDBCookieSourceType(
    CookieSourceType value) {}

CookieSourceType DBCookieSourceTypeToCookieSourceType(
    DBCookieSourceType value) {}

CookieSourceScheme DBToCookieSourceScheme(int value) {}

// Increments a specified TimeDelta by the duration between this object's
// constructor and destructor. Not thread safe. Multiple instances may be
// created with the same delta instance as long as their lifetimes are nested.
// The shortest lived instances have no impact.
class IncrementTimeDelta {};

bool CreateV20Schema(sql::Database* db) {}

bool CreateV21Schema(sql::Database* db) {}

bool CreateV22Schema(sql::Database* db) {}

bool CreateV23Schema(sql::Database* db) {}

// v24 schema is identical to v23 schema.
bool CreateV24Schema(sql::Database* db) {}

}  // namespace

void SQLitePersistentCookieStore::Backend::Load(
    LoadedCallback loaded_callback) {}

void SQLitePersistentCookieStore::Backend::LoadCookiesForKey(
    base::optional_ref<const std::string> key,
    LoadedCallback loaded_callback) {}

void SQLitePersistentCookieStore::Backend::CryptoHasInitFromLoad(
    base::optional_ref<const std::string> key,
    LoadedCallback loaded_callback) {}

void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground(
    base::optional_ref<const std::string> key,
    LoadedCallback loaded_callback) {}

void SQLitePersistentCookieStore::Backend::NotifyLoadCompleteInForeground(
    LoadedCallback loaded_callback,
    bool load_success) {}

bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() {}

bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() {}

void SQLitePersistentCookieStore::Backend::ChainLoadCookies(
    LoadedCallback loaded_callback) {}

bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
    const std::set<std::string>& domains) {}

void SQLitePersistentCookieStore::Backend::DeleteTopFrameSiteKeys(
    const std::unordered_set<std::string>& top_frame_site_keys) {}

bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
    std::vector<std::unique_ptr<CanonicalCookie>>& cookies,
    sql::Statement& statement,
    std::unordered_set<std::string>& top_frame_site_keys_to_delete) {}

std::optional<int>
SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() {}

void SQLitePersistentCookieStore::Backend::AddCookie(
    const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::Backend::UpdateCookieAccessTime(
    const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::Backend::DeleteCookie(
    const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::Backend::BatchOperation(
    PendingOperation::OperationType op,
    const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::Backend::DoCommit() {}

size_t SQLitePersistentCookieStore::Backend::GetQueueLengthForTesting() {}

void SQLitePersistentCookieStore::Backend::DeleteAllInList(
    const std::list<CookieOrigin>& cookies) {}

void SQLitePersistentCookieStore::Backend::DeleteSessionCookiesOnStartup() {}

// TODO(crbug.com/40188414) Investigate including top_frame_site_key in the
// WHERE clause.
void SQLitePersistentCookieStore::Backend::BackgroundDeleteAllInList(
    const std::list<CookieOrigin>& cookies) {}

void SQLitePersistentCookieStore::Backend::FinishedLoadingCookies(
    LoadedCallback loaded_callback,
    bool success) {}

SQLitePersistentCookieStore::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)
    :{}

void SQLitePersistentCookieStore::DeleteAllInList(
    const std::list<CookieOrigin>& cookies) {}

void SQLitePersistentCookieStore::Load(LoadedCallback loaded_callback,
                                       const NetLogWithSource& net_log) {}

void SQLitePersistentCookieStore::LoadCookiesForKey(
    const std::string& key,
    LoadedCallback loaded_callback) {}

void SQLitePersistentCookieStore::AddCookie(const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::UpdateCookieAccessTime(
    const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::DeleteCookie(const CanonicalCookie& cc) {}

void SQLitePersistentCookieStore::SetForceKeepSessionState() {}

void SQLitePersistentCookieStore::SetBeforeCommitCallback(
    base::RepeatingClosure callback) {}

void SQLitePersistentCookieStore::Flush(base::OnceClosure callback) {}

size_t SQLitePersistentCookieStore::GetQueueLengthForTesting() {}

SQLitePersistentCookieStore::~SQLitePersistentCookieStore() {}

void SQLitePersistentCookieStore::CompleteLoad(
    LoadedCallback callback,
    std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) {}

void SQLitePersistentCookieStore::CompleteKeyedLoad(
    const std::string& key,
    LoadedCallback callback,
    std::vector<std::unique_ptr<CanonicalCookie>> cookie_list) {}

}  // namespace net