From 1f8331e9eb058c8ac71cbd8df48f065096171f51 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 16:41:56 +0100 Subject: [PATCH 1/6] Hide range header values on no-cors requests --- fetch.bs | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/fetch.bs b/fetch.bs index aac85636d..ee06029fc 100755 --- a/fetch.bs +++ b/fetch.bs @@ -618,6 +618,27 @@ are always combined when exposed to client-side JavaScript, implementations coul efficient representation, as long as they also support an associated data structure for `Set-Cookie` headers. +

A header list has an associated +hidden range value +(null or a header value). It is initially null. + +

This is for cases where a "no-cors" request needs to include a +`Range` header, but it can not be exposed via {{Headers}}. See add a range +header. + +

+

To get the range value +from a header list list, run these steps. They return null or a +header value. + +

    +
  1. If list contains `Range`, then return the + result of getting `Range` from list. + +

  2. Return list's hidden range value. +

+
+

To get a structured field value @@ -2446,8 +2467,8 @@ is to return the result of serializing a request origin with request

  • If last is given, then serialize and isomorphic encode it, and append the result to rangeValue. -

  • Append (`Range`, rangeValue) to - request's header list. +

  • Set request's header list's + hidden range value to rangeValue.

    A range header denotes an inclusive byte range. There a range header where @@ -5126,10 +5147,10 @@ steps:

  • If response's type is "opaque", internalResponse's status is a range status, - internalResponse's range-requested flag is set, and - request's header list does not contain - `Range`, then set response and internalResponse to a - network error. + internalResponse's range-requested flag is set, and the result of + getting the range value from request's + header list is null, then set response and + internalResponse to a network error.

    Traditionally, APIs accept a ranged response even if a range was not requested. This prevents @@ -5556,9 +5577,13 @@ returning a response directly, or allowing the request to proceed by returning n

  • Let type be blob's {{Blob/type}}. +

  • Let rangeHeader be the result of getting the range + value from request's header list. + +

  • -

    If request's header list - does not contain `Range`: +

    If rangeHeader is null:

    1. Let bodyWithType be the result of safely extracting @@ -5580,11 +5605,6 @@ returning a response directly, or allowing the request to proceed by returning n

      1. Set response's range-requested flag. -

      2. Let rangeHeader be the result of getting - `Range` from request's header list. - -

      3. Let rangeValue be the result of parsing a single range header value given rangeHeader and true. @@ -6251,6 +6271,12 @@ run these steps:

      +
    2. If httpRequest's header list's + hidden range value is non-null, then append + (`Range`, httpRequest's header list's + hidden range value) to httpRequest's + header list. +

    3. If httpRequest's header list contains `Range`, then append (`Accept-Encoding`, @@ -7999,6 +8025,9 @@ from a {{Headers}} object (headers), run these steps:

    4. Delete headerName from headers's header list.

    + +
  • Set headers's header list's + hidden range value to null.

    This is called when headers are modified by unprivileged code. From 7f0a0ebb4467554e433d6be37f98df3bb0e18ba5 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 16:54:12 +0100 Subject: [PATCH 2/6] Empty headers safely --- fetch.bs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/fetch.bs b/fetch.bs index ee06029fc..e542ecb09 100755 --- a/fetch.bs +++ b/fetch.bs @@ -8033,6 +8033,18 @@ from a {{Headers}} object (headers), run these steps:

    This is called when headers are modified by unprivileged code.

  • +
    +

    To empty a {{Headers}} object +(headers), run these steps: + +

      +
    1. Empty headers's header list. + +

    2. Set headers's header list's + hidden range value to null. +

    +
    +

    The new Headers(init) @@ -9105,7 +9117,7 @@ constructor steps are:

  • If init["{{RequestInit/headers}}"] exists, then set headers to init["{{RequestInit/headers}}"]. -

  • Empty this's headers's header list. +

  • Empty this's headers.

  • If headers is a {{Headers}} object, then for each header of its header list, append From 77b5efbf03913efaa7ca68384aad331b917174b8 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 17:07:45 +0100 Subject: [PATCH 3/6] Clean up use of privileged headers --- fetch.bs | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/fetch.bs b/fetch.bs index e542ecb09..f6329c4bb 100755 --- a/fetch.bs +++ b/fetch.bs @@ -622,9 +622,17 @@ efficient representation, as long as they also support an associated data struct hidden range value (null or a header value). It is initially null. -

    This is for cases where a "no-cors" request needs to include a -`Range` header, but it can not be exposed via {{Headers}}. See add a range -header. +

    +

    This is for cases where a "no-cors" request needs to include a + `Range` header, but it can not be exposed via {{Headers}}. It can be set by privileged + APIs, and will be preserved if its associated request object is copied, but will be removed if the + request is modified by unprivileged APIs. + +

    `Range` headers are commonly used by downloads + and media fetches. + +

    A helper is provided to add a range header to a particular request. +

    To get the range value @@ -1161,23 +1169,6 @@ following is true:

    A CORS non-wildcard request-header name is a header name that is a byte-case-insensitive match for `Authorization`. -

    A privileged no-CORS request-header name is a header name that is -a byte-case-insensitive match for one of - -

      -
    • `Range`. -
    - -
    -

    These are headers that can be set by privileged APIs, and will be preserved if their associated - request object is copied, but will be removed if the request is modified by unprivileged APIs. - -

    `Range` headers are commonly used by downloads - and media fetches. - -

    A helper is provided to add a range header to a particular request. -

    -

    A CORS-safelisted response-header name, given a list of header names list, is a header name that is a byte-case-insensitive match for one of @@ -8015,20 +8006,8 @@ value (for {{Headers/delete()}}) that always succeeds in CORS-safelisted requ

    To remove privileged no-CORS request-headers -from a {{Headers}} object (headers), run these steps: - -

      -
    1. For each headerName of - privileged no-CORS request-header names: - -

        -
      1. Delete headerName from headers's - header list. -

      - -
    2. Set headers's header list's - hidden range value to null. -

    +from a {{Headers}} object (headers), set headers's +header list's hidden range value to null.

    This is called when headers are modified by unprivileged code.

    @@ -8074,7 +8053,7 @@ method steps are to append (name, value
  • If this's guard is "request-no-cors", name is not a no-CORS-safelisted request-header name, and name is not a - privileged no-CORS request-header name, then return. + byte-case-insensitive match for `Range`, then return.

  • If this's header list does not contain name, then return. From fda85bf5946f34ea8a3ba46149aabb41a01430b3 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 17:13:22 +0100 Subject: [PATCH 4/6] Move empty to header list --- fetch.bs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fetch.bs b/fetch.bs index f6329c4bb..7f2dd2760 100755 --- a/fetch.bs +++ b/fetch.bs @@ -910,6 +910,17 @@ directly. Use get, decode, and split instead. byte-case-insensitive match for name from list.

  • +
    +

    To empty a +header list list: + +

      +
    1. Empty list. + +

    2. Set list's hidden range value to null. +

    +
    +

    To set a header (name, value) in a header list list: @@ -8012,18 +8023,6 @@ from a {{Headers}} object (headers), set headers's

    This is called when headers are modified by unprivileged code.

    -
    -

    To empty a {{Headers}} object -(headers), run these steps: - -

      -
    1. Empty headers's header list. - -

    2. Set headers's header list's - hidden range value to null. -

    -
    -

    The new Headers(init) @@ -9096,7 +9095,8 @@ constructor steps are:

  • If init["{{RequestInit/headers}}"] exists, then set headers to init["{{RequestInit/headers}}"]. -

  • Empty this's headers. +

  • Empty this's headers's + header list.

  • If headers is a {{Headers}} object, then for each header of its header list, append From f28bbecacfa9acef3ac32a7d4c5da6353cf4e0f9 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 17:22:26 +0100 Subject: [PATCH 5/6] Don't special case deleting range headers --- fetch.bs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fetch.bs b/fetch.bs index 7f2dd2760..a64c39466 100755 --- a/fetch.bs +++ b/fetch.bs @@ -8051,8 +8051,7 @@ method steps are to append (name, value

    Passing a dummy header value ought not to have any negative repercussions.

  • If this's guard is "request-no-cors", name - is not a no-CORS-safelisted request-header name, and name is not a - byte-case-insensitive match for `Range`, then return. + is not a no-CORS-safelisted request-header name, then return.

  • If this's header list does not contain name, then return. From 20d2ac72b9ceb1c7fb461da960b41f536f7ab23b Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 23 Jun 2026 17:22:39 +0100 Subject: [PATCH 6/6] Correctly detect empty headers --- fetch.bs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fetch.bs b/fetch.bs index a64c39466..b93223a09 100755 --- a/fetch.bs +++ b/fetch.bs @@ -921,6 +921,11 @@ directly. Use get, decode, and split instead.

  • +

    A header list list +is empty +if list is empty and list's +hidden range value is null. +

    To set a header (name, value) in a header list list: @@ -4733,7 +4738,7 @@ the response. [[!HTTP-CACHING]]

  • request's method is `GET`

  • request's unsafe-request flag is not set or - request's header list is empty + request's header list is empty

    then: