diff --git a/fetch.bs b/fetch.bs index 1668dda27..c173bbe12 100755 --- a/fetch.bs +++ b/fetch.bs @@ -392,6 +392,23 @@ following items: [[RESOURCE-TIMING]] [[NAVIGATION-TIMING]]
An ASCII string. +

A fetch retry params is a struct used to maintain bookkeeping details for +retrying fetch() calls. It has the following items: +

+
expiry time +
A {{DOMHighResTimeStamp}}. + +
remaining attempts +
backoff factor +
next delay +
A number. + +
allow after unload +
allow non-idempotent methods +
allow post-connection errors +
A boolean. +
+

To create an opaque timing info, @@ -2245,6 +2262,10 @@ Unless stated otherwise, it is unset.

This flag is for exclusive use by HTML's navigate algorithm. [[!HTML]] +

A request has an associated +retry params (null or a fetch retry params). Unless stated otherwise, +it is null. +

A request has an associated boolean user-activation. Unless stated otherwise, it is false. @@ -2600,6 +2621,9 @@ this is also tracked internally using the request's timing allow ("same-origin", "same-site", or "cross-site"), which is initially "same-origin". +

A response has an associated boolean potentially transient, +which is initially false. +


A network error is a response whose @@ -2884,12 +2908,22 @@ invoke a fetch at a later time, e.g., when a document is unloaded or becomes not terminated:

    -
  1. For each fetch record record of - fetchGroup's fetch records, if record's - controller is non-null and record's - request's done flag is unset and keepalive is - false, terminate record's - controller. +

  2. +

    For each fetch record record of + fetchGroup's fetch records: + +

      +
    1. +

      If record's controller is non-null and + record's request's done flag is unset and keepalive is false, + +

      terminate record's controller. + +

    2. If record's request's retry params + is non-null and its allow after unload is false, set + record's request's retry params to null. +

  3. Process deferred fetches for fetchGroup.

@@ -5088,7 +5122,7 @@ steps:

If request's integrity metadata is not the empty string, then:

    -
  1. Let processBodyError be this step: run fetch response handover given +

  2. Let processBodyError be this step: retry or process response given fetchParams and a network error.

  3. If response's body is null, then run @@ -5105,20 +5139,83 @@ steps:

  4. Set response's body to bytes as a body. -

  5. Run fetch response handover given fetchParams and response. +

  6. Retry or process response given fetchParams and response.

  • Fully read response's body given processBody and processBodyError. -

  • Otherwise, run fetch response handover given fetchParams and - response. +

  • Retry or process response given fetchParams and response.


  • +
    +

    To retry or process response given fetchParams and response, run +the steps corresponding to the first matching statement: + +

    +
    response is not a network error +
    fetchParams's request's retry params is + null + +
    Run fetch response handover given fetchParams and response. + +
    fetchParams's request's retry params's + expiry time is before the coarsened shared current + time given fetchParams's cross-origin isolated capability + +
    fetchParams's request's retry + params's remaining attempts is 0 +
    fetchParams's request's method is + `POST`, `PUT`, `PATCH`, or `DELETE`, and + retryParams's allow non-idempotent methods is false + +
    response is not potentially transient + +
    +
      +
    1. Wait until the coarsened shared current time given + fetchParams's cross-origin isolated capability is + fetchParams's request's retry params's + expiry time. + +

    2. Run fetch response handover given fetchParams and response. +

    + +
    Otherwise +
    +
      +
    1. Let retryParams be fetchParams's request's + retry params. + +

    2. Let errorTime be the coarsened shared current timegiven + fetchParams's cross-origin isolated capability. + +

    3. Let expiryTime be errorTime + retryParams's next delay. + +

    4. Decrement retryParams's remaining attempts by + 1. + +

    5. Multiply retryParams's next delay by + retryParams's backoff factor. + +

    6. Wait until the coarsened shared current time given + fetchParams's cross-origin isolated capability is + expiryTime. + +

    7. Run main fetch given fetchParams. +

    +
    + + +
    + +
    +

    The fetch response handover, given a fetch params fetchParams and a response response, run these steps: @@ -6507,7 +6604,7 @@ optional boolean forceNewConnection (default false), run these steps:

  • Let request be fetchParams's request.

  • If request's client is offline, then return a - network error. + network error whose potentially transient is true.

  • Let response be null. @@ -6544,7 +6641,8 @@ optional boolean forceNewConnection (default false), run these steps: canceled:

      -
    1. If connection is failure, then return a network error. +

    2. If connection is failure, then return a network error whose potentially transient is true.

    3. Set timingInfo's final connection timing info to the result of calling clamp and coarsen connection timing info with @@ -6598,8 +6696,15 @@ optional boolean forceNewConnection (default false), run these steps: 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). +

    4. If fetchParams's request's retry + params is non-null and its allow post-connection errors + is false, then set request's retry params to null. +

    5. Wait until all the HTTP response headers are transmitted. +

    6. If the connection was lost, reset, or timed out, then return a + network error whose potentially transient is true. +

    7. Let status be the HTTP response's status code.

    8. @@ -8404,6 +8509,16 @@ interface Request { }; Request includes Body; +dictionary RetryOptions { + [EnforceRange] required unsigned short maxAttempts; + [EnforceRange] unsigned long long initialDelay; + double backoffFactor; + [EnforceRange] unsigned long long maxAge; + boolean retryAfterUnload; + boolean retryNonIdempotent; + boolean retryOnlyIfServerUnreached; +}; + dictionary RequestInit { ByteString method; HeadersInit headers; @@ -8420,6 +8535,7 @@ dictionary RequestInit { RequestDuplex duplex; RequestPriority priority; any window; // can only be set to null + [SecureContext] RetryOptions retryOptions; }; enum RequestDestination { "", "audio", "audioworklet", "document", "embed", "font", "frame", "iframe", "image", "json", "manifest", "object", "paintworklet", "report", "script", "sharedworker", "style", "text", "track", "video", "worker", "xslt" }; @@ -8858,6 +8974,24 @@ constructor steps are:
    9. If init["{{RequestInit/keepalive}}"] exists, then set request's keepalive to it. +

    10. +

      If init["{{RequestInit/retryOptions}}"] exists, then: + +

        +
      1. Let options be init["{{RequestInit/retryOptions}}"]. + +

      2. Set request's retry params to a new fetch retry params whose + remaining attempts is options["{{RetryOptions/maxAttempts}}"], + backoff factor is options["{{RetryOptions/backoffFactor}}"] if it exists and 1.0 otherwise, + next delay is options["{{RetryOptions/initialDelay}}"] if it exists and 0 otherwise, + allow after unload is options["{{RetryOptions/retryAfterUnload}}"] if it exists and false otherwise, + allow non-idempotent methods is options["{{RetryOptions/retryNonIdempotent}}"] if it exists and false otherwise, and + allow post-connection errors is the negation of options["{{RetryOptions/retryOnlyIfServerUnreached}}"] if it exists and true otherwise. + +

      3. If options["{{RetryOptions/maxAge}}"] exists, then set + request's retry params's expiry time to the result of adding options["{{RetryOptions/maxAge}}"] to the current time. +

      +
    11. If init["{{RequestInit/method}}"] exists, then: @@ -9466,7 +9600,7 @@ method steps are:

    12. Set controller to the result of calling fetch given - request and processResponse given response being + request, and processResponse given response being these steps: