tree: 96d6cf02e16f18f0512e6769255c4544eac26a70 [path history] [tgz]
  1. DIR_METADATA
  2. OWNERS
  3. README.md
  4. canonical_cookie.cc
  5. canonical_cookie.h
  6. canonical_cookie_fuzzer.cc
  7. canonical_cookie_test_helpers.h
  8. canonical_cookie_unittest.cc
  9. cookie_access_delegate.cc
  10. cookie_access_delegate.h
  11. cookie_access_result.cc
  12. cookie_access_result.h
  13. cookie_change_dispatcher.cc
  14. cookie_change_dispatcher.h
  15. cookie_change_dispatcher_test_helpers.cc
  16. cookie_change_dispatcher_test_helpers.h
  17. cookie_constants.cc
  18. cookie_constants.h
  19. cookie_constants_unittest.cc
  20. cookie_deletion_info.cc
  21. cookie_deletion_info.h
  22. cookie_deletion_info_unittest.cc
  23. cookie_inclusion_status.cc
  24. cookie_inclusion_status.h
  25. cookie_inclusion_status_unittest.cc
  26. cookie_monster.cc
  27. cookie_monster.h
  28. cookie_monster_change_dispatcher.cc
  29. cookie_monster_change_dispatcher.h
  30. cookie_monster_netlog_params.cc
  31. cookie_monster_netlog_params.h
  32. cookie_monster_perftest.cc
  33. cookie_monster_store_test.cc
  34. cookie_monster_store_test.h
  35. cookie_monster_unittest.cc
  36. cookie_options.cc
  37. cookie_options.h
  38. cookie_options_unittest.cc
  39. cookie_store.cc
  40. cookie_store.h
  41. cookie_store_change_unittest.h
  42. cookie_store_test_callbacks.cc
  43. cookie_store_test_callbacks.h
  44. cookie_store_test_helpers.cc
  45. cookie_store_test_helpers.h
  46. cookie_store_unittest.h
  47. cookie_util.cc
  48. cookie_util.h
  49. cookie_util_unittest.cc
  50. parse_cookie_line_fuzzer.cc
  51. parsed_cookie.cc
  52. parsed_cookie.h
  53. parsed_cookie_unittest.cc
  54. site_for_cookies.cc
  55. site_for_cookies.h
  56. site_for_cookies_unittest.cc
  57. static_cookie_policy.cc
  58. static_cookie_policy.h
  59. static_cookie_policy_unittest.cc
  60. test_cookie_access_delegate.cc
  61. test_cookie_access_delegate.h
net/cookies/README.md

Cookies

“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 directory is concerned with the management of cookies, as specified by RFC 6265bis. Cookies are implemented mostly in this directory, but also elsewhere, as described below.

Life of a cookie

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.

This only covers cookie accesses via HTTP requests. Other APIs for accessing cookies include JavaScript (document.cookie and CookieStore API) or Chrome extensions (chrome.cookies).

Cookie is received and parsed

Summary:

  1. An HTTP response containing a Set-Cookie header is received.
  2. The Set-Cookie header is processed by URLRequestHttpJob.
  3. The header contents are parsed into a CanonicalCookie and passed to the CookieStore for storage.

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 HttpNetworkTransaction and 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.

The 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 CanonicalCookies. A 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 Set-Cookie header.

The 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 Set-Cookie header.

If this did result in a valid and not-blocked CanonicalCookie, it is then passed to the CookieStore to be stored.

Cookie is stored

Summary:

  1. The CookieStore receives the CanonicalCookie and validates some additional criteria before updating its in-memory cache of cookies.
  2. The CookieStore may also update its on-disk backing store via the CookieMonster::PersistentCookieStore interface.
  3. The result of the cookie storage attempt is reported back to the URLRequestHttpJob.

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.

When 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.

Cookie is retrieved and sent

Summary:

  1. A network request reaches the net stack and generates a URLRequestHttpJob, which queries the CookieStore for cookies to include with the request.
  2. The CookieStore evaluates each of its candidate cookies for whether it can be included in the request, and reports back to the URLRequestHttpJob with included and excluded cookies.
  3. URLRequestHttpJob serializes the included cookies into a Cookie request 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.

The 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 Domain and 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.

Cookie implementation classes

This section lists classes involved in cookie management and access.

The core classes are highlighted.

In this directory (//net/cookies)

  • CanonicalCookie

    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 CanonicalCookie.

  • CookieStore

    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.

  • CookieMonster

    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.

  • CookieOptions

    Contains parameters for a given attempt to access cookies via CookieStore, such as whether the access is for an HTTP request (as opposed to a JavaScript API), and the same-site or cross-site context of the request (relevant to enforcement of the SameSite cookie attribute).

  • SiteForCookies

    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 CookieOptions).

    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).

  • CookieInclusionStatus

    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.

  • CookieAccessDelegate

    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. CookieManager).

  • CookieChangeDispatcher

    Interface for subscribing to changes in the contents of the CookieStore. The main implementation is CookieMonsterChangeDispatcher.

