Fetch

Living Standard — Last Updated

Participate:
GitHub whatwg/fetch (new issue, open issues)
Chat on Matrix
Commits:
GitHub whatwg/fetch/commits
Snapshot as of this commit
@fetchstandard
Tests:
web-platform-tests fetch/ (ongoing work)
Translations (non-normative):
日本語
简体中文
한국어

Abstract

The Fetch standard defines requests, responses, and the process that binds them: fetching.

Goals

The goal is to unify fetching across the web platform and provide consistent handling of everything that involves, including:

To do so it also supersedes the HTTP `Origin` header semantics originally defined in The Web Origin Concept. [ORIGIN]

1. Preface

At a high level, fetching a resource is a fairly simple operation. A request goes in, a response comes out. The details of that operation are however quite involved and used to not be written down carefully and differ from one API to the next.

Numerous APIs provide the ability to fetch a resource, e.g. HTML’s img and script element, CSS' cursor and list-style-image, the navigator.sendBeacon() and self.importScripts() JavaScript APIs. The Fetch Standard provides a unified architecture for these features so they are all consistent when it comes to various aspects of fetching, such as redirects and the CORS protocol.

The Fetch Standard also defines the fetch() JavaScript API, which exposes most of the networking functionality at a fairly low level of abstraction.

2. Infrastructure

This specification depends on the Infra Standard. [INFRA]

This specification uses terminology from ABNF, Encoding, HTML, HTTP, MIME Sniffing, Streams, URL, Web IDL, WebSockets, and WebTransport. [ABNF] [ENCODING] [HTML] [HTTP] [MIMESNIFF] [STREAMS] [URL] [WEBIDL] [WEBSOCKETS] [WEBTRANSPORT]

ABNF means ABNF as augmented by HTTP (in particular the addition of #) and RFC 7405. [RFC7405]


Credentials are HTTP cookies, TLS client certificates, and authentication entries (for HTTP authentication). [COOKIES] [TLS] [HTTP]


A fetch params is a struct used as a bookkeeping detail by the fetch algorithm. It has the following items:

request
A request.
process request body chunk length (default null)
process request end-of-body (default null)
process early hints response (default null)
process response (default null)
process response end-of-body (default null)
process response consume body (default null)
Null or an algorithm.
task destination (default null)
Null, a global object, or a parallel queue.
cross-origin isolated capability (default false)
A boolean.
controller (default a new fetch controller)
A fetch controller.
timing info
A fetch timing info.
preloaded response candidate (default null)
Null, "pending", or a response.

A fetch controller is a struct used to enable callers of fetch to perform certain operations on it after it has started. It has the following items:

state (default "ongoing")
"ongoing", "terminated", or "aborted"
full timing info (default null)
Null or a fetch timing info.
report timing steps (default null)
Null or an algorithm accepting a global object.
serialized abort reason (default null)
Null or a Record (result of StructuredSerialize).
next manual redirect steps (default null)
Null or an algorithm accepting nothing.

To report timing for a fetch controller controller given a global object global:

  1. Assert: controller’s report timing steps is non-null.

  2. Call controller’s report timing steps with global.

To process the next manual redirect for a fetch controller controller:

  1. Assert: controller’s next manual redirect steps is non-null.

  2. Call controller’s next manual redirect steps.

To extract full timing info given a fetch controller controller:

  1. Assert: controller’s full timing info is non-null.

  2. Return controller’s full timing info.

To abort a fetch controller controller with an optional error:

  1. Set controller’s state to "aborted".

  2. Let fallbackError be an "AbortError" DOMException.

  3. Set error to fallbackError if it is not given.

  4. Let serializedError be StructuredSerialize(error). If that threw an exception, catch it, and let serializedError be StructuredSerialize(fallbackError).

  5. Set controller’s serialized abort reason to serializedError.

To deserialize a serialized abort reason, given null or a Record abortReason and a realm realm:

  1. Let fallbackError be an "AbortError" DOMException.

  2. Let deserializedError be fallbackError.

  3. If abortReason is non-null, then set deserializedError to StructuredDeserialize(abortReason, realm). If that threw an exception or returned undefined, then set deserializedError to fallbackError.

  4. Return deserializedError.

To terminate a fetch controller controller, set controller’s state to "terminated".

A fetch params fetchParams is aborted if its controller’s state is "aborted".

A fetch params fetchParams is canceled if its controller’s state is "aborted" or "terminated".

A fetch timing info is a struct used to maintain timing information needed by Resource Timing and Navigation Timing. It has the following items: [RESOURCE-TIMING] [NAVIGATION-TIMING]

start time (default 0)
redirect start time (default 0)
redirect end time (default 0)
post-redirect start time (default 0)
final service worker start time (default 0)
final network-request start time (default 0)
first interim network-response start time (default 0)
final network-response start time (default 0)
end time (default 0)
A DOMHighResTimeStamp.
final connection timing info (default null)
Null or a connection timing info.
service worker timing info (default null)
Null or a service worker timing info.
server-timing headers (default « »)
A list of strings.
render-blocking (default false)
A boolean.

A response body info is a struct used to maintain information needed by Resource Timing and Navigation Timing. It has the following items: [RESOURCE-TIMING] [NAVIGATION-TIMING]

encoded size (default 0)
decoded size (default 0)
A number.
content type (default the empty string)
An ASCII string.
content encoding (default the empty string)
An ASCII string.

To create an opaque timing info, given a fetch timing info timingInfo, return a new fetch timing info whose start time and post-redirect start time are timingInfo’s start time.

To queue a fetch task, given an algorithm algorithm, a global object or a parallel queue taskDestination, run these steps:

  1. If taskDestination is a parallel queue, then enqueue algorithm to taskDestination.

  2. Otherwise, queue a global task on the networking task source with taskDestination and algorithm.

To check if the environment settings object environment is offline:


To serialize an integer, represent it as a string of the shortest possible decimal number.

This will be replaced by a more descriptive algorithm in Infra. See infra/201.

2.1. URL

A local scheme is "about", "blob", or "data".

A URL is local if its scheme is a local scheme.

This definition is also used by Referrer Policy. [REFERRER]

An HTTP(S) scheme is "http" or "https".

A fetch scheme is "about", "blob", "data", "file", or an HTTP(S) scheme.

HTTP(S) scheme and fetch scheme are also used by HTML. [HTML]

2.2. HTTP

While fetching encompasses more than just HTTP, it borrows a number of concepts from HTTP and applies these to resources obtained via other means (e.g., data URLs).

An HTTP tab or space is U+0009 TAB or U+0020 SPACE.

HTTP whitespace is U+000A LF, U+000D CR, or an HTTP tab or space.

HTTP whitespace is only useful for specific constructs that are reused outside the context of HTTP headers (e.g., MIME types). For HTTP header values, using HTTP tab or space is preferred, and outside that context ASCII whitespace is preferred. Unlike ASCII whitespace this excludes U+000C FF.

An HTTP newline byte is 0x0A (LF) or 0x0D (CR).

An HTTP tab or space byte is 0x09 (HT) or 0x20 (SP).

An HTTP whitespace byte is an HTTP newline byte or HTTP tab or space byte.

To collect an HTTP quoted string from a string input, given a position variable position and an optional boolean extract-value (default false):

  1. Let positionStart be position.

  2. Let value be the empty string.

  3. Assert: the code point at position within input is U+0022 (").

  4. Advance position by 1.

  5. While true:

    1. Append the result of collecting a sequence of code points that are not U+0022 (") or U+005C (\) from input, given position, to value.

    2. If position is past the end of input, then break.

    3. Let quoteOrBackslash be the code point at position within input.

    4. Advance position by 1.

    5. If quoteOrBackslash is U+005C (\), then:

      1. If position is past the end of input, then append U+005C (\) to value and break.

      2. Append the code point at position within input to value.

      3. Advance position by 1.

    6. Otherwise:

      1. Assert: quoteOrBackslash is U+0022 (").

      2. Break.

  6. If extract-value is true, then return value.

  7. Return the code points from positionStart to position, inclusive, within input.

Input Output Output with extract-value set to true Final position variable value
""\" ""\" "\" 2
""Hello" World" ""Hello"" "Hello" 7
""Hello \\ World\""" ""Hello \\ World\""" "Hello \ World"" 18

The position variable always starts at 0 in these examples.

2.2.1. Methods

A method is a byte sequence that matches the method token production.

A CORS-safelisted method is a method that is `GET`, `HEAD`, or `POST`.

A forbidden method is a method that is a byte-case-insensitive match for `CONNECT`, `TRACE`, or `TRACK`. [HTTPVERBSEC1], [HTTPVERBSEC2], [HTTPVERBSEC3]

To normalize a method, if it is a byte-case-insensitive match for `DELETE`, `GET`, `HEAD`, `OPTIONS`, `POST`, or `PUT`, byte-uppercase it.

Normalization is done for backwards compatibility and consistency across APIs as methods are actually "case-sensitive".

Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.

There are no restrictions on methods. `CHICKEN` is perfectly acceptable (and not a misspelling of `CHECKIN`). Other than those that are normalized there are no casing restrictions either. `Egg` or `eGg` would be fine, though uppercase is encouraged for consistency.

2.2.2. Headers

HTTP generally refers to a header as a "field" or "header field". The web platform uses the more colloquial term "header". [HTTP]

A header list is a list of zero or more headers. It is initially « ».

A header list is essentially a specialized multimap: an ordered list of key-value pairs with potentially duplicate keys. Since headers other than `Set-Cookie` are always combined when exposed to client-side JavaScript, implementations could choose a more efficient representation, as long as they also support an associated data structure for `Set-Cookie` headers.

To get a structured field value given a header name name and a string type from a header list list, run these steps. They return null or a structured field value.

  1. Assert: type is one of "dictionary", "list", or "item".

  2. Let value be the result of getting name from list.

  3. If value is null, then return null.

  4. Let result be the result of parsing structured fields with input_string set to value and header_type set to type.

  5. If parsing failed, then return null.

  6. Return result.

Get a structured field value intentionally does not distinguish between a header not being present and its value failing to parse as a structured field value. This ensures uniform processing across the web platform.

To set a structured field value given a tuple (header name name, structured field value structuredValue), in a header list list:

  1. Let serializedValue be the result of executing the serializing structured fields algorithm on structuredValue.

  2. Set (name, serializedValue) in list.

Structured field values are defined as objects which HTTP can (eventually) serialize in interesting and efficient ways. For the moment, Fetch only supports header values as byte sequences, which means that these objects can be set in header lists only via serialization, and they can be obtained from header lists only by parsing. In the future the fact that they are objects might be preserved end-to-end. [RFC9651]


A header list list contains a header name name if list contains a header whose name is a byte-case-insensitive match for name.

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

  1. If list does not contain name, then return null.

  2. Return the values of all headers in list whose name is a byte-case-insensitive match for name, separated from each other by 0x2C 0x20, in order.

To get, decode, and split a header name name from header list list, run these steps. They return null or a list of strings.

  1. Let value be the result of getting name from list.

  2. If value is null, then return null.

  3. Return the result of getting, decoding, and splitting value.

This is how get, decode, and split functions in practice with `A` as the name argument:

Headers (as on the network) Output
A: nosniff,
« "nosniff", "" »
A: nosniff
B: sniff
A:
A:
B: sniff
« "" »
B: sniff
null
A: text/html;", x/x
« "text/html;", x/x" »
A: text/html;"
A: x/x
A: x/x;test="hi",y/y
« "x/x;test="hi"", "y/y" »
A: x/x;test="hi"
C: **bingo**
A: y/y
A: x / x,,,1
« "x / x", "", "", "1" »
A: x / x
A: ,
A: 1
A: "1,2", 3
« ""1,2"", "3" »
A: "1,2"
D: 4
A: 3

To get, decode, and split a header value value, run these steps. They return a list of strings.

  1. Let input be the result of isomorphic decoding value.

  2. Let position be a position variable for input, initially pointing at the start of input.

  3. Let values be a list of strings, initially « ».

  4. Let temporaryValue be the empty string.

  5. While true:

    1. Append the result of collecting a sequence of code points that are not U+0022 (") or U+002C (,) from input, given position, to temporaryValue.

      The result might be the empty string.

    2. If position is not past the end of input and the code point at position within input is U+0022 ("):

      1. Append the result of collecting an HTTP quoted string from input, given position, to temporaryValue.

      2. If position is not past the end of input, then continue.
    3. Remove all HTTP tab or space from the start and end of temporaryValue.

    4. Append temporaryValue to values.

    5. Set temporaryValue to the empty string.

    6. If position is past the end of input, then return values.

    7. Assert: the code point at position within input is U+002C (,).

    8. Advance position by 1.

Except for blessed call sites, the algorithm directly above is not to be invoked directly. Use get, decode, and split instead.

To append a header (name, value) to a header list list:

  1. If list contains name, then set name to the first such header’s name.

    This reuses the casing of the name of the header already in list, if any. If there are multiple matched headers their names will all be identical.

  2. Append (name, value) to list.

To delete a header name name from a header list list, remove all headers whose name is a byte-case-insensitive match for name from list.

To set a header (name, value) in a header list list:

  1. If list contains name, then set the value of the first such header to value and remove the others.

  2. Otherwise, append (name, value) to list.

To combine a header (name, value) in a header list list:

  1. If list contains name, then set the value of the first such header to its value, followed by 0x2C 0x20, followed by value.

  2. Otherwise, append (name, value) to list.

Combine is used by XMLHttpRequest and the WebSocket protocol handshake.

To convert header names to a sorted-lowercase set, given a list of names headerNames, run these steps. They return an ordered set of header names.

  1. Let headerNamesSet be a new ordered set.

  2. For each name of headerNames, append the result of byte-lowercasing name to headerNamesSet.

  3. Return the result of sorting headerNamesSet in ascending order with byte less than.

To sort and combine a header list list, run these steps. They return a header list.

  1. Let headers be a header list.

  2. Let names be the result of convert header names to a sorted-lowercase set with all the names of the headers in list.

  3. For each name of names:

    1. If name is `set-cookie`, then:

      1. Let values be a list of all values of headers in list whose name is a byte-case-insensitive match for name, in order.

      2. For each value of values:

        1. Append (name, value) to headers.

    2. Otherwise:

      1. Let value be the result of getting name from list.

      2. Assert: value is non-null.

      3. Append (name, value) to headers.

  4. Return headers.


A header is a tuple that consists of a name (a header name) and value (a header value).

A header name is a byte sequence that matches the field-name token production.

A header value is a byte sequence that matches the following conditions:

The definition of header value is not defined in terms of the field-value token production as it is not compatible with deployed content.

To normalize a byte sequence potentialValue, remove any leading and trailing HTTP whitespace bytes from potentialValue.


To determine whether a header (name, value) is a CORS-safelisted request-header, run these steps:

  1. If value’s length is greater than 128, then return false.

  2. Byte-lowercase name and switch on the result:

    `accept`

    If value contains a CORS-unsafe request-header byte, then return false.

    `accept-language`
    `content-language`

    If value contains a byte that is not in the range 0x30 (0) to 0x39 (9), inclusive, is not in the range 0x41 (A) to 0x5A (Z), inclusive, is not in the range 0x61 (a) to 0x7A (z), inclusive, and is not 0x20 (SP), 0x2A (*), 0x2C (,), 0x2D (-), 0x2E (.), 0x3B (;), or 0x3D (=), then return false.

    `content-type`
    1. If value contains a CORS-unsafe request-header byte, then return false.

    2. Let mimeType be the result of parsing the result of isomorphic decoding value.

    3. If mimeType is failure, then return false.

    4. If mimeType’s essence is not "application/x-www-form-urlencoded", "multipart/form-data", or "text/plain", then return false.

    This intentionally does not use extract a MIME type as that algorithm is rather forgiving and servers are not expected to implement it.

    If extract a MIME type were used the following request would not result in a CORS preflight and a naïve parser on the server might treat the request body as JSON:

    fetch("https://victim.example/naïve-endpoint", {
      method: "POST",
      headers: [
        ["Content-Type", "application/json"],
        ["Content-Type", "text/plain"]
      ],
      credentials: "include",
      body: JSON.stringify(exerciseForTheReader)
    });
    
    `range`
    1. Let rangeValue be the result of parsing a single range header value given value and false.

    2. If rangeValue is failure, then return false.

    3. If rangeValue[0] is null, then return false.

      As web browsers have historically not emitted ranges such as `bytes=-500` this algorithm does not safelist them.

    Otherwise

    Return false.

  3. Return true.

There are limited exceptions to the `Content-Type` header safelist, as documented in CORS protocol exceptions.

A CORS-unsafe request-header byte is a byte byte for which one of the following is true:

The CORS-unsafe request-header names, given a header list headers, are determined as follows:

  1. Let unsafeNames be a new list.

  2. Let potentiallyUnsafeNames be a new list.

  3. Let safelistValueSize be 0.

  4. For each header of headers:

    1. If header is not a CORS-safelisted request-header, then append header’s name to unsafeNames.

    2. Otherwise, append header’s name to potentiallyUnsafeNames and increase safelistValueSize by header’s value’s length.

  5. If safelistValueSize is greater than 1024, then for each name of potentiallyUnsafeNames, append name to unsafeNames.

  6. Return the result of convert header names to a sorted-lowercase set with unsafeNames.

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

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

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

To determine whether a header (name, value) is a no-CORS-safelisted request-header, run these steps:

  1. If name is not a no-CORS-safelisted request-header name, then return false.

  2. Return whether (name, value) is a CORS-safelisted request-header.

A header (name, value) is forbidden request-header if these steps return true:

  1. If name is a byte-case-insensitive match for one of:

    then return true.

  2. If name when byte-lowercased starts with `proxy-` or `sec-`, then return true.

  3. If name is a byte-case-insensitive match for one of:

    • `X-HTTP-Method`
    • `X-HTTP-Method-Override`
    • `X-Method-Override`

    then:

    1. Let parsedValues be the result of getting, decoding, and splitting value.

    2. For each method of parsedValues: if the isomorphic encoding of method is a forbidden method, then return true.

  4. Return false.

These are forbidden so the user agent remains in full control over them.

Header names starting with `Sec-` are reserved to allow new headers to be minted that are safe from APIs using fetch that allow control over headers by developers, such as XMLHttpRequest. [XHR]

The `Set-Cookie` header is semantically a response header, so it is not useful on requests. Because `Set-Cookie` headers cannot be combined, they require more complex handling in the Headers object. It is forbidden here to avoid leaking this complexity into requests.

A forbidden response-header name is a header name that is a byte-case-insensitive match for one of:

A request-body-header name is a header name that is a byte-case-insensitive match for one of:


To extract header values given a header header, run these steps:

  1. If parsing header’s value, per the ABNF for header’s name, fails, then return failure.

  2. Return one or more values resulting from parsing header’s value, per the ABNF for header’s name.

To extract header list values given a header name name and a header list list, run these steps:

  1. If list does not contain name, then return null.

  2. If the ABNF for name allows a single header and list contains more than one, then return failure.

    If different error handling is needed, extract the desired header first.

  3. Let values be an empty list.

  4. For each header header list contains whose name is name:

    1. Let extract be the result of extracting header values from header.

    2. If extract is failure, then return failure.

    3. Append each value in extract, in order, to values.

  5. Return values.

To build a content range given an integer rangeStart, an integer rangeEnd, and an integer fullLength, run these steps:

  1. Let contentRange be `bytes `.

  2. Append rangeStart, serialized and isomorphic encoded, to contentRange.

  3. Append 0x2D (-) to contentRange.

  4. Append rangeEnd, serialized and isomorphic encoded to contentRange.

  5. Append 0x2F (/) to contentRange.

  6. Append fullLength, serialized and isomorphic encoded to contentRange.

  7. Return contentRange.

To parse a single range header value from a byte sequence value and a boolean allowWhitespace, run these steps:

  1. Let data be the isomorphic decoding of value.

  2. If data does not start with "bytes", then return failure.

  3. Let position be a position variable for data, initially pointing at the 5th code point of data.

  4. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from data given position.

  5. If the code point at position within data is not U+003D (=), then return failure.

  6. Advance position by 1.

  7. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from data given position.

  8. Let rangeStart be the result of collecting a sequence of code points that are ASCII digits, from data given position.

  9. Let rangeStartValue be rangeStart, interpreted as decimal number, if rangeStart is not the empty string; otherwise null.

  10. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from data given position.

  11. If the code point at position within data is not U+002D (-), then return failure.

  12. Advance position by 1.

  13. If allowWhitespace is true, collect a sequence of code points that are HTTP tab or space, from data given position.

  14. Let rangeEnd be the result of collecting a sequence of code points that are ASCII digits, from data given position.

  15. Let rangeEndValue be rangeEnd, interpreted as decimal number, if rangeEnd is not the empty string; otherwise null.

  16. If position is not past the end of data, then return failure.

  17. If rangeEndValue and rangeStartValue are null, then return failure.

  18. If rangeStartValue and rangeEndValue are numbers, and rangeStartValue is greater than rangeEndValue, then return failure.

  19. Return (rangeStartValue, rangeEndValue).

    The range end or start can be omitted, e.g., `bytes=0-` or `bytes=-500` are valid ranges.

Parse a single range header value succeeds for a subset of allowed range header values, but it is the most common form used by user agents when requesting media or resuming downloads. This format of range header value can be set using add a range header.


A default `User-Agent` value is an implementation-defined header value for the `User-Agent` header.

For unfortunate web compatibility reasons, web browsers are strongly encouraged to have this value start with `Mozilla/5.0 (` and be generally modeled after other web browsers.

To get the environment settings object environment’s environment default `User-Agent` value:

  1. Let userAgent be the WebDriver BiDi emulated User-Agent for environment.

  2. If userAgent is non-null, then return userAgent, isomorphic encoded.

  3. Return the default `User-Agent` value.

The document `Accept` header value is `text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`.

2.2.3. Statuses

A status is an integer in the range 0 to 999, inclusive.

Various edge cases in mapping HTTP/1’s status-code to this concept are worked on in issue #1156.

A null body status is a status that is 101, 103, 204, 205, or 304.

An ok status is a status in the range 200 to 299, inclusive.

A redirect status is a status that is 301, 302, 303, 307, or 308.

2.2.4. Bodies

A body consists of:

To clone a body body, run these steps:

  1. Let « out1, out2 » be the result of teeing body’s stream.

  2. Set body’s stream to out1.

  3. Return a body whose stream is out2 and other members are copied from body.

To get a byte sequence bytes as a body, return the body of the result of safely extracting bytes.


To incrementally read a body body, given an algorithm processBodyChunk, an algorithm processEndOfBody, an algorithm processBodyError, and an optional null, parallel queue, or global object taskDestination (default null), run these steps. processBodyChunk must be an algorithm accepting a byte sequence. processEndOfBody must be an algorithm accepting no arguments. processBodyError must be an algorithm accepting an exception.

  1. If taskDestination is null, then set taskDestination to the result of starting a new parallel queue.

  2. Let reader be the result of getting a reader for body’s stream.

    This operation will not throw an exception.

  3. Perform the incrementally-read loop given reader, taskDestination, processBodyChunk, processEndOfBody, and processBodyError.

To perform the incrementally-read loop, given a ReadableStreamDefaultReader object reader, parallel queue or global object taskDestination, algorithm processBodyChunk, algorithm processEndOfBody, and algorithm processBodyError:

  1. Let readRequest be the following read request:

    chunk steps, given chunk
    1. Let continueAlgorithm be null.

    2. If chunk is not a Uint8Array object, then set continueAlgorithm to this step: run processBodyError given a TypeError.

    3. Otherwise:

      1. Let bytes be a copy of chunk.

        Implementations are strongly encouraged to use an implementation strategy that avoids this copy where possible.

      2. Set continueAlgorithm to these steps:

        1. Run processBodyChunk given bytes.

        2. Perform the incrementally-read loop given reader, taskDestination, processBodyChunk, processEndOfBody, and processBodyError.

    4. Queue a fetch task given continueAlgorithm and taskDestination.

    close steps
    1. Queue a fetch task given processEndOfBody and taskDestination.

    error steps, given e
    1. Queue a fetch task to run processBodyError given e, with taskDestination.

  2. Read a chunk from reader given readRequest.

To fully read a body body, given an algorithm processBody, an algorithm processBodyError, and an optional null, parallel queue, or global object taskDestination (default null), run these steps. processBody must be an algorithm accepting a byte sequence. processBodyError must be an algorithm optionally accepting an exception.

  1. If taskDestination is null, then set taskDestination to the result of starting a new parallel queue.

  2. Let successSteps given a byte sequence bytes be to queue a fetch task to run processBody given bytes, with taskDestination.

  3. Let errorSteps optionally given an exception exception be to queue a fetch task to run processBodyError given exception, with taskDestination.

  4. Let reader be the result of getting a reader for body’s stream. If that threw an exception, then run errorSteps with that exception and return.

  5. Read all bytes from reader, given successSteps and errorSteps.


A body with type is a tuple that consists of a body (a body) and a type (a header value or null).


To handle content codings given codings and bytes, run these steps:

  1. If codings are not supported, then return bytes.

  2. Return the result of decoding bytes with codings as explained in HTTP, if decoding does not result in an error, and failure otherwise. [HTTP]

2.2.5. Requests

This section documents how requests work in detail. To get started, see Setting up a request.

The input to fetch is a request.

A request has an associated method (a method). Unless stated otherwise it is `GET`.

This can be updated during redirects to `GET` as described in HTTP fetch.

A request has an associated URL (a URL).

Implementations are encouraged to make this a pointer to the first URL in request’s URL list. It is provided as a distinct field solely for the convenience of other standards hooking into Fetch.

A request has an associated local-URLs-only flag. Unless stated otherwise it is unset.

A request has an associated header list (a header list). Unless stated otherwise it is « ».

A request has an associated unsafe-request flag. Unless stated otherwise it is unset.

The unsafe-request flag is set by APIs such as fetch() and XMLHttpRequest to ensure a CORS-preflight fetch is done based on the supplied method and header list. It does not free an API from outlawing forbidden methods and forbidden request-headers.

A request has an associated body (null, a byte sequence, or a body). Unless stated otherwise it is null.

A byte sequence will be safely extracted into a body early on in fetch. As part of HTTP fetch it is possible for this field to be set to null due to certain redirects.


A request has an associated client (null or an environment settings object).

A request has an associated reserved client (null, an environment, or an environment settings object). Unless stated otherwise it is null.

This is only used by navigation requests and worker requests, but not service worker requests. It references an environment for a navigation request and an environment settings object for a worker request.

A request has an associated replaces client id (a string). Unless stated otherwise it is the empty string.

This is only used by navigation requests. It is the id of the target browsing context’s active document’s environment settings object.

A request has an associated traversable for user prompts, that is "no-traversable", "client", or a traversable navigable. Unless stated otherwise it is "client".

This is used to determine whether and where to show necessary UI for the request, such as authentication prompts or client certificate dialogs.

"no-traversable"
No UI is shown; usually the request fails with a network error.
"client"
This value will automatically be changed to either "no-traversable" or to a traversable navigable derived from the request’s client during fetching. This provides a convenient way for standards to not have to explicitly set a request’s traversable for user prompts.
a traversable navigable
The UI shown will be associated with the browser interface elements that are displaying that traversable navigable.

When displaying a user interface associated with a request in that request’s traversable for user prompts, the user agent should update the address bar to display something derived from the request’s current URL (and not, e.g., leave it at its previous value, derived from the URL of the request’s initiator). Additionally, the user agent should avoid displaying content from the request’s initiator in the traversable for user prompts, especially in the case of cross-origin requests. Displaying a blank page behind such prompts is a good way to fulfill these requirements. Failing to follow these guidelines can confuse users as to which origin is responsible for the prompt.

A request has an associated boolean keepalive. Unless stated otherwise it is false.

This can be used to allow the request to outlive the environment settings object, e.g., navigator.sendBeacon() and the HTML img element use this. Requests with this set to true are subject to additional processing requirements.

A request has an associated initiator type, which is null, "audio", "beacon", "body", "css", "early-hints", "embed", "fetch", "font", "frame", "iframe", "image", "img", "input", "link", "object", "ping", "script", "track", "video", "xmlhttprequest", or "other". Unless stated otherwise it is null. [RESOURCE-TIMING]

A request has an associated service-workers mode, that is "all" or "none". Unless stated otherwise it is "all".

This determines which service workers will receive a fetch event for this fetch.

"all"
Relevant service workers will get a fetch event for this fetch.
"none"
No service workers will get events for this fetch.

A request has an associated initiator, which is the empty string, "download", "imageset", "manifest", "prefetch", "prerender", or "xslt". Unless stated otherwise it is the empty string.

A request’s initiator is not particularly granular for the time being as other specifications do not require it to be. It is primarily a specification device to assist defining CSP and Mixed Content. It is not exposed to JavaScript. [CSP] [MIX]

A destination type is one of: the empty string, "audio", "audioworklet", "document", "embed", "font", "frame", "iframe", "image", "json", "manifest", "object", "paintworklet", "report", "script", "serviceworker", "sharedworker", "style", "track", "video", "webidentity", "worker", or "xslt".

A request has an associated destination, which is destination type. Unless stated otherwise it is the empty string.

These are reflected on RequestDestination except for "serviceworker" and "webidentity" as fetches with those destinations skip service workers.

A request’s destination is script-like if it is "audioworklet", "paintworklet", "script", "serviceworker", "sharedworker", or "worker".

Algorithms that use script-like should also consider "xslt" as that too can cause script execution. It is not included in the list as it is not always relevant and might require different behavior.

The following table illustrates the relationship between a request’s initiator, destination, CSP directives, and features. It is not exhaustive with respect to features. Features need to have the relevant values defined in their respective standards.

Initiator Destination CSP directive Features
"" "report" CSP, NEL reports.
"document" HTML’s navigate algorithm (top-level only).
"frame" child-src HTML’s <frame>
"iframe" child-src HTML’s <iframe>
"" connect-src navigator.sendBeacon(), EventSource, HTML’s <a ping=""> and <area ping="">, fetch(), fetchLater(), XMLHttpRequest, WebSocket, WebTransport, Cache API
"object" object-src HTML’s <object>
"embed" object-src HTML’s <embed>
"audio" media-src HTML’s <audio>
"font" font-src CSS' @font-face
"image" img-src HTML’s <img src>, /favicon.ico resource, SVG’s <image>, CSS' background-image, CSS' cursor, CSS' list-style-image, …
"audioworklet" script-src audioWorklet.addModule()
"paintworklet" script-src CSS.paintWorklet.addModule()
"script" script-src HTML’s <script>, importScripts()
"serviceworker" child-src, script-src, worker-src navigator.serviceWorker.register()
"sharedworker" child-src, script-src, worker-src SharedWorker
"webidentity" connect-src Federated Credential Management requests
"worker" child-src, script-src, worker-src Worker
"json" connect-src import "..." with { type: "json" }
"style" style-src HTML’s <link rel=stylesheet>, CSS' @import, import "..." with { type: "css" }
"track" media-src HTML’s <track>
"video" media-src HTML’s <video> element
"download" "" HTML’s download="", "Save Link As…" UI
"imageset" "image" img-src HTML’s <img srcset> and <picture>
"manifest" "manifest" manifest-src HTML’s <link rel=manifest>
"prefetch" "" default-src (no specific directive) HTML’s <link rel=prefetch>
"prerender" HTML’s <link rel=prerender>
"xslt" "xslt" script-src <?xml-stylesheet>

CSP’s form-action needs to be a hook directly in HTML’s navigate or form submission algorithm.

CSP will also need to check request’s client’s global object’s associated Document’s ancestor navigables for various CSP directives.


A request has an associated priority, which is "high", "low", or "auto". Unless stated otherwise it is "auto".

A request has an associated internal priority (null or an implementation-defined object). Unless otherwise stated it is null.

A request has an associated origin, which is "client" or an origin. Unless stated otherwise it is "client".

"client" is changed to an origin during fetching. It provides a convenient way for standards to not have to set request’s origin.

A request has an associated top-level navigation initiator origin, which is an origin or null. Unless stated otherwise it is null.

A request has an associated policy container, which is "client" or a policy container. Unless stated otherwise it is "client".

"client" is changed to a policy container during fetching. It provides a convenient way for standards to not have to set request’s policy container.

A request has an associated referrer, which is "no-referrer", "client", or a URL. Unless stated otherwise it is "client".

"client" is changed to "no-referrer" or a URL during fetching. It provides a convenient way for standards to not have to set request’s referrer.

A request has an associated referrer policy, which is a referrer policy. Unless stated otherwise it is the empty string. [REFERRER]

This can be used to override the referrer policy to be used for this request.

A request has an associated mode, which is "same-origin", "cors", "no-cors", "navigate", "websocket", or "webtransport". Unless stated otherwise, it is "no-cors".

"same-origin"
Used to ensure requests are made to same-origin URLs. Fetch will return a network error if the request is not made to a same-origin URL.
"cors"
For requests whose response tainting gets set to "cors", makes the request a CORS request — in which case, fetch will return a network error if the requested resource does not understand the CORS protocol, or if the requested resource is one that intentionally does not participate in the CORS protocol.
"no-cors"
Restricts requests to using CORS-safelisted methods and CORS-safelisted request-headers. Upon success, fetch will return an opaque filtered response.
"navigate"
This is a special mode used only when navigating between documents.
"websocket"
This is a special mode used only when establishing a WebSocket connection.
"webtransport"
This is a special mode used only by WebTransport(url, options).

Even though the default request mode is "no-cors", standards are highly discouraged from using it for new features. It is rather unsafe.

A request has an associated use-CORS-preflight flag. Unless stated otherwise, it is unset.

The use-CORS-preflight flag being set is one of several conditions that results in a CORS-preflight request. The use-CORS-preflight flag is set if either one or more event listeners are registered on an XMLHttpRequestUpload object or if a ReadableStream object is used in a request.

A request has an associated credentials mode, which is "omit", "same-origin", or "include". Unless stated otherwise, it is "same-origin".

"omit"
Excludes credentials from this request, and causes any credentials sent back in the response to be ignored.
"same-origin"
Include credentials with requests made to same-origin URLs, and use any credentials sent back in responses from same-origin URLs.
"include"
Always includes credentials with this request, and always use any credentials sent back in the response.

Request’s credentials mode controls the flow of credentials during a fetch. When request’s mode is "navigate", its credentials mode is assumed to be "include" and fetch does not currently account for other values. If HTML changes here, this standard will need corresponding changes.

A request has an associated use-URL-credentials flag. Unless stated otherwise, it is unset.

When this flag is set, when a request’s URL has a username and password, and there is an available authentication entry for the request, then the URL’s credentials are preferred over that of the authentication entry. Modern specifications avoid setting this flag, since putting credentials in URLs is discouraged, but some older features set it for compatibility reasons.

A request has an associated cache mode, which is "default", "no-store", "reload", "no-cache", "force-cache", or "only-if-cached". Unless stated otherwise, it is "default".

"default"
Fetch will inspect the HTTP cache on the way to the network. If the HTTP cache contains a matching fresh response it will be returned. If the HTTP cache contains a matching stale-while-revalidate response it will be returned, and a conditional network fetch will be made to update the entry in the HTTP cache. If the HTTP cache contains a matching stale response, a conditional network fetch will be returned to update the entry in the HTTP cache. Otherwise, a non-conditional network fetch will be returned to update the entry in the HTTP cache. [HTTP] [HTTP-CACHING] [STALE-WHILE-REVALIDATE]
"no-store"
Fetch behaves as if there is no HTTP cache at all.
"reload"
Fetch behaves as if there is no HTTP cache on the way to the network. Ergo, it creates a normal request and updates the HTTP cache with the response.
"no-cache"
Fetch creates a conditional request if there is a response in the HTTP cache and a normal request otherwise. It then updates the HTTP cache with the response.
"force-cache"
Fetch uses any response in the HTTP cache matching the request, not paying attention to staleness. If there was no response, it creates a normal request and updates the HTTP cache with the response.
"only-if-cached"
Fetch uses any response in the HTTP cache matching the request, not paying attention to staleness. If there was no response, it returns a network error. (Can only be used when request’s mode is "same-origin". Any cached redirects will be followed assuming request’s redirect mode is "follow" and the redirects do not violate request’s mode.)

If header list contains `If-Modified-Since`, `If-None-Match`, `If-Unmodified-Since`, `If-Match`, or `If-Range`, fetch will set cache mode to "no-store" if it is "default".

A request has an associated redirect mode, which is "follow", "error", or "manual". Unless stated otherwise, it is "follow".

"follow"
Follow all redirects incurred when fetching a resource.
"error"
Return a network error when a request is met with a redirect.
"manual"
Retrieves an opaque-redirect filtered response when a request is met with a redirect, to allow a service worker to replay the redirect offline. The response is otherwise indistinguishable from a network error, to not violate atomic HTTP redirect handling.

A request has associated integrity metadata (a string). Unless stated otherwise, it is the empty string.

A request has associated cryptographic nonce metadata (a string). Unless stated otherwise, it is the empty string.

A request has associated parser metadata which is the empty string, "parser-inserted", or "not-parser-inserted". Unless otherwise stated, it is the empty string.

A request’s cryptographic nonce metadata and parser metadata are generally populated from attributes and flags on the HTML element responsible for creating a request. They are used by various algorithms in Content Security Policy to determine whether requests or responses are to be blocked in a given context. [CSP]

A request has an associated reload-navigation flag. Unless stated otherwise, it is unset.

This flag is for exclusive use by HTML’s navigate algorithm. [HTML]

A request has an associated history-navigation flag. Unless stated otherwise, it is unset.

This flag is for exclusive use by HTML’s navigate algorithm. [HTML]

A request has an associated boolean user-activation. Unless stated otherwise, it is false.

This is for exclusive use by HTML’s navigate algorithm. [HTML]

A request has an associated boolean render-blocking. Unless stated otherwise, it is false.

This flag is for exclusive use by HTML’s render-blocking mechanism. [HTML]


A request has an associated URL list (a list of one or more URLs). Unless stated otherwise, it is a list containing a copy of request’s URL.

A request has an associated current URL. It is a pointer to the last URL in request’s URL list.

A request has an associated redirect count. Unless stated otherwise, it is zero.

A request has an associated response tainting, which is "basic", "cors", or "opaque". Unless stated otherwise, it is "basic".

A request has an associated prevent no-cache cache-control header modification flag. Unless stated otherwise, it is unset.

A request has an associated done flag. Unless stated otherwise, it is unset.

A request has an associated timing allow failed flag. Unless stated otherwise, it is unset.

A request’s URL list, current URL, redirect count, response tainting, done flag, and timing allow failed flag are used as bookkeeping details by the fetch algorithm.


A subresource request is a request whose destination is "audio", "audioworklet", "font", "image", "json", "manifest", "paintworklet", "script", "style", "track", "video", "xslt", or the empty string.

A non-subresource request is a request whose destination is "document", "embed", "frame", "iframe", "object", "report", "serviceworker", "sharedworker", or "worker".

A navigation request is a request whose destination is "document", "embed", "frame", "iframe", or "object".

See handle fetch for usage of these terms. [SW]


To compute the redirect-taint of a request request, perform the following steps. They return "same-origin", "same-site", or "cross-site".

  1. Assert: request’s origin is not "client".

  2. Let lastURL be null.

  3. Let taint be "same-origin".

  4. For each url of request’s URL list:

    1. If lastURL is null, then set lastURL to url and continue.

    2. If url’s origin is not same site with lastURL’s origin and request’s origin is not same site with lastURL’s origin, then return "cross-site".

    3. If url’s origin is not same origin with lastURL’s origin and request’s origin is not same origin with lastURL’s origin, then set taint to "same-site".

    4. Set lastURL to url.

  5. Return taint.

Serializing a request origin, given a request request, is to run these steps:

  1. Assert: request’s origin is not "client".

  2. If request’s redirect-taint is not "same-origin", then return "null".

  3. Return request’s origin, serialized.

Byte-serializing a request origin, given a request request, is to return the result of serializing a request origin with request, isomorphic encoded.


To clone a request request, run these steps:

  1. Let newRequest be a copy of request, except for its body.

  2. If request’s body is non-null, set newRequest’s body to the result of cloning request’s body.

  3. Return newRequest.


To add a range header to a request request, with an integer first, and an optional integer last, run these steps:

  1. Assert: last is not given, or first is less than or equal to last.

  2. Let rangeValue be `bytes=`.

  3. Serialize and isomorphic encode first, and append the result to rangeValue.

  4. Append 0x2D (-) to rangeValue.

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

  6. Append (`Range`, rangeValue) to request’s header list.

A range header denotes an inclusive byte range. There a range header where first is 0 and last is 500, is a range of 501 bytes.

Features that combine multiple responses into one logical resource are historically a source of security bugs. Please seek security review for features that deal with partial responses.


To serialize a response URL for reporting, given a response response, run these steps:

  1. Assert: response’s URL list is not empty.

  2. Let url be a copy of response’s URL list[0].

    This is not response’s URL in order to avoid leaking information about redirect targets (see similar considerations for CSP reporting too). [CSP]

  3. Set the username given url and the empty string.

  4. Set the password given url and the empty string.

  5. Return the serialization of url with exclude fragment set to true.

To check if Cross-Origin-Embedder-Policy allows credentials, given a request request, run these steps:

  1. Assert: request’s origin is not "client".

  2. If request’s mode is not "no-cors", then return true.

  3. If request’s client is null, then return true.

  4. If request’s client’s policy container’s embedder policy’s value is not "credentialless", then return true.

  5. If request’s origin is same origin with request’s current URL’s origin and request’s redirect-taint is not "same-origin", then return true.

  6. Return false.

2.2.6. Responses

The result of fetch is a response. A response evolves over time. That is, not all its fields are available straight away.

A response has an associated type which is "basic", "cors", "default", "error", "opaque", or "opaqueredirect". Unless stated otherwise, it is "default".

A response can have an associated aborted flag, which is initially unset.

This indicates that the request was intentionally aborted by the developer or end-user.

A response has an associated URL. It is a pointer to the last URL in response’s URL list and null if response’s URL list is empty.

A response has an associated URL list (a list of zero or more URLs). Unless stated otherwise, it is « ».

Except for the first and last URL, if any, a response’s URL list is not directly exposed to script as that would violate atomic HTTP redirect handling.

A response has an associated status, which is a status. Unless stated otherwise it is 200.

A response has an associated status message. Unless stated otherwise it is the empty byte sequence.

Responses over an HTTP/2 connection will always have the empty byte sequence as status message as HTTP/2 does not support them.

A response has an associated header list (a header list). Unless stated otherwise it is « ».

A response has an associated body (null or a body). Unless stated otherwise it is null.

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

A response has an associated cache state (the empty string, "local", or "validated"). Unless stated otherwise, it is the empty string.

This is intended for usage by Service Workers and Resource Timing. [SW] [RESOURCE-TIMING]

A response has an associated CORS-exposed header-name list (a list of zero or more header names). The list is empty unless otherwise specified.

A response will typically get its CORS-exposed header-name list set by extracting header values from the `Access-Control-Expose-Headers` header. This list is used by a CORS filtered response to determine which headers to expose.

A response has an associated range-requested flag, which is initially unset.

This is used to prevent a partial response from an earlier ranged request being provided to an API that didn’t make a range request. See the flag’s usage for a detailed description of the attack.

A response has an associated request-includes-credentials (a boolean), which is initially true.

A response has an associated timing allow passed flag, which is initially unset.

This is used so that the caller to a fetch can determine if sensitive timing data is allowed on the resource fetched by looking at the flag of the response returned. Because the flag on the response of a redirect has to be set if it was set for previous responses in the redirect chain, this is also tracked internally using the request’s timing allow failed flag.

A response has an associated body info (a response body info). Unless stated otherwise, it is a new response body info.

A response has an associated service worker timing info (null or a service worker timing info), which is initially null.

A response has an associated redirect taint ("same-origin", "same-site", or "cross-site"), which is initially "same-origin".


A network error is a response whose type is "error", status is 0, status message is the empty byte sequence, header list is « », body is null, and body info is a new response body info.

An aborted network error is a network error whose aborted flag is set.

To create the appropriate network error given fetch params fetchParams:

  1. Assert: fetchParams is canceled.

  2. Return an aborted network error if fetchParams is aborted; otherwise return a network error.


A filtered response is a response that offers a limited view on an associated response. This associated response can be accessed through filtered response’s internal response (a response that is neither a network error nor a filtered response).

Unless stated otherwise a filtered response’s associated concepts (such as its body) refer to the associated concepts of its internal response. (The exceptions to this are listed below as part of defining the concrete types of filtered responses.)

The fetch algorithm by way of processResponse and equivalent parameters exposes filtered responses to callers to ensure they do not accidentally leak information. If the information needs to be revealed for legacy reasons, e.g., to feed image data to a decoder, the associated internal response can be used by specification algorithms.

New specifications ought not to build further on opaque filtered responses or opaque-redirect filtered responses. Those are legacy constructs and cannot always be adequately protected given contemporary computer architecture.

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

A CORS filtered response is a filtered response whose type is "cors" and header list excludes any headers in internal response’s 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 filtered response whose type is "opaque", URL list is « », status is 0, status message is the empty byte sequence, header list is « », body is null, and body info is a new response body info.

An opaque-redirect filtered response is a filtered response whose type is "opaqueredirect", status is 0, status message is the empty byte sequence, header list is « », body is null, and body info is a new response body info.

Exposing the URL list for opaque-redirect filtered responses is harmless since no redirects are followed.

In other words, an opaque filtered response and an opaque-redirect filtered response are nearly indistinguishable from a network error. When introducing new APIs, do not use the internal response for internal specification algorithms as that will leak information.

This also means that JavaScript APIs, such as response.ok, will return rather useless results.

The type of a response is exposed to script through the type getter:

console.log(new Response().type); // "default"

console.log((await fetch("/")).type); // "basic"

console.log((await fetch("https://api.example/status")).type); // "cors"

console.log((await fetch("https://crossorigin.example/image", { mode: "no-cors" })).type); // "opaque"

console.log((await fetch("/surprise-me", { redirect: "manual" })).type); // "opaqueredirect"

(This assumes that the various resources exist, https://api.example/status has the appropriate CORS headers, and /surprise-me uses a redirect status.)


To clone a response response, run these steps:

  1. If response is a filtered response, then return a new identical filtered response whose internal response is a clone of response’s internal response.

  2. Let newResponse be a copy of response, except for its body.

  3. If response’s body is non-null, then set newResponse’s body to the result of cloning response’s body.

  4. Return newResponse.


A fresh response is a response whose current age is within its freshness lifetime.

A stale-while-revalidate response is a response that is not a fresh response and whose current age is within the stale-while-revalidate lifetime. [HTTP-CACHING] [STALE-WHILE-REVALIDATE]

A stale response is a response that is not a fresh response or a stale-while-revalidate response.


The location URL of a response response, given null or an ASCII string requestFragment, is the value returned by the following steps. They return null, failure, or a URL.

  1. If response’s status is not a redirect status, then return null.

  2. Let location be the result of extracting header list values given `Location` and response’s header list.

  3. If location is a header value, then set location to the result of parsing location with response’s URL.

    If response was constructed through the Response constructor, response’s URL will be null, meaning that location will only parse successfully if it is an absolute-URL-with-fragment string.

  4. If location is a URL whose fragment is null, then set location’s fragment to requestFragment.

    This ensures that synthetic (indeed, all) responses follow the processing model for redirects defined by HTTP. [HTTP]

  5. Return location.

The location URL algorithm is exclusively used for redirect handling in this standard and in HTML’s navigate algorithm which handles redirects manually. [HTML]

2.2.7. Miscellaneous

A potential destination is "fetch" or a destination which is not the empty string.

To translate a potential destination potentialDestination, run these steps:

  1. If potentialDestination is "fetch", then return the empty string.

  2. Assert: potentialDestination is a destination.

  3. Return potentialDestination.

2.3. Authentication entries

An authentication entry and a proxy-authentication entry are tuples of username, password, and realm, used for HTTP authentication and HTTP proxy authentication, and associated with one or more requests.

User agents should allow both to be cleared together with HTTP cookies and similar tracking functionality.

Further details are defined by HTTP. [HTTP] [HTTP-CACHING]

2.4. Fetch groups

Each environment settings object has an associated fetch group, which holds a fetch group.

A fetch group holds information about fetches.

A fetch group has associated:

fetch records
A list of fetch records.
deferred fetch records
A list of deferred fetch records.

A fetch record is a struct with the following items:

request
A request.
controller
A fetch controller or null.

A deferred fetch record is a struct used to maintain state needed to invoke a fetch at a later time, e.g., when a document is unloaded or becomes not fully active. It has the following items:

request
A request.
notify invoked
An algorithm accepting no arguments.
invoke state (default "pending")
"pending", "sent", or "aborted".

When a fetch group fetchGroup is 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. Process deferred fetches for fetchGroup.

2.5. Resolving domains

(This is a tracking vector.) To resolve an origin, given a network partition key key and an origin origin:

  1. If origin’s host is an IP address, then return « origin’s host ».

  2. If origin’s host’s public suffix is "localhost" or "localhost.", then return « ::1, 127.0.0.1 ».

  3. Perform an implementation-defined operation to turn origin into a set of one or more IP addresses.

    It is also implementation-defined whether other operations might be performed to get connection information beyond just IP addresses. For example, if origin’s scheme is an HTTP(S) scheme, the implementation might perform a DNS query for HTTPS RRs. [SVCB]

    If this operation succeeds, return the set of IP addresses and any additional implementation-defined information.

  4. Return failure.

The results of resolve an origin may be cached. If they are cached, key should be used as part of the cache key.

Typically this operation would involve DNS and as such caching can happen on DNS servers without key being taken into account. Depending on the implementation it might also not be possible to take key into account locally. [RFC1035]

The order of the IP addresses that the resolve an origin algorithm can return can differ between invocations.

The particulars (apart from the cache key) are not tied down as they are not pertinent to the system the Fetch Standard establishes. Other documents ought not to build on this primitive without having a considered discussion with the Fetch Standard community first.

2.6. Connections

A user agent has an associated connection pool. A connection pool is an ordered set of zero or more connections. Each connection is identified by an associated key (a network partition key), origin (an origin), and credentials (a boolean).

Each connection has an associated timing info (a connection timing info).

A connection timing info is a struct used to maintain timing information pertaining to the process of obtaining a connection. It has the following items:

domain lookup start time (default 0)
domain lookup end time (default 0)
connection start time (default 0)
connection end time (default 0)
secure connection start time (default 0)
A DOMHighResTimeStamp.
ALPN negotiated protocol (default the empty byte sequence)
A byte sequence.

To clamp and coarsen connection timing info, given a connection timing info timingInfo, a DOMHighResTimeStamp defaultStartTime, and a boolean crossOriginIsolatedCapability, run these steps:

  1. If timingInfo’s connection start time is less than defaultStartTime, then return a new connection timing info whose domain lookup start time is defaultStartTime, domain lookup end time is defaultStartTime, connection start time is defaultStartTime, connection end time is defaultStartTime, secure connection start time is defaultStartTime, and ALPN negotiated protocol is timingInfo’s ALPN negotiated protocol.

  2. Return a new connection timing info whose domain lookup start time is the result of coarsen time given timingInfo’s domain lookup start time and crossOriginIsolatedCapability, domain lookup end time is the result of coarsen time given timingInfo’s domain lookup end time and crossOriginIsolatedCapability, connection start time is the result of coarsen time given timingInfo’s connection start time and crossOriginIsolatedCapability, connection end time is the result of coarsen time given timingInfo’s connection end time and crossOriginIsolatedCapability, secure connection start time is the result of coarsen time given timingInfo’s connection end time and crossOriginIsolatedCapability, and ALPN negotiated protocol is timingInfo’s ALPN negotiated protocol.


A new connection setting is "no", "yes", or "yes-and-dedicated".

To obtain a connection, given a network partition key key, URL url, boolean credentials, an optional new connection setting new (default "no"), and an optional boolean requireUnreliable (default false), run these steps:

  1. If new is "no", then:

    1. Let connections be a set of connections in the user agent’s connection pool whose key is key, origin is url’s origin, and credentials is credentials.

    2. If connections is not empty and requireUnreliable is false, then return one of connections.

    3. If there is a connection capable of supporting unreliable transport in connections, e.g., HTTP/3, then return that connection.

  2. Let proxies be the result of finding proxies for url in an implementation-defined manner. If there are no proxies, let proxies be « "DIRECT" ».

    This is where non-standard technology such as Web Proxy Auto-Discovery Protocol (WPAD) and proxy auto-config (PAC) come into play. The "DIRECT" value means to not use a proxy for this particular url.

  3. Let timingInfo be a new connection timing info.

  4. For each proxy of proxies:

    1. Set timingInfo’s domain lookup start time to the unsafe shared current time.

    2. Let hosts be « url’s origin’s host ».

    3. If proxy is "DIRECT", then set hosts to the result of running resolve an origin given key and url’s origin.

    4. If hosts is failure, then continue.

    5. Set timingInfo’s domain lookup end time to the unsafe shared current time.

    6. Let connection be the result of running this step: run create a connection given key, url’s origin, credentials, proxy, an implementation-defined host from hosts, timingInfo, and requireUnreliable an implementation-defined number of times, in parallel from each other, and wait for at least 1 to return a value. In an implementation-defined manner, select a value to return from the returned values and return it. Any other returned values that are connections may be closed.

      Essentially this allows an implementation to pick one or more IP addresses from the return value of resolve an origin (assuming proxy is "DIRECT") and race them against each other, favor IPv6 addresses, retry in case of a timeout, etc.

    7. If connection is failure, then continue.

    8. If new is not "yes-and-dedicated", then append connection to the user agent’s connection pool.

    9. Return connection.

  5. Return failure.

This is intentionally a little vague as there are a lot of nuances to connection management that are best left to the discretion of implementers. Describing this helps explain the <link rel=preconnect> feature and clearly stipulates that connections are keyed on credentials. The latter clarifies that, e.g., TLS session identifiers are not reused across connections whose credentials are false with connections whose credentials are true.


To create a connection, given a network partition key key, origin origin, boolean credentials, string proxy, host host, connection timing info timingInfo, and boolean requireUnreliable, run these steps:

  1. Set timingInfo’s connection start time to the unsafe shared current time.

  2. Let connection be a new connection whose key is key, origin is origin, credentials is credentials, and timing info is timingInfo. Record connection timing info given connection and use connection to establish an HTTP connection to host, taking proxy and origin into account, with the following caveats: [HTTP] [HTTP1] [TLS]

    • If requireUnreliable is true, then establish a connection capable of unreliable transport, e.g., an HTTP/3 connection. [HTTP3]

    • When establishing a connection capable of unreliable transport, enable options that are necessary for WebTransport. For HTTP/3, this means including SETTINGS_ENABLE_WEBTRANSPORT with a value of 1 and H3_DATAGRAM with a value of 1 in the initial SETTINGS frame. [WEBTRANSPORT-HTTP3] [HTTP3-DATAGRAM]

    • If credentials is false, then do not send a TLS client certificate.

    • If establishing a connection does not succeed (e.g., a UDP, TCP, or TLS error), then return failure.

  3. Set timingInfo’s ALPN negotiated protocol to connection’s ALPN Protocol ID, with the following caveats: [RFC7301]

    • When a proxy is configured, if a tunnel connection is established then this must be the ALPN Protocol ID of the tunneled protocol, otherwise it must be the ALPN Protocol ID of the first hop to the proxy.

    • In case the user agent is using an experimental, non-registered protocol, the user agent must use the used ALPN Protocol ID, if any. If ALPN was not used for protocol negotiations, the user agent may use another descriptive string.

      timingInfo’s ALPN negotiated protocol is intended to identify the network protocol in use regardless of how it was actually negotiated; that is, even if ALPN is not used to negotiate the network protocol, this is the ALPN Protocol IDs that indicates the protocol in use.

    IANA maintains a list of ALPN Protocol IDs.

  4. Return connection.


To record connection timing info given a connection connection, let timingInfo be connection’s timing info and observe these requirements:

The clamp and coarsen connection timing info algorithm ensures that details of reused connections are not exposed and time values are coarsened.

2.7. Network partition keys

A network partition key is a tuple consisting of a site and null or an implementation-defined value.

To determine the network partition key, given an environment environment:

  1. Let topLevelOrigin be environment’s top-level origin.

  2. If topLevelOrigin is null, then set topLevelOrigin to environment’s top-level creation URL’s origin.

  3. Assert: topLevelOrigin is an origin.

  4. Let topLevelSite be the result of obtaining a site, given topLevelOrigin.

  5. Let secondKey be null or an implementation-defined value.

    The second key is intentionally a little vague as the finer points are still evolving. See issue #1035.

  6. Return (topLevelSite, secondKey).

To determine the network partition key, given a request request:

  1. If request’s reserved client is non-null, then return the result of determining the network partition key given request’s reserved client.

  2. If request’s client is non-null, then return the result of determining the network partition key given request’s client.

  3. Return null.

2.8. HTTP cache partitions

To determine the HTTP cache partition, given a request request:

  1. Let key be the result of determining the network partition key given request.

  2. If key is null, then return null.

  3. Return the unique HTTP cache associated with key. [HTTP-CACHING]

2.9. Port blocking

New protocols can avoid the need for blocking ports by negotiating the protocol through TLS using ALPN. The protocol cannot be spoofed through HTTP requests in that case. [RFC7301]

To determine whether fetching a request request should be blocked due to a bad port:

  1. Let url be request’s current URL.

  2. If url’s scheme is an HTTP(S) scheme and url’s port is a bad port, then return blocked.

  3. Return allowed.

A port is a bad port if it is listed in the first column of the following table.

Port Typical service
0 —​
1 tcpmux
7 echo
9 discard
11 systat
13 daytime
15 netstat
17 qotd
19 chargen
20 ftp-data
21 ftp
22 ssh
23 telnet
25 smtp
37 time
42 name
43 nicname
53 domain
69 tftp
77 —​
79 finger
87 —​
95 supdup
101 hostname
102 iso-tsap
103 gppitnp
104 acr-nema
109 pop2
110 pop3
111 sunrpc
113 auth
115 sftp
117 uucp-path
119 nntp
123 ntp
135 epmap
137 netbios-ns
139 netbios-ssn
143 imap
161 snmp
179 bgp
389 ldap
427 svrloc
465 submissions
512 exec
513 login
514 shell
515 printer
526 tempo
530 courier
531 chat
532 netnews
540 uucp
548 afp
554 rtsp
556 remotefs
563 nntps
587 submission
601 syslog-conn
636 ldaps
989 ftps-data
990 ftps
993 imaps
995 pop3s
1719 h323gatestat
1720 h323hostcall
1723 pptp
2049 nfs
3659 apple-sasl
4045 npp
4190 sieve
5060 sip
5061 sips
6000 x11
6566 sane-port
6665 ircu
6666 ircu
6667 ircu
6668 ircu
6669 ircu
6679 osaut
6697 ircs-u
10080 amanda

2.10. Should response to request be blocked due to its MIME type?

Run these steps:

  1. Let mimeType be the result of extracting a MIME type from response’s header list.

  2. If mimeType is failure, then return allowed.

  3. Let destination be request’s destination.

  4. If destination is script-like and one of the following is true, then return blocked:

  5. Return allowed.

3. HTTP extensions

3.1. Cookies

The `Cookie` request header and `Set-Cookie` response headers are largely defined in their own specifications. We define additional infrastructure to be able to use them conveniently here. [COOKIES].

To append a request `Cookie` header, given a request request:

  1. If the user agent is configured to disable cookies for request, then it should return.

  2. Let sameSite be the result of determining the same-site mode for request.

  3. Let isSecure be true if request’s current URL’s scheme is "https"; otherwise false.

  4. Let httpOnlyAllowed be true.

    True follows from this being invoked from fetch, as opposed to the document.cookie getter steps for instance.

  5. Let cookies be the result of running retrieve cookies given isSecure, request’s current URL’s host, request’s current URL’s path, httpOnlyAllowed, and sameSite.

    The cookie store returns an ordered list of cookies

  6. If cookies is empty, then return.

  7. Let value be the result of running serialize cookies given cookies.

  8. Append (`Cookie`, value) to request’s header list.

To parse and store response `Set-Cookie` headers, given a request request and a response response:

  1. If the user agent is configured to disable cookies for request, then it should return.

  2. Let allowNonHostOnlyCookieForPublicSuffix be false.

  3. Let isSecure be true if request’s current URL’s scheme is "https"; otherwise false.

  4. Let httpOnlyAllowed be true.

    True follows from this being invoked from fetch, as opposed to the document.cookie getter steps for instance.

  5. Let sameSiteStrictOrLaxAllowed be true if the result of determine the same-site mode for request is "strict-or-less"; otherwise false.

  6. For each header of response’s header list:

    1. If header’s name is not a byte-case-insensitive match for `Set-Cookie`, then continue.

    2. Parse and store a cookie given header’s value, isSecure, request’s current URL’s host, request’s current URL’s path, httpOnlyAllowed, allowNonHostOnlyCookieForPublicSuffix, and sameSiteStrictOrLaxAllowed.

    3. Garbage collect cookies given request’s current URL’s host.

    As noted elsewhere the `Set-Cookie` header cannot be combined and therefore each occurrence is processed independently. This is not allowed for any other header.

To determine the same-site mode for a given request request:

  1. Assert: request’s method is "GET" or "POST".

  2. If request’s top-level navigation initiator origin is not null and is not same site with request’s URL’s origin, then return "unset-or-less".

  3. If request’s method is "GET" and request’s destination is "document", then return "lax-or-less".

  4. If request’s client’s has cross-site ancestor is true, then return "unset-or-less".

  5. If request’s redirect-taint is "cross-site", then return "unset-or-less".

  6. Return "strict-or-less".

To obtain a serialized cookie default path given a URL url:

  1. Let cloneURL be a clone of url.

  2. Set cloneURL’s path to the cookie default path of cloneURL’s path.

  3. Return the URL path serialization of cloneURL.

3.2. `Origin` header

The `Origin` request header indicates where a fetch originates from.

The `Origin` header is a version of the `Referer` [sic] header that does not reveal a path. It is used for all HTTP fetches whose request’s response tainting is "cors", as well as those where request’s method is neither `GET` nor `HEAD`. Due to compatibility constraints it is not included in all fetches.

Its possible values are all the return values of byte-serializing a request origin, given a request.

This supplants the definition in The Web Origin Concept. [ORIGIN]


To append a request `Origin` header, given a request request, run these steps:

  1. Assert: request’s origin is not "client".

  2. Let serializedOrigin be the result of byte-serializing a request origin with request.

  3. If request’s response tainting is "cors" or request’s mode is either "websocket" or "webtransport", then append (`Origin`, serializedOrigin) to request’s header list.

  4. Otherwise, if request’s method is neither `GET` nor `HEAD`, then:

    1. If request’s mode is not "cors", then switch on request’s referrer policy:

      "no-referrer"

      Set serializedOrigin to `null`.

      "no-referrer-when-downgrade"
      "strict-origin"
      "strict-origin-when-cross-origin"

      If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`.

      "same-origin"

      If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`.

      Otherwise
      Do nothing.
    2. Append (`Origin`, serializedOrigin) to request’s header list.

A request’s referrer policy is taken into account for all fetches where the fetcher did not explicitly opt into sharing their origin with the server, e.g., via using the CORS protocol.

3.3. CORS protocol

To allow sharing responses cross-origin and allow for more versatile fetches than possible with HTML’s form element, the CORS protocol exists. It is layered on top of HTTP and allows responses to declare they can be shared with other origins.

It needs to be an opt-in mechanism to prevent leaking data from responses behind a firewall (intranets). Additionally, for requests including credentials it needs to be opt-in to prevent leaking potentially-sensitive data.

This section explains the CORS protocol as it pertains to server developers. Requirements for user agents are part of the fetch algorithm, except for the new HTTP header syntax.

3.3.1. General

The CORS protocol consists of a set of headers that indicates whether a response can be shared cross-origin.

For requests that are more involved than what is possible with HTML’s form element, a CORS-preflight request is performed, to ensure request’s current URL supports the CORS protocol.

3.3.2. HTTP requests

A CORS request is an HTTP request that includes an `Origin` header. It cannot be reliably identified as participating in the CORS protocol as the `Origin` header is also included for all requests whose method is neither `GET` nor `HEAD`.

A CORS-preflight request is a CORS request that checks to see if the CORS protocol is understood. It uses `OPTIONS` as method and includes the following