1*6777b538SAndroid Build Coastguard Worker# Cookies 2*6777b538SAndroid Build Coastguard Worker 3*6777b538SAndroid Build Coastguard Worker*** aside 4*6777b538SAndroid Build Coastguard Worker_"In the beginning ~~the Universe was~~ cookies were created. This has 5*6777b538SAndroid Build Coastguard Workermade a lot of people very angry and has been widely regarded as a bad move."_ 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker_"Sometimes me think, what is friend? And then me say: a friend is someone to 8*6777b538SAndroid Build Coastguard Workershare last cookie with."_ 9*6777b538SAndroid Build Coastguard Worker*** 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard WorkerThis directory is concerned with the management of cookies, as specified by 12*6777b538SAndroid Build Coastguard Worker[RFC 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis). 13*6777b538SAndroid Build Coastguard WorkerCookies are implemented mostly in this directory, but also elsewhere, as 14*6777b538SAndroid Build Coastguard Workerdescribed [below](#Cookie-implementation-classes). 15*6777b538SAndroid Build Coastguard Worker 16*6777b538SAndroid Build Coastguard Worker*** promo 17*6777b538SAndroid Build Coastguard Worker* Those who wish to work with the implementation of cookies may refer to 18*6777b538SAndroid Build Coastguard Worker [Life of a cookie](#Life-of-a-cookie) and 19*6777b538SAndroid Build Coastguard Worker [Cookie implementation classes](#Cookie-implementation-classes). 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker* Those who wish to make use of cookies elsewhere in Chromium may refer to 22*6777b538SAndroid Build Coastguard Worker [Main interfaces for finding, setting, deleting, and observing cookies](#Main-interfaces-for-finding_setting_deleting_and-observing-cookies). 23*6777b538SAndroid Build Coastguard Worker*** 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker[TOC] 26*6777b538SAndroid Build Coastguard Worker 27*6777b538SAndroid Build Coastguard Worker## Life of a cookie 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard WorkerThis section describes the lifecycle of a typical/simple cookie on most 30*6777b538SAndroid Build Coastguard Workerplatforms, and serves as an overview of some important classes involved in 31*6777b538SAndroid Build Coastguard Workermanaging cookies. 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard WorkerThis only covers cookie accesses via 34*6777b538SAndroid Build Coastguard Worker[HTTP requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies). 35*6777b538SAndroid Build Coastguard WorkerOther APIs for accessing cookies include JavaScript 36*6777b538SAndroid Build Coastguard Worker([`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) 37*6777b538SAndroid Build Coastguard Workerand [CookieStore API](https://wicg.github.io/cookie-store/)) or Chrome 38*6777b538SAndroid Build Coastguard Workerextensions 39*6777b538SAndroid Build Coastguard Worker([`chrome.cookies`](https://developer.chrome.com/extensions/cookies)). 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker### Cookie is received and parsed 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker*** note 44*6777b538SAndroid Build Coastguard Worker**Summary:** 45*6777b538SAndroid Build Coastguard Worker 46*6777b538SAndroid Build Coastguard Worker1. An HTTP response containing a `Set-Cookie` header is received. 47*6777b538SAndroid Build Coastguard Worker2. The `Set-Cookie` header is processed by `URLRequestHttpJob`. 48*6777b538SAndroid Build Coastguard Worker3. The header contents are parsed into a `CanonicalCookie` and passed to the 49*6777b538SAndroid Build Coastguard Worker `CookieStore` for storage. 50*6777b538SAndroid Build Coastguard Worker*** 51*6777b538SAndroid Build Coastguard Worker 52*6777b538SAndroid Build Coastguard WorkerA cookie starts as a `Set-Cookie` header sent in the server's response to an 53*6777b538SAndroid Build Coastguard WorkerHTTP request: 54*6777b538SAndroid Build Coastguard Worker 55*6777b538SAndroid Build Coastguard Worker``` 56*6777b538SAndroid Build Coastguard WorkerHTTP/1.1 200 OK 57*6777b538SAndroid Build Coastguard WorkerDate: ... 58*6777b538SAndroid Build Coastguard WorkerServer: ... 59*6777b538SAndroid Build Coastguard Worker... 60*6777b538SAndroid Build Coastguard WorkerSet-Cookie: chocolate_chip=tasty; Secure; SameSite=Lax; Max-Age=3600 61*6777b538SAndroid Build Coastguard Worker``` 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard WorkerThe response passes through the `HttpNetworkTransaction` and 64*6777b538SAndroid Build Coastguard Worker`HttpCache::Transaction` to the `URLRequestHttpJob`. (See 65*6777b538SAndroid Build Coastguard Worker[Life of a `URLRequest`](/net/docs/life-of-a-url-request.md#send-request-and-read-the-response-headers) 66*6777b538SAndroid Build Coastguard Workerfor more details.) The `URLRequestHttpJob` then reads any `Set-Cookie` headers 67*6777b538SAndroid Build Coastguard Workerin the response (there may be multiple) and processes each `Set-Cookie` header 68*6777b538SAndroid Build Coastguard Workerby calling into `//net/cookies` classes for parsing and storing: 69*6777b538SAndroid Build Coastguard Worker 70*6777b538SAndroid Build Coastguard WorkerFirst, the cookie, which has been provided as a string, is parsed into a 71*6777b538SAndroid Build Coastguard Worker`ParsedCookie`. This struct simply records all the token-value pairs present in 72*6777b538SAndroid Build Coastguard Workerthe `Set-Cookie` header and keeps track of which cookie attribute each 73*6777b538SAndroid Build Coastguard Workercorresponds to. The first token-value pair is always treated as the cookie's 74*6777b538SAndroid Build Coastguard Workername and value. 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard WorkerThe `ParsedCookie` is then converted into a `CanonicalCookie`. This is the main 77*6777b538SAndroid Build Coastguard Workerdata type representing cookies. Any cookie consumer that does not deal directly 78*6777b538SAndroid Build Coastguard Workerwith HTTP headers operates on `CanonicalCookie`s. A `CanonicalCookie` has some 79*6777b538SAndroid Build Coastguard Workeradditional guarantees of validity over a `ParsedCookie`, such as valid 80*6777b538SAndroid Build Coastguard Workerexpiration times, valid domain and path attributes, etc. Once a 81*6777b538SAndroid Build Coastguard Worker`CanonicalCookie` is created, you will almost never see a `ParsedCookie` used 82*6777b538SAndroid Build Coastguard Workerfor anything else. 83*6777b538SAndroid Build Coastguard Worker 84*6777b538SAndroid Build Coastguard WorkerIf a valid `CanonicalCookie` could not be created (due to some illegal syntax, 85*6777b538SAndroid Build Coastguard Workerinconsistent attribute values, or other circumstances preventing parsing), then 86*6777b538SAndroid Build Coastguard Workerwe stop here, and `URLRequestHttpJob` moves on to the next `Set-Cookie` header. 87*6777b538SAndroid Build Coastguard Worker 88*6777b538SAndroid Build Coastguard WorkerThe `NetworkDelegate` also gets a chance to block the setting of the cookie, 89*6777b538SAndroid Build Coastguard Workerbased on the user's third-party cookie blocking settings. If it is blocked, 90*6777b538SAndroid Build Coastguard Worker`URLRequestHttpJob` likewise moves on to the next `Set-Cookie` header. 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard WorkerIf this did result in a valid and not-blocked `CanonicalCookie`, it is then 93*6777b538SAndroid Build Coastguard Workerpassed to the `CookieStore` to be stored. 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker### Cookie is stored 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker*** note 98*6777b538SAndroid Build Coastguard Worker**Summary:** 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker1. The `CookieStore` receives the `CanonicalCookie` and validates some 101*6777b538SAndroid Build Coastguard Worker additional criteria before updating its in-memory cache of cookies. 102*6777b538SAndroid Build Coastguard Worker2. The `CookieStore` may also update its on-disk backing store via the 103*6777b538SAndroid Build Coastguard Worker `CookieMonster::PersistentCookieStore` interface. 104*6777b538SAndroid Build Coastguard Worker3. The result of the cookie storage attempt is reported back to the 105*6777b538SAndroid Build Coastguard Worker `URLRequestHttpJob`. 106*6777b538SAndroid Build Coastguard Worker*** 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard WorkerThe `CookieStore` lives in the `URLRequestContext` and its main implementation, 109*6777b538SAndroid Build Coastguard Workerused for most platforms, is `CookieMonster`. (The rest of this section assumes 110*6777b538SAndroid Build Coastguard Workerthat we are using a `CookieMonster`.) It exposes an asynchronous interface for 111*6777b538SAndroid Build Coastguard Workerstoring and retrieving cookies. 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard WorkerWhen `CookieMonster` receives a `CanonicalCookie` to be set, it queues a task to 114*6777b538SAndroid Build Coastguard Workervalidate and set the cookie. Most of the time this runs immediately, but it may 115*6777b538SAndroid Build Coastguard Workerbe delayed if the network service has just started up, and the contents of the 116*6777b538SAndroid Build Coastguard Worker`PersistentCookieStore` are still being loaded from disk. It checks some 117*6777b538SAndroid Build Coastguard Workercriteria against the cookie's source URL and a `CookieOptions` object (which 118*6777b538SAndroid Build Coastguard Workercontains some other parameters describing the "context" in which the cookie is 119*6777b538SAndroid Build Coastguard Workerbeing set, such as whether it's being accessed in a same-site or cross-site 120*6777b538SAndroid Build Coastguard Workercontext). 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard WorkerIf everything checks out, the `CookieMonster` proceeds with setting the cookie. 123*6777b538SAndroid Build Coastguard WorkerIf an equivalent cookie is present in the store, then it may be deleted. 124*6777b538SAndroid Build Coastguard WorkerEquivalent is defined as sharing a name, domain, and path, based on the 125*6777b538SAndroid Build Coastguard Workerinvariant specified by the RFC that no two such cookies may exist at a given 126*6777b538SAndroid Build Coastguard Workertime. `CookieMonster` stores its `CanonicalCookie`s in a multimap keyed on the 127*6777b538SAndroid Build Coastguard Workerregistrable domain (eTLD+1) of the cookie's domain attribute. 128*6777b538SAndroid Build Coastguard Worker 129*6777b538SAndroid Build Coastguard WorkerThe cookie may also be persisted to disk by a 130*6777b538SAndroid Build Coastguard Worker`CookieMonster::PersistentCookieStore` depending on factors like whether the 131*6777b538SAndroid Build Coastguard Workercookie is a persistent cookie (has an expiration date), whether session cookies 132*6777b538SAndroid Build Coastguard Workershould also be persisted (e.g. if the browser is set to restore the previous 133*6777b538SAndroid Build Coastguard Workerbrowsing session), and whether the profile should have persistent storage (e.g. 134*6777b538SAndroid Build Coastguard Workeryes for normal profiles, but not for Incognito profiles). The 135*6777b538SAndroid Build Coastguard Worker`SQLitePersistentCookieStore` is the main implementation of 136*6777b538SAndroid Build Coastguard Worker`CookieMonster::PersistentCookieStore`. It stores cookies in a SQLite database 137*6777b538SAndroid Build Coastguard Workeron disk, at a filepath specified by the user's profile. 138*6777b538SAndroid Build Coastguard Worker 139*6777b538SAndroid Build Coastguard WorkerAfter the cookie has been stored (or rejected), the `CookieMonster` calls back 140*6777b538SAndroid Build Coastguard Workerto the `URLRequestHttpJob` with the outcome of the storage attempt. The 141*6777b538SAndroid Build Coastguard Worker`URLRequestHttpJob` stashes away the outcomes and stores them in the 142*6777b538SAndroid Build Coastguard Worker`URLRequest` after all `Set-Cookie` headers in the response are processed, so 143*6777b538SAndroid Build Coastguard Workerthat interested parties (e.g. DevTools) can subsequently be notified of cookie 144*6777b538SAndroid Build Coastguard Workeractivity. 145*6777b538SAndroid Build Coastguard Worker 146*6777b538SAndroid Build Coastguard Worker### Cookie is retrieved and sent 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker*** note 149*6777b538SAndroid Build Coastguard Worker**Summary:** 150*6777b538SAndroid Build Coastguard Worker 151*6777b538SAndroid Build Coastguard Worker1. A network request reaches the net stack and generates a `URLRequestHttpJob`, 152*6777b538SAndroid Build Coastguard Worker which queries the `CookieStore` for cookies to include with the request. 153*6777b538SAndroid Build Coastguard Worker2. The `CookieStore` evaluates each of its candidate cookies for whether it can 154*6777b538SAndroid Build Coastguard Worker be included in the request, and reports back to the `URLRequestHttpJob` with 155*6777b538SAndroid Build Coastguard Worker included and excluded cookies. 156*6777b538SAndroid Build Coastguard Worker3. `URLRequestHttpJob` serializes the included cookies into a `Cookie` request 157*6777b538SAndroid Build Coastguard Worker header and attaches it to the outgoing request. 158*6777b538SAndroid Build Coastguard Worker*** 159*6777b538SAndroid Build Coastguard Worker 160*6777b538SAndroid Build Coastguard WorkerSome time later, a (credentialed) request to the same eTLD+1 triggers a cookie 161*6777b538SAndroid Build Coastguard Workeraccess in order to retrieve the relevant cookies to include in the outgoing 162*6777b538SAndroid Build Coastguard Worker`Cookie` request header. The request makes its way to the net stack and causes a 163*6777b538SAndroid Build Coastguard Worker`URLRequestHttpJob` to be created. (See 164*6777b538SAndroid Build Coastguard Worker[Life of a `URLRequest`](/net/docs/life-of-a-url-request.md#check-the-cache_request-an-httpstream) 165*6777b538SAndroid Build Coastguard Workerfor more details.) Upon being started, the `URLRequestHttpJob` asks the 166*6777b538SAndroid Build Coastguard Worker`CookieStore` to retrieve the correct cookies for the URL being requested. 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard WorkerThe `CookieMonster` queues a task to retrieve the cookies. Most of the time this 169*6777b538SAndroid Build Coastguard Workerruns immediately, except if the contents of the `PersistentCookieStore` are 170*6777b538SAndroid Build Coastguard Workerstill being loaded from disk. The `CookieMonster` examines each of the cookies 171*6777b538SAndroid Build Coastguard Workerit has stored for that URL's registrable domain and decides whether it should be 172*6777b538SAndroid Build Coastguard Workerincluded or excluded for that request based on the requested URL and the 173*6777b538SAndroid Build Coastguard Worker`CookieOptions`, by computing a `CookieInclusionStatus`. Criteria for inclusion 174*6777b538SAndroid Build Coastguard Workerare described in 175*6777b538SAndroid Build Coastguard Worker[RFC 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis#section-5.5) 176*6777b538SAndroid Build Coastguard Workerand include: the URL matching the cookie's `Domain` and `Path` attributes, the 177*6777b538SAndroid Build Coastguard WorkerURL being secure if the cookie has the `Secure` attribute, the request context 178*6777b538SAndroid Build Coastguard Worker(i.e. `CookieOptions`) being same-site if the cookie is subject to `SameSite` 179*6777b538SAndroid Build Coastguard Workerenforcement, etc. If any of the requirements are not met, a 180*6777b538SAndroid Build Coastguard Worker`CookieInclusionStatus::ExclusionReason` is recorded. 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard WorkerAfter the exclusion reasons have been tallied up for each cookie, the cookies 183*6777b538SAndroid Build Coastguard Workerwithout any exclusion reasons are deemed suitable for inclusion, and are 184*6777b538SAndroid Build Coastguard Workerreturned to the `URLRequestHttpJob`. The excluded cookies are also returned, 185*6777b538SAndroid Build Coastguard Workeralong with the `CookieInclusionStatus` describing why each cookie was excluded. 186*6777b538SAndroid Build Coastguard Worker 187*6777b538SAndroid Build Coastguard WorkerThe included cookies are serialized into a `Cookie` header string (if the 188*6777b538SAndroid Build Coastguard Worker`NetworkDelegate` is ok with it, based on the user's third-party cookie blocking 189*6777b538SAndroid Build Coastguard Workersettings). The `URLRequestHttpJob` attaches this `Cookie` header to the outgoing 190*6777b538SAndroid Build Coastguard Workerrequest headers: 191*6777b538SAndroid Build Coastguard Worker 192*6777b538SAndroid Build Coastguard Worker``` 193*6777b538SAndroid Build Coastguard WorkerGET /me/want/cookie/omnomnomnom HTTP/1.1 194*6777b538SAndroid Build Coastguard WorkerHost: ... 195*6777b538SAndroid Build Coastguard WorkerUser-Agent: ... 196*6777b538SAndroid Build Coastguard WorkerCookie: chocolate_chip=tasty 197*6777b538SAndroid Build Coastguard Worker... 198*6777b538SAndroid Build Coastguard Worker``` 199*6777b538SAndroid Build Coastguard Worker 200*6777b538SAndroid Build Coastguard WorkerThe included cookies, excluded cookies, and their corresponding 201*6777b538SAndroid Build Coastguard Worker`CookieInclusionStatus`es are also stored in the `URLRequest` to notify 202*6777b538SAndroid Build Coastguard Workerconsumers of cookie activity notifications. 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Worker## Cookie implementation classes 205*6777b538SAndroid Build Coastguard Worker 206*6777b538SAndroid Build Coastguard WorkerThis section lists classes involved in cookie management and access. 207*6777b538SAndroid Build Coastguard Worker 208*6777b538SAndroid Build Coastguard WorkerThe core classes are highlighted. 209*6777b538SAndroid Build Coastguard Worker 210*6777b538SAndroid Build Coastguard Worker### In this directory (//net/cookies) 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker*** note 213*6777b538SAndroid Build Coastguard Worker* **[`CanonicalCookie`](/net/cookies/canonical_cookie.h)** 214*6777b538SAndroid Build Coastguard Worker 215*6777b538SAndroid Build Coastguard Worker The main data type representing cookies. Basically everything that's not 216*6777b538SAndroid Build Coastguard Worker directly dealing with HTTP headers or their equivalents operates on these. 217*6777b538SAndroid Build Coastguard Worker 218*6777b538SAndroid Build Coastguard Worker These are generally obtained via `CanonicalCookie::Create()`, which parses a 219*6777b538SAndroid Build Coastguard Worker string (a `Set-Cookie` header) into an intermediate `ParsedCookie`, whose 220*6777b538SAndroid Build Coastguard Worker fields it canonicalizes/validates and then copies into a `CanonicalCookie`. 221*6777b538SAndroid Build Coastguard Worker*** 222*6777b538SAndroid Build Coastguard Worker 223*6777b538SAndroid Build Coastguard Worker*** note 224*6777b538SAndroid Build Coastguard Worker* **[`CookieStore`](/net/cookies/cookie_store.h)** 225*6777b538SAndroid Build Coastguard Worker 226*6777b538SAndroid Build Coastguard Worker The main interface for a given platform's cookie handling. Provides 227*6777b538SAndroid Build Coastguard Worker asynchronous methods for setting and retrieving cookies. 228*6777b538SAndroid Build Coastguard Worker 229*6777b538SAndroid Build Coastguard Worker Its implementations are responsible for keeping track of all the cookies, 230*6777b538SAndroid Build Coastguard Worker finding cookies relevant for given HTTP requests, saving cookies received in 231*6777b538SAndroid Build Coastguard Worker HTTP responses, etc., and need to know quite a bit about cookie semantics. 232*6777b538SAndroid Build Coastguard Worker*** 233*6777b538SAndroid Build Coastguard Worker 234*6777b538SAndroid Build Coastguard Worker*** note 235*6777b538SAndroid Build Coastguard Worker* **[`CookieMonster`](/net/cookies/cookie_monster.h)** 236*6777b538SAndroid Build Coastguard Worker 237*6777b538SAndroid Build Coastguard Worker The implementation of `CookieStore` used on most platforms. 238*6777b538SAndroid Build Coastguard Worker 239*6777b538SAndroid Build Coastguard Worker It stores all cookies in a multimap keyed on the eTLD+1 of the cookie's 240*6777b538SAndroid Build Coastguard Worker domain. Also manages storage limits by evicting cookies when per-eTLD+1 or 241*6777b538SAndroid Build Coastguard Worker global cookie counts are exceeded. 242*6777b538SAndroid Build Coastguard Worker 243*6777b538SAndroid Build Coastguard Worker It can optionally take an implementation of 244*6777b538SAndroid Build Coastguard Worker `CookieMonster::PersistentCookieStore` to load and store cookies 245*6777b538SAndroid Build Coastguard Worker persisently. 246*6777b538SAndroid Build Coastguard Worker*** 247*6777b538SAndroid Build Coastguard Worker 248*6777b538SAndroid Build Coastguard Worker* [`CookieOptions`](/net/cookies/cookie_options.h) 249*6777b538SAndroid Build Coastguard Worker 250*6777b538SAndroid Build Coastguard Worker Contains parameters for a given attempt to access cookies via 251*6777b538SAndroid Build Coastguard Worker `CookieStore`, such as whether the access is for an HTTP request (as opposed 252*6777b538SAndroid Build Coastguard Worker to a JavaScript API), and the same-site or cross-site context of the request 253*6777b538SAndroid Build Coastguard Worker (relevant to enforcement of the `SameSite` cookie attribute). 254*6777b538SAndroid Build Coastguard Worker 255*6777b538SAndroid Build Coastguard Worker* [`SiteForCookies`](/net/cookies/site_for_cookies.h) 256*6777b538SAndroid Build Coastguard Worker 257*6777b538SAndroid Build Coastguard Worker Represents which origins should be considered "same-site" for a given 258*6777b538SAndroid Build Coastguard Worker context (e.g. frame). This is used to compute the same-site or cross-site 259*6777b538SAndroid Build Coastguard Worker context of a cookie access attempt (which is then conveyed to the 260*6777b538SAndroid Build Coastguard Worker `CookieStore` via a `CookieOptions`). 261*6777b538SAndroid Build Coastguard Worker 262*6777b538SAndroid Build Coastguard Worker It is generally the eTLD+1 and scheme of the top-level frame. It may also be 263*6777b538SAndroid Build Coastguard Worker empty, in which case it represents a context that is cross-site to 264*6777b538SAndroid Build Coastguard Worker everything (e.g. a nested iframe whose ancestor frames don't all belong to 265*6777b538SAndroid Build Coastguard Worker the same site). 266*6777b538SAndroid Build Coastguard Worker 267*6777b538SAndroid Build Coastguard Worker* [`CookieInclusionStatus`](/net/cookies/cookie_inclusion_status.h) 268*6777b538SAndroid Build Coastguard Worker 269*6777b538SAndroid Build Coastguard Worker Records the outcome of a given attempt to access a cookie. Various reasons 270*6777b538SAndroid Build Coastguard Worker for cookie exclusion are recorded 271*6777b538SAndroid Build Coastguard Worker (`CookieInclusionStatus::ExclusionReason`), as well as informational 272*6777b538SAndroid Build Coastguard Worker statuses (`CookieInclusionStatus::WarningReason`) typically used to emit 273*6777b538SAndroid Build Coastguard Worker warnings in DevTools. 274*6777b538SAndroid Build Coastguard Worker 275*6777b538SAndroid Build Coastguard Worker May be used as a member of a `CookieAccessResult`, which includes even more 276*6777b538SAndroid Build Coastguard Worker metadata about the outcome of a cookie access attempt. 277*6777b538SAndroid Build Coastguard Worker 278*6777b538SAndroid Build Coastguard Worker* [`CookieAccessDelegate`](/net/cookies/cookie_access_delegate.h) 279*6777b538SAndroid Build Coastguard Worker 280*6777b538SAndroid Build Coastguard Worker Interface for a `CookieStore` to query information from its embedder that 281*6777b538SAndroid Build Coastguard Worker may modify its decisions on cookie inclusion/exclusion. Its main 282*6777b538SAndroid Build Coastguard Worker implementation allows `CookieMonster` to access data from the network 283*6777b538SAndroid Build Coastguard Worker service layer (e.g. `CookieManager`). 284*6777b538SAndroid Build Coastguard Worker 285*6777b538SAndroid Build Coastguard Worker* [`CookieChangeDispatcher`](/net/cookies/cookie_monster_change_dispatcher.h) 286*6777b538SAndroid Build Coastguard Worker 287*6777b538SAndroid Build Coastguard Worker Interface for subscribing to changes in the contents of the `CookieStore`. 288*6777b538SAndroid Build Coastguard Worker The main implementation is `CookieMonsterChangeDispatcher`. 289*6777b538SAndroid Build Coastguard Worker 290*6777b538SAndroid Build Coastguard Worker### Elsewhere in //net 291*6777b538SAndroid Build Coastguard Worker 292*6777b538SAndroid Build Coastguard Worker*** note 293*6777b538SAndroid Build Coastguard Worker* **[`SQLitePersistentCookieStore`](/net/extras/sqlite/sqlite_persistent_cookie_store.h)** 294*6777b538SAndroid Build Coastguard Worker 295*6777b538SAndroid Build Coastguard Worker Implementation of `CookieMonster::PersistentCookieStore` used on most 296*6777b538SAndroid Build Coastguard Worker platforms. Uses a SQLite database to load and store cookies, potentially 297*6777b538SAndroid Build Coastguard Worker using an optional delegate to encrypt and decrypt their at-rest versions. 298*6777b538SAndroid Build Coastguard Worker This class is refcounted. 299*6777b538SAndroid Build Coastguard Worker 300*6777b538SAndroid Build Coastguard Worker `CookieMonster` loads cookies from here on startup. All other operations 301*6777b538SAndroid Build Coastguard Worker attempting to access cookies in the process of being loaded are blocked 302*6777b538SAndroid Build Coastguard Worker until loading of those cookies completes. Thus, it fast-tracks loading of 303*6777b538SAndroid Build Coastguard Worker cookies for an eTLD+1 with pending requests, to decrease latency for 304*6777b538SAndroid Build Coastguard Worker cookie access operations made soon after browser startup (by decreasing the 305*6777b538SAndroid Build Coastguard Worker number of cookies whose loading is blocking requests). 306*6777b538SAndroid Build Coastguard Worker*** 307*6777b538SAndroid Build Coastguard Worker 308*6777b538SAndroid Build Coastguard Worker*** note 309*6777b538SAndroid Build Coastguard Worker* **[`URLRequestHttpJob`](/net/url_request/url_request_http_job.h)** 310*6777b538SAndroid Build Coastguard Worker 311*6777b538SAndroid Build Coastguard Worker A `URLRequestJob` implementation that handles HTTP requests; most 312*6777b538SAndroid Build Coastguard Worker relevantly, the `Cookie` and `Set-Cookie` HTTP headers. It drives the 313*6777b538SAndroid Build Coastguard Worker process for storing cookies and retrieving cookies for HTTP requests. 314*6777b538SAndroid Build Coastguard Worker 315*6777b538SAndroid Build Coastguard Worker Also logs cookie events to the NetLog for each request. 316*6777b538SAndroid Build Coastguard Worker*** 317*6777b538SAndroid Build Coastguard Worker 318*6777b538SAndroid Build Coastguard Worker* [`URLRequest`](/net/url_request/url_request.h) 319*6777b538SAndroid Build Coastguard Worker 320*6777b538SAndroid Build Coastguard Worker Mostly relevant for its two members, `maybe_sent_cookies_` and 321*6777b538SAndroid Build Coastguard Worker `maybe_stored_cookies_`, which are vectors in which `URLRequestHttpJob` 322*6777b538SAndroid Build Coastguard Worker stashes the cookies it considered sending/storing and their 323*6777b538SAndroid Build Coastguard Worker `CookieInclusionStatus`es. These then get mojo'ed over to the browser 324*6777b538SAndroid Build Coastguard Worker process to notify observers of cookie activity. 325*6777b538SAndroid Build Coastguard Worker 326*6777b538SAndroid Build Coastguard Worker### In //services/network 327*6777b538SAndroid Build Coastguard Worker 328*6777b538SAndroid Build Coastguard Worker*** note 329*6777b538SAndroid Build Coastguard Worker* **[`CookieManager`](/services/network/cookie_manager.h)** 330*6777b538SAndroid Build Coastguard Worker 331*6777b538SAndroid Build Coastguard Worker The network service API to cookies. Basically exports a `CookieStore` via 332*6777b538SAndroid Build Coastguard Worker mojo IPC. 333*6777b538SAndroid Build Coastguard Worker 334*6777b538SAndroid Build Coastguard Worker Owned by the `NetworkContext`. 335*6777b538SAndroid Build Coastguard Worker*** 336*6777b538SAndroid Build Coastguard Worker 337*6777b538SAndroid Build Coastguard Worker*** note 338*6777b538SAndroid Build Coastguard Worker* **[`RestrictedCookieManager`](/services/network/restricted_cookie_manager.h)** 339*6777b538SAndroid Build Coastguard Worker 340*6777b538SAndroid Build Coastguard Worker Mojo interface for accessing cookies for a specific origin. This can be 341*6777b538SAndroid Build Coastguard Worker handed out to untrusted (i.e. renderer) processes, as inputs are assumed to 342*6777b538SAndroid Build Coastguard Worker be unsafe. 343*6777b538SAndroid Build Coastguard Worker 344*6777b538SAndroid Build Coastguard Worker It is primarily used for accessing cookies via JavaScript. 345*6777b538SAndroid Build Coastguard Worker It provides a synchronous interface for 346*6777b538SAndroid Build Coastguard Worker [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie), 347*6777b538SAndroid Build Coastguard Worker as well as an asynchronous one for the [CookieStore API](https://wicg.github.io/cookie-store/). 348*6777b538SAndroid Build Coastguard Worker*** 349*6777b538SAndroid Build Coastguard Worker 350*6777b538SAndroid Build Coastguard Worker* [`CookieSettings`](/services/network/cookie_settings.h) 351*6777b538SAndroid Build Coastguard Worker 352*6777b538SAndroid Build Coastguard Worker Keeps track of the content settings (per-profile 353*6777b538SAndroid Build Coastguard Worker [permissions](/components/permissions/README.md) for types of 354*6777b538SAndroid Build Coastguard Worker content that a given origin is allowed to use) for cookies, such as the 355*6777b538SAndroid Build Coastguard Worker user's third-party cookie blocking settings, origins/domains with 356*6777b538SAndroid Build Coastguard Worker third-party cookie blocking exceptions or "legacy" access settings. 357*6777b538SAndroid Build Coastguard Worker 358*6777b538SAndroid Build Coastguard Worker It is not to be confused with `content_settings::CookieSettings`, which 359*6777b538SAndroid Build Coastguard Worker manages the browser's version of the cookie content settings, of which 360*6777b538SAndroid Build Coastguard Worker `network::ContentSettings` is approximately a copy/mirror. The 361*6777b538SAndroid Build Coastguard Worker `ProfileNetworkContextService` populates its contents upon `NetworkContext` 362*6777b538SAndroid Build Coastguard Worker construction from the browser-side content settings, and also updates it 363*6777b538SAndroid Build Coastguard Worker whenever the browser-side content settings change. 364*6777b538SAndroid Build Coastguard Worker 365*6777b538SAndroid Build Coastguard Worker* [`SessionCleanupCookieStore`](/services/network/session_cleanup_cookie_store.h) 366*6777b538SAndroid Build Coastguard Worker 367*6777b538SAndroid Build Coastguard Worker Implements `CookieMonster::PersistentCookieStore`, by wrapping a 368*6777b538SAndroid Build Coastguard Worker `SQLitePersistentCookieStore`. Keeps an in-memory map of cookies per eTLD+1 369*6777b538SAndroid Build Coastguard Worker to allow deletion of cookies for sites whose cookie content setting is 370*6777b538SAndroid Build Coastguard Worker "session-only" from the persistent store when the session ends. 371*6777b538SAndroid Build Coastguard Worker 372*6777b538SAndroid Build Coastguard Worker 373*6777b538SAndroid Build Coastguard Worker### Elsewhere 374*6777b538SAndroid Build Coastguard Worker 375*6777b538SAndroid Build Coastguard Worker* [`CookieAccessObserver`](/services/network/public/mojom/cookie_access_observer.mojom) 376*6777b538SAndroid Build Coastguard Worker and [`WebContentsObserver`](/content/public/browser/web_contents_observer.h) 377*6777b538SAndroid Build Coastguard Worker 378*6777b538SAndroid Build Coastguard Worker `CookieAccessObserver` is a mojo interface used to observe attempts to 379*6777b538SAndroid Build Coastguard Worker access (read or write) cookies. It is implemented by `NavigationHandle` and 380*6777b538SAndroid Build Coastguard Worker `RenderFrameHost`. 381*6777b538SAndroid Build Coastguard Worker 382*6777b538SAndroid Build Coastguard Worker The cookie accesses are attributable to a committed document that called 383*6777b538SAndroid Build Coastguard Worker `document.cookie` or made a network request (if notified through 384*6777b538SAndroid Build Coastguard Worker `RenderFrameHost`), or a not-yet-committed navigation that resulted in a 385*6777b538SAndroid Build Coastguard Worker network request (if notified through `NavigationHandle`). 386*6777b538SAndroid Build Coastguard Worker 387*6777b538SAndroid Build Coastguard Worker The `CookieAccessObserver`s forward the notifications to `WebContents`, 388*6777b538SAndroid Build Coastguard Worker which then notifies its `WebContentsObserver`s. One such 389*6777b538SAndroid Build Coastguard Worker `WebContentsObserver` that cares about this information is 390*6777b538SAndroid Build Coastguard Worker `PageSpecificContentSettings`, which displays information about allowed and 391*6777b538SAndroid Build Coastguard Worker blocked cookies in UI surfaces (see next item). 392*6777b538SAndroid Build Coastguard Worker 393*6777b538SAndroid Build Coastguard Worker* [`CookiesTreeModel`](/chrome/browser/browsing_data/cookies_tree_model.h) 394*6777b538SAndroid Build Coastguard Worker 395*6777b538SAndroid Build Coastguard Worker Stores cookie information for use in settings UI (the Page Info Bubble and 396*6777b538SAndroid Build Coastguard Worker various `chrome://settings` pages). Populated with info from 397*6777b538SAndroid Build Coastguard Worker `PageSpecificContentSettings`. 398*6777b538SAndroid Build Coastguard Worker 399*6777b538SAndroid Build Coastguard Worker* [`CookieJar`](/third_party/blink/renderer/core/loader/cookie_jar.h) 400*6777b538SAndroid Build Coastguard Worker 401*6777b538SAndroid Build Coastguard Worker Implements the `document.cookie` API in the renderer by requesting a 402*6777b538SAndroid Build Coastguard Worker `RestrictedCookieManager` from the browser. 403*6777b538SAndroid Build Coastguard Worker 404*6777b538SAndroid Build Coastguard Worker* [`CookieStore`](/third_party/blink/renderer/modules/cookie_store/cookie_store.h) 405*6777b538SAndroid Build Coastguard Worker 406*6777b538SAndroid Build Coastguard Worker Implements the JavaScript 407*6777b538SAndroid Build Coastguard Worker [CookieStore API](https://wicg.github.io/cookie-store/) in the renderer by 408*6777b538SAndroid Build Coastguard Worker requesting a `RestrictedCookieManager` from the browser. (Not to be confused 409*6777b538SAndroid Build Coastguard Worker with `net::CookieStore`.) 410*6777b538SAndroid Build Coastguard Worker 411*6777b538SAndroid Build Coastguard Worker* [`CookiesAPI`](/chrome/browser/extensions/api/cookies/cookies_api.h) 412*6777b538SAndroid Build Coastguard Worker 413*6777b538SAndroid Build Coastguard Worker Implements the 414*6777b538SAndroid Build Coastguard Worker [`chrome.cookies`](https://developer.chrome.com/extensions/cookies) API for 415*6777b538SAndroid Build Coastguard Worker Chrome extensions. Gives extensions with the proper permissions essentially 416*6777b538SAndroid Build Coastguard Worker unfettered access to the `CookieStore`. 417*6777b538SAndroid Build Coastguard Worker 418*6777b538SAndroid Build Coastguard Worker### Platform-specific 419*6777b538SAndroid Build Coastguard Worker 420*6777b538SAndroid Build Coastguard Worker* [`CookieStoreIOS` and `CookieStoreIOSPersistent`](/ios/net/cookies) 421*6777b538SAndroid Build Coastguard Worker 422*6777b538SAndroid Build Coastguard Worker iOS-specific `CookieStore` implementations, mainly relying on the iOS native 423*6777b538SAndroid Build Coastguard Worker cookie implementation (`NSHTTPCookie`). 424*6777b538SAndroid Build Coastguard Worker 425*6777b538SAndroid Build Coastguard Worker* [`android_webview::CookieManager`](/android_webview/browser/cookie_manager.h) 426*6777b538SAndroid Build Coastguard Worker 427*6777b538SAndroid Build Coastguard Worker Manages cookies for Android WebView. It typically wraps a 428*6777b538SAndroid Build Coastguard Worker `network::mojom::CookieManager`, but it can also be used before a 429*6777b538SAndroid Build Coastguard Worker `NetworkContext` even exists, thanks to Android WebView's 430*6777b538SAndroid Build Coastguard Worker [cookie API](https://developer.android.com/reference/kotlin/android/webkit/CookieManager), 431*6777b538SAndroid Build Coastguard Worker which means it is sometimes initialized with a bare `net::CookieStore`. 432*6777b538SAndroid Build Coastguard Worker 433*6777b538SAndroid Build Coastguard Worker Also notable for allowing cookies for `file://` scheme URLs (normally they 434*6777b538SAndroid Build Coastguard Worker are only allowed for HTTP and websocket schemes and `chrome-extension://`), 435*6777b538SAndroid Build Coastguard Worker though this is non-default and deprecated. 436*6777b538SAndroid Build Coastguard Worker 437*6777b538SAndroid Build Coastguard Worker## Main interfaces for finding, setting, deleting, and observing cookies 438*6777b538SAndroid Build Coastguard Worker 439*6777b538SAndroid Build Coastguard WorkerThis section summarizes interfaces for interacting with cookies from various 440*6777b538SAndroid Build Coastguard Workerparts of the codebase. 441*6777b538SAndroid Build Coastguard Worker 442*6777b538SAndroid Build Coastguard Worker### From //net or //services/network 443*6777b538SAndroid Build Coastguard Worker 444*6777b538SAndroid Build Coastguard Worker*** note 445*6777b538SAndroid Build Coastguard WorkerUse [`net::CookieStore`](/net/cookies/cookie_store.h) to save and retrieve 446*6777b538SAndroid Build Coastguard Worker[`CanonicalCookie`](/net/cookies/canonical_cookie.h)s. 447*6777b538SAndroid Build Coastguard Worker*** 448*6777b538SAndroid Build Coastguard Worker 449*6777b538SAndroid Build Coastguard Worker* `CanonicalCookie`s are the main data type representing cookies. Get one using 450*6777b538SAndroid Build Coastguard Worker `CanonicalCookie::Create()`. 451*6777b538SAndroid Build Coastguard Worker 452*6777b538SAndroid Build Coastguard Worker* The `CookieStore` can be accessed via its owning `URLRequestContext`, which 453*6777b538SAndroid Build Coastguard Worker can be accessed through `NetworkContext`. 454*6777b538SAndroid Build Coastguard Worker 455*6777b538SAndroid Build Coastguard Worker* To access cookies, you need a `CookieOptions`. The main things in this object 456*6777b538SAndroid Build Coastguard Worker are the `HttpOnly` access permission and the `SameSite` context. The latter 457*6777b538SAndroid Build Coastguard Worker can be obtained from [`cookie_util`](/net/cookies/cookie_util.h) functions. 458*6777b538SAndroid Build Coastguard Worker 459*6777b538SAndroid Build Coastguard Worker* Retrieve cookies using `GetCookieListWithOptionsAsync()`. 460*6777b538SAndroid Build Coastguard Worker 461*6777b538SAndroid Build Coastguard Worker* Save cookies using `SetCanonicalCookieAsync()`. 462*6777b538SAndroid Build Coastguard Worker 463*6777b538SAndroid Build Coastguard Worker*** note 464*6777b538SAndroid Build Coastguard WorkerUse `CookieStore` to selectively delete cookies. 465*6777b538SAndroid Build Coastguard Worker*** 466*6777b538SAndroid Build Coastguard Worker 467*6777b538SAndroid Build Coastguard Worker* `DeleteCanonicalCookieAsync()` deletes a single cookie. 468*6777b538SAndroid Build Coastguard Worker 469*6777b538SAndroid Build Coastguard Worker* `DeleteAllCreatedInTimeRangeAsync()` deletes cookies created in a time range. 470*6777b538SAndroid Build Coastguard Worker 471*6777b538SAndroid Build Coastguard Worker* `DeleteAllMatchingInfoAsync()` deletes cookies that match a filter. 472*6777b538SAndroid Build Coastguard Worker 473*6777b538SAndroid Build Coastguard Worker*** note 474*6777b538SAndroid Build Coastguard WorkerUse the [`CookieChangeDispatcher`](/net/cookies/cookie_change_dispatcher.h) 475*6777b538SAndroid Build Coastguard Workerinterface to subscribe to changes. 476*6777b538SAndroid Build Coastguard Worker*** 477*6777b538SAndroid Build Coastguard Worker 478*6777b538SAndroid Build Coastguard Worker* Use `AddCallbackForCookie()` to observe changes to cookies with a given name 479*6777b538SAndroid Build Coastguard Worker that would be sent with a request to a specific URL. 480*6777b538SAndroid Build Coastguard Worker 481*6777b538SAndroid Build Coastguard Worker* Use `AddCallbackForUrl()` to observe changes to all cookies that would be sent 482*6777b538SAndroid Build Coastguard Worker with a request to a specific URL. 483*6777b538SAndroid Build Coastguard Worker 484*6777b538SAndroid Build Coastguard Worker* Use `AddCallbackForAllChanges()` to observe changes to all cookies in the 485*6777b538SAndroid Build Coastguard Worker `CookieStore`. 486*6777b538SAndroid Build Coastguard Worker 487*6777b538SAndroid Build Coastguard Worker### From the browser process 488*6777b538SAndroid Build Coastguard Worker 489*6777b538SAndroid Build Coastguard Worker*** note 490*6777b538SAndroid Build Coastguard WorkerUse [`CookieManager`](/services/network/cookie_manager.h) 491*6777b538SAndroid Build Coastguard Worker(which basically exports a `net::CookieStore` interface via mojo) to save 492*6777b538SAndroid Build Coastguard Workerand retrieve [`CanonicalCookie`](/net/cookies/canonical_cookie.h)s. 493*6777b538SAndroid Build Coastguard Worker*** 494*6777b538SAndroid Build Coastguard Worker 495*6777b538SAndroid Build Coastguard Worker* The profile's `CookieManager` can be accessed from the browser process through 496*6777b538SAndroid Build Coastguard Worker `StoragePartition::GetCookieManagerForBrowserProcess()`. 497*6777b538SAndroid Build Coastguard Worker 498*6777b538SAndroid Build Coastguard Worker* You can also get get a `CookieManager` pipe from the `NetworkContext` using 499*6777b538SAndroid Build Coastguard Worker `GetCookieManager()`. 500*6777b538SAndroid Build Coastguard Worker 501*6777b538SAndroid Build Coastguard Worker* Retrieve cookies using `CookieManager::GetCookieList()`. 502*6777b538SAndroid Build Coastguard Worker 503*6777b538SAndroid Build Coastguard Worker* Save cookies using `CookieManager::SetCanonicalCookie()`. 504*6777b538SAndroid Build Coastguard Worker 505*6777b538SAndroid Build Coastguard Worker*** note 506*6777b538SAndroid Build Coastguard WorkerUse `CookieManager` to selectively delete cookies. 507*6777b538SAndroid Build Coastguard Worker*** 508*6777b538SAndroid Build Coastguard Worker 509*6777b538SAndroid Build Coastguard Worker* If you have a copy of the `CanonicalCookie` to delete (e.g. a cookie 510*6777b538SAndroid Build Coastguard Worker previously fetched from the store), use 511*6777b538SAndroid Build Coastguard Worker `CookieManager::DeleteCanonicalCookie()`. 512*6777b538SAndroid Build Coastguard Worker 513*6777b538SAndroid Build Coastguard Worker* To delete cookies with certain characteristics, construct a 514*6777b538SAndroid Build Coastguard Worker [`CookieDeletionFilter`](/services/network/public/mojom/cookie_manager.mojom) 515*6777b538SAndroid Build Coastguard Worker and use `CookieManager::DeleteCookies()`. 516*6777b538SAndroid Build Coastguard Worker 517*6777b538SAndroid Build Coastguard Worker*** note 518*6777b538SAndroid Build Coastguard WorkerUse `CookieManager`'s change listener interface to subscribe to changes (this 519*6777b538SAndroid Build Coastguard Workerparallels the `net::CookieChangeDispatcher` interface). 520*6777b538SAndroid Build Coastguard Worker*** 521*6777b538SAndroid Build Coastguard Worker 522*6777b538SAndroid Build Coastguard Worker* Add a `CookieChangeListener` registration for a URL (and optionally a cookie 523*6777b538SAndroid Build Coastguard Worker name) via `AddCookieChangeListener()` 524*6777b538SAndroid Build Coastguard Worker 525*6777b538SAndroid Build Coastguard Worker* Add a `CookieChangeListener` registration for all cookies via 526*6777b538SAndroid Build Coastguard Worker `AddGlobalChangeListener()`. 527*6777b538SAndroid Build Coastguard Worker 528*6777b538SAndroid Build Coastguard Worker### From untrusted (e.g. renderer) processes 529*6777b538SAndroid Build Coastguard Worker 530*6777b538SAndroid Build Coastguard Worker*** note 531*6777b538SAndroid Build Coastguard WorkerUse a 532*6777b538SAndroid Build Coastguard Worker[`network::mojom::RestrictedCookieManager`](/services/network/public/mojom/restricted_cookie_manager.mojom) 533*6777b538SAndroid Build Coastguard Workerinterface to access cookies for a particular origin. 534*6777b538SAndroid Build Coastguard Worker*** 535*6777b538SAndroid Build Coastguard Worker 536*6777b538SAndroid Build Coastguard Worker* Request a `RestrictedCookieManager` interface from the browser. This creates a 537*6777b538SAndroid Build Coastguard Worker `RestrictedCookieManager` bound to a `RenderFrameHost`, which can only access 538*6777b538SAndroid Build Coastguard Worker cookies on behalf of the corresponding origin. 539*6777b538SAndroid Build Coastguard Worker 540*6777b538SAndroid Build Coastguard Worker* Cookies can be read and written asynchronously (`GetAllForUrl()`, 541*6777b538SAndroid Build Coastguard Worker `SetCanonicalCookie()`) or synchronously (`SetCookieFromString()`, 542*6777b538SAndroid Build Coastguard Worker `GetCookiesString()`). 543*6777b538SAndroid Build Coastguard Worker 544*6777b538SAndroid Build Coastguard Worker* [Compromised renderers](/docs/security/compromised-renderers.md#Cookies) 545*6777b538SAndroid Build Coastguard Worker shouldn't be able to access cookies of another site, or `HttpOnly` cookies 546*6777b538SAndroid Build Coastguard Worker (even from the same site). 547