Elsewhere in //net

  • SQLitePersistentCookieStore

    Implementation of 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).

  • URLRequestHttpJob

    A URLRequestJob implementation that handles HTTP requests; most relevantly, the Cookie and 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.

  • URLRequest

    Mostly relevant for its two members, maybe_sent_cookies_ and 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.

In //services/network

  • CookieManager

    The network service API to cookies. Basically exports a CookieStore via mojo IPC.

    Owned by the NetworkContext.

  • RestrictedCookieManager

    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.

    It is primarily used for accessing cookies via JavaScript. It provides a synchronous interface for document.cookie, as well as an asynchronous one for the CookieStore API.

  • CookieSettings

    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.

  • SessionCleanupCookieStore

    Implements 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.

Elsewhere

  • CookieAccessObserver and WebContentsObserver

    CookieAccessObserver is a mojo interface used to observe attempts to access (read or write) cookies. It is implemented by NavigationHandle and RenderFrameHost.

    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 NavigationHandle).

    The 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).

  • CookiesTreeModel

    Stores cookie information for use in settings UI (the Page Info Bubble and various chrome://settings pages). Populated with info from PageSpecificContentSettings.

  • CookieJar

    Implements the document.cookie API in the renderer by requesting a RestrictedCookieManager from the browser.

  • CookieStore

    Implements the JavaScript CookieStore API in the renderer by requesting a RestrictedCookieManager from the browser. (Not to be confused with net::CookieStore.)

  • CookiesAPI

    Implements the chrome.cookies API for Chrome extensions. Gives extensions with the proper permissions essentially unfettered access to the CookieStore.

Platform-specific

  • CookieStoreIOS and CookieStoreIOSPersistent

    iOS-specific CookieStore implementations, mainly relying on the iOS native cookie implementation (NSHTTPCookie).

  • android_webview::CookieManager

    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 net::CookieStore.

    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.

Main interfaces for finding, setting, deleting, and observing cookies

This section summarizes interfaces for interacting with cookies from various parts of the codebase.

From //net or //services/network

Use net::CookieStore to save and retrieve CanonicalCookies.
  • CanonicalCookies are the main data type representing cookies. Get one using CanonicalCookie::Create().

  • The CookieStore can be accessed via its owning URLRequestContext, which can be accessed through NetworkContext.

  • 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 cookie_util functions.

  • Retrieve cookies using GetCookieListWithOptionsAsync().

  • Save cookies using SetCanonicalCookieAsync().

Use CookieStore to selectively delete cookies.
  • DeleteCanonicalCookieAsync() deletes a single cookie.

  • DeleteAllCreatedInTimeRangeAsync() deletes cookies created in a time range.

  • DeleteAllMatchingInfoAsync() deletes cookies that match a filter.

Use the CookieChangeDispatcher interface to subscribe to changes.
  • Use AddCallbackForCookie() to observe changes to cookies with a given name that would be sent with a request to a specific URL.

  • Use AddCallbackForUrl() to observe changes to all cookies that would be sent with a request to a specific URL.

  • Use AddCallbackForAllChanges() to observe changes to all cookies in the CookieStore.

From the browser process

Use CookieManager (which basically exports a net::CookieStore interface via mojo) to save and retrieve CanonicalCookies.
  • The profile's CookieManager can be accessed from the browser process through StoragePartition::GetCookieManagerForBrowserProcess().

  • You can also get get a CookieManager pipe from the NetworkContext using GetCookieManager().

  • Retrieve cookies using CookieManager::GetCookieList().

  • Save cookies using CookieManager::SetCanonicalCookie().

Use CookieManager to selectively delete cookies.
  • If you have a copy of the CanonicalCookie to delete (e.g. a cookie previously fetched from the store), use CookieManager::DeleteCanonicalCookie().

  • To delete cookies with certain characteristics, construct a CookieDeletionFilter and use CookieManager::DeleteCookies().

Use CookieManager's change listener interface to subscribe to changes (this parallels the net::CookieChangeDispatcher interface).
  • Add a CookieChangeListener registration for a URL (and optionally a cookie name) via AddCookieChangeListener()

  • Add a CookieChangeListener registration for all cookies via AddGlobalChangeListener().

From untrusted (e.g. renderer) processes

Use a network::mojom::RestrictedCookieManager interface to access cookies for a particular origin.
  • Request a 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 (GetAllForUrl(), SetCanonicalCookie()) or synchronously (SetCookieFromString(), GetCookiesString()).

  • Compromised renderers shouldn't be able to access cookies of another site, or HttpOnly cookies (even from the same site).