Skip to content

Commit

Permalink
Merge pull request #4959 from quicwg/http/control-data
Browse files Browse the repository at this point in the history
Rearrange and rename to align with updated HTTP/2 spec
  • Loading branch information
MikeBishop authored Feb 22, 2022
2 parents f5afa39 + eecbcb1 commit 56d492a
Showing 1 changed file with 130 additions and 124 deletions.
254 changes: 130 additions & 124 deletions rfc9114.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,9 @@ origin can indicate that it is not authoritative for a request by sending a 421
of HTTP}}.


# HTTP Request Lifecycle
# Expressing HTTP Semantics in HTTP/3 {#http-request-lifecycle}

## HTTP Message Exchanges {#request-response}
## HTTP Message Framing {#request-response}

A client sends an HTTP request on a request stream, which is a client-initiated
bidirectional QUIC stream; see {{request-streams}}. A client MUST send only a
Expand All @@ -506,7 +506,8 @@ response following a final HTTP response MUST be treated as malformed

An HTTP message (request or response) consists of:

1. the header section, sent as a single HEADERS frame (see {{frame-headers}}),
1. the header section, including message control data, sent as a single HEADERS
frame (see {{frame-headers}}),

2. optionally, the content, if present, sent as a series of DATA frames
(see {{frame-data}}), and
Expand Down Expand Up @@ -572,8 +573,81 @@ 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 body of the request and close the stream normally.

### Request Cancellation and Rejection {#request-cancellation}

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.

### Field Formatting and Compression {#header-formatting}
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
{{Section 2.4 of 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.

### Malformed Requests and Responses {#malformed}

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 6.4.1 of HTTP}}),
is malformed if the value of a 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 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 ({{errors}}) 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 Fields {#header-formatting}

HTTP messages carry metadata as a series of key-value pairs called "HTTP
fields"; see {{Sections 6.3 and 6.5 of HTTP}}. For a listing of registered HTTP
Expand Down Expand Up @@ -602,15 +676,49 @@ 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 ({{malformed}}).

#### Pseudo-Header Fields
### Field Compression

{{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" field ({{!RFC6265}})
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 0x3b, 0x20 (the ASCII string "; ") 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.

### Header Size Constraints

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 ({{?RFC6585}}). 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.

## HTTP Control Data

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 the target URI, the method of the request, and the status code for the
response.
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
pseudo-header fields other than those defined in this document. However, an
extension could negotiate a modification of this restriction; see
{{extensions}}.

Expand All @@ -626,6 +734,8 @@ 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 ({{malformed}}).

### Request Pseudo-Header Fields

The following pseudo-header fields are defined for requests:

":method":
Expand Down Expand Up @@ -688,123 +798,19 @@ An HTTP request that omits mandatory pseudo-header fields or contains invalid
values for those pseudo-header fields is malformed ({{malformed}}).

HTTP/3 does not define a way to carry the version identifier that is included in
the HTTP/1.1 request line.
the HTTP/1.1 request line. HTTP/3 requests implicitly have a protocol version
of "3.0".

### Response Pseudo-Header Fields

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 {{malformed}}).

HTTP/3 does not define a way to carry the version or reason phrase that is
included in an HTTP/1.1 status line.

#### Field Compression

{{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 pseudo-header fields present
in the header section.

To allow for better compression efficiency, the "Cookie" field ({{!RFC6265}})
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 0x3b, 0x20 (the ASCII string "; ") 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.

#### Header Size Constraints

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 ({{?RFC6585}}). 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.

### Request Cancellation and Rejection {#request-cancellation}

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
{{Section 2.4 of 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.

### Malformed Requests and Responses {#malformed}

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 6.4.1 of HTTP}}),
is malformed if the value of a 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 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 ({{errors}}) 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.
included in an HTTP/1.1 status line. HTTP/3 responses implicitly have a protocol
version of "3.0".


## The CONNECT Method {#connect}
Expand Down Expand Up @@ -903,12 +909,12 @@ treat receipt of a push stream as a connection error of type H3_ID_ERROR
references a Push ID that is greater than the maximum Push ID.

The Push ID is used in one or more PUSH_PROMISE frames ({{frame-push-promise}})
that carry the header section 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.
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; see {{push-streams}}. The push stream identifies the Push ID of
Expand Down

0 comments on commit 56d492a

Please sign in to comment.