@@ -114,6 +114,7 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262
114114
115115<pre class=link-defaults>
116116spec:dom; type:dfn; text:element
117+ spec:dom; type:dfn; text:event;
117118spec:infra; type:dfn; text:implementation-defined
118119</pre>
119120
@@ -8512,7 +8513,18 @@ otherwise false.
85128513
85138514<pre class=idl>
85148515partial interface mixin WindowOrWorkerGlobalScope {
8515- [NewObject] Promise<Response> fetch(RequestInfo input, optional RequestInit init = {});
8516+ [NewObject] Promise<Response> fetch(RequestInfo input, optional FetchInit init = {});
8517+ };
8518+
8519+ dictionary FetchInit : RequestInit {
8520+ FetchMonitorCallback monitor;
8521+ };
8522+
8523+ callback FetchMonitorCallback = undefined (FetchMonitor requestMonitor, FetchMonitor responseMonitor);
8524+
8525+ [Exposed=(Window,Worker)]
8526+ interface FetchMonitor : EventTarget {
8527+ attribute EventHandler onprogress;
85168528};
85178529</pre>
85188530
@@ -8584,10 +8596,65 @@ method steps are:
85848596 https://github.com/whatwg/dom/issues/1031#issuecomment-1233206400 -->
85858597 </ol>
85868598
8599+ <li><p> Let <var> hasUploadListeners</var> be false.
8600+
8601+ <li><p> Let <var> requestMonitor</var> be null.
8602+
8603+ <li><p> Let <var> responseMonitor</var> be null.
8604+
8605+ <li>
8606+ <p> If <var> init</var> ["{{FetchInit/monitor}}"] <a for=map>exists</a> , then:
8607+
8608+ <ol>
8609+ <li><p> Let <var> monitorCallback</var> be <var> init</var> ["{{FetchInit/monitor}}"] .
8610+
8611+ <li><p> Set <var> requestMonitor</var> to a {{FetchMonitor}} .
8612+
8613+ <li><p> Set <var> responseMonitor</var> to a {{FetchMonitor}} .
8614+
8615+ <li><p> Let <var> args</var> be « <var> requestMonitor</var> , <var> responseMonitor</var> ».
8616+
8617+ <li><p> [=invoke|Invoke=] <var> monitorCallback</var> with <var> args</var>
8618+ and <code> "rethrow"</code> . If this throws an exception, <a for=/>reject</a> <var> p</var> with it
8619+ and return <var> p</var> .
8620+
8621+ <li><p> If one or more <a event><code>progress</code></a> event listeners were added to
8622+ <var> requestMonitor</var> , then set <var> hasUploadListeners</var> to true.
8623+ </ol>
8624+
8625+ <li><p> Let <var> requestBodyTransmitted</var> be 0.
8626+
8627+ <li><p> Let <var> requestBodyLength</var> be <var> request</var> 's <a for=request>body</a>' s
8628+ <a for=body>length</a> , if <var> request</var> 's <a for=request>body</a> is non-null;
8629+ otherwise 0.
8630+
8631+ <li><p> Assert: <var> requestBodyLength</var> is an integer.
8632+
8633+ <li>
8634+ <p> Let <var> processRequestBodyChunkLength</var> , given a <var> bytesLength</var> , be these steps:
8635+
8636+ <ol>
8637+ <li><p> Increase <var> requestBodyTransmitted</var> by <var> bytesLength</var> .
8638+
8639+ <li><p> If not roughly 50ms has passed since these steps were last invoked, then return.
8640+
8641+ <li><p> If <var> hasUploadListeners</var> is true, then <a>fire a progress event</a> named
8642+ <a event><code>progress</code></a> at <var> requestMonitor</var> with <var> requestBodyTransmitted</var>
8643+ and <var> requestBodyLength</var> .
8644+ </ol>
8645+
85878646 <li>
8588- < p > < p > Set < var > controller</ var > to the result of calling < a for =/ > fetch</ a > given
8589- < var > request</ var > and < a for =fetch > < i > processResponse</ i > </ a > given < var > response</ var > being
8590- these steps:
8647+ <p> Let <var> processRequestEndOfBody</var> be these steps:
8648+
8649+ <ol>
8650+ <li><p> If <var> hasUploadListeners</var> is false, then return.
8651+
8652+ <li><p> <a>Fire a progress event</a> named <a event><code>progress</code></a> at <var> requestMonitor</var>
8653+ with <var> requestBodyTransmitted</var> and <var> requestBodyLength</var> .
8654+ </ol>
8655+
8656+ <li>
8657+ <p> Let <var> processResponse</var> given a <var> response</var> be these steps:
85918658
85928659 <ol>
85938660 <li><p> If <var> locallyAborted</var> is true, then abort these steps.
@@ -8615,10 +8682,17 @@ method steps are:
86158682 <li><p> <a for=/>Resolve</a> <var> p</var> with <var> responseObject</var> .
86168683 </ol>
86178684
8685+ <li><p> Set <var> controller</var> to the result of calling <a for=/>fetch</a> given
8686+ <var> request</var> with <a for=fetch><i>processResponse</i></a> set to <var> processResponse</var> ,
8687+ <a for=fetch><i>processRequestBodyChunkLength</i></a> set to <var> processRequestBodyChunkLength</var> ,
8688+ and <a for=fetch><i>processRequestEndOfBody</i></a> set to <var> processRequestEndOfBody</var> .
8689+
86188690 <li><p> Return <var> p</var> .
86198691</ol>
86208692</div>
86218693
8694+ TEMPORARY <dfn id=event-fetchmonitor-progress event for=FetchMonitor><code>progress</code></dfn>
8695+
86228696<div algorithm>
86238697<p> To <dfn lt="Abort the fetch() call" export id=abort-fetch>abort a <code>fetch()</code> call</dfn>
86248698with a <var> promise</var> , <var> request</var> , <var> responseObject</var> , and an <var> error</var> :
@@ -9132,6 +9206,119 @@ done only by navigations). The <a>fetch controller</a> is also used to
91329206<a for="fetch controller">process the next manual redirect</a> for <a for=/>requests</a> with
91339207<a for=request>redirect mode</a> set to "<code> manual</code> ".
91349208
9209+ <h2 id=interface-progressevent>Interface {{ProgressEvent}}</h2>
9210+
9211+ <pre class=idl>
9212+ [Exposed=(Window,Worker)]
9213+ interface ProgressEvent : Event {
9214+ constructor(DOMString type, optional ProgressEventInit eventInitDict = {});
9215+
9216+ readonly attribute boolean lengthComputable;
9217+ readonly attribute double loaded;
9218+ readonly attribute double total;
9219+ };
9220+
9221+ dictionary ProgressEventInit : EventInit {
9222+ boolean lengthComputable = false;
9223+ double loaded = 0;
9224+ double total = 0;
9225+ };
9226+ </pre>
9227+
9228+ <p> <a>Events</a> using the {{ProgressEvent}} interface indicate some kind of progression.
9229+
9230+ <p> The
9231+ <dfn attribute for=ProgressEvent><code>lengthComputable</code></dfn> ,
9232+ <dfn attribute for=ProgressEvent><code>loaded</code></dfn> , and
9233+ <dfn attribute for=ProgressEvent><code>total</code></dfn>
9234+ getter steps are to return the value they were initialized to.
9235+
9236+
9237+ <h3 id=firing-events-using-the-progressevent-interface>Firing events using the {{ProgressEvent}} interface</h3>
9238+
9239+ <p> To <dfn id=concept-event-fire-progress>fire a progress event</dfn> named <var> e</var> at
9240+ <var> target</var> , given <var> transmitted</var> and <var> length</var> , means to <a>fire an event</a>
9241+ named <var> e</var> at <var> target</var> , using {{ProgressEvent}} , with the {{ProgressEvent/loaded}}
9242+ attribute initialized to <var> transmitted</var> , and if <var> length</var> is not 0, with the
9243+ {{ProgressEvent/lengthComputable}} attribute initialized to true and the {{ProgressEvent/total}}
9244+ attribute initialized to <var> length</var> .
9245+
9246+
9247+ <h3 id=suggested-names-for-events-using-the-progressevent-interface>Suggested names for events using the {{ProgressEvent}} interface</h3>
9248+
9249+ <p><em> This section is non-normative.</em>
9250+
9251+ <p> The suggested {{Event/type}}
9252+ attribute values for use with
9253+ <a>events</a> using the
9254+ {{ProgressEvent}} interface are summarized in the table below.
9255+ Specification editors are free to tune the details to their specific
9256+ scenarios, though are strongly encouraged to discuss their usage with the
9257+ WHATWG community to ensure input from people familiar with the subject.
9258+
9259+ <table>
9260+ <tbody>
9261+ <tr>
9262+ <th> {{Event/type}} attribute value
9263+ <th> Description
9264+ <th> Times
9265+ <th> When
9266+ <tr>
9267+ <th><code> loadstart</code>
9268+ <td> Progress has begun.
9269+ <td> Once.
9270+ <td> First.
9271+ <tr>
9272+ <th> <a event><code>progress</code></a>
9273+ <td> In progress.
9274+ <td> Once or more.
9275+ <td> After <code> loadstart</code> has been
9276+ <a>dispatched</a> .
9277+ <tr>
9278+ <th><code> error</code>
9279+ <td> Progression failed.
9280+ <td rowspan=4> Zero or once (mutually exclusive).
9281+ <td rowspan=4> After the last <a event><code>progress</code></a> has
9282+ been
9283+ <a>dispatched</a> .
9284+ <tr>
9285+ <th><code> abort</code>
9286+ <td> Progression is terminated.
9287+ <tr>
9288+ <th><code> timeout</code>
9289+ <td> Progression is terminated due to preset time expiring.
9290+ <tr>
9291+ <th><code> load</code>
9292+ <td> Progression is successful.
9293+ <tr>
9294+ <th><code> loadend</code>
9295+ <td> Progress has stopped.
9296+ <td> Once.
9297+ <td> After one of <code> error</code> , <code> abort</code> ,
9298+ <code> timeout</code> or <code> load</code> has been
9299+ <a>dispatched</a> .
9300+ </table>
9301+
9302+ <p> The <code> error</code> , <code> abort</code> , <code> timeout</code> , and
9303+ <code> load</code> event types are mutually exclusive.
9304+
9305+ <p> Throughout the web platform the <code> error</code> , <code> abort</code> ,
9306+ <code> timeout</code> and <code> load</code> event types have
9307+ their {{Event/bubbles}} and {{Event/cancelable}}
9308+ attributes initialized to false, so it is suggested that for consistency all
9309+ <a>events</a> using the
9310+ {{ProgressEvent}} interface do the same.
9311+
9312+
9313+ <h3 id=security-considerations>Security considerations</h3>
9314+
9315+ <p> For cross-origin requests some kind of opt-in, e.g., the
9316+ <a>CORS protocol</a> , has to be used before <a>events</a> using the
9317+ {{ProgressEvent}} interface are
9318+ <a>dispatched</a>
9319+ as information (e.g., size) would be revealed that cannot be obtained
9320+ otherwise.
9321+
91359322
91369323<h2 id=acknowledgments class=no-num>Acknowledgments</h2>
91379324
0 commit comments