Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate with new draft cookie spec (draft-annevk-johannhof-httpbis-cookies/00+ε) #1807

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 113 additions & 37 deletions fetch.bs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,28 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
url:realm;text:realm
url:sec-list-and-record-specification-type;text:Record
url:current-realm;text:current realm

urlPrefix:https://www.ietf.org/archive/id/draft-annevk-johannhof-httpbis-cookies-00.html#;type:dfn;spec:cookies
url:name-cookie-store-and-limits;text:cookie store
url:name-parse-and-store-a-cookie;text:parse and store a cookie
url:name-parse-a-cookie;text:parse a cookie
url:name-store-a-cookie;text:store a cookie
url:name-retrieve-cookies;text:retrieve cookies
url:name-serialize-cookies;text:serialize cookies

<!-- TODO: pending HTML changes- ancestor enum (https://github.com/whatwg/html/pull/10559), has storage access bit, initiator origin plumbing -->
urlPrefix:https://html.spec.whatwg.org#;type:dfn;spec:html
url:TODO;text:ancestry;for:environment
url:TODO;text:has storage access;for:environment
</pre>

<pre class=biblio>
{
"COOKIES": {
"authors": ["Johann Hofmann", "Anne van Kesteren"],
"href": "https://www.ietf.org/archive/id/draft-annevk-johannhof-httpbis-cookies-00.html",
"title": "Cookies: HTTP State Management Mechanism"
},
"HTTP": {
"aliasOf": "RFC9110"
},
Expand Down Expand Up @@ -1938,6 +1956,10 @@ not always relevant and might require different behavior.
"<code>client</code>" or an <a for=/>origin</a>. Unless stated otherwise it is
"<code>client</code>".

<p>A <a for=/>request</a> has an associated
<dfn export for=request id=concept-request-navigation-initiator-origin>top-level navigation initiator origin</dfn>, which is
an <a for=/>origin</a> or null. Unless stated otherwise it is null.

<p class=note>"<code>client</code>" is changed to an <a for=/>origin</a> during
<a lt=fetch for=/>fetching</a>. It provides a convenient way for standards to not have to set
<a for=/>request</a>'s <a for=request>origin</a>.
Expand Down Expand Up @@ -2226,31 +2248,38 @@ or "<code>object</code>".
<hr>

<div algorithm>
<p>A <a for=/>request</a> <var>request</var> has a
<dfn for=request id=concept-request-tainted-origin>redirect-tainted origin</dfn> if these steps
return true:
<p>A <a for=/>request</a> has a <dfn for=request id=concept-request-redirect-taint>redirect-taint</dfn>,
which is "<code>same-origin</code>", "<code>same-site</code>", or "<code>cross-site</code>".
<p>To get <a for=/>request</a> <var>request</var>'s <a>redirect-taint</a>:

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

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

<li><p>Let <var>computedTaint</var> be "<code>same-origin</code>".

<li>
<p><a for=list>For each</a> <var>url</var> of <var>request</var>'s <a for=request>URL list</a>:

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

<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a for=/>same site</a> with
<var>lastURL</var>'s <a for=url>origin</a> and <var>request</var>'s <a for=request>origin</a> is
not <a for=/>same site</a> with <var>lastURL</var>'s <a for=url>origin</a>, then return "<code>cross-site</code>".

<li><p>If <var>url</var>'s <a for=url>origin</a> is not <a>same origin</a> with
<var>lastURL</var>'s <a for=url>origin</a> and <var>request</var>'s <a for=request>origin</a> is
not <a>same origin</a> with <var>lastURL</var>'s <a for=url>origin</a>, then return true.
not <a>same origin</a> with <var>lastURL</var>'s <a for=url>origin</a>,
then set <var>computedTaint</var> to "<code>same-site</code>".

<li>Set <var>lastURL</var> to <var>url</var>.
</ol>

<li>Return false.
<li>Return <var>computedTaint</var>.
</ol>
</div>

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

<li><p>If <var>request</var> has a <a for=request>redirect-tainted origin</a>, then return
"<code>null</code>".
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is not "<code>same-origin</code>",
then return "<code>null</code>".

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

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

<li><p>Return false.</p>
</ol>
Expand Down Expand Up @@ -2486,8 +2515,8 @@ this is also tracked internally using the request's <a for=request>timing allow
<dfn export for=response>service worker timing info</dfn> (null or a
<a for=/>service worker timing info</a>), which is initially null.

<p>A <a for=/>response</a> has an associated <dfn for=response>has-cross-origin-redirects</dfn>
(a boolean), which is initially false.
<p>A <a for=/>response</a> has an associated <dfn for=response>redirect taint</dfn> ("<code>same-origin</code>",
"<code>same-site</code>", or "<code>cross-site</code>", which is initially "<code>same-origin</code>".

<hr>

Expand Down Expand Up @@ -4225,7 +4254,75 @@ indicates the request’s purpose is to fetch a resource that is anticipated to
<p class=note>The server can use this to adjust the caching expiry for prefetches, to disallow the
prefetch, or to treat it differently when counting page visits.

<h2 id=cookies>Cookies</h2>

<h3 id=cookie-header>`<code>Cookie</code>` header</h3>

<p>The `<code>Cookie</code>` header is largely defined in its own specification. [[COOKIES]].
We define infrastructure to be able to use conveniently here.

<div algorithm>
<p>To <dfn id=append-a-request-cookie-header>append a request `<code>Cookie</code>` header</dfn>,
given a <a for=/>request</a> <var>request</var>, run these steps:
<ol>
<li><p>If the user-agent is configured to disable cookies for <var>request</var>, it should return.
<li><p>Let |sameSite| be the result of [=determining the same-site mode=] for <var>request</var>.
<li><p>Let |isSecure| be false.
<li><p>If <var>request</var>'s <a for=request>client</a> is a <a>secure context</a>, then set |isSecure| to true.
<li><p>Let |httpOnlyAllowed| be true.
<p class=note>Fetch implies that the request is http-only, as opposed to document.cookie
<li><p>Let |cookies| be the result of running <a>retrieve cookies</a> given
|isSecure|,
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>host</a>,
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>path</a>,
|httpOnlyAllowed|, and
|sameSite|

<p class=note>It is expected that the cookie store returns an ordered list of cookies
<li>If |cookies| <a for="list">is empty</a>, then return.
<li>Let |value| be the result of running <a>serialize cookies</a> given |cookies|.
<li><a for="header list">Append</a> (`<code>Cookie</code>`, <var>value</var>) to <var>request</var>'s <a for=request>header list</a>.
</ol>
</div>

<div algorithm>
<p>To <dfn id=parse-and-store-response-cookie-headers>parse and store response `<code>Set-Cookie</code>` headers</dfn>,
given a <a for=/>request</a> <var>request</var> and a <a for=/>response</a> <var>response</var>, run these steps:
<ol>
<li><p>If the user-agent is configured to disable cookies for <var>request</var>, it should return.
<li><p>Let |allowNonHostOnlyCookieForPublicSuffix| be false.
<li><p>Let |isSecure| be false.
<li><p>If <var>request</var>'s <a for=request>client</a> is a <a>secure context</a>, then set |isSecure| to true.
<li><p>Let |httpOnlyAllowed| be true.
<p class=note>Fetch implies that the request is http-only, as opposed to document.cookie
<li><p>Let |sameSiteStrictOrLaxAllowed| be true if the result of [=determine the same-site mode=] for |request| is "<code>StrictOrLess</code>", and false otherwise.
<li><p><a for=list>For each</a> <var>header</var> of <var>response</var>'s <a for=response>header list</a>:
<ol>
<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>.
<li><p><a>Parse and store a cookie</a> given
<var>header</var>'s <a for=header>value</a>,
|isSecure|,
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>host</a>,
<var>request</var>'s <a for=request>current URL</a>'s <a for=url>path</a>,
|httpOnlyAllowed|,
|allowNonHostOnlyCookieForPublicSuffix|, and
|sameSiteStrictOrLaxAllowed|
</ol>
</ol>
</div>

<div algorithm>
<p>To <dfn>determine the same-site mode</dfn> for a given <a for=/>request</a> <var>request</var>, run these steps:
<ol>
<li><p><a for=/>Assert</a>: <var>request</var>'s <a for=request>method</a> is "GET" or "POST".
<li><p>If <var>request</var>'s <a for=request>top-level 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>".
<li><p>If <var>request</var>'s <a for=request>method</a> is "GET" and
<var>request</var>'s <a for=request>destination</a> is "document", return "<code>LaxOrLess</code>".
<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>".
<li><p>If <var>request</var>'s <a for=request>redirect-taint</a> is "<code>cross-site</code>", return "<code>UnsetOrLess</code>".
<li><p>Return "StrictOrLess".
</ol>
</div>

<h2 id=fetching>Fetching</h2>

Expand Down Expand Up @@ -4680,8 +4777,8 @@ steps:
<!-- If you are ever tempted to move this around, carefully consider responses from about URLs,
blob URLs, service workers, HTTP cache, HTTP network, etc. -->

<li><p>If <var>request</var> has a <a for=request>redirect-tainted origin</a>, then set
<var>internalResponse</var>'s <a for=response>has-cross-origin-redirects</a> to true.
<li><p>Set <var>internalResponse</var>'s <a for=response>redirect taint</a> to <var>request</var>'s
<a for=request>redirect-taint</a>.

<li><p>If <var>request</var>'s <a for=request>timing allow failed flag</a> is unset, then set
<var>internalResponse</var>'s <a for=response>timing allow passed flag</a>.
Expand Down Expand Up @@ -4834,7 +4931,7 @@ steps:
<li>
<p>If <var>fetchParams</var>'s <a for="fetch params">request</a>'s <a for=request>mode</a> is
not "<code>navigate</code>" or <var>response</var>'s
<a for=response>has-cross-origin-redirects</a> is false:
<a for=response>redirect taint</a> is "<code>same-origin</code>":

<ol>
<li><p>Set <var>responseStatus</var> to <var>response</var>'s <a for=response>status</a>.
Expand Down Expand Up @@ -5710,21 +5807,7 @@ run these steps:
<p>If <var>includeCredentials</var> is true, then:

<ol>
<li>
<p>If the user agent is not configured to block cookies for <var>httpRequest</var> (see
<a href=https://httpwg.org/specs/rfc6265.html#privacy-considerations>section 7</a> of
[[!COOKIES]]), then:

<ol>
<li><p>Let <var>cookies</var> be the result of running the "cookie-string" algorithm (see
<a href=https://httpwg.org/specs/rfc6265.html#cookie>section 5.4</a> of
[[!COOKIES]]) with the user agent's cookie store and <var>httpRequest</var>'s
<a for=request>current URL</a>.

<li>If <var>cookies</var> is not the empty string, then <a for="header list">append</a>
(`<code>Cookie</code>`, <var>cookies</var>) to <var>httpRequest</var>'s
<a for=request>header list</a>.
</ol>
<li><p><a>Append a request `<code>Cookie</code>` header</a> for <var>httpRequest</var>.

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

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

<li>
<p>Run these steps <a>in parallel</a>:
Expand Down