diff --git a/fetch.bs b/fetch.bs index fa6deae20..6dca829f3 100755 --- a/fetch.bs +++ b/fetch.bs @@ -1651,6 +1651,74 @@ these steps: +

Trailer state

+ +

A trailer state is a struct used to represent +HTTP trailer fields received after a response body +([[HTTP]], Section 6.5). +It has: + +

+ +

A trailer state is shared by reference between a +response and its clones. + +

+

To complete a trailer state given a trailer state +trailerState: + +

    +
  1. If trailerState's state is not + "pending", then return. + +

  2. Set trailerState's state to + "complete". + +

  3. For each observer of + trailerState's observers: + run observer. + +

  4. Empty trailerState's + observers. +

+
+ +
+

To error a trailer state given a trailer state +trailerState and a value reason: + +

    +
  1. If trailerState's state is not + "pending", then return. + +

  2. Set trailerState's state to + "errored". + +

  3. Set trailerState's error to + reason. + +

  4. For each observer of + trailerState's observers: + run observer. + +

  5. Empty trailerState's + observers. +

+
+ +

Requests

This section documents how requests work in detail. To get started, see @@ -2579,6 +2647,18 @@ message as HTTP/2 does not support them.

The source and length concepts of a network's response's body are always null. +

A response has an associated +trailer state +(a trailer state). Unless stated otherwise it is a new trailer state. + +

A response's +trailer header list +is its trailer state's header list. + +

The trailer state is shared by reference between a +response and its clones (see clone), ensuring trailer fields +received after cloning are visible to all copies. +

A response has an associated cache state (the empty string, "local", or "validated"). Unless stated otherwise, it is the empty @@ -2692,17 +2772,23 @@ of defining the concrete types of filtered responses.)

A basic filtered response is a filtered response whose -type is "basic" and +type is "basic", header list excludes any headers in internal response's header list whose name is a +forbidden response-header name, and +trailer header list excludes any +headers in +internal response's +trailer header list whose +name is a forbidden response-header name.

A CORS filtered response is a filtered response whose -type is "cors" and +type is "cors", header list excludes any headers in internal response's @@ -2710,6 +2796,14 @@ of defining the concrete types of filtered responses.) name is not a CORS-safelisted response-header name, given internal response's +CORS-exposed header-name list, and +trailer header list excludes any +headers in +internal response's +trailer header list whose +name is not a +CORS-safelisted response-header name, given +internal response's CORS-exposed header-name list.

