Skip to content

Commit 4aa94f8

Browse files
Pick up, dust off, and improve cookie layering
This patch does the following to the work in #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 4aa94f8

File tree

1 file changed

+147
-33
lines changed

1 file changed

+147
-33
lines changed

fetch.bs

+147-33
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,28 @@ 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
5770
</pre>
5871

5972
<pre class=biblio>
6073
{
74+
"COOKIES": {
75+
"authors": ["Johann Hofmann", "Anne Van Kesteren"],
76+
"href": "https://www.ietf.org/archive/id/draft-annevk-johannhof-httpbis-cookies-00.html",
77+
"title": "Cookies: HTTP State Management Mechanism"
78+
},
6179
"HTTP": {
6280
"aliasOf": "RFC9110"
6381
},
@@ -1938,6 +1956,10 @@ not always relevant and might require different behavior.
19381956
"<code>client</code>" or an <a for=/>origin</a>. Unless stated otherwise it is
19391957
"<code>client</code>".
19401958

1959+
<p>A <a for=/>request</a> has an associated
1960+
<dfn export for=request id=concept-request-navigation-initiator-origin>navigation initiator origin</dfn>, which is
1961+
an <a for=/>origin</a> or null. Unless stated otherwise it is null.
1962+
19411963
<p class=note>"<code>client</code>" is changed to an <a for=/>origin</a> during
19421964
<a lt=fetch for=/>fetching</a>. It provides a convenient way for standards to not have to set
19431965
<a for=/>request</a>'s <a for=request>origin</a>.
@@ -2226,31 +2248,38 @@ or "<code>object</code>".
22262248
<hr>
22272249

22282250
<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:
2251+
<p>A <a for=/>request</a> has a <dfn for=request id=concept-request-redirect-taint>redirect-taint</dfn>,
2252+
which is "<code>None</code>", "<code>Cross-Origin</code>", or "<code>Cross-Site</code>".
2253+
<p>To get <a for=/>request</a> <var>request</var>'s <a>redirect-taint</a>:
22322254

22332255
<ol>
22342256
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>origin</a> is not
22352257
"<code>client</code>".
22362258

22372259
<li><p>Let <var>lastURL</var> be null.
22382260

2261+
<li><p>Let <var>crossOriginTaint</var> be "<code>None</code>".
2262+
22392263
<li>
22402264
<p><a for=list>For each</a> <var>url</var> of <var>request</var>'s <a for=request>URL list</a>:
22412265

22422266
<ol>
22432267
<li><p>If <var>lastURL</var> is null, then set <var>lastURL</var> to <var>url</var> and
22442268
<a for=iteration>continue</a>.
22452269

2270+
<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a for=/>same site</a> with
2271+
<var>lastURL</var>'s <a for=url>origin</a> and <var>request</var>'s <a for=request>origin</a> is
2272+
not <a for=/>same site</a> with <var>lastURL</var>'s <a for=url>origin</a>, then return "<code>Cross-Site</code>".
2273+
22462274
<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a>same origin</a> with
22472275
<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.
2276+
not <a>same origin</a> with <var>lastURL</var>'s <a for=url>origin</a>,
2277+
then let <var>crossOriginTaint</var> be "<code>Cross-Origin</code>"..
22492278

22502279
<li>Set <var>lastURL</var> to <var>url</var>.
22512280
</ol>
22522281

2253-
<li>Return false.
2282+
<li>Return <var>crossOriginTaint</var>.
22542283
</ol>
22552284
</div>
22562285

@@ -2262,8 +2291,8 @@ run these steps:
22622291
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>origin</a> is not
22632292
"<code>client</code>".
22642293

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

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

23742403
<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>
2404+
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>origin</a> and <var>request</var>'s
2405+
<a for=request>redirect-taint</a> is not "<code>None</code>", then return true.</p>
23772406

23782407
<li><p>Return false.</p>
23792408
</ol>
@@ -2489,6 +2518,9 @@ this is also tracked internally using the request's <a for=request>timing allow
24892518
<p>A <a for=/>response</a> has an associated <dfn for=response>has-cross-origin-redirects</dfn>
24902519
(a boolean), which is initially false.
24912520

2521+
<p>A <a for=/>response</a> has an associated <dfn for=response>has-cross-site-redirects</dfn>
2522+
(a boolean), which is initially false.
2523+
24922524
<hr>
24932525

24942526
<p>A <dfn export id=concept-network-error>network error</dfn> is a <a for=/>response</a> whose
@@ -2710,7 +2742,6 @@ manually. [[!HTML]]
27102742
</ol>
27112743
</div>
27122744

2713-
27142745
<h3 id=authentication-entries>Authentication entries</h3>
27152746

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

32933324
<h2 id=http-extensions>HTTP extensions</h2>
32943325

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

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

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

4816+
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is "<code>Cross-Site</code>", then set
4817+
<var>internalResponse</var>'s <a for=response>has-cross-site-redirects</a> to true.
4818+
46864819
<li><p>If <var>request</var>'s <a for=request>timing allow failed flag</a> is unset, then set
46874820
<var>internalResponse</var>'s <a for=response>timing allow passed flag</a>.
46884821

@@ -5710,21 +5843,9 @@ run these steps:
57105843
<p>If <var>includeCredentials</var> is true, then:
57115844

57125845
<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>.
5846+
<p class=note>This permits some implementations to choose to not support cookies for some or all <var>httpRequest</var>s.
57235847

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>
5848+
<li><p>The user agent should <a>append a request `<code>Cookie</code>` header</a> for <var>httpRequest</var>.
57285849

57295850
<li>
57305851
<p>If <var>httpRequest</var>'s <a for=request>header list</a>
@@ -6288,14 +6409,7 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
62886409
<li><p>Set <var>response</var>'s <a for=response>body</a> to a new <a for=/>body</a> whose
62896410
<a for=body>stream</a> is <var>stream</var>.
62906411

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>.
6412+
<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>.
62996413

63006414
<li>
63016415
<p>Run these steps <a>in parallel</a>:

0 commit comments

Comments
 (0)