Skip to content

Commit

Permalink
Initial resource timing integration.
Browse files Browse the repository at this point in the history
Created a "fetch timing info" struct to hold the bookkeeping
necessary for resource timing.

Populated it with some of the required values, leaving some of
them for later patches as this is a big undertaking.

See w3c/resource-timing#252
  • Loading branch information
noamr committed Mar 9, 2021
1 parent c5eb621 commit 0538a2f
Showing 1 changed file with 220 additions and 4 deletions.
224 changes: 220 additions & 4 deletions fetch.bs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,65 @@ lt="authentication entry">authentication entries</a> (for HTTP authentication).

<dt><dfn for="fetch params">task destination</dfn> (default null)
<dd>Null, a <a for=/>global object</a>, or a <a for=/>parallel queue</a>.
<dt><dfn for="fetch params">timing info</dfn>
<dd>A <a for=/>fetch timing info</a>.
</dl>

<p>A <dfn export>fetch timing info</dfn> is a <a for=/>struct</a> used to maintain timing information
later required by the resource timing and navigation timing specs. It has the following
<a for=struct>items</a>:
<dl>
<dt><dfn for="fetch timing info">redirect start time</dfn> (default zero)
<dt><dfn for="fetch timing info">redirect end time</dfn> (default zero)
<dt><dfn for="fetch timing info">fetch start time</dfn> (default zero)
<dt><dfn for="fetch timing info">request start time</dfn> (default zero)
<dt><dfn for="fetch timing info">response start time</dfn> (default zero)
<dt><dfn for="fetch timing info">response end time</dfn> (default zero)
<dd>A <a for=/>DOMHighResTimeStamp</a>.
<dt><dfn for="fetch timing info">encoded body size</dfn> (default zero)
<dt><dfn for="fetch timing info">decoded body size</dfn> (default zero)
<dd>A number.
<dt><dfn for="fetch timing info">connection timing info</dfn> (default null)
<dd>Null or a <a for=/>connection timing info</a>.
</dl>

<p>A <dfn export>connection timing info</dfn> is a <a for=/>struct</a> used to maintain timing
information pertaining to the process of obtaining a connection. It has the following
<a for=struct>items</a>:
<dl>
<dt><dfn for="connection timing info">domain lookup start time</dfn> (default zero)
<dt><dfn for="connection timing info">domain lookup end time</dfn> (default zero)
<dt><dfn for="connection timing info">connection start time</dfn> (default zero)
<dt><dfn for="connection timing info">connection end time</dfn> (default zero)
<dt><dfn for="connection timing info">secure connection start time</dfn> (default zero)
<dd>A <a for=/>DOMHighResTimeStamp</a>
<dt><dfn for="connection timing info">alpn negotiated protocol</dfn> (default empty string)
<dd>A string.
</dl>

<p><dfn data-cite="hr-time-2#dom-domhighrestimestamp">DOMHighResTimeStamp</dfn> and
<dfn data-cite="hr-time-2#dfn-unsafe-shared-current-time">unsafe shared current time</dfn> </code>
are defined in [[HR-TIME]].

<p class=note>Note that timestamps in this spec are usually unsafe, and are meant to be coarsened
and normalized to a <a for=/>global object</a> prior to being exposed.

<p>To <dfn>clamp connection timing to fetch timing</dfn>, given <a for=/>connection timing info</a>
<var>timingInfo</var> and <a for=/>DOMHighResTimeStamp</a> <var>defaultStartTime</var>, run these
steps:
<ol>
<li><p>If <var>timingInfo</var>'s <a for="connection timing info">connection start time</a> is
greater than <var>defaultStartTime</var>, then return <var>timingInfo</var>.

<li><p>Otherwise, return a new <a for=/>connection timing info</a>, with
<a for="connection timing info">domain lookup start time</a> set to <var>defaultStartTime</var>,
<a for="connection timing info">domain lookup end time</a> set to <var>defaultStartTime</var>,
<a for="connection timing info">connection start time</a> set to <var>defaultStartTime</var>,
<a for="connection timing info">connection end time</a> set to <var>defaultStartTime</var>,
<a for="connection timing info">secure connection start time</a> set to
<var>defaultStartTime</var>, and <a for="connection timing info">alpn negotiated protocol</a>
set to <var>timingInfo</var>'s <a for="connection timing info">alpn negotiated protocol</a>.

<p>To <dfn>queue a fetch task</dfn>, given an algorithm <var>algorithm</var>, a
<a for=/>global object</a> or a <a for=/>parallel queue</a> <var>taskDestination</var>, run these
steps:
Expand Down Expand Up @@ -1108,7 +1165,8 @@ must be an algorithm accepting an exception.

<dt><a for="read request">close steps</a>
<dd><ol><li><p><a>Queue a fetch task</a> given <var>processEndOfBody</var> and
<var>taskDestination</var>.</ol>
<var>taskDestination</var>.
</ol>

<dt><a for="read request">error steps</a>, given <var>e</var>
<dd><ol><li><p><a>Queue a fetch task</a> to run <var>processBodyError</var> given <var>e</var>,
Expand Down Expand Up @@ -2144,6 +2202,9 @@ unset or <a for=request>keepalive</a> is false, <a lt=terminated for=fetch>termi
identified by a <b>key</b> (a <a>network partition key</a>), an <b>origin</b> (an
<a for=/>origin</a>), and <b>credentials</b> (a boolean).

<p>Each <a>connection</a> has an associated <a for=/>connection timing info</a>
<dfn for=connection>timingInfo</dfn>, initially a new <a for=/>connection timing info</a>.

<p>To <dfn export id=concept-connection-obtain>obtain a connection</dfn>, given a <var>key</var>,
<var>origin</var>, <var>credentials</var>, an optional boolean <var>forceNew</var> (default false),
an optional boolean <dfn export for="obtain a connection"><var>http3Only</var></dfn> (default
Expand Down Expand Up @@ -2175,8 +2236,9 @@ false), and an optional boolean <dfn export for="obtain a connection"><var>dedic
<ol>
<li>
<p>Set <var>connection</var> to the result of establishing an HTTP connection to
<var>origin</var>. [[!HTTP]] [[!HTTP-SEMANTICS]] [[!HTTP-COND]] [[!HTTP-CACHING]] [[!HTTP-AUTH]]
[[!TLS]]
<var>origin</var>, following the requirements for
<a>recording <var>connection</var> timing info</a>.
[[!HTTP]] [[!HTTP-SEMANTICS]] [[!HTTP-COND]] [[!HTTP-CACHING]] [[!HTTP-AUTH]] [[!TLS]]

<p>If <var>http3Only</var> is true, then establish an HTTP/3 connection. [[!HTTP3]]

Expand Down Expand Up @@ -2215,6 +2277,93 @@ clearly stipulates that <a>connections</a> are keyed on
<!-- See https://github.com/whatwg/fetch/issues/114#issuecomment-143500095 for when we make
WebSocket saner -->

<p>When <dfn>recording connection timing info</dfn> given a <var>connection</var>, perform the
following steps:
<ol>
<li><p>Let <var>timingInfo</var> be <var>connection</var>'s <a for=connection>timingInfo</a>.

<li>If the domain information is available in cache, then set <var>timingInfo</var>'s
<a for="connection timing info">domain lookup start time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately after beginning retrieval of the
information from cache.

<li>Otherwise, set <var>timingInfo</var>'s
<a for="connection timing info">domain lookup start time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately before starting the domain lookup.

<li>If the domain information is available in cache, then set <var>timingInfo</var>'s
<a for="connection timing info">domain lookup end time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately after retrieving the information from
cache.

<li>Otherwise, set <var>timingInfo</var>'s
<a for="connection timing info">domain lookup end time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately after finishing the domain lookup.

<li>Set <var>timingInfo</var>'s
<a for="connection timing info">connection start time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately before establishing the connection to
the server or proxy.

<li>Set <var>timingInfo</var>'s
<a for="connection timing info">connection end time</a> to the result of calling
<a for=/>unsafe shared current time</a> immediately after establishing the connection to the
server or proxy, as follows:
<ul>
<li>The returned time MUST include the time interval to establish the transport
connection, as well as other time intervals such as SOCKS authentication. It
MUST include the time interval to complete enough of the TLS handshake to
request the resource.</li>
<li>If the user agent used TLS False Start [[RFC7918]] for this connection,
this interval MUST NOT include the time needed to receive the server's
Finished message.</li>
<li>If the user agent sends the request with early data [[RFC8470]] without
waiting for the full handshare to complete, this interval MUST NOT include
the time needed to receive the server's ServerHello message.</li>
<li>If the user agent waits for full handshake completion to send the
request, this interval includes the full TLS handshake even if other
requests were sent using early data on this connection.</li>
</ul>

<p class=note>Example: Suppose the user agent establishes an HTTP/2 connection
over TLS 1.3 to send a GET request and a POST request. It sends the ClientHello
at time <code>t1</code> and then sends the GET request with early data. The
POST request is not safe [[HTTP-SEMANTICS]] (section 4.2.1), so the user agent waits
to complete the handshake at time <code>t2</code> before sending it. Although
both requests used the same connection, the GET request reports a connectEnd
value of <code>t1</code>, while the POST request reports a connectEnd value for
<code>t2</code>.</p>

<li>If a secure transport is used, set <var>timingInfo</var>'s
<a for="connection timing info">secure connection start time</a> to the result of calling
<a for=/>unsafe shared current time</a> immmediately before starting the handshake process to
secure <var>connection</var>. [[!TLS]]

<li>Set <var>timingInfo</var>'s <a for="connection timing info">alpn negotiated protocol</a>
to the <var>connection</var>'s ALPN Protocol ID as specified in [[RFC7301]], with the
following caveats:
<ul>
<li><p>When a proxy is configured, if a tunnel connection is established then this attribute
MUST return the ALPN Protocol ID of the tunneled protocol, otherwise it MUST return the ALPN
Protocol ID of the first hop to the proxy.
<li><p>Octets in the ALPN protocol MUST NOT be percent-encoded if they are valid token
characters except "%", and when using percent-encoding, uppercase hex digits MUST be used.
<li><p>Formally registered ALPN protocol IDs are documented by <a href=
"https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids">
IANA</a>.
<li><p>In case the user agent is using an experimental, non-registered protocol, the user
agent MUST use the ALPN negotiated value if any. If ALPN was not used for protocol
negotiations, the user agent MAY use another descriptive string.
<p class="note">The "h3" ALPN ID is defined for the final version
of the HTTP/3 protocol in the
<a href="https://tools.ietf.org/html/draft-ietf-quic-http-17#section-10.1">HTTP/3
Internet Draft</a>.
<p class="note">Note that <a for="connection timing info">alpn negotiated protocol</a> is
intended to identify the network protocol in use for the fetch regardless of how it was
actually negotiated; that is, even if ALPN is not used to negotiate the network protocol,
this attribute still uses the ALPN Protocol IDs to indicate the protocol in use.
</ul>
</ol>

<h3 id=network-partition-keys>Network partition keys</h3>

Expand Down Expand Up @@ -3351,6 +3500,7 @@ the request.

<li><p>Let <var>fetchParams</var> be a new <a for=/>fetch params</a> whose
<a for="fetch params">request</a> is <var>request</var>,
<a for="fetch params">timing info</a> is a new <a for=/>fetch timing info</a>,
<a for="fetch params">process request body</a> is <var>processRequestBody</var>,
<a for="fetch params">process request end-of-body</a> is <var>processRequestEndOfBody</var>,
<a for="fetch params">process response</a> is <var>processResponse</var>,
Expand Down Expand Up @@ -3439,6 +3589,10 @@ steps:

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

<li><p>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
<a for="fetch timing info">fetch start time</a> to the result of calling
<a for=/>unsafe shared current time</a>.

<li><p>If <var>request</var>'s <a>local-URLs-only flag</a> is set and <var>request</var>'s
<a for=request>current URL</a> is not <a lt="is local">local</a>, then set <var>response</var> to a
<a>network error</a>.
Expand Down Expand Up @@ -3768,6 +3922,35 @@ steps:
<!-- This is really bad and needs to be handled differently at some point. -->
</ol>

<p>To <dfn>handle response end</dfn>, given <a for=/>fetch params</a> <var>fetchParams</var> and
<a for=/>response</a> <var>response</var>, perform the following steps:
<ol>
<li>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
<a for="fetch timing info">response end time</a> to the <a for=/>unsafe shared current time</a>.

<li>Let <var>request</var> be <var>fetchParams</var>'s <a for="fetch params">request</a>.

<li>Let <var>globalObject</var> be <a for="fetch params">request</a>'s
<a for=request>client</a>'s <a for="environment settings object">global object</a>.

<li>Let <var>timingInfo</var> be <var>fetchParams</var>'s <a for="fetch params">timing info</a>.

<li>Let <var>requestedURL</var> be <var>response</var>'s <a for=response>URL list</a>'s first
item.

<li>If <var>request</var>'s <a for=request>destination</a> is <code>"document"</code> or
<code>"report"</code>, then return.

<li>If <var>response</var>'s <a for=response>timing allow passed flag</a> is not set, set
<var>timingInfo</var> to a new <a for=/>fetch timing info</a>, with its
<a for="fetch timing info">fetch start time</a> set to <var>timingInfo</var>'s
<a for="fetch timing info">fetch start time</a>,
and <a for="fetch timing info">response end time</a> set to <var>timingInfo</var>'s
<a for="fetch timing info">response end time</a>.
<p class=XXX>TODO: enqueue in [[resource-timing]] with <var>timingInfo</var>,
<var>requestedURL</var> and <var>globalObject</var>. See
<a href="https://github.com/w3c/resource-timing/issues/252">Issue #252</a>.
</ol>

<h3 id=scheme-fetch oldids=basic-fetch>Scheme fetch</h3>

Expand Down Expand Up @@ -3891,6 +4074,8 @@ these steps:

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

<li><p>Let <var>timingInfo</var> be <var>fetchParams</var>'s <a for="fetch params">timing info</a>

<li>
<p>If <var>request</var>'s <a>service-workers mode</a> is "<code>all</code>", then:

Expand Down Expand Up @@ -4059,6 +4244,10 @@ run these steps:
<li><p>Let <var>locationURL</var> be <var>actualResponse</var>'s <a for=response>location URL</a>
given <var>request</var>'s <a for=request>current URL</a>'s <a for=url>fragment</a>.

<li><p>If <var>timingInfo</var>'s <a for="fetch timing info">redirect start time</a> is zero,
<p>set <var>timingInfo</var>'s <a for="fetch timing info">redirect start time</a> to
<var>timingInfo</var>'s <a for="fetch timing info">fetch start time</a>.

<li><p>If <var>locationURL</var> is null, then return <var>response</var>.

<li><p>If <var>locationURL</var> is failure, then return a <a>network error</a>.
Expand Down Expand Up @@ -4122,6 +4311,9 @@ run these steps:
<p class="note no-backref"><var>request</var>'s <a for=request>body</a>'s <a for=body>source</a>'s
nullity has already been checked.

<li><p>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
<a for="fetch timing info">redirect end time</a> to the <a for=/>unsafe shared current time</a>.

<li><p><a for=list>Append</a> <var>locationURL</var> to <var>request</var>'s
<a for=request>URL list</a>.

Expand Down Expand Up @@ -4710,6 +4902,8 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:

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

<li><p>Let <var>timingInfo</var> be <var>fetchParams</var>'s <a for="fetch params">timing info</a>.

<li><p>Let <var>httpCache</var> be the result of <a>determining the HTTP cache partition</a>, given
<var>httpRequest</var>.

Expand All @@ -4735,6 +4929,11 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
<var>includeCredentials</var>, and <var>forceNewConnection</var>.
</dl>

<li>Set <var>timingInfo</var>'s <a for="fetch timing info">connection timing info</a> to the
result of calling <a>clamp connection timing to fetch timing</a> with <var>connection</var>'s
<a for=connection>timingInfo</a> and <var>timingInfo</var>'s
<a for="fetch timing info">fetch start time</a>.

<li>
<p>Run these steps, but <a>abort when</a> the ongoing fetch is <a for=fetch>terminated</a>:

Expand All @@ -4748,13 +4947,21 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
`<code>Transfer-Encoding</code>`/`<code>chunked</code>` to <var>request</var>'s
<a for=request>header list</a>.

<li>Set <var>timingInfo</var>'s <a for="fetch timing info">request start time</a> to
<a for=/>unsafe shared current time</a>.

<li>
<p>Set <var>response</var> to the result of making an HTTP request over <var>connection</var>
using <var>request</var> with the following caveats:

<ul>
<li><p>Follow the relevant requirements from HTTP. [[!HTTP]] [[!HTTP-SEMANTICS]] [[!HTTP-COND]] [[!HTTP-CACHING]] [[!HTTP-AUTH]]

<li><p>Set <var>timingInfo</var>'s <a for="fetch timing info">response start time</a> to
the <a for=/>unsafe shared current time</a>immediately after the user agent's HTTP parser
receives the first byte of the response (e.g. frame header bytes for HTTP/2, or response
status line for HTTP/1.x).

<li><p>Wait until all the <a for=/>headers</a> are transmitted.

<li>
Expand Down Expand Up @@ -4938,13 +5145,19 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
<li><p>Let <var>codings</var> be the result of <a>extracting header list values</a> given
`<code>Content-Encoding</code>` and <var>response</var>'s <a for=response>header list</a>.

<li><p>Increase <var>timingInfo</var>'s <a for="fetch timing info">encoded body size</a>
by <var>bytes</var>'s <a for="byte sequence">length</a>.

<li>
<p>Set <var>bytes</var> to the result of <a lt="handle content codings">handling content
codings</a> given <var>codings</var> and <var>bytes</var>.

<p class="note no-backref">This makes the `<code>Content-Length</code>` <a for=/>header</a>
unreliable to the extent that it was reliable to begin with.

<li><p>Increase <var>timingInfo</var>'s <a for="fetch timing info">decoded body size</a> by
<var>bytes</var>'s <a for="byte sequence">length</a>.

<li><p>If <var>bytes</var> is failure, then <a lt=terminated for=fetch>terminate</a> the
ongoing fetch.

Expand All @@ -4960,7 +5173,8 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:

<li><p>Otherwise, if the bytes transmission for <var>response</var>'s message body is done
normally and <var>stream</var> is <a for=ReadableStream>readable</a>, then
<a for=ReadableStream>close</a> <var>stream</var> and abort these in-parallel steps.
<a for=ReadableStream>close</a> <var>stream</var>, Call <a for=/>handle response end</a>
with <var>fetchParams</var> and <var>response</var>, and abort these in-parallel steps.
</ol>
</ol>

Expand All @@ -4974,6 +5188,8 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
<p>If <var>aborted</var> is set, then:

<ol>
<li><p>Call <a for=/>handle response end</a> with <var>fetchParams</var> and <var>response</var>.

<li><p>Set <var>response</var>'s <a for=response>aborted flag</a>.

<li><p>If <var>stream</var> is <a for=ReadableStream>readable</a>,
Expand Down

0 comments on commit 0538a2f

Please sign in to comment.