An opaque filtered response is a @@ -2719,6 +2813,7 @@ of defining the concrete types of filtered responses.) status is 0, status message is the empty byte sequence, header list is « », +trailer header list is « », body is null, and body info is a new response body info. @@ -2729,6 +2824,7 @@ is a filtered response whose status is 0, status message is the empty byte sequence, header list is « », +trailer header list is « », body is null, and body info is a new response body info. @@ -2781,7 +2877,10 @@ console.log((await fetch("/surprise-me", { redirect: "manual" })).type); // "opa internal response.

  • Let newResponse be a copy of response, except for its - body. + body and trailer state. + +

  • Set newResponse's trailer state to + response's trailer state.

  • If response's body is non-null, then set newResponse's body to the result of cloning @@ -5310,6 +5409,9 @@ steps:

  • Set fetchParams's request's done flag. +

  • Complete a trailer state given response's + trailer state. +

  • If fetchParams's process response end-of-body is non-null, then run fetchParams's process response end-of-body given response. @@ -5360,13 +5462,34 @@ steps: flushAlgorithm set to processResponseEndOfBody. -

  • Set internalResponse's body's stream to the - result of internalResponse's body's stream - piped through transformStream. +

  • Let readable be transformStream's + readable. + +

  • Let pipePromise be the result of + piping internalResponse's + body's stream to + transformStream's writable. + +

  • Set internalResponse's body's + stream to readable. + +

  • +

    Upon rejection of pipePromise with + reason: + +

      +
    1. Error a trailer state given response's + trailer state and reason. +

    -

    This {{TransformStream}} is needed for the purpose of receiving a notification when - the stream reaches its end, and is otherwise an identity transform stream. +

    The {{TransformStream}} receives a notification when the body + stream reaches its end (via the flush algorithm) or when it errors (via the + pipe promise rejection). On successful completion, + processResponseEndOfBody completes + the trailer state. On error, the trailer state is + errored, which rejects any pending + {{Response/trailers}} promises.

  • If fetchParams's process response consume body is @@ -6760,6 +6883,21 @@ optional boolean forceNewConnection (default false), run these steps:

  • Break. + +

  • +

    If the HTTP response includes trailer fields + ([[HTTP]], Section 6.5), + then, after the response body has been fully transmitted, set + response's trailer header list to a + header list containing each received trailer field as a + header. + +

    Trailer fields are received after the response body. The HTTP + layer is responsible for omitting trailer fields prohibited by HTTP semantics + (e.g., fields used in transfer codings, content framing, or routing). The + trailer header list is populated before + completing the trailer state + in the fetch response handover steps.

    The exact layering between Fetch and HTTP still needs to be sorted through and @@ -8616,6 +8754,7 @@ interface Request { readonly attribute boolean isHistoryNavigation; readonly attribute AbortSignal signal; readonly attribute RequestDuplex duplex; + readonly attribute Promise<Headers> trailers; [NewObject] Request clone(); }; @@ -8663,6 +8802,9 @@ used or observed from JavaScript.

    A {{Request}} object has an associated signal (null or an {{AbortSignal}} object), initially null. +

    A {{Request}} object has an associated +trailers promise (null or a {{Promise}}), initially null. +

    A {{Request}} object's body is its request's body. @@ -8815,6 +8957,10 @@ object), initially null. See issue #1254 for defining "full". +

    request . trailers +

    Returns a promise that resolves to an empty immutable {{Headers}} object. Client-side + requests do not support sending trailer fields. +

    request . clone()

    Returns a clone of request. @@ -9287,6 +9433,32 @@ set; otherwise false.

    The duplex getter steps are to return "half". +

    +

    The trailers getter steps are: + +

      +
    1. +

      If this's trailers promise is null, then: + +

        +
      1. Let promise be a new promise. + +

      2. Resolve promise with a new {{Headers}} object + whose header list is « » and whose guard is + "immutable". + +

      3. Set this's trailers promise to promise. +

      + +
    2. Return this's trailers promise. +

    +
    + +

    Client-side requests do not support sending trailer fields. The +{{Request/trailers}} attribute always returns a promise that resolves to empty +immutable {{Headers}}. This does not foreclose future extension to support sending +trailer fields. +


    @@ -9331,6 +9503,7 @@ interface Response { readonly attribute boolean ok; readonly attribute ByteString statusText; [SameObject] readonly attribute Headers headers; + readonly attribute Promise<Headers> trailers; [NewObject] Response clone(); }; @@ -9352,6 +9525,9 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredire

    A {{Response}} object also has an associated headers (null or a {{Headers}} object), initially null. +

    A {{Response}} object has an associated +trailers promise (null or a {{Promise}}), initially null. +

    A {{Response}} object's body is its response's body. @@ -9394,8 +9570,20 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredire

    response . headers

    Returns response's headers as {{Headers}}. +

    response . trailers +
    +

    Returns a promise that resolves to {{Headers}} containing the response's trailer fields. + +

    For responses obtained from {{WindowOrWorkerGlobalScope/fetch()}}, the promise resolves after the + response body has been fully received. For synthetically constructed responses (via the + {{Response/Response()}} constructor, {{Response/error()}}, {{Response/redirect()}}, or + {{Response/json()}}), the promise resolves immediately to empty immutable {{Headers}}. + +

    If the response body stream errors, the promise is rejected. +

    response . clone() -

    Returns a clone of response. +

    Returns a clone of response. The clone shares the same + trailer state, so both will receive the same trailer fields.


    @@ -9486,12 +9674,25 @@ constructor steps are:
  • Perform initialize a response given this, init, and bodyWithType. + +

  • Complete a trailer state given this's response's + trailer state. -

    The static error() method steps are to return the -result of creating a {{Response}} object, given a new network error, -"immutable", and the current realm. +

    +

    The static error() method steps are: + +

      +
    1. Let responseObject be the result of creating a {{Response}} + object, given a new network error, "immutable", and the current realm. + +

    2. Complete a trailer state given responseObject's + response's trailer state. + +

    3. Return responseObject. +

    +

    The static @@ -9518,6 +9719,9 @@ are:

  • Append (`Location`, value) to responseObject's response's header list. +

  • Complete a trailer state given responseObject's + response's trailer state. +

  • Return responseObject. @@ -9540,6 +9744,9 @@ are:

  • Perform initialize a response given responseObject, init, and (body, "application/json"). +

  • Complete a trailer state given responseObject's + response's trailer state. +

  • Return responseObject. @@ -9574,6 +9781,72 @@ otherwise false.

    The headers getter steps are to return this's headers. +

    +

    The trailers getter steps are: + +

      +
    1. If this's trailers promise is null, then: + +

        +
      1. Let response be this's response. + +

      2. Let trailerState be response's + trailer state. + +

      3. Let promise be a new promise. + +

      4. +

        If trailerState's state is + "complete", then: + +

          +
        1. Let headers be a new {{Headers}} object whose + header list is response's + trailer header list and whose guard is + "immutable". + +

        2. Resolve promise with headers. +

        + +
      5. +

        Otherwise, if trailerState's state is + "errored", then reject promise with + trailerState's error. + +

      6. +

        Otherwise (trailerState's state is + "pending"): + +

          +
        1. +

          Append the following steps to trailerState's + observers: + +

            +
          1. If trailerState's state is + "complete", then: + +

              +
            1. Let headers be a new {{Headers}} object whose + header list is response's + trailer header list and whose guard is + "immutable". + +

            2. Resolve promise with headers. +

            + +
          2. Otherwise, reject promise with + trailerState's error. +

          +
        + +
      7. Set this's trailers promise to promise. +

      + +
    2. Return this's trailers promise. +

    +
    +
    @@ -9741,6 +10014,9 @@ with a promise, request, responseObject, and an
  • If response's body is non-null and is readable, then error response's body with error. + +

  • Error a trailer state given response's + trailer state and error.