A client sends an HTTP request on a
request stream, which is a client-initiated bidirectional QUIC stream; see
Section 6.1. A client
MUST send only a single request on a given stream. A server sends zero or more interim HTTP responses on the same stream as the request, followed by a single final HTTP response, as detailed below. See
Section 15 of [
HTTP] for a description of interim and final HTTP responses.
Pushed responses are sent on a server-initiated unidirectional QUIC stream; see
Section 6.2.2. A server sends zero or more interim HTTP responses, followed by a single final HTTP response, in the same manner as a standard response. Push is described in more detail in
Section 4.6.
On a given stream, receipt of multiple requests or receipt of an additional HTTP response following a final HTTP response
MUST be treated as
malformed.
An HTTP message (request or response) consists of:
-
the header section, including message control data, sent as a single HEADERS frame,
-
optionally, the content, if present, sent as a series of DATA frames, and
-
optionally, the trailer section, if present, sent as a single HEADERS frame.
Header and trailer sections are described in Sections [
HTTP] and [
HTTP] of [
HTTP]; the content is described in
Section 6.4 of [
HTTP].
Receipt of an invalid sequence of frames
MUST be treated as a
connection error of type
H3_FRAME_UNEXPECTED. In particular, a
DATA frame before any
HEADERS frame, or a
HEADERS or
DATA frame after the trailing
HEADERS frame, is considered invalid. Other frame types, especially unknown frame types, might be permitted subject to their own rules; see
Section 9.
A server
MAY send one or more
PUSH_PROMISE frames before, after, or interleaved with the frames of a response message. These
PUSH_PROMISE frames are not part of the response; see
Section 4.6 for more details.
PUSH_PROMISE frames are not permitted on
push streams; a pushed response that includes
PUSH_PROMISE frames
MUST be treated as a
connection error of type
H3_FRAME_UNEXPECTED.
Frames of unknown types (
Section 9), including reserved frames (
Section 7.2.8)
MAY be sent on a request or
push stream before, after, or interleaved with other frames described in this section.
The
HEADERS and
PUSH_PROMISE frames might reference updates to the QPACK dynamic table. While these updates are not directly part of the message exchange, they must be received and processed before the message can be consumed. See
Section 4.2 for more details.
Transfer codings (see
Section 7 of [
HTTP/1.1]) are not defined for HTTP/3; the Transfer-Encoding header field
MUST NOT be used.
A response
MAY consist of multiple messages when and only when one or more interim responses (1xx; see
Section 15.2 of [
HTTP]) precede a final response to the same request. Interim responses do not contain content or trailer sections.
An HTTP request/response exchange fully consumes a client-initiated bidirectional QUIC stream. After sending a request, a client
MUST close the stream for sending. Unless using the CONNECT method (see
Section 4.4), clients
MUST NOT make stream closure dependent on receiving a response to their request. After sending a final response, the server
MUST close the stream for sending. At this point, the QUIC stream is fully closed.
When a stream is closed, this indicates the end of the final HTTP message. Because some messages are large or unbounded, endpoints
SHOULD begin processing partial HTTP messages once enough of the message has been received to make progress. If a client-initiated stream terminates without enough of the HTTP message to provide a complete response, the server
SHOULD abort its response stream with the error code
H3_REQUEST_INCOMPLETE.
A server can send a complete response prior to the client sending an entire request if the response does not depend on any portion of the request that has not been sent and received. When the server does not need to receive the remainder of the request, it
MAY abort reading the
request stream, send a complete response, and cleanly close the sending part of the stream. The error code
H3_NO_ERROR SHOULD be used when requesting that the client stop sending on the
request stream. Clients
MUST NOT discard complete responses as a result of having their request terminated abruptly, though clients can always discard responses at their discretion for other reasons. If the server sends a partial or complete response but does not abort reading the request, clients
SHOULD continue sending the content of the request and close the stream normally.
Once a
request stream has been opened, the request
MAY be cancelled by either endpoint. Clients cancel requests if the response is no longer of interest; servers cancel requests if they are unable to or choose not to respond. When possible, it is
RECOMMENDED that servers send an HTTP response with an appropriate status code rather than cancelling a request it has already begun processing.
Implementations
SHOULD cancel requests by abruptly terminating any directions of a stream that are still open. To do so, an implementation resets the sending parts of streams and aborts reading on the receiving parts of streams; see [
QUIC-TRANSPORT].
When the server cancels a request without performing any application processing, the request is considered "rejected". The server
SHOULD abort its response stream with the error code
H3_REQUEST_REJECTED. In this context, "processed" means that some data from the stream was passed to some higher layer of software that might have taken some action as a result. The client can treat requests rejected by the server as though they had never been sent at all, thereby allowing them to be retried later.
Servers
MUST NOT use the
H3_REQUEST_REJECTED error code for requests that were partially or fully processed. When a server abandons a response after partial processing, it
SHOULD abort its response stream with the error code
H3_REQUEST_CANCELLED.
Client
SHOULD use the error code
H3_REQUEST_CANCELLED to cancel requests. Upon receipt of this error code, a server
MAY abruptly terminate the response using the error code
H3_REQUEST_REJECTED if no processing was performed. Clients
MUST NOT use the
H3_REQUEST_REJECTED error code, except when a server has requested closure of the
request stream with this error code.
If a stream is cancelled after receiving a complete response, the client
MAY ignore the cancellation and use the response. However, if a stream is cancelled after receiving a partial response, the response
SHOULD NOT be used. Only idempotent actions such as GET, PUT, or DELETE can be safely retried; a client
SHOULD NOT automatically retry a request with a non-idempotent method unless it has some means to know that the request semantics are idempotent independent of the method or some means to detect that the original request was never applied. See
Section 9.2.2 of [
HTTP] for more details.
A malformed request or response is one that is an otherwise valid sequence of frames but is invalid due to:
-
the presence of prohibited fields or pseudo-header fields,
-
the absence of mandatory pseudo-header fields,
-
invalid values for pseudo-header fields,
-
pseudo-header fields after fields,
-
an invalid sequence of HTTP messages,
-
the inclusion of uppercase field names, or
-
the inclusion of invalid characters in field names or values.
A request or response that is defined as having content when it contains a Content-Length header field (
Section 8.6 of [
HTTP]) is malformed if the value of the Content-Length header field does not equal the sum of the
DATA frame lengths received. A response that is defined as never having content, even when a Content-Length is present, can have a non-zero Content-Length header field even though no content is included in
DATA frames.
Intermediaries that process HTTP requests or responses (i.e., any intermediary not acting as a tunnel)
MUST NOT forward a malformed request or response. Malformed requests or responses that are detected
MUST be treated as a
stream error of type
H3_MESSAGE_ERROR.
For malformed requests, a server
MAY send an HTTP response indicating the error prior to closing or resetting the stream. Clients
MUST NOT accept a malformed response. Note that these requirements are intended to protect against several types of common attacks against HTTP; they are deliberately strict because being permissive can expose implementations to these vulnerabilities.
HTTP messages carry metadata as a series of key-value pairs called "HTTP fields"; see Sections [
HTTP] and [
HTTP] of [
HTTP]. For a listing of registered HTTP fields, see the "Hypertext Transfer Protocol (HTTP) Field Name Registry" maintained at <
https://www.iana.org/assignments/http-fields/>. Like HTTP/2, HTTP/3 has additional considerations related to the use of characters in field names, the Connection header field, and pseudo-header fields.
Field names are strings containing a subset of ASCII characters. Properties of HTTP field names and values are discussed in more detail in
Section 5.1 of [
HTTP]. Characters in field names
MUST be converted to lowercase prior to their encoding. A request or response containing uppercase characters in field names
MUST be treated as
malformed.
HTTP/3 does not use the Connection header field to indicate connection-specific fields; in this protocol, connection-specific metadata is conveyed by other means. An endpoint
MUST NOT generate an HTTP/3 field section containing connection-specific fields; any message containing connection-specific fields
MUST be treated as
malformed.
The only exception to this is the TE header field, which
MAY be present in an HTTP/3 request header; when it is, it
MUST NOT contain any value other than "trailers".
An intermediary transforming an HTTP/1.x message to HTTP/3
MUST remove connection-specific header fields as discussed in
Section 7.6.1 of [
HTTP], or their messages will be treated by other HTTP/3 endpoints as
malformed.
[
QPACK] describes a variation of HPACK that gives an encoder some control over how much head-of-line blocking can be caused by compression. This allows an encoder to balance compression efficiency with latency. HTTP/3 uses QPACK to compress header and trailer sections, including the control data present in the header section.
To allow for better compression efficiency, the Cookie header field ([
COOKIES])
MAY be split into separate field lines, each with one or more cookie-pairs, before compression. If a decompressed field section contains multiple cookie field lines, these
MUST be concatenated into a single byte string using the two-byte delimiter of "
; " (ASCII 0x3b, 0x20) before being passed into a context other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic HTTP server application.
An HTTP/3 implementation
MAY impose a limit on the maximum size of the message header it will accept on an individual HTTP message. A server that receives a larger header section than it is willing to handle can send an HTTP 431 (Request Header Fields Too Large) status code ([
RFC 6585]). A client can discard responses that it cannot process. The size of a field list is calculated based on the uncompressed size of fields, including the length of the name and value in bytes plus an overhead of 32 bytes for each field.
If an implementation wishes to advise its peer of this limit, it can be conveyed as a number of bytes in the
SETTINGS_MAX_FIELD_SECTION_SIZE parameter. An implementation that has received this parameter
SHOULD NOT send an HTTP message header that exceeds the indicated size, as the peer will likely refuse to process it. However, an HTTP message can traverse one or more intermediaries before reaching the origin server; see
Section 3.7 of [
HTTP]. Because this limit is applied separately by each implementation that processes the message, messages below this limit are not guaranteed to be accepted.
Like HTTP/2, HTTP/3 employs a series of pseudo-header fields, where the field name begins with the
: character (ASCII 0x3a). These pseudo-header fields convey message control data; see
Section 6.2 of [
HTTP].
Pseudo-header fields are not HTTP fields. Endpoints
MUST NOT generate pseudo-header fields other than those defined in this document. However, an extension could negotiate a modification of this restriction; see
Section 9.
Pseudo-header fields are only valid in the context in which they are defined. Pseudo-header fields defined for requests
MUST NOT appear in responses; pseudo-header fields defined for responses
MUST NOT appear in requests. Pseudo-header fields
MUST NOT appear in trailer sections. Endpoints
MUST treat a request or response that contains undefined or invalid pseudo-header fields as
malformed.
All pseudo-header fields
MUST appear in the header section before regular header fields. Any request or response that contains a pseudo-header field that appears in a header section after a regular header field
MUST be treated as
malformed.
The following pseudo-header fields are defined for requests:
-
":method":
-
Contains the HTTP method (Section 9 of [HTTP])
-
":scheme":
-
Contains the scheme portion of the target URI ([URI]).
-
-
The :scheme pseudo-header is not restricted to URIs with scheme "http" and "https". A proxy or gateway can translate requests for non-HTTP schemes, enabling the use of HTTP to interact with non-HTTP services.
-
-
See Section 3.1.2 for guidance on using a scheme other than "https".
-
":authority":
-
Contains the authority portion of the target URI ([URI]). The authority MUST NOT include the deprecated userinfo subcomponent for URIs of scheme "http" or "https".
-
-
To ensure that the HTTP/1.1 request line can be reproduced accurately, this pseudo-header field MUST be omitted when translating from an HTTP/1.1 request that has a request target in a method-specific form; see Section 7.1 of [HTTP]. Clients that generate HTTP/3 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. An intermediary that converts an HTTP/3 request to HTTP/1.1 MUST create a Host field if one is not present in a request by copying the value of the :authority pseudo-header field.
-
":path":
-
Contains the path and query parts of the target URI (the "path-absolute" production and optionally a ? character (ASCII 0x3f) followed by the "query" production; see Sections [URI] and [URI] of [URI].
-
-
This pseudo-header field MUST NOT be empty for "http" or "https" URIs; "http" or "https" URIs that do not contain a path component MUST include a value of / (ASCII 0x2f). An OPTIONS request that does not include a path component includes the value * (ASCII 0x2a) for the :path pseudo-header field; see Section 7.1 of [HTTP].
All HTTP/3 requests
MUST include exactly one value for the :method, :scheme, and :path pseudo-header fields, unless the request is a CONNECT request; see
Section 4.4.
If the :scheme pseudo-header field identifies a scheme that has a mandatory authority component (including "http" and "https"), the request
MUST contain either an :authority pseudo-header field or a Host header field. If these fields are present, they
MUST NOT be empty. If both fields are present, they
MUST contain the same value. If the scheme does not have a mandatory authority component and none is provided in the request target, the request
MUST NOT contain the :authority pseudo-header or Host header fields.
An HTTP request that omits mandatory pseudo-header fields or contains invalid values for those pseudo-header fields is
malformed.
HTTP/3 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line. HTTP/3 requests implicitly have a protocol version of "3.0".
For responses, a single ":status" pseudo-header field is defined that carries the HTTP status code; see
Section 15 of [
HTTP]. This pseudo-header field
MUST be included in all responses; otherwise, the response is
malformed (see
Section 4.1.2).
HTTP/3 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line. HTTP/3 responses implicitly have a protocol version of "3.0".
The CONNECT method requests that the recipient establish a tunnel to the destination origin server identified by the request-target; see
Section 9.3.6 of [
HTTP]. It is primarily used with HTTP proxies to establish a TLS session with an origin server for the purposes of interacting with "https" resources.
In HTTP/1.x, CONNECT is used to convert an entire HTTP connection into a tunnel to a remote host. In HTTP/2 and HTTP/3, the CONNECT method is used to establish a tunnel over a single stream.
A CONNECT request
MUST be constructed as follows:
-
The :method pseudo-header field is set to "CONNECT"
-
The :scheme and :path pseudo-header fields are omitted
-
The :authority pseudo-header field contains the host and port to connect to (equivalent to the authority-form of the request-target of CONNECT requests; see Section 7.1 of [HTTP]).
The
request stream remains open at the end of the request to carry the data to be transferred. A CONNECT request that does not conform to these restrictions is
malformed.
A proxy that supports CONNECT establishes a TCP connection ([
RFC 0793]) to the server identified in the :authority pseudo-header field. Once this connection is successfully established, the proxy sends a
HEADERS frame containing a 2xx series status code to the client, as defined in
Section 15.3 of [
HTTP].
All
DATA frames on the stream correspond to data sent or received on the TCP connection. The payload of any
DATA frame sent by the client is transmitted by the proxy to the TCP server; data received from the TCP server is packaged into
DATA frames by the proxy. Note that the size and number of TCP segments is not guaranteed to map predictably to the size and number of HTTP
DATA or QUIC STREAM frames.
Once the CONNECT method has completed, only
DATA frames are permitted to be sent on the stream. Extension frames
MAY be used if specifically permitted by the definition of the extension. Receipt of any other known frame type
MUST be treated as a
connection error of type
H3_FRAME_UNEXPECTED.
The TCP connection can be closed by either peer. When the client ends the
request stream (that is, the receive stream at the proxy enters the "Data Recvd" state), the proxy will set the FIN bit on its connection to the TCP server. When the proxy receives a packet with the FIN bit set, it will close the send stream that it sends to the client. TCP connections that remain half closed in a single direction are not invalid, but are often handled poorly by servers, so clients
SHOULD NOT close a stream for sending while they still expect to receive data from the target of the CONNECT.
A TCP
connection error is signaled by abruptly terminating the stream. A proxy treats any error in the TCP connection, which includes receiving a TCP segment with the RST bit set, as a
stream error of type
H3_CONNECT_ERROR.
Correspondingly, if a proxy detects an error with the stream or the QUIC connection, it
MUST close the TCP connection. If the proxy detects that the client has reset the stream or aborted reading from the stream, it
MUST close the TCP connection. If the stream is reset or reading is aborted by the client, a proxy
SHOULD perform the same operation on the other direction in order to ensure that both directions of the stream are cancelled. In all these cases, if the underlying TCP implementation permits it, the proxy
SHOULD send a TCP segment with the RST bit set.
Since CONNECT creates a tunnel to an arbitrary server, proxies that support CONNECT
SHOULD restrict its use to a set of known ports or a list of safe request targets; see
Section 9.3.6 of [
HTTP] for more details.
Server push is an interaction mode that permits a server to push a request-response exchange to a client in anticipation of the client making the indicated request. This trades off network usage against a potential latency gain. HTTP/3 server push is similar to what is described in
Section 8.2 of [
HTTP/2], but it uses different mechanisms.
Each server push is assigned a unique push ID by the server. The push ID is used to refer to the push in various contexts throughout the lifetime of the HTTP/3 connection.
The push ID space begins at zero and ends at a maximum value set by the
MAX_PUSH_ID frame. In particular, a server is not able to push until after the client sends a
MAX_PUSH_ID frame. A client sends
MAX_PUSH_ID frames to control the number of pushes that a server can promise. A server
SHOULD use push IDs sequentially, beginning from zero. A client
MUST treat receipt of a
push stream as a
connection error of type
H3_ID_ERROR when no
MAX_PUSH_ID frame has been sent or when the stream references a push ID that is greater than the maximum push ID.
The push ID is used in one or more
PUSH_PROMISE frames that carry the control data and header fields of the request message. These frames are sent on the
request stream that generated the push. This allows the server push to be associated with a client request. When the same push ID is promised on multiple
request streams, the decompressed request field sections
MUST contain the same fields in the same order, and both the name and the value in each field
MUST be identical.
The push ID is then included with the
push stream that ultimately fulfills those promises. The
push stream identifies the push ID of the promise that it fulfills, then contains a response to the promised request as described in
Section 4.1.
Finally, the push ID can be used in
CANCEL_PUSH frames; see
Section 7.2.3. Clients use this frame to indicate they do not wish to receive a promised resource. Servers use this frame to indicate they will not be fulfilling a previous promise.
Not all requests can be pushed. A server
MAY push requests that have the following properties:
The server
MUST include a value in the :authority pseudo-header field for which the server is authoritative. If the client has not yet validated the connection for the origin indicated by the pushed request, it
MUST perform the same verification process it would do before sending a request for that origin on the connection; see
Section 3.3. If this verification fails, the client
MUST NOT consider the server authoritative for that origin.
Clients
SHOULD send a
CANCEL_PUSH frame upon receipt of a
PUSH_PROMISE frame carrying a request that is not cacheable, is not known to be safe, that indicates the presence of request content, or for which it does not consider the server authoritative. Any corresponding responses
MUST NOT be used or cached.
Each pushed response is associated with one or more client requests. The push is associated with the
request stream on which the
PUSH_PROMISE frame was received. The same server push can be associated with additional client requests using a
PUSH_PROMISE frame with the same push ID on multiple
request streams. These associations do not affect the operation of the protocol, but they
MAY be considered by user agents when deciding how to use pushed resources.
Ordering of a
PUSH_PROMISE frame in relation to certain parts of the response is important. The server
SHOULD send
PUSH_PROMISE frames prior to sending
HEADERS or
DATA frames that reference the promised responses. This reduces the chance that a client requests a resource that will be pushed by the server.
Due to reordering,
push stream data can arrive before the corresponding
PUSH_PROMISE frame. When a client receives a new
push stream with an as-yet-unknown push ID, both the associated client request and the pushed request header fields are unknown. The client can buffer the stream data in expectation of the matching
PUSH_PROMISE. The client can use stream flow control ([
QUIC-TRANSPORT]) to limit the amount of data a server may commit to the pushed stream. Clients
SHOULD abort reading and discard data already read from
push streams if no corresponding
PUSH_PROMISE frame is processed in a reasonable amount of time.
Push stream data can also arrive after a client has cancelled a push. In this case, the client can abort reading the stream with an error code of
H3_REQUEST_CANCELLED. This asks the server not to transfer additional data and indicates that it will be discarded upon receipt.
Pushed responses that are cacheable (see
Section 3 of [
HTTP-CACHING]) can be stored by the client, if it implements an HTTP cache. Pushed responses are considered successfully validated on the origin server (e.g., if the "no-cache" cache response directive is present; see
Section 5.2.2.4 of [
HTTP-CACHING]) at the time the pushed response is received.
Pushed responses that are not cacheable
MUST NOT be stored by any HTTP cache. They
MAY be made available to the application separately.