Skip to content

Commit e4f29cf

Browse files
committed
Initial resource timing integration.
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
1 parent 4202f5c commit e4f29cf

File tree

1 file changed

+237
-2
lines changed

1 file changed

+237
-2
lines changed

fetch.bs

Lines changed: 237 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,76 @@ lt="authentication entry">authentication entries</a> (for HTTP authentication).
194194

195195
<dt><dfn for="fetch params">task destination</dfn> (default null)
196196
<dd>Null, a <a for=/>global object</a>, or a <a for=/>parallel queue</a>.
197+
<dt><dfn for="fetch params">timing info</dfn>
198+
<dd>A <a for=/>fetch timing info</a>.
199+
<dt><dfn for="fetch params">redirect timing info list</dfn>(default an empty list)
200+
<dd>A list of <a for=/>redirect timing info</a>
197201
</dl>
198202

203+
<p>A <dfn export>fetch timing info</dfn> is a <a for=/>struct</a> used to maintain timing
204+
information later required by the resource timing and navigation timing specs. It has the following
205+
<a for=struct>items</a>:
206+
<dl>
207+
<dt><dfn export for="fetch timing info">fetch start time</dfn> (default zero)
208+
<dt><dfn export for="fetch timing info">worker start time</dfn> (default zero)
209+
<dt><dfn export for="fetch timing info">request start time</dfn> (default zero)
210+
<dt><dfn export for="fetch timing info">response start time</dfn> (default zero)
211+
<dt><dfn export for="fetch timing info">response end time</dfn> (default zero)
212+
<dd>A <a for=/>DOMHighResTimeStamp</a>.
213+
<dt><dfn export for="fetch timing info">encoded body size</dfn> (default zero)
214+
<dt><dfn export for="fetch timing info">decoded body size</dfn> (default zero)
215+
<dd>A number.
216+
<dt><dfn export for="fetch timing info">connection timing info</dfn> (default null)
217+
<dd>Null or a <a for=/>connection timing info</a>.
218+
</dl>
219+
220+
<p>A <dfn export>redirect timing info</dfn> is a <a for=/>struct</a> used to maintain timing
221+
information about a redirect.
222+
<a for=struct>items</a>:
223+
<dl>
224+
<dt><dfn export for="redirect timing info">redirect location URL</dfn>
225+
<dd>A URL.
226+
<dt><dfn export for="redirect timing info">timing info</dfn>
227+
<dd>A <a for=/>fetch timing info</a>.
228+
</dl>
229+
230+
<p>A <dfn export>connection timing info</dfn> is a <a for=/>struct</a> used to maintain timing
231+
information pertaining to the process of obtaining a connection. It has the following
232+
<a for=struct>items</a>:
233+
<dl>
234+
<dt><dfn export for="connection timing info">domain lookup start time</dfn> (default zero)
235+
<dt><dfn export for="connection timing info">domain lookup end time</dfn> (default zero)
236+
<dt><dfn export for="connection timing info">connection start time</dfn> (default zero)
237+
<dt><dfn export for="connection timing info">connection end time</dfn> (default zero)
238+
<dt><dfn export for="connection timing info">secure connection start time</dfn> (default zero)
239+
<dd>A <a for=/>DOMHighResTimeStamp</a>
240+
<dt><dfn export for="connection timing info">alpn negotiated protocol</dfn> (default empty string)
241+
<dd>A string.
242+
</dl>
243+
244+
<p><dfn data-cite="hr-time-2#dom-domhighrestimestamp">DOMHighResTimeStamp</dfn> and
245+
<dfn data-cite="hr-time-2#dfn-unsafe-shared-current-time">unsafe shared current time</dfn> </code>
246+
are defined in [[HR-TIME]].
247+
248+
<p class=note>Note that timestamps in this spec are usually unsafe, and are meant to be coarsened
249+
and normalized to a <a for=/>global object</a> prior to being exposed.
250+
251+
<p>To <dfn>clamp connection timing to fetch timing</dfn>, given <a for=/>connection timing info</a>
252+
<var>timingInfo</var> and <a for=/>DOMHighResTimeStamp</a> <var>defaultStartTime</var>, run these
253+
steps:
254+
<ol>
255+
<li><p>If <var>timingInfo</var>'s <a for="connection timing info">connection start time</a> is
256+
greater than <var>defaultStartTime</var>, then return <var>timingInfo</var>.
257+
258+
<li><p>Otherwise, return a new <a for=/>connection timing info</a>, with
259+
<a for="connection timing info">domain lookup start time</a> set to <var>defaultStartTime</var>,
260+
<a for="connection timing info">domain lookup end time</a> set to <var>defaultStartTime</var>,
261+
<a for="connection timing info">connection start time</a> set to <var>defaultStartTime</var>,
262+
<a for="connection timing info">connection end time</a> set to <var>defaultStartTime</var>,
263+
<a for="connection timing info">secure connection start time</a> set to
264+
<var>defaultStartTime</var>, and <a for="connection timing info">alpn negotiated protocol</a>
265+
set to <var>timingInfo</var>'s <a for="connection timing info">alpn negotiated protocol</a>.
266+
199267
<p>To <dfn>queue a fetch task</dfn>, given an algorithm <var>algorithm</var>, a
200268
<a for=/>global object</a> or a <a for=/>parallel queue</a> <var>taskDestination</var>, run these
201269
steps:
@@ -1926,6 +1994,14 @@ description of the attack.
19261994
<dfn for=response id=concept-response-timing-allow-passed>timing allow passed flag</dfn>, which is
19271995
initially unset.
19281996

1997+
<p>A <a for=/>response</a> can have an associated
1998+
<dfn export for=response id=concept-response-timing-info>timing info</dfn>, which is Null or a
1999+
<a for=/>fetch timing info</a>, initially set to null.
2000+
2001+
<p>A <a for=/>response</a> has an associated
2002+
<dfn export for=response id=concept-response-redirect-timing-info-list>redirect timing info list</dfn>,
2003+
which is initially set to an empty <a for=/>list</a>.
2004+
19292005
<p class=note>This is used so that the caller to a fetch can determine if sensitive timing data is
19302006
allowed on the resource fetched by looking at the flag of the response returned. Because the flag on
19312007
the response of a redirect has to be set if it was set for previous responses in the redirect chain,
@@ -2148,6 +2224,9 @@ unset or <a for=request>keepalive</a> is false, <a lt=terminated for=fetch>termi
21482224
identified by a <b>key</b> (a <a>network partition key</a>), an <b>origin</b> (an
21492225
<a for=/>origin</a>), and <b>credentials</b> (a boolean).
21502226

2227+
<p>Each <a>connection</a> has an associated <a for=/>connection timing info</a>
2228+
<dfn for=connection>timingInfo</dfn>.
2229+
21512230
<p>To <dfn export id=concept-connection-obtain>obtain a connection</dfn>, given a <var>key</var>,
21522231
<var>origin</var>, <var>credentials</var>, an optional boolean <var>forceNew</var> (default false),
21532232
an optional boolean <dfn export for="obtain a connection"><var>http3Only</var></dfn> (default
@@ -2179,8 +2258,9 @@ false), and an optional boolean <dfn export for="obtain a connection"><var>dedic
21792258
<ol>
21802259
<li>
21812260
<p>Set <var>connection</var> to the result of establishing an HTTP connection to
2182-
<var>origin</var>. [[!HTTP]] [[!HTTP-SEMANTICS]] [[!HTTP-COND]] [[!HTTP-CACHING]] [[!HTTP-AUTH]]
2183-
[[!TLS]]
2261+
<var>origin</var>, following the requirements for
2262+
<a>recording <var>connection</var> timing info</a>.
2263+
[[!HTTP]] [[!HTTP-SEMANTICS]] [[!HTTP-COND]] [[!HTTP-CACHING]] [[!HTTP-AUTH]] [[!TLS]]
21842264

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

@@ -2219,6 +2299,88 @@ clearly stipulates that <a>connections</a> are keyed on
22192299
<!-- See https://github.com/whatwg/fetch/issues/114#issuecomment-143500095 for when we make
22202300
WebSocket saner -->
22212301

