“In the beginning
the Universe was cookies were created. This has made a lot of people very angry and has been widely regarded as a bad move.”
“Sometimes me think, what is friend? And then me say: a friend is someone to share last cookie with.”
This section describes the lifecycle of a typical/simple cookie on most platforms, and serves as an overview of some important classes involved in managing cookies.
Set-Cookieheader is received.
Set-Cookieheader is processed by
CanonicalCookieand passed to the
A cookie starts as a
Set-Cookie header sent in the server's response to an HTTP request:
HTTP/1.1 200 OK Date: ... Server: ... ... Set-Cookie: chocolate_chip=tasty; Secure; SameSite=Lax; Max-Age=3600
The response passes through the
HttpCache::Transaction to the
URLRequestHttpJob. (See Life of a
URLRequest for more details.) The
URLRequestHttpJob then reads any
Set-Cookie headers in the response (there may be multiple) and processes each
Set-Cookie header by calling into
//net/cookies classes for parsing and storing:
First, the cookie, which has been provided as a string, is parsed into a
ParsedCookie. This struct simply records all the token-value pairs present in the
Set-Cookie header and keeps track of which cookie attribute each corresponds to. The first token-value pair is always treated as the cookie's name and value.
ParsedCookie is then converted into a
CanonicalCookie. This is the main data type representing cookies. Any cookie consumer that does not deal directly with HTTP headers operates on
CanonicalCookie has some additional guarantees of validity over a
ParsedCookie, such as valid expiration times, valid domain and path attributes, etc. Once a
CanonicalCookie is created, you will almost never see a
ParsedCookie used for anything else.
If a valid
CanonicalCookie could not be created (due to some illegal syntax, inconsistent attribute values, or other circumstances preventing parsing), then we stop here, and
URLRequestHttpJob moves on to the next
NetworkDelegate also gets a chance to block the setting of the cookie, based on the user's third-party cookie blocking settings. If it is blocked,
URLRequestHttpJob likewise moves on to the next
If this did result in a valid and not-blocked
CanonicalCookie, it is then passed to the
CookieStore to be stored.
CanonicalCookieand validates some additional criteria before updating its in-memory cache of cookies.
CookieStoremay also update its on-disk backing store via the
CookieStore lives in the
URLRequestContext and its main implementation, used for most platforms, is
CookieMonster. (The rest of this section assumes that we are using a
CookieMonster.) It exposes an asynchronous interface for storing and retrieving cookies.
CookieMonster receives a
CanonicalCookie to be set, it queues a task to validate and set the cookie. Most of the time this runs immediately, but it may be delayed if the network service has just started up, and the contents of the
PersistentCookieStore are still being loaded from disk. It checks some criteria against the cookie‘s source URL and a
CookieOptions object (which contains some other parameters describing the “context” in which the cookie is being set, such as whether it’s being accessed in a same-site or cross-site context).
If everything checks out, the
CookieMonster proceeds with setting the cookie. If an equivalent cookie is present in the store, then it may be deleted. Equivalent is defined as sharing a name, domain, and path, based on the invariant specified by the RFC that no two such cookies may exist at a given time.
CookieMonster stores its
CanonicalCookies in a multimap keyed on the registrable domain (eTLD+1) of the cookie's domain attribute.
The cookie may also be persisted to disk by a
CookieMonster::PersistentCookieStore depending on factors like whether the cookie is a persistent cookie (has an expiration date), whether session cookies should also be persisted (e.g. if the browser is set to restore the previous browsing session), and whether the profile should have persistent storage (e.g. yes for normal profiles, but not for Incognito profiles). The
SQLitePersistentCookieStore is the main implementation of
CookieMonster::PersistentCookieStore. It stores cookies in a SQLite database on disk, at a filepath specified by the user's profile.
After the cookie has been stored (or rejected), the
CookieMonster calls back to the
URLRequestHttpJob with the outcome of the storage attempt. The
URLRequestHttpJob stashes away the outcomes and stores them in the
URLRequest after all
Set-Cookie headers in the response are processed, so that interested parties (e.g. DevTools) can subsequently be notified of cookie activity.
URLRequestHttpJob, which queries the
CookieStorefor cookies to include with the request.
CookieStoreevaluates each of its candidate cookies for whether it can be included in the request, and reports back to the
URLRequestHttpJobwith included and excluded cookies.
URLRequestHttpJobserializes the included cookies into a
Cookierequest header and attaches it to the outgoing request.
Some time later, a (credentialed) request to the same eTLD+1 triggers a cookie access in order to retrieve the relevant cookies to include in the outgoing
Cookie request header. The request makes its way to the net stack and causes a
URLRequestHttpJob to be created. (See Life of a
URLRequest for more details.) Upon being started, the
URLRequestHttpJob asks the
CookieStore to retrieve the correct cookies for the URL being requested.
CookieMonster queues a task to retrieve the cookies. Most of the time this runs immediately, except if the contents of the
PersistentCookieStore are still being loaded from disk. The
CookieMonster examines each of the cookies it has stored for that URL‘s registrable domain and decides whether it should be included or excluded for that request based on the requested URL and the
CookieOptions, by computing a
CookieInclusionStatus. Criteria for inclusion are described in RFC 6265bis and include: the URL matching the cookie’s
Path attributes, the URL being secure if the cookie has the
Secure attribute, the request context (i.e.
CookieOptions) being same-site if the cookie is subject to
SameSite enforcement, etc. If any of the requirements are not met, a
CookieInclusionStatus::ExclusionReason is recorded.
After the exclusion reasons have been tallied up for each cookie, the cookies without any exclusion reasons are deemed suitable for inclusion, and are returned to the
URLRequestHttpJob. The excluded cookies are also returned, along with the
CookieInclusionStatus describing why each cookie was excluded.
The included cookies are serialized into a
Cookie header string (if the
NetworkDelegate is ok with it, based on the user's third-party cookie blocking settings). The
URLRequestHttpJob attaches this
Cookie header to the outgoing request headers:
GET /me/want/cookie/omnomnomnom HTTP/1.1 Host: ... User-Agent: ... Cookie: chocolate_chip=tasty ...
The included cookies, excluded cookies, and their corresponding
CookieInclusionStatuses are also stored in the
URLRequest to notify consumers of cookie activity notifications.
This section lists classes involved in cookie management and access.
The core classes are highlighted.
The main data type representing cookies. Basically everything that's not directly dealing with HTTP headers or their equivalents operates on these.
These are generally obtained via
CanonicalCookie::Create(), which parses a string (a
Set-Cookie header) into an intermediate
ParsedCookie, whose fields it canonicalizes/validates and then copies into a
The main interface for a given platform's cookie handling. Provides asynchronous methods for setting and retrieving cookies.
Its implementations are responsible for keeping track of all the cookies, finding cookies relevant for given HTTP requests, saving cookies received in HTTP responses, etc., and need to know quite a bit about cookie semantics.
The implementation of
CookieStore used on most platforms.
It stores all cookies in a multimap keyed on the eTLD+1 of the cookie's domain. Also manages storage limits by evicting cookies when per-eTLD+1 or global cookie counts are exceeded.
It can optionally take an implementation of
CookieMonster::PersistentCookieStore to load and store cookies persisently.
Contains parameters for a given attempt to access cookies via
SameSite cookie attribute).
Represents which origins should be considered “same-site” for a given context (e.g. frame). This is used to compute the same-site or cross-site context of a cookie access attempt (which is then conveyed to the
CookieStore via a
It is generally the eTLD+1 and scheme of the top-level frame. It may also be empty, in which case it represents a context that is cross-site to everything (e.g. a nested iframe whose ancestor frames don't all belong to the same site).
Records the outcome of a given attempt to access a cookie. Various reasons for cookie exclusion are recorded (
CookieInclusionStatus::ExclusionReason), as well as informational statuses (
CookieInclusionStatus::WarningReason) typically used to emit warnings in DevTools.
May be used as a member of a
CookieAccessResult, which includes even more metadata about the outcome of a cookie access attempt.
Interface for a
CookieStore to query information from its embedder that may modify its decisions on cookie inclusion/exclusion. Its main implementation allows
CookieMonster to access data from the network service layer (e.g.
Interface for subscribing to changes in the contents of the
CookieStore. The main implementation is
CookieMonster::PersistentCookieStore used on most platforms. Uses a SQLite database to load and store cookies, potentially using an optional delegate to encrypt and decrypt their at-rest versions. This class is refcounted.
CookieMonster loads cookies from here on startup. All other operations attempting to access cookies in the process of being loaded are blocked until loading of those cookies completes. Thus, it fast-tracks loading of cookies for an eTLD+1 with pending requests, to decrease latency for cookie access operations made soon after browser startup (by decreasing the number of cookies whose loading is blocking requests).
URLRequestJob implementation that handles HTTP requests; most relevantly, the
Set-Cookie HTTP headers. It drives the process for storing cookies and retrieving cookies for HTTP requests.
Also logs cookie events to the NetLog for each request.
Mostly relevant for its two members,
maybe_stored_cookies_, which are vectors in which
URLRequestHttpJob stashes the cookies it considered sending/storing and their
CookieInclusionStatuses. These then get mojo'ed over to the browser process to notify observers of cookie activity.
The network service API to cookies. Basically exports a
CookieStore via mojo IPC.
Owned by the
Mojo interface for accessing cookies for a specific origin. This can be handed out to untrusted (i.e. renderer) processes, as inputs are assumed to be unsafe.
Keeps track of the content settings (per-profile permissions for types of content that a given origin is allowed to use) for cookies, such as the user's third-party cookie blocking settings, origins/domains with third-party cookie blocking exceptions or “legacy” access settings.
It is not to be confused with
content_settings::CookieSettings, which manages the browser's version of the cookie content settings, of which
network::ContentSettings is approximately a copy/mirror. The
ProfileNetworkContextService populates its contents upon
NetworkContext construction from the browser-side content settings, and also updates it whenever the browser-side content settings change.
CookieMonster::PersistentCookieStore, by wrapping a
SQLitePersistentCookieStore. Keeps an in-memory map of cookies per eTLD+1 to allow deletion of cookies for sites whose cookie content setting is “session-only” from the persistent store when the session ends.
CookieAccessObserver is a mojo interface used to observe attempts to access (read or write) cookies. It is implemented by
The cookie accesses are attributable to a committed document that called
document.cookie or made a network request (if notified through
RenderFrameHost), or a not-yet-committed navigation that resulted in a network request (if notified through
CookieAccessObservers forward the notifications to
WebContents, which then notifies its
WebContentsObservers. One such
WebContentsObserver that cares about this information is
PageSpecificContentSettings, which displays information about allowed and blocked cookies in UI surfaces (see next item).
Stores cookie information for use in settings UI (the Page Info Bubble and various
chrome://settings pages). Populated with info from
document.cookie API in the renderer by requesting a
RestrictedCookieManager from the browser.
RestrictedCookieManager from the browser. (Not to be confused with
chrome.cookies API for Chrome extensions. Gives extensions with the proper permissions essentially unfettered access to the
CookieStore implementations, mainly relying on the iOS native cookie implementation (
Manages cookies for Android WebView. It typically wraps a
network::mojom::CookieManager, but it can also be used before a
NetworkContext even exists, thanks to Android WebView's cookie API, which means it is sometimes initialized with a bare
Also notable for allowing cookies for
file:// scheme URLs (normally they are only allowed for HTTP and websocket schemes and
chrome-extension://), though this is non-default and deprecated.
This section summarizes interfaces for interacting with cookies from various parts of the codebase.
CanonicalCookies are the main data type representing cookies. Get one using
CookieStore can be accessed via its owning
URLRequestContext, which can be accessed through
To access cookies, you need a
CookieOptions. The main things in this object are the
HttpOnly access permission and the
SameSite context. The latter can be obtained from
Retrieve cookies using
Save cookies using
CookieStoreto selectively delete cookies.
DeleteCanonicalCookieAsync() deletes a single cookie.
DeleteAllCreatedInTimeRangeAsync() deletes cookies created in a time range.
DeleteAllMatchingInfoAsync() deletes cookies that match a filter.
CookieChangeDispatcherinterface to subscribe to changes.
AddCallbackForCookie() to observe changes to cookies with a given name that would be sent with a request to a specific URL.
AddCallbackForUrl() to observe changes to all cookies that would be sent with a request to a specific URL.
AddCallbackForAllChanges() to observe changes to all cookies in the
CookieManager(which basically exports a
net::CookieStoreinterface via mojo) to save and retrieve
CookieManager can be accessed from the browser process through
You can also get get a
CookieManager pipe from the
Retrieve cookies using
Save cookies using
CookieManagerto selectively delete cookies.
If you have a copy of the
CanonicalCookie to delete (e.g. a cookie previously fetched from the store), use
To delete cookies with certain characteristics, construct a
CookieDeletionFilter and use
CookieManager's change listener interface to subscribe to changes (this parallels the
CookieChangeListener registration for a URL (and optionally a cookie name) via
CookieChangeListener registration for all cookies via
network::mojom::RestrictedCookieManagerinterface to access cookies for a particular origin.
RestrictedCookieManager interface from the browser. This creates a
RestrictedCookieManager bound to a
RenderFrameHost, which can only access cookies on behalf of the corresponding origin.
Cookies can be read and written asynchronously (
SetCanonicalCookie()) or synchronously (
Compromised renderers shouldn't be able to access cookies of another site, or
HttpOnly cookies (even from the same site).