Skip to content

Commit 5971b14

Browse files
Pick up, dust off, and improve cookie layering
This patch does the following to the work in whatwg#1707: - rebase to main - add logic for parsing and storing cookies - point to the IETF-hosted draft cookie spec - don't point to storage access API for has storage access, use a broken link instead - add a broken link to environment/ancestry - add a broken link for the request's initiator origin plumbed in from HTML. It'll be defined here, but we need to modify HTML so we can track it in the top. - add broken links to things that need to be added to HTML - fix some nits (e.g. "foo" -> "<code>foo</code>") - use [=secure context=] not scheme=https - use SameSite=None by default. Let's punt on that for now, given the current state of implementations and lack of clear path forward.
1 parent 07662d3 commit 5971b14

File tree

1 file changed

+144
-33
lines changed

1 file changed

+144
-33
lines changed

fetch.bs

+144-33
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,29 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
5454
url:realm;text:realm
5555
url:sec-list-and-record-specification-type;text:Record
5656
url:current-realm;text:current realm
57+
58+
urlPrefix:https://www.ietf.org/archive/id/draft-annevk-johannhof-httpbis-cookies-00.html#;type:dfn;spec:cookies
59+
url:name-cookie-store-and-limits;text:cookie store
60+
url:name-parse-and-store-a-cookie;text:parse and store a cookie
61+
url:name-parse-a-cookie;text:parse a cookie
62+
url:name-store-a-cookie;text:store a cookie
63+
url:name-retrieve-cookies;text:retrieve cookies
64+
url:name-serialize-cookies;text:serialize cookies
65+
66+
<!-- TODO: pending HTML changes- ancestor enum (https://github.com/whatwg/html/pull/10559), has storage access bit, initiator origin plumbing -->
67+
urlPrefix:https://html.spec.whatwg.org#;type:dfn;spec:html
68+
url:TODO;text:ancestry;for:environment
69+
url:TODO;text:has storage access;for:environment
70+
url:TODO;text:initiator origin;for:request
5771
</pre>
5872

5973
<pre class=biblio>
6074
{
75+
"COOKIES": {
76+
"authors": ["Johann Hofmann", "Anne Van Kesteren"],
77+
"href": "https://www.ietf.org/archive/id/draft-annevk-johannhof-httpbis-cookies-00.html",
78+
"title": "Cookies: HTTP State Management Mechanism"
79+
},
6180
"HTTP": {
6281
"aliasOf": "RFC9110"
6382
},
@@ -2226,31 +2245,38 @@ or "<code>object</code>".
22262245
<hr>
22272246

22282247
<div algorithm>
2229-
<p>A <a for=/>request</a> <var>request</var> has a
2230-
<dfn for=request id=concept-request-tainted-origin>redirect-tainted origin</dfn> if these steps
2231-
return true:
2248+
<p>A <a for=/>request</a> has a <dfn for=request id=concept-request-redirect-taint>redirect-taint</dfn>,
2249+
which is "<code>None</code>", "<code>Cross-Origin</code>", or "<code>Cross-Site</code>".
2250+
<p>To get <a for=/>request</a> <var>request</var>'s <a>redirect-taint</a>:
22322251

22332252
<ol>
22342253
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>origin</a> is not
22352254
"<code>client</code>".
22362255

22372256
<li><p>Let <var>lastURL</var> be null.
22382257

2258+
<li><p>Let <var>crossOriginTaint</var> be "<code>None</code>".
2259+
22392260
<li>
22402261
<p><a for=list>For each</a> <var>url</var> of <var>request</var>'s <a for=request>URL list</a>:
22412262

22422263
<ol>
22432264
<li><p>If <var>lastURL</var> is null, then set <var>lastURL</var> to <var>url</var> and
22442265
<a for=iteration>continue</a>.
22452266

2267+
<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a for=/>same site</a> with
2268+
<var>lastURL</var>'s <a for=url>origin</a> and <var>request</var>'s <a for=request>origin</a> is
2269+
not <a for=/>same site</a> with <var>lastURL</var>'s <a for=url>origin</a>, then return "<code>Cross-Site</code>".
2270+
22462271
<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a>same origin</a> with
22472272
<var>lastURL</var>'s <a for=url>origin</a> and <var>request</var>'s <a for=request>origin</a> is
2248-
not <a>same origin</a> with <var>lastURL</var>'s <a for=url>origin</a>, then return true.
2273+
not <a>same origin</a> with <var>lastURL</var>'s <a for=url>origin</a>,
2274+
then let <var>crossOriginTaint</var> be "<code>Cross-Origin</code>"..
22492275

22502276
<li>Set <var>lastURL</var> to <var>url</var>.
22512277
</ol>
22522278

2253-
<li>Return false.
2279+
<li>Return <var>crossOriginTaint</var>.
22542280
</ol>
22552281
</div>
22562282

@@ -2262,8 +2288,8 @@ run these steps:
22622288
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>origin</a> is not
22632289
"<code>client</code>".
22642290

2265-
<li><p>If <var>request</var> has a <a for=request>redirect-tainted origin</a>, then return
2266-
"<code>null</code>".
2291+
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is not "<code>None</code>",
2292+
then return "<code>null</code>".
22672293

22682294
<li><p>Return <var>request</var>'s <a for=request>origin</a>,
22692295
<a lt="ASCII serialization of an origin">serialized</a>.
@@ -2372,8 +2398,8 @@ source of security bugs. Please seek security review for features that deal with
23722398
"<a for="embedder policy value"><code>credentialless</code></a>", then return true.</p>
23732399

23742400
<li><p>If <var>request</var>'s <a for=request>origin</a> is <a>same origin</a> with
2375-
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>origin</a> and <var>request</var>
2376-
does not have a <a for=request>redirect-tainted origin</a>, then return true.</p>
2401+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>origin</a> and <var>request</var>'s
2402+
<a for=request>redirect-taint</a> is not "<code>None</code>", then return true.</p>
23772403

23782404
<li><p>Return false.</p>
23792405
</ol>
@@ -2489,6 +2515,9 @@ this is also tracked internally using the request's <a for=request>timing allow
24892515
<p>A <a for=/>response</a> has an associated <dfn for=response>has-cross-origin-redirects</dfn>
24902516
(a boolean), which is initially false.
24912517

2518+
<p>A <a for=/>response</a> has an associated <dfn for=response>has-cross-site-redirects</dfn>
2519+
(a boolean), which is initially false.
2520+
24922521
<hr>
24932522

24942523
<p>A <dfn export id=concept-network-error>network error</dfn> is a <a for=/>response</a> whose
@@ -2710,7 +2739,6 @@ manually. [[!HTML]]
27102739
</ol>
27112740
</div>
27122741

2713-
27142742
<h3 id=authentication-entries>Authentication entries</h3>
27152743

27162744
<p>An <dfn export>authentication entry</dfn> and a <dfn export>proxy-authentication entry</dfn> are
@@ -3292,6 +3320,105 @@ through TLS using ALPN. The protocol cannot be spoofed through HTTP requests in
32923320

32933321
<h2 id=http-extensions>HTTP extensions</h2>
32943322

3323+
<h3 id=cookie-header>`<code>Cookie</code>` header</h3>
3324+
3325+
<p>The `<dfn export http-header id=http-cookie><code>Cookie</code></dfn>`
3326+
request <a for=/>header</a> allows the request to carry locally stored state, such as user credentials.
3327+
3328+
<div algorithm>
3329+
<p>To <dfn id=append-a-request-cookie-header>append a request `<code>Cookie</code>` header</dfn>,
3330+
given a <a for=/>request</a> <var>request</var>, run these steps:
3331+
<ol>
3332+
<li><p>Let |sameSite| be the result of [=determining the same-site mode=] for <var>request</var>.
3333+
<li><p>Let |isSecure| be false.
3334+
<li><p>If <var>request</var>'s <a for=request>client</a> is a <a>secure context</a>, then set |isSecure| to true.
3335+
<li><p>Let |httpOnlyAllowed| be true.
3336+
<p class=note>Fetch implies that the request is http-only, as opposed to document.cookie
3337+
<li><p>Let |partitionKey| be the result of [=computing the cookie partition key=] for <var>request</var>.
3338+
<li><p>Let |partitionedContext| be the result of [=determining the partitioned context state=] for |request|.
3339+
<li><p>Let |cookies| be the result of running <a>retrieve cookies</a> given
3340+
|isSecure|,
3341+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>host</a>,
3342+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>path</a>,
3343+
|httpOnlyAllowed|,
3344+
|sameSite|,
3345+
|partitionKey|
3346+
and |partitionedContext|.
3347+
3348+
<p class=note>It is expected that the cookie store returns an ordered list of cookies
3349+
<li>If |cookies| <a for="list">is empty</a>, then return.
3350+
<li>Let |value| be the result of running <a>serialize cookies</a> given |cookies|.
3351+
<li><a for="header list">Append</a> (`<code>Cookie</code>`, <var>value</var>) to <var>request</var>'s <a for=request>header list</a>.
3352+
</ol>
3353+
</div>
3354+
3355+
<div algorithm>
3356+
<p>To <dfn id=parse-and-store-response-cookie-headers>parse and store response `<code>Set-Cookie</code>` headers</dfn>,
3357+
given a <a for=/>request</a> <var>request</var> and a <a for=/>response</a> <var>response</var>, run these steps:
3358+
<ol>
3359+
<li><p>Let |allowNonHostOnlyCookieForPublicSuffix| be false.
3360+
<li><p>Let |isSecure| be false.
3361+
<li><p>If <var>request</var>'s <a for=request>client</a> is a <a>secure context</a>, then set |isSecure| to true.
3362+
<li><p>Let |httpOnlyAllowed| be true.
3363+
<p class=note>Fetch implies that the request is http-only, as opposed to document.cookie
3364+
<li><p>Let |partitionKey| be the result of [=computing the cookie partition key=] for <var>request</var>.
3365+
<li><p>Let |partitionedContext| be the result of [=determining the partitioned context state=] for |request|.
3366+
<li><p>Let |sameSiteStrictOrLaxAllowed| be true if the result of [=determine the same-site mode=] for |request| is "<code>StrictOrLess</code>", and false otherwise.
3367+
<li><p><a for=list>For each</a> <var>header</var> of <var>response</var>'s <a for=response>header list</a>:
3368+
<ol>
3369+
<li><p>If <var>header</var>'s <a for=header>name</a> is not a <a>byte-case-insensitive</a> match for `<code>Set-Cookie</code>`, then <a for=iteration>continue</a>.
3370+
<li><p><a>Parse and store a cookie</a> given
3371+
<var>header</var>'s <a for=header>value</a>,
3372+
|isSecure|,
3373+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>host</a>,
3374+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>path</a>,
3375+
|httpOnlyAllowed|,
3376+
|allowNonHostOnlyCookieForPublicSuffix|,
3377+
|sameSiteStrictOrLaxAllowed|,
3378+
|partitionKey|
3379+
and |partitionedContext|.
3380+
</ol>
3381+
</ol>
3382+
</div>
3383+
3384+
<div algorithm>
3385+
<p>To <dfn>determine the same-site mode</dfn> for a given <a for=/>request</a> <var>request</var>, run these steps:
3386+
<ol>
3387+
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>method</a> is "GET" or "POST".
3388+
<li><p>If <var>request</var>'s <a for=request>method</a> is "GET" and
3389+
<var>request</var>'s <a for=request>destination</a> is "document", return "<code>LaxOrLess</code>".
3390+
<li><p>If <var>request</var>'s <a for=request>client</a>'s <a for=environment>ancestry</a> is "<code>cross-site</code>", return "<code>UnsetOrLess</code>".
3391+
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is "<code>Cross-Site</code>", return "<code>UnsetOrLess</code>".
3392+
<li><p>If <var>request</var>'s <a for=request>initiator origin</a> is not <a for=/>same site</a> to <var>request</var>'s <a for=request>URL</a>'s <a for=url>origin</a>, return "<code>UnsetOrLess</code>".
3393+
<li><p>Return "StrictOrLess".
3394+
</ol>
3395+
</div>
3396+
3397+
3398+
<div algorithm>
3399+
<p>To <dfn>compute the cookie partition key</dfn> for a given <a for=/>request</a> <var>request</var>, run these steps:
3400+
<ol>
3401+
<li><p>Let <var>topLevelOrigin</var> be <var>request</var>'s <a for=request>client</a>'s
3402+
<a for="environment">top-level origin</a>.
3403+
3404+
<li><p>Let <var>topLevelSite</var> be the result of <a lt="obtain a site">obtaining a site</a>,
3405+
given <var>topLevelOrigin</var>.
3406+
3407+
<li><p>Let <var>crossSiteAncestors</var> be true if <var>request</var>'s <a for=request>client</a>'s <a for=environment>ancestry</a> is "<code>cross-site</code>", false otherwise.
3408+
3409+
<li><p>Return (<var>topLevelSite</var>, <var>crossSiteAncestors</var>).
3410+
</ol>
3411+
</div>
3412+
3413+
<div algorithm>
3414+
<p>To <dfn>determine the partitioned context state</dfn> for a given <a for=/>request</a> <var>request</var>, run these steps:
3415+
<ol>
3416+
<li><p>If <var>request</var>'s <a for=request>client</a>'s <a for=environment>ancestry</a> is not "<code>cross-site</code>", return false.
3417+
<li><p>If <var>request</var>'s <a for=request>client</a>'s [=environment/has storage access=] is true, return false.
3418+
<li><p>Return true.
3419+
</ol>
3420+
</div>
3421+
32953422
<h3 id=origin-header>`<code>Origin</code>` header</h3>
32963423

32973424
<p>The `<dfn export http-header id=http-origin><code>Origin</code></dfn>`
@@ -4680,9 +4807,12 @@ steps:
46804807
<!-- If you are ever tempted to move this around, carefully consider responses from about URLs,
46814808
blob URLs, service workers, HTTP cache, HTTP network, etc. -->
46824809

4683-
<li><p>If <var>request</var> has a <a for=request>redirect-tainted origin</a>, then set
4810+
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is not "<code>None</code>", then set
46844811
<var>internalResponse</var>'s <a for=response>has-cross-origin-redirects</a> to true.
46854812

4813+
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is "<code>Cross-Site</code>", then set
4814+
<var>internalResponse</var>'s <a for=response>has-cross-site-redirects</a> to true.
4815+
46864816
<li><p>If <var>request</var>'s <a for=request>timing allow failed flag</a> is unset, then set
46874817
<var>internalResponse</var>'s <a for=response>timing allow passed flag</a>.
46884818

@@ -5710,21 +5840,9 @@ run these steps:
57105840
<p>If <var>includeCredentials</var> is true, then:
57115841

57125842
<ol>
5713-
<li>
5714-
<p>If the user agent is not configured to block cookies for <var>httpRequest</var> (see
5715-
<a href=https://httpwg.org/specs/rfc6265.html#privacy-considerations>section 7</a> of
5716-
[[!COOKIES]]), then:
5717-
5718-
<ol>
5719-
<li><p>Let <var>cookies</var> be the result of running the "cookie-string" algorithm (see
5720-
<a href=https://httpwg.org/specs/rfc6265.html#cookie>section 5.4</a> of
5721-
[[!COOKIES]]) with the user agent's cookie store and <var>httpRequest</var>'s
5722-
<a for=request>current URL</a>.
5843+
<p class=note>This permits some implementations to choose to not support cookies for some or all <var>httpRequest</var>s.
57235844

5724-
<li>If <var>cookies</var> is not the empty string, then <a for="header list">append</a>
5725-
(`<code>Cookie</code>`, <var>cookies</var>) to <var>httpRequest</var>'s
5726-
<a for=request>header list</a>.
5727-
</ol>
5845+
<li><p>The user agent should <a>append a request `<code>Cookie</code>` header</a> for <var>httpRequest</var>.
57285846

57295847
<li>
57305848
<p>If <var>httpRequest</var>'s <a for=request>header list</a>
@@ -6288,14 +6406,7 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
62886406
<li><p>Set <var>response</var>'s <a for=response>body</a> to a new <a for=/>body</a> whose
62896407
<a for=body>stream</a> is <var>stream</var>.
62906408

6291-
<li><p tracking-vector>If <var>includeCredentials</var> is true and the user agent is not
6292-
configured to block cookies for <var>request</var> (see
6293-
<a href=https://httpwg.org/specs/rfc6265.html#privacy-considerations>section 7</a> of
6294-
[[!COOKIES]]), then run the "set-cookie-string" parsing algorithm (see
6295-
<a href=https://httpwg.org/specs/rfc6265.html#set-cookie>section 5.2</a> of [[!COOKIES]]) on the
6296-
<a for=header>value</a> of each <a for=/>header</a> whose <a for=header>name</a> is a
6297-
<a>byte-case-insensitive</a> match for `<code>Set-Cookie</code>` in <var>response</var>'s
6298-
<a for=response>header list</a>, if any, and <var>request</var>'s <a for=request>current URL</a>.
6409+
<li><p tracking-vector>If <var>includeCredentials</var> is true, the user agent should <a>parse and store response `<code>Set-Cookie</code>` headers</a> given <var>request</var> and <var>response</var>.
62996410

63006411
<li>
63016412
<p>Run these steps <a>in parallel</a>:

0 commit comments

Comments
 (0)