2302+
<p>The requirements for <dfn>recording connection timing info</dfn> given a <var>connection</var>
2303+
and its <a for=/>connection timing info</a> <var>timingInfo</var>, are as follows:
2304+
<ul>
2305+
<li><p><var>timingInfo</var>'s <a for="connection timing info">domain lookup start time</a>
2306+
SHOULD be the <a for=/>unsafe shared current time</a> immediately before starting the domain
2307+
lookup, or beginning retrieval of the information from cache.
2308+
2309+
<li><p><var>timingInfo</var>'s <a for="connection timing info">domain lookup end time</a> SHOULD
2310+
be the <a for=/>unsafe shared current time</a> immediately after finishing the domain lookup, or
2311+
retrieving the information from cache.
2312+
2313+
<li><p><var>timingInfo</var>'s <a for="connection timing info">connection start time</a> SHOULD
2314+
be the <a for=/>unsafe shared current time</a> immediately before establishing the connection to
2315+
the server or proxy.
2316+
2317+
<li><p><var>timingInfo</var>'s <a for="connection timing info">connection end time</a> SHOULD be
2318+
the <a for=/>unsafe shared current time</a> immediately after establishing the connection to the
2319+
server or proxy, as follows:
2320+
<ul>
2321+
<li><p>The returned time MUST include the time interval to establish the transport
2322+
connection, as well as other time intervals such as SOCKS authentication. It
2323+
MUST include the time interval to complete enough of the TLS handshake to
2324+
request the resource.
2325+
2326+
<li><p>If the user agent used TLS False Start [[RFC7918]] for this connection,
2327+
this interval MUST NOT include the time needed to receive the server's
2328+
Finished message.
2329+
2330+
<li><p>If the user agent sends the request with early data [[RFC8470]] without
2331+
waiting for the full handshare to complete, this interval MUST NOT include
2332+
the time needed to receive the server's ServerHello message.
2333+
2334+
<li><p>If the user agent waits for full handshake completion to send the
2335+
request, this interval includes the full TLS handshake even if other
2336+
requests were sent using early data on <var>connection</var>.
2337+
</ul>
2338+
2339+
<p class=note>Example: Suppose the user agent establishes an HTTP/2 connection
2340+
over TLS 1.3 to send a GET request and a POST request. It sends the ClientHello
2341+
at time <code>t1</code> and then sends the GET request with early data. The
2342+
POST request is not safe [[HTTP-SEMANTICS]] (section 4.2.1), so the user agent waits
2343+
to complete the handshake at time <code>t2</code> before sending it. Although
2344+
both requests used the same connection, the GET request reports a connectEnd
2345+
value of <code>t1</code>, while the POST request reports a connectEnd value for
2346+
<code>t2</code>.
2347+
2348+
<li><p>If a secure transport is used, <var>timingInfo</var>'s
2349+
<a for="connection timing info">secure connection start time</a> should be the result of calling
2350+
<a for=/>unsafe shared current time</a> immmediately before starting the handshake process to
2351+
secure <var>connection</var>. [[!TLS]]
2352+
2353+
<li><p><var>timingInfo</var>'s <a for="connection timing info">alpn negotiated protocol</a>
2354+
should be the <var>connection</var>'s ALPN Protocol ID as specified in [[RFC7301]], with the
2355+
following caveats:
2356+
<ul>
2357+
<li><p>When a proxy is configured, if a tunnel connection is established then this attribute
2358+
MUST return the ALPN Protocol ID of the tunneled protocol, otherwise it MUST return the ALPN
2359+
Protocol ID of the first hop to the proxy.
2360+
2361+
<li><p>Octets in the ALPN protocol MUST NOT be percent-encoded if they are valid token
2362+
characters except "%", and when using percent-encoding, uppercase hex digits MUST be used.
2363+
2364+
<li><p>Formally registered ALPN protocol IDs are documented by <a href=
2365+
"https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids">
2366+
IANA</a>.
2367+
2368+
<li><p>In case the user agent is using an experimental, non-registered protocol, the user
2369+
agent MUST use the ALPN negotiated value if any. If ALPN was not used for protocol
2370+
negotiations, the user agent MAY use another descriptive string.
2371+
2372+
<p class="note">The "h3" ALPN ID is defined for the final version
2373+
of the HTTP/3 protocol in the
2374+
<a href="https://tools.ietf.org/html/draft-ietf-quic-http-17#section-10.1">HTTP/3
2375+
Internet Draft</a>.
2376+
2377+
<p class="note">Note that <a for="connection timing info">alpn negotiated protocol</a> is
2378+
intended to identify the network protocol in use for the fetch regardless of how it was
2379+
actually negotiated; that is, even if ALPN is not used to negotiate the network protocol,
2380+
this attribute still uses the ALPN Protocol IDs to indicate the protocol in use.
2381+
</ul>
2382+
</ul>
2383+
</ol>
22222384

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

@@ -3362,6 +3524,7 @@ the request.
33623524

33633525
<li><p>Let <var>fetchParams</var> be a new <a for=/>fetch params</a> whose
33643526
<a for="fetch params">request</a> is <var>request</var>,
3527+
<a for="fetch params">timing info</a> is a new <a for=/>fetch timing info</a>,
33653528
<a for="fetch params">process request body</a> is <var>processRequestBody</var>,
33663529
<a for="fetch params">process request end-of-body</a> is <var>processRequestEndOfBody</var>,
33673530
<a for="fetch params">process response</a> is <var>processResponse</var>,
@@ -3450,6 +3613,10 @@ steps:
34503613

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

3616+
<li><p>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a> be a new
3617+
<a for=/>fetch timing info</a> with its <a for="fetch timing info">fetch start time</a> set to the
3618+
<a for=/>unsafe shared current time</a>.
3619+
34533620
<li><p>If <var>request</var>'s <a>local-URLs-only flag</a> is set and <var>request</var>'s
34543621
<a for=request>current URL</a> is not <a lt="is local">local</a>, then set <var>response</var> to a
34553622
<a>network error</a>.
@@ -3746,6 +3913,8 @@ steps:
37463913
<a for=/>response</a> <var>response</var>, run these steps:
37473914

37483915
<ol>
3916+
<li><p><a for=/>Finalize timing info</a> with <var>fetchParams</var> and <var>response</var>.
3917+
37493918
<li><p>If <var>fetchParams</var>'s <a for="fetch params">process response</a> is non-null, then
37503919
<a>queue a fetch task</a> to run <var>fetchParams</var>'s
37513920
<a for="fetch params">process response</a> given <var>response</var>, with <var>fetchParams</var>'s
@@ -3779,6 +3948,32 @@ steps:
37793948
<!-- This is really bad and needs to be handled differently at some point. -->
37803949
</ol>
37813950

3951+
<p>To <dfn>finalize timing info</dfn>, given <a for=/>fetch params</a> <var>fetchParams</var> and
3952+
<a for=/>response</a> <var>response</var>, perform the following steps:
3953+
<ol>
3954+
<li><p>Let <var>timingInfo</var> be <var>fetchParams</var>'s
3955+
<a for="fetch params">timing info</a>.
3956+
3957+
<li><p>Let <var>startTime</var> be <var>timingInfo</var>'s
3958+
<a for="fetch timing info">fetch start time</a>.
3959+
3960+
<li><p>Let <var>redirectTimings</var> be <var>fetchParams</var>'s
3961+
<a for="fetch params">redirect timing info list</a>.
3962+
3963+
<li><p>If <var>redirectTimings</var> is not empty, then set <var>startTime</var> to
3964+
<a for="fetch params">redirect timing info list</a> first item's
3965+
<a for="redirect timing info">timing info</a>'s <A for="fetch timing info">fetch start time</a>.
3966+
3967+
<li><p>If <var>response</var>'s <a for=response>timing allow passed flag</a> is set, then set
3968+
<var>response</var>'s <a for=response>timing info</a> to <var>fetchParams</var>'s
3969+
<a for="fetch params">timing info</a> to <var>timingInfo</var> and <var>response</var>'s
3970+
<a for=response>redirect timing info list</a> to <var>redirectTimings</var>.
3971+
3972+
<li><p>Otherwise, set <var>response</var>'s <a for=response>timing info</a> to a new
3973+
<a for=/>fetch timing info</a>, with its <a for="fetch timing info">fetch start time</a>
3974+
set to <var>startTime</var>.
3975+
</ol>
3976+
37823977

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

@@ -3902,20 +4097,28 @@ these steps:
39024097

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

4100+
<li><p>Let <var>timingInfo</var> be <var>fetchParams</var>'s <a for="fetch params">timing info</a>
4101+
39054102
<li>
39064103
<p>If <var>request</var>'s <a>service-workers mode</a> is "<code>all</code>", then:
39074104

39084105
<ol>
39094106
<li><p>Let <var>requestForServiceWorker</var> be a <a for=request>clone</a> of
39104107
<var>request</var>.
39114108

4109+
<li><p>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
4110+
<a for="fetch timing info">worker start time</a> to the <a for=/>unsafe shared current time</a>.
4111+
39124112
<li><p>Set <var>response</var> to the result of invoking <a for=/>handle fetch</a> for
39134113
<var>requestForServiceWorker</var>. [[!HTML]] [[!SW]]
39144114

39154115
<li>
39164116
<p>If <var>response</var> is not null, then:
39174117

39184118
<ol>
4119+
<li><p>Set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
4120+
<a for="fetch timing info">response start time</a> to the <a for=/>unsafe shared current time</a>.
4121+
39194122
<li>If <var>request</var>'s <a for=request>body</a> is non-null, then
39204123
<a for=ReadableStream>cancel</a> <var>request</var>'s <a for=request>body</a> with undefined.
39214124

@@ -3946,6 +4149,9 @@ these steps:
39464149
</ol>
39474150
</ol>
39484151

4152+
<p>Otheriwse, set <var>fetchParams</var>'s <a for="fetch params">timing info</a>'s
4153+
<a for="fetch timing info">worker start time</a> to zero.
4154+
39494155
<li>
39504156
<p>If <var>response</var> is null, then:
39514157

@@ -4133,6 +4339,14 @@ run these steps:
41334339
<p class="note no-backref"><var>request</var>'s <a for=request>body</a>'s <a for=body>source</a>'s
41344340
nullity has already been checked.
41354341

4342+
<li><p>Let <var>redirectInfo</var> be a new <a for=/>redirect timing info</a> with its
4343+
<a for="redirect timing info">redirect location URL</a> set to <var>locationURL</var> and its
4344+
<a for="redirect timing info">timing info</a> set to <var>fetchParams</var>'s
4345+
<a for="fetch params">timing info</a>.
4346+
4347+
<li><p>Append <var>redirectInfo</var> to <var>fetchParams</var>'s
4348+
<a for="fetch params">redirect timing info list</a>.
4349+
41364350
<li><p><a for=list>Append</a> <var>locationURL</var> to <var>request</var>'s
41374351
<a for=request>URL list</a>.
41384352

@@ -4720,6 +4934,8 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
47204934

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

4937+
<li><p>Let <var>timingInfo</var> be <var>fetchParams</var>'s <a for="fetch params">timing info</a>.
4938+
47234939
<li><p>Let <var>httpCache</var> be the result of <a>determining the HTTP cache partition</a>, given
47244940
<var>httpRequest</var>.
47254941

@@ -4745,6 +4961,11 @@ optional boolean <var>forceNewConnection</var> (default false), run these steps:
47454961
<var>includeCredentials</var>, and <var>forceNewConnection</var>.
47464962
</dl>
47474963

4964+
<li>Set <var>timingInfo</var>'s <a for="fetch timing info">connection timing info</a> to the
4965+
result of calling <a>clamp connection timing to fetch timing</a> with <var>connection</var>'s
4966+
<a for=connection>timingInfo</a> and <var>timingInfo</var>'s
4967+
<a for="fetch timing info">fetch start time</a>.
4968+
47484969
<li>
47494970
<p>Run these steps, but <a>abort when</a> the ongoing fetch is <a for=fetch>terminated</a>:
47504971

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

4982+
<li>Set <var>timingInfo</var>'s <a for="fetch timing info">request start time</a> to
4983+
<a for=/>unsafe shared current time</a>.
4984+
47614985
<li>
47624986
<p>Set <var>response</var> to the result of making an HTTP request over <var>connection</var>
47634987
using <var>request</var> with the following caveats:
47644988

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

4992+
<li><p>Set <var>timingInfo</var>'s <a for="fetch timing info">response start time</a> to
4993+
the <a for=/>unsafe shared current time</a>immediately after the user agent's HTTP parser
4994+
receives the first byte of the response (e.g. frame header bytes for HTTP/2, or response
4995+
status line for HTTP/1.x).
4996+
47684997
<li><p>Wait until all the <a for=/>headers</a> are transmitted.
47694998

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

5175+
<li><p>Increase <var>timingInfo</var>'s <a for="fetch timing info">encoded body size</a>
5176+
by <var>bytes</var>'s <a for="byte sequence">length</a>.
5177+
49465178
<li>
49475179
<p>Set <var>bytes</var> to the result of <a lt="handle content codings">handling content
49485180
codings</a> given <var>codings</var> and <var>bytes</var>.
49495181

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

5185+
<li><p>Increase <var>timingInfo</var>'s <a for="fetch timing info">decoded body size</a> by
5186+
<var>bytes</var>'s <a for="byte sequence">length</a>.
5187+
49535188
<li><p>If <var>bytes</var> is failure, then <a lt=terminated for=fetch>terminate</a> the
49545189
ongoing fetch.
49555190

0 commit comments

Comments
 (0)