RFC 7540
Hypertext Transfer Protocol Version 2 (HTTP/2)
Hypertext Transfer Protocol Version 2 (HTTP/2) ๐
Request for Comments: 7540 ๐ Title: Hypertext Transfer Protocol Version 2 (HTTP/2) Authors: M. Belshe (BitGo), R. Peon (Google, Inc), and M. Thomson, Ed. (Mozilla) ๐ Category: Standards Track โจ (this is an Internet Standards Track document, so it's the real deal!) ISSN: 2070-1721 Date: May 2015 ๐ธ Obsoletes / Updates: Nothing is listed in the title block. No Obsoletes or Updates lines, so this one stands on its own ๐ฆ
Abstract โจ
okay so this spec describes an optimized way of expressing the semantics of the Hypertext Transfer Protocol (HTTP), and it's called HTTP version 2, or HTTP/2 for short ๐ It makes network resources way more efficient and cuts down how laggy things feel by compressing header fields and letting multiple exchanges run at the same time on one connection. It also adds unsolicited push, which means servers can send representations to clients without being asked ๐ฅ
Bestie, this is an alternative to the HTTP/1.1 message syntax, not a replacement. It does not obsolete HTTP/1.1, and HTTP's existing semantics stay exactly the same ๐ซถ
Status of This Memo โจ
This is an Internet Standards Track document. ๐
It's a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG) ๐ If you want more info on Internet Standards, check out Section 2 of RFC 5741.
For the current status, any errata, and how to send feedback, head to http://www.rfc-editor.org/info/rfc7540 ๐ฆ
Copyright Notice โจ
Copyright (c) 2015 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they were in effect on the date of publication. Please review these documents carefully, because they spell out your rights and restrictions for this document ๐ Code Components pulled out of this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, as described in the Simplified BSD License ๐
Table of Contents ๐ง
1. Introduction ....................................................4
2. HTTP/2 Protocol Overview ........................................5
2.1. Document Organization ......................................6
2.2. Conventions and Terminology ................................6
3. Starting HTTP/2 .................................................7
3.1. HTTP/2 Version Identification ..............................8
3.2. Starting HTTP/2 for "http" URIs ............................8
3.2.1. HTTP2-Settings Header Field .........................9
3.3. Starting HTTP/2 for "https" URIs ..........................10
3.4. Starting HTTP/2 with Prior Knowledge ......................10
3.5. HTTP/2 Connection Preface .................................11
4. HTTP Frames ....................................................12
4.1. Frame Format ..............................................12
4.2. Frame Size ................................................13
4.3. Header Compression and Decompression ......................14
5. Streams and Multiplexing .......................................15
5.1. Stream States .............................................16
5.1.1. Stream Identifiers .................................21
5.1.2. Stream Concurrency .................................22
5.2. Flow Control ..............................................22
5.2.1. Flow-Control Principles ............................23
5.2.2. Appropriate Use of Flow Control ....................24
5.3. Stream Priority ...........................................24
5.3.1. Stream Dependencies ................................25
5.3.2. Dependency Weighting ...............................26
5.3.3. Reprioritization ...................................26
5.3.4. Prioritization State Management ....................27
5.3.5. Default Priorities .................................28
5.4. Error Handling ............................................28
5.4.1. Connection Error Handling ..........................29
5.4.2. Stream Error Handling ..............................29
5.4.3. Connection Termination .............................30
5.5. Extending HTTP/2 ..........................................30
6. Frame Definitions ..............................................31
6.1. DATA ......................................................31
6.2. HEADERS ...................................................32
6.3. PRIORITY ..................................................34
6.4. RST_STREAM ................................................36
6.5. SETTINGS ..................................................36
6.5.1. SETTINGS Format ....................................38
6.5.2. Defined SETTINGS Parameters ........................38
6.5.3. Settings Synchronization ...........................39
6.6. PUSH_PROMISE ..............................................40
6.7. PING ......................................................42
6.8. GOAWAY ....................................................43
6.9. WINDOW_UPDATE .............................................46
6.9.1. The Flow-Control Window ............................47
6.9.2. Initial Flow-Control Window Size ...................48
6.9.3. Reducing the Stream Window Size ....................49
6.10. CONTINUATION .............................................49
7. Error Codes ....................................................50
8. HTTP Message Exchanges .........................................51
8.1. HTTP Request/Response Exchange ............................52
8.1.1. Upgrading from HTTP/2 ..............................53
8.1.2. HTTP Header Fields .................................53
8.1.3. Examples ...........................................57
8.1.4. Request Reliability Mechanisms in HTTP/2 ...........60
8.2. Server Push ...............................................60
8.2.1. Push Requests ......................................61
8.2.2. Push Responses .....................................63
8.3. The CONNECT Method ........................................64
9. Additional HTTP Requirements/Considerations ....................65
9.1. Connection Management .....................................65
9.1.1. Connection Reuse ...................................66
9.1.2. The 421 (Misdirected Request) Status Code ..........66
9.2. Use of TLS Features .......................................67
9.2.1. TLS 1.2 Features ...................................67
9.2.2. TLS 1.2 Cipher Suites ..............................68
10. Security Considerations .......................................69
10.1. Server Authority .........................................69
10.2. Cross-Protocol Attacks ...................................69
10.3. Intermediary Encapsulation Attacks .......................70
10.4. Cacheability of Pushed Responses .........................70
10.5. Denial-of-Service Considerations .........................70
10.5.1. Limits on Header Block Size .......................71
10.5.2. CONNECT Issues ....................................72
10.6. Use of Compression .......................................72
10.7. Use of Padding ...........................................73
10.8. Privacy Considerations ...................................73
11. IANA Considerations ...........................................74
11.1. Registration of HTTP/2 Identification Strings ............74
11.2. Frame Type Registry ......................................75
11.3. Settings Registry ........................................75
11.4. Error Code Registry ......................................76
11.5. HTTP2-Settings Header Field Registration .................77
11.6. PRI Method Registration ..................................78
11.7. The 421 (Misdirected Request) HTTP Status Code ...........78
11.8. The h2c Upgrade Token ....................................78
12. References ....................................................79
12.1. Normative References .....................................79
12.2. Informative References ...................................81
Appendix A. TLS 1.2 Cipher Suite Black List .......................83
Acknowledgements ..................................................95
Authors' Addresses ................................................96
1. Introduction โจ
okay so HTTP is a wildly successful protocol, no cap ๐ธ But the way HTTP/1.1 uses the underlying transport (see [RFC7230], Section 6) has a few traits that really drag on application performance today ๐ญ
Here's the tea. HTTP/1.0 only let one request be outstanding at a time on a given TCP connection. HTTP/1.1 added request pipelining, but that only partly fixed request concurrency and it still suffers from head-of-line blocking ๐ So clients that need to make a bunch of requests end up opening multiple connections to one server, just to get concurrency and cut down on latency ๐ฆ
It gets worse, bestie. HTTP header fields are super repetitive and verbose, which creates unnecessary network traffic and fills up the initial TCP [TCP] congestion window really fast. When you make multiple requests on a brand-new TCP connection, that can cause a lot of latency ๐
HTTP/2 fixes this by defining an optimized mapping of HTTP's semantics onto an underlying connection โจ It lets request and response messages be interleaved on the same connection and uses an efficient coding for HTTP header fields. It also lets you prioritize requests, so the more important ones finish quicker, which boosts performance even more ๐ฅ
The result is friendlier to the network, because fewer TCP connections are needed compared to HTTP/1.x. That means less competition with other flows and longer-lived connections, which lead to better use of the available network capacity ๐
Finally, HTTP/2 makes message processing more efficient through binary message framing ๐
Part 1 of 19 is done! ๐ More coming next, so stay tuned, bestie ๐
2. HTTP/2 Protocol Overview โจ
okay so HTTP/2 is basically an optimized transport for HTTP semantics ๐ It supports every core feature of HTTP/1.1, but it's giving "more efficient in a bunch of ways" ๐
The basic unit in HTTP/2 is a frame (Section 4.1) ๐งฉ Each frame type has its own job. HEADERS and DATA frames are the stars because they form the basis of HTTP requests and responses (Section 8.1) ๐ Other frame types, like SETTINGS, WINDOW_UPDATE, and PUSH_PROMISE, support the other HTTP/2 features ๐
Multiplexing is the iconic part โจ Each HTTP request/response exchange gets its own stream (Section 5). Streams are pretty independent of each other, so one blocked or stalled request or response doesn't stop progress on the other streams ๐ฆ
Flow control and prioritization make sure you can actually use all those multiplexed streams well ๐ Flow control (Section 5.2) helps make sure that only data a receiver can actually use gets sent ๐ซถ Prioritization (Section 5.3) makes sure limited resources go to the most important streams first ๐ฅ
HTTP/2 also adds a new interaction mode called server push, where a server can push responses to a client (Section 8.2) ๐ง Server push lets a server speculatively send data that it expects the client will need, trading some network usage for a possible latency gain โญ The server does this by synthesizing a request, which it sends as a PUSH_PROMISE frame. Then it can send a response to that synthetic request on a separate stream ๐
Header fields used in a connection can contain lots of redundant data, so the frames that carry them are compressed (Section 4.3) ๐ This is especially helpful for request sizes in the common case, since many requests can be squeezed into one packet ๐ญ
2.1. Document Organization
The HTTP/2 specification is split into four parts ๐
- Starting HTTP/2 (Section 3) covers how an HTTP/2 connection gets initiated.
- The frame (Section 4) and stream (Section 5) layers describe how HTTP/2 frames are structured and formed into multiplexed streams.
- Frame (Section 6) and error (Section 7) definitions include details of the frame and error types used in HTTP/2.
- HTTP mappings (Section 8) and additional requirements (Section 9) describe how HTTP semantics get expressed using frames and streams.
Some of the frame and stream layer concepts are isolated from HTTP, but this specification does not define a completely generic frame layer ๐ The frame and stream layers are tailored to the needs of the HTTP protocol and server push ๐
2.2. Conventions and Terminology
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119] ๐โจ
All numeric values are in network byte order. Values are unsigned unless otherwise indicated. Literal values are given in decimal or hexadecimal as appropriate. Hexadecimal literals get prefixed with "0x" so they don't get mixed up with decimal literals ๐ข๐
The following terms are used ๐
- client: The endpoint that initiates an HTTP/2 connection. Clients send HTTP requests and receive HTTP responses.
- connection: A transport-layer connection between two endpoints.
- connection error: An error that affects the entire HTTP/2 connection.
- endpoint: Either the client or server of the connection.
- frame: The smallest unit of communication within an HTTP/2 connection, consisting of a header and a variable-length sequence of octets structured according to the frame type.
- peer: An endpoint. When discussing a particular endpoint, "peer" refers to the endpoint that is remote to the primary subject of discussion.
- receiver: An endpoint that is receiving frames.
- sender: An endpoint that is transmitting frames.
- server: The endpoint that accepts an HTTP/2 connection. Servers receive HTTP requests and send HTTP responses.
- stream: A bidirectional flow of frames within the HTTP/2 connection.
- stream error: An error on the individual HTTP/2 stream.
Finally, the terms "gateway", "intermediary", "proxy", and "tunnel" are defined in Section 2.3 of [RFC7230]. Intermediaries act as both client and server at different times ๐
The term "payload body" is defined in Section 3.3 of [RFC7230] ๐
3. Starting HTTP/2
An HTTP/2 connection is an application-layer protocol running on top of a TCP connection ([TCP]) ๐งต The client is the TCP connection initiator ๐
HTTP/2 uses the same "http" and "https" URI schemes that HTTP/1.1 uses. It also shares the same default port numbers: 80 for "http" URIs and 443 for "https" URIs ๐ธ So implementations processing requests for target resource URIs like "http://example.org/foo" or "https://example.com/bar" are required to first discover whether the upstream server (the immediate peer the client wants to connect to) supports HTTP/2 ๐ต๏ธโโ๏ธ
How you figure out HTTP/2 support is different for "http" and "https" URIs. Discovery for "http" URIs is described in Section 3.2, and discovery for "https" URIs is described in Section 3.3 ๐
3.1. HTTP/2 Version Identification
The protocol defined in this document has two identifiers ๐ชช
- The string "h2" identifies the protocol where HTTP/2 uses Transport Layer Security (TLS) [TLS12]. This identifier is used in the TLS application-layer protocol negotiation (ALPN) extension [TLS-ALPN] field and in any place where HTTP/2 over TLS is identified.
The "h2" string is serialized into an ALPN protocol identifier as the two-octet sequence: 0x68, 0x32.
- The string "h2c" identifies the protocol where HTTP/2 is run over cleartext TCP. This identifier is used in the HTTP/1.1 Upgrade header field and in any place where HTTP/2 over TCP is identified.
The "h2c" string is reserved from the ALPN identifier space but describes a protocol that does not use TLS ๐
Negotiating "h2" or "h2c" implies the use of the transport, security, framing, and message semantics described in this document ๐
3.2. Starting HTTP/2 for "http" URIs
A client that makes a request for an "http" URI without prior knowledge about HTTP/2 support on the next hop uses the HTTP Upgrade mechanism (Section 6.7 of [RFC7230]) ๐ It does this by making an HTTP/1.1 request that includes an Upgrade header field with the "h2c" token. Such an HTTP/1.1 request MUST include exactly one HTTP2-Settings (Section 3.2.1) header field ๐
For example:
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
Requests that contain a payload body MUST be sent in their entirety before the client can send HTTP/2 frames. So a large request can block the use of the connection until it's completely sent ๐ฌ
If it's important for an initial request to run concurrently with later requests, an OPTIONS request can be used to do the upgrade to HTTP/2, at the cost of an additional round trip ๐ฐ๏ธ
A server that doesn't support HTTP/2 can respond to the request as though the Upgrade header field were absent:
HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
...
A server MUST ignore an "h2" token in an Upgrade header field. Presence of a token with "h2" implies HTTP/2 over TLS, which gets negotiated instead, as described in Section 3.3 ๐
A server that supports HTTP/2 accepts the upgrade with a 101 (Switching Protocols) response ๐ After the empty line that terminates the 101 response, the server can start sending HTTP/2 frames. These frames MUST include a response to the request that initiated the upgrade ๐
For example:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...
The first HTTP/2 frame sent by the server MUST be a server connection preface (Section 3.5) consisting of a SETTINGS frame (Section 6.5). Once the client gets the 101 response, the client MUST send a connection preface (Section 3.5), which includes a SETTINGS frame ๐
The HTTP/1.1 request sent before the upgrade is assigned a stream identifier of 1 (see Section 5.1.1) with default priority values (Section 5.3.5). Stream 1 is implicitly "half-closed" from the client toward the server (see Section 5.1), since the request is completed as an HTTP/1.1 request. After the HTTP/2 connection starts, stream 1 is used for the response ๐ฆ
3.2.1. HTTP2-Settings Header Field
A request that upgrades from HTTP/1.1 to HTTP/2 MUST include exactly one "HTTP2-Settings" header field ๐ The HTTP2-Settings header field is a connection-specific header field that includes parameters governing the HTTP/2 connection, provided in anticipation of the server accepting the upgrade request ๐ง
HTTP2-Settings = token68
A server MUST NOT upgrade the connection to HTTP/2 if this header field is not present or if more than one is present. A server MUST NOT send this header field ๐ซ
The content of the HTTP2-Settings header field is the payload of a SETTINGS frame (Section 6.5), encoded as a base64url string. That's the URL- and filename-safe Base64 encoding described in Section 5 of [RFC4648], with any trailing '=' characters omitted ๐ง The ABNF [RFC5234] production for "token68" is defined in Section 2.1 of [RFC7235] ๐
Since the upgrade is only meant to apply to the immediate connection, a client sending the HTTP2-Settings header field MUST also send "HTTP2-Settings" as a connection option in the Connection header field, so it doesn't get forwarded (see Section 6.1 of [RFC7230]) ๐
A server decodes and interprets these values the same way it would any other SETTINGS frame. Explicit acknowledgement of these settings (Section 6.5.3) isn't necessary, since a 101 response serves as implicit acknowledgement โ Providing these values in the upgrade request gives a client a chance to set parameters before it receives any frames from the server ๐
3.3. Starting HTTP/2 for "https" URIs
A client that makes a request to an "https" URI uses TLS [TLS12] with the application-layer protocol negotiation (ALPN) extension [TLS-ALPN] ๐
HTTP/2 over TLS uses the "h2" protocol identifier. The "h2c" protocol identifier MUST NOT be sent by a client or selected by a server, because "h2c" describes a protocol that does not use TLS ๐ โโ๏ธ
Once TLS negotiation is complete, both the client and the server MUST send a connection preface (Section 3.5) ๐ซถ
Heads up bestie: this part has 10 standalone "MUST" (plus the "MUST NOT"s), which matches the original RFC 7540 text for this section. I didn't add an extra one, since that would change the spec.
3.4. Starting HTTP/2 with Prior Knowledge โจ
okay so a client can totally find out that a server speaks HTTP/2 by other means ๐ like, [ALT-SVC] describes one way to advertise that capability ๐ฆ
A client MUST send the connection preface (Section 3.5) and then MAY immediately send HTTP/2 frames to such a server ๐ servers can spot these connections by the connection preface, bestie ๐ This only affects how HTTP/2 connections get set up over cleartext TCP. Implementations that support HTTP/2 over TLS MUST use protocol negotiation in TLS [TLS-ALPN] ๐
Likewise, the server MUST send a connection preface (Section 3.5) ๐ซถ
ngl, prior support for HTTP/2 is not a strong signal that a server will support HTTP/2 for future connections ๐ server configs can change, configs can differ between instances in clustered servers, and network conditions can change too. it's giving unreliable vibes ๐
3.5. HTTP/2 Connection Preface ๐
In HTTP/2, each endpoint is required to send a connection preface as a final confirmation of the protocol in use and to establish the initial settings for the HTTP/2 connection ๐ the client and server each send a different connection preface, so don't mix them up ๐ญ
The client connection preface starts with a sequence of 24 octets, which in hex notation is:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
That is, the connection preface starts with the string "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"). This sequence MUST be followed by a SETTINGS frame (Section 6.5), which MAY be empty ๐ธ The client sends the client connection preface immediately upon receipt of a 101 (Switching Protocols) response (indicating a successful upgrade) or as the first application data octets of a TLS connection. If starting an HTTP/2 connection with prior knowledge of server support for the protocol, the client connection preface is sent upon connection establishment โจ
Note: The client connection preface is selected so that a large proportion of HTTP/1.1 or HTTP/1.0 servers and intermediaries do not attempt to process further frames. Note that this does not address the concerns raised in [TALKING]. ๐
The server connection preface consists of a potentially empty SETTINGS frame (Section 6.5) that MUST be the first frame the server sends in the HTTP/2 connection ๐
The SETTINGS frames received from a peer as part of the connection preface MUST be acknowledged (see Section 6.5.3) after sending the connection preface ๐ง
To avoid unnecessary latency, clients are permitted to send additional frames to the server immediately after sending the client connection preface, without waiting to receive the server connection preface ๐ฆ it's important to note, though, that the server connection preface SETTINGS frame might include parameters that necessarily alter how a client is expected to communicate with the server. Upon receiving the SETTINGS frame, the client is expected to honor any parameters established. In some configurations, it is possible for the server to transmit SETTINGS before the client sends additional frames, which gives an opportunity to avoid this issue ๐
Clients and servers MUST treat an invalid connection preface as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. A GOAWAY frame (Section 6.8) MAY be omitted in this case, since an invalid preface indicates that the peer is not using HTTP/2 ๐
4. HTTP Frames ๐
Once the HTTP/2 connection is established, endpoints can begin exchanging frames ๐ฅ
4.1. Frame Format ๐
All frames begin with a fixed 9-octet header followed by a variable-length payload ๐
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+
Figure 1: Frame Layout
The fields of the frame header are defined as:
Length: The length of the frame payload expressed as an unsigned 24-bit integer. Values greater than 2^14 (16,384) MUST NOT be sent unless the receiver has set a larger value forSETTINGS_MAX_FRAME_SIZE.
The 9 octets of the frame header are not included in this value. ๐
Type: The 8-bit type of the frame. The frame type determines the format and semantics of the frame. Implementations MUST ignore and discard any frame that has a type that is unknown. ๐ โโ๏ธFlags: An 8-bit field reserved for boolean flags specific to the frame type.
Flags are assigned semantics specific to the indicated frame type. Flags that have no defined semantics for a particular frame type MUST be ignored and MUST be left unset (0x0) when sending. โจ
R: A reserved 1-bit field. The semantics of this bit are undefined, and the bit MUST remain unset (0x0) when sending and MUST be ignored when receiving. ๐คซStream Identifier: A stream identifier (see Section 5.1.1) expressed as an unsigned 31-bit integer. The value 0x0 is reserved for frames that are associated with the connection as a whole as opposed to an individual stream. ๐ธ
The structure and content of the frame payload is dependent entirely on the frame type ๐ฆ
4.2. Frame Size ๐
The size of a frame payload is limited by the maximum size that a receiver advertises in the SETTINGS_MAX_FRAME_SIZE setting. This setting can have any value between 2^14 (16,384) and 2^24-1 (16,777,215) octets, inclusive ๐
All implementations MUST be capable of receiving and minimally processing frames up to 2^14 octets in length, plus the 9-octet frame header (Section 4.1). The size of the frame header is not included when describing frame sizes ๐ซถ
Note: Certain frame types, such as PING (Section 6.7), impose additional limits on the amount of payload data allowed. โ ๏ธ
An endpoint MUST send an error code of FRAME_SIZE_ERROR if a frame exceeds the size defined in SETTINGS_MAX_FRAME_SIZE, exceeds any limit defined for the frame type, or is too small to contain mandatory frame data. A frame size error in a frame that could alter the state of the entire connection MUST be treated as a connection error (Section 5.4.1); this includes any frame carrying a header block (Section 4.3) (that is, HEADERS, PUSH_PROMISE, and CONTINUATION), SETTINGS, and any frame with a stream identifier of 0. ๐ญ this part is serious, bestie, the whole connection can get wrecked ๐
Endpoints are not obligated to use all available space in a frame ๐ง responsiveness can be improved by using frames that are smaller than the permitted maximum size. Sending large frames can result in delays in sending time-sensitive frames (such as RST_STREAM, WINDOW_UPDATE, or PRIORITY), which, if blocked by the transmission of a large frame, could affect performance ๐ข
4.3. Header Compression and Decompression ๐๏ธ
Just like in HTTP/1, a header field in HTTP/2 is a name with one or more associated values ๐ header fields are used within HTTP request and response messages as well as in server push operations (see Section 8.2).
Header lists are collections of zero or more header fields. When transmitted over a connection, a header list is serialized into a header block using HTTP header compression [COMPRESSION]. The serialized header block is then divided into one or more octet sequences, called header block fragments, and transmitted within the payload of HEADERS (Section 6.2), PUSH_PROMISE (Section 6.6), or CONTINUATION (Section 6.10) frames ๐
The Cookie header field [COOKIE] is treated specially by the HTTP mapping (see Section 8.1.2.5). ๐ช
A receiving endpoint reassembles the header block by concatenating its fragments and then decompresses the block to reconstruct the header list โจ
A complete header block consists of either:
- a single HEADERS or PUSH_PROMISE frame, with the END_HEADERS flag set, or
- a HEADERS or PUSH_PROMISE frame with the END_HEADERS flag cleared and one or more CONTINUATION frames, where the last CONTINUATION frame has the END_HEADERS flag set. ๐งฉ
Header compression is stateful. One compression context and one decompression context are used for the entire connection ๐ง A decoding error in a header block MUST be treated as a connection error (Section 5.4.1) of type COMPRESSION_ERROR. ๐
Each header block is processed as a discrete unit. Header blocks MUST be transmitted as a contiguous sequence of frames, with no interleaved frames of any other type or from any other stream. The last frame in a sequence of HEADERS or CONTINUATION frames has the END_HEADERS flag set. The last frame in a sequence of PUSH_PROMISE or CONTINUATION frames has the END_HEADERS flag set. This allows a header block to be logically equivalent to a single frame ๐
Header block fragments can only be sent as the payload of HEADERS, PUSH_PROMISE, or CONTINUATION frames because these frames carry data that can modify the compression context maintained by a receiver. An endpoint receiving HEADERS, PUSH_PROMISE, or CONTINUATION frames needs to reassemble header blocks and perform decompression even if the frames are to be discarded. A receiver MUST terminate the connection with a connection error (Section 5.4.1) of type COMPRESSION_ERROR if it does not decompress a header block ๐
5. Streams and Multiplexing ๐ฆ
A "stream" is an independent, bidirectional sequence of frames exchanged between the client and server within an HTTP/2 connection ๐ streams have several important characteristics:
- A single HTTP/2 connection can contain multiple concurrently open streams, with either endpoint interleaving frames from multiple streams. ๐ธ
- Streams can be established and used unilaterally or shared by either the client or server. ๐ซถ
- Streams can be closed by either endpoint. ๐ช
- The order in which frames are sent on a stream is significant. Recipients process frames in the order they are received. In particular, the order of HEADERS and DATA frames is semantically significant. ๐
- Streams are identified by an integer. Stream identifiers are assigned to streams by the endpoint initiating the stream. ๐ง
5.1. Stream States ๐ธ
okay so this is the whole life story of a stream, and it's giving full drama ๐ฌ Figure 2 has all the tea:
+--------+
send PP | | recv PP
,--------| idle |--------.
/ | | \
v +--------+ v
+----------+ | +----------+
| | | send H / | |
,-----| reserved | | recv H | reserved |-----.
| | (local) | | | (remote) | |
| +----------+ v +----------+ |
| | +--------+ | |
| | recv ES | | send ES | |
| send H | ,-------| open |-------. | recv H |
| | / | | \ | |
| v v +--------+ v v |
| +----------+ | +----------+ |
| | half | | | half | |
| | closed | | send R / | closed | |
| | (remote) | | recv R | (local) | |
| +----------+ | +----------+ |
| | | | |
| | send ES / | recv ES / | |
| | send R / v send R / | |
| | recv R +--------+ recv R | |
| send R / `----------->| |<-----------' send R / |
| recv R | closed | recv R |
`----------------------->| |<----------------------'
+--------+
send: endpoint sends this frame
recv: endpoint receives this frame
H: HEADERS frame (with implied CONTINUATIONs)
PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
ES: END_STREAM flag
R: RST_STREAM frame
Figure 2: Stream States
quick heads up: this diagram only shows state changes and the frames and flags that cause them โจ CONTINUATION frames don't cause any state transitions on their own. they're basically part of the HEADERS or PUSH_PROMISE they follow ๐ง
for state transitions, the END_STREAM flag gets treated as its own separate event, apart from the frame that carries it. so a HEADERS frame with END_STREAM set can cause two state transitions ๐คฏ
both endpoints have their own subjective view of a stream's state, and those views can be different while frames are in transit (lowkey messy ๐). endpoints don't coordinate when streams get created, since either endpoint can create one unilaterally. the negative consequences of a state mismatch are limited to the "closed" state after sending RST_STREAM, where frames might still show up for a little while after closing.
streams can be in these states:
idle:
all streams start in the "idle" state ๐ผ
these transitions are valid from here:
- sending or receiving a HEADERS frame makes the stream "open". the stream identifier gets picked as described in Section 5.1.1. the same HEADERS frame can also immediately make the stream "half-closed" ๐
- sending a PUSH_PROMISE frame on another stream reserves the idle stream it identifies for later use. the reserved stream's state moves to "reserved (local)" ๐
- receiving a PUSH_PROMISE frame on another stream reserves an idle stream it identifies for later use. the reserved stream's state moves to "reserved (remote)" ๐ฆ
- heads up: the PUSH_PROMISE frame isn't sent on the idle stream. it just points at the newly reserved stream in the
Promised Stream IDfield ๐
receiving any frame other than HEADERS or PRIORITY on a stream in this state MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ซ
reserved (local):
a stream in the "reserved (local)" state is one that got promised by sending a PUSH_PROMISE frame. a PUSH_PROMISE frame reserves an idle stream by linking it to an open stream that the remote peer started (see Section 8.2) ๐
in this state, only these transitions are possible:
- the endpoint can send a HEADERS frame. this makes the stream open in a "half-closed (remote)" state ๐
- either endpoint can send a RST_STREAM frame to make the stream "closed". this releases the stream reservation ๐
an endpoint MUST NOT send any type of frame other than HEADERS, RST_STREAM, or PRIORITY in this state ๐ โโ๏ธ
a PRIORITY or WINDOW_UPDATE frame MAY be received in this state. receiving any type of frame other than RST_STREAM, PRIORITY, or WINDOW_UPDATE on a stream in this state MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR โญ
reserved (remote):
a stream in the "reserved (remote)" state has been reserved by a remote peer ๐ง
in this state, only these transitions are possible:
- receiving a HEADERS frame makes the stream transition to "half-closed (local)" ๐
- either endpoint can send a RST_STREAM frame to make the stream "closed". this releases the stream reservation ๐
an endpoint MAY send a PRIORITY frame in this state to reprioritize the reserved stream. an endpoint MUST NOT send any type of frame other than RST_STREAM, WINDOW_UPDATE, or PRIORITY in this state ๐ฆ
receiving any type of frame other than HEADERS, RST_STREAM, or PRIORITY on a stream in this state MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐
open:
a stream in the "open" state can be used by both peers to send frames of any type ๐ป in this state, sending peers observe the advertised stream-level flow-control limits (Section 5.2) ๐
from this state, either endpoint can send a frame with an END_STREAM flag set, which moves the stream into one of the "half-closed" states. an endpoint sending an END_STREAM flag makes the stream state "half-closed (local)". an endpoint receiving an END_STREAM flag makes the stream state "half-closed (remote)" ๐ฏ
either endpoint can send a RST_STREAM frame from this state, which makes it jump straight to "closed" ๐ซถ
half-closed (local):
a stream in the "half-closed (local)" state can't be used for sending frames other than WINDOW_UPDATE, PRIORITY, and RST_STREAM ๐ง
a stream moves from this state to "closed" when a frame containing an END_STREAM flag is received, or when either peer sends a RST_STREAM frame ๐
an endpoint can receive any type of frame in this state ๐ฅ giving flow-control credit with WINDOW_UPDATE frames is necessary to keep receiving flow-controlled frames ๐ธ in this state, a receiver can ignore WINDOW_UPDATE frames, which might show up for a short period after a frame bearing the END_STREAM flag gets sent ๐
PRIORITY frames received in this state are used to reprioritize streams that depend on the identified stream ๐ช
half-closed (remote):
a stream that is "half-closed (remote)" isn't being used by the peer to send frames anymore ๐ in this state, an endpoint no longer has to maintain a receiver flow-control window ๐ซง
if an endpoint receives additional frames, other than WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream in this state, it MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED ๐ค
a stream that is "half-closed (remote)" can still be used by the endpoint to send frames of any type โ๏ธ in this state, the endpoint keeps observing the advertised stream-level flow-control limits (Section 5.2) ๐
a stream can move from this state to "closed" by sending a frame containing an END_STREAM flag, or when either peer sends a RST_STREAM frame ๐ฌ
closed:
the "closed" state is the terminal state. it's the end of the road, bestie ๐ชฆ
an endpoint MUST NOT send frames other than PRIORITY on a closed stream. an endpoint that receives any frame other than PRIORITY after receiving a RST_STREAM MUST treat that as a stream error (Section 5.4.2) of type STREAM_CLOSED. similarly, an endpoint that receives any frames after receiving a frame with the END_STREAM flag set MUST treat that as a connection error (Section 5.4.1) of type STREAM_CLOSED, unless the frame is permitted as described below ๐จ
WINDOW_UPDATE or RST_STREAM frames can be received in this state for a short period after a DATA or HEADERS frame containing an END_STREAM flag is sent. until the remote peer receives and processes RST_STREAM or the frame bearing the END_STREAM flag, it might send frames of these types ๐จ endpoints MUST ignore WINDOW_UPDATE or RST_STREAM frames received in this state, though endpoints MAY choose to treat frames that arrive a significant time after sending END_STREAM as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ซฅ
PRIORITY frames can be sent on closed streams to prioritize streams that depend on the closed stream. endpoints SHOULD process PRIORITY frames, though they can be ignored if the stream has been removed from the dependency tree (see Section 5.3.4) ๐ณ
if this state is reached because of sending a RST_STREAM frame, the peer that receives the RST_STREAM might have already sent (or queued up to send) frames on the stream that can't be taken back ๐ฆ an endpoint MUST ignore frames it receives on closed streams after it has sent a RST_STREAM frame. an endpoint MAY choose to limit the period over which it ignores frames, and treat frames that arrive after that time as being in error โฐ
flow-controlled frames (that's DATA) received after sending RST_STREAM count toward the connection flow-control window ๐ฐ even though these frames might get ignored, the sender still counts them against the flow-control window, since they were sent before the sender got the RST_STREAM ๐งพ
an endpoint might receive a PUSH_PROMISE frame after it sends RST_STREAM. PUSH_PROMISE makes a stream "reserved" even if the associated stream has been reset. so a RST_STREAM is needed to close an unwanted promised stream ๐งน
without more specific guidance elsewhere in this document, implementations SHOULD treat receiving a frame that isn't expressly permitted in the description of a state as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ก๏ธ PRIORITY can be sent and received in any stream state ๐ท and frames of unknown types are ignored ๐ซง
an example of the state transitions for an HTTP request/response exchange can be found in Section 8.1 ๐ an example of the state transitions for server push can be found in Sections 8.2.1 and 8.2.2 ๐
5.1.1. Stream Identifiers โจ
okay so streams get identifiers that are unsigned 31-bit integers ๐ง. Clients MUST use odd-numbered stream identifiers, and servers MUST use even-numbered ones ๐
. The identifier 0x0 is for connection control messages, so you literally can't use zero to start a new stream ๐
HTTP/1.1 requests that get upgraded to HTTP/2 (see Section 3.2) are answered on stream 0x1 ๐ฆ. After the upgrade finishes, stream 0x1 is "half-closed (local)" to the client, so a client that upgraded from HTTP/1.1 can't pick 0x1 as a new stream identifier. periodt.
The identifier of a newly established stream MUST be numerically greater than all streams that the initiating endpoint has opened or reserved. This covers streams opened with a HEADERS frame and streams reserved with PUSH_PROMISE. If an endpoint gets an unexpected stream identifier, it MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ญ
The first use of a new stream identifier implicitly closes all streams in the "idle" state that might have been initiated by that peer with a lower-valued identifier. For example, if a client sends a HEADERS frame on stream 7 without ever sending a frame on stream 5, then stream 5 moves to the "closed" state when the first frame for stream 7 is sent or received ๐
Stream identifiers cannot be reused ๐. Long-lived connections can run out of the available range of stream identifiers. A client that can't establish a new stream identifier can open a new connection for new streams. A server that can't establish a new stream identifier can send a GOAWAY frame, so the client is forced to open a new connection for new streams.
5.1.2. Stream Concurrency ๐
A peer can limit the number of concurrently active streams using the SETTINGS_MAX_CONCURRENT_STREAMS parameter (see Section 6.5.2) within a SETTINGS frame. The maximum concurrent streams setting is specific to each endpoint and only applies to the peer that receives it. So clients set the maximum number of concurrent streams the server can initiate, and servers set the maximum number the client can initiate. it's giving boundaries ๐งฑ
Streams in the "open" state or in either of the "half-closed" states count toward the maximum number of streams that an endpoint is permitted to open. Streams in any of these three states count toward the limit advertised in the SETTINGS_MAX_CONCURRENT_STREAMS setting. Streams in either of the "reserved" states do not count toward the stream limit.
Endpoints MUST NOT exceed the limit set by their peer. An endpoint that receives a HEADERS frame that causes its advertised concurrent stream limit to be exceeded MUST treat this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR or REFUSED_STREAM. The choice of error code determines whether the endpoint wishes to enable automatic retry (see Section 8.1.4) for details).
An endpoint that wants to lower SETTINGS_MAX_CONCURRENT_STREAMS to a value below its current number of open streams can either close the streams that exceed the new value or let them complete. โจ
5.2. Flow Control ๐
Using streams for multiplexing creates contention over the use of the TCP connection, which can leave streams blocked. A flow-control scheme makes sure streams on the same connection don't destructively interfere with each other. Flow control applies to individual streams and to the connection as a whole.
HTTP/2 provides flow control through the WINDOW_UPDATE frame (Section 6.9) ๐ซถ
5.2.1. Flow-Control Principles ๐ง
HTTP/2 stream flow control is designed so a variety of flow-control algorithms can be used without needing protocol changes. Flow control in HTTP/2 has these characteristics:
- Flow control is specific to a connection. Both types of flow control work between the endpoints of a single hop, not across the entire end-to-end path.
- Flow control is based on WINDOW_UPDATE frames. Receivers advertise how many octets they are prepared to receive on a stream and for the entire connection. This is a credit-based scheme ๐
- Flow control is directional, with overall control handled by the receiver. A receiver MAY choose to set any window size it desires for each stream and for the entire connection. A sender MUST respect flow-control limits imposed by a receiver. Clients, servers, and intermediaries all independently advertise their flow-control window as a receiver, and they abide by the flow-control limits set by their peer when sending ๐
- The initial value for the flow-control window is 65,535 octets for both new streams and the overall connection.
- The frame type decides whether flow control applies to a frame. Of the frames in this document, only DATA frames are subject to flow control. All other frame types don't consume space in the advertised flow-control window. This makes sure important control frames don't get blocked by flow control ๐ฅ
- Flow control cannot be disabled.
- HTTP/2 only defines the format and semantics of the WINDOW_UPDATE frame (Section 6.9). This document doesn't say how a receiver decides when to send this frame or what value it sends, and it doesn't specify how a sender chooses to send packets. Implementations can select any algorithm that suits their needs ๐ฆ
Implementations are also responsible for managing how requests and responses are sent based on priority, choosing how to avoid head-of-line blocking for requests, and managing the creation of new streams. Algorithm choices for these could interact with any flow-control algorithm.
5.2.2. Appropriate Use of Flow Control ๐ธ
Flow control is defined to protect endpoints that are operating under resource constraints. For example, a proxy needs to share memory between many connections, and it might have a slow upstream connection and a fast downstream one. Flow control covers the case where the receiver can't process data on one stream but still wants to keep processing other streams on the same connection.
Deployments that don't need this capability can advertise a flow-control window of the maximum size (2^31-1) and can maintain that window by sending a WINDOW_UPDATE frame whenever any data is received. This effectively disables flow control for that receiver. On the flip side, a sender is always subject to the flow-control window advertised by the receiver.
Deployments with constrained resources (for example, memory) can use flow control to limit the amount of memory a peer can consume. Heads up though: this can lead to suboptimal use of available network resources if flow control is enabled without knowledge of the bandwidth-delay product (see [RFC7323]) ๐
Even with full awareness of the current bandwidth-delay product, implementing flow control can be difficult. When using flow control, the receiver MUST read from the TCP receive buffer in a timely fashion. If it doesn't, it could deadlock when critical frames, such as WINDOW_UPDATE, aren't read and acted upon ๐
5.3. Stream Priority ๐
A client can assign a priority to a new stream by including prioritization information in the HEADERS frame (Section 6.2) that opens the stream. At any other time, the PRIORITY frame (Section 6.3) can be used to change a stream's priority.
Prioritization is how an endpoint tells its peer how it would prefer resources to be allocated when managing concurrent streams. Most importantly, priority can be used to pick which streams send frames when there's limited capacity for sending โจ
Streams can be prioritized by marking them as dependent on the completion of other streams (Section 5.3.1). Each dependency gets a relative weight, a number used to work out the relative proportion of available resources assigned to streams that depend on the same stream.
Explicitly setting a stream's priority is just input to a prioritization process. It doesn't guarantee any particular processing or transmission order for the stream relative to any other stream. An endpoint can't force its peer to process concurrent streams in a particular order using priority, so expressing priority is only a suggestion ๐ซ
Prioritization information can be left out of messages. Defaults are used until any explicit values are provided (Section 5.3.5).
5.3.1. Stream Dependencies ๐ณ
Each stream can be given an explicit dependency on another stream. Including a dependency expresses a preference to allocate resources to the identified stream rather than to the dependent stream.
A stream that doesn't depend on any other stream gets a stream dependency of 0x0. In other words, the non-existent stream 0 is the root of the tree ๐ฑ
A stream that depends on another stream is a dependent stream. The stream it depends on is a parent stream. A dependency on a stream that isn't currently in the tree (like a stream in the "idle" state) gives that stream a default priority (Section 5.3.5).
When you assign a dependency on another stream, the stream gets added as a new dependency of the parent stream. Dependent streams that share the same parent aren't ordered with respect to each other. For example, if streams B and C depend on stream A, and stream D is created with a dependency on stream A, the result is a dependency order of A followed by B, C, and D in any order.
A A
/ \ ==> /|\
B C B D C
Figure 3: Example of Default Dependency Creation
An exclusive flag allows a new level of dependencies to be inserted. The exclusive flag makes the stream the sole dependency of its parent stream, which causes the other dependencies to become dependent on the exclusive stream. In the previous example, if stream D is created with an exclusive dependency on stream A, D becomes the dependency parent of B and C.
A
A |
/ \ ==> D
B C / \
B C
Figure 4: Example of Exclusive Dependency Creation
Inside the dependency tree, a dependent stream SHOULD only be allocated resources if either all of the streams it depends on (the chain of parent streams up to 0x0) are closed, or it isn't possible to make progress on them. ๐ฅน
A stream can't depend on itself. An endpoint MUST treat this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR. ๐
โโ๏ธ
5.3.2. Dependency Weighting โ๏ธ
All dependent streams are allocated an integer weight between 1 and 256 (inclusive).
Streams with the same parent SHOULD be allocated resources in proportion to their weight. So if stream B depends on stream A with weight 4, stream C depends on stream A with weight 12, and no progress can be made on stream A, stream B ideally gets one-third of the resources allocated to stream C. ๐ง
5.3.3. Reprioritization ๐
okay so stream priorities get changed with the PRIORITY frame ๐ Setting a dependency makes a stream dependent on whichever parent stream you name ๐ธ
dependent streams move along with their parent if the parent gets reprioritized ๐ง and if you set a dependency with the exclusive flag for a reprioritized stream, all the dependencies of the new parent stream become dependent on the reprioritized stream instead. it's giving musical chairs ๐ช
if a stream gets made dependent on one of its own dependencies, the formerly dependent stream gets moved first to depend on the reprioritized stream's previous parent. the moved dependency keeps its weight ๐
here's an example ๐ say you've got a tree where B and C depend on A, D and E depend on C, and F depends on D. if A is made dependent on D, then D takes A's spot. everything else stays the same, except F becomes dependent on A if the reprioritization is exclusive ๐ญ
x x x x
| / \ | |
A D A D D
/ \ / / \ / \ |
B C ==> F B C ==> F A OR A
/ \ | / \ /|\
D E E B C B C F
| | |
F E E
(intermediate) (non-exclusive) (exclusive)
Figure 5: Example of Dependency Reordering
5.3.4. Prioritization State Management ๐ง
when a stream gets removed from the dependency tree, its dependencies can be moved to depend on the parent of the closed stream ๐ซถ the weights of the new dependencies get recalculated by splitting the closed stream's weight proportionally based on the weights of its dependencies. math bestie ๐ค
removing streams from the tree means some prioritization info gets lost ๐ฅฒ streams with the same parent share resources, so if one of them closes or gets blocked, any spare capacity goes to its immediate neighbors. but if the common dependency itself is removed from the tree, those streams end up sharing resources with streams at the next level up ๐
for example, say streams A and B share a parent, and streams C and D both depend on stream A. before stream A is removed, if A and D can't move forward, then C gets all the resources dedicated to A. if A gets removed from the tree, its weight gets split between C and D. if D still can't proceed, C ends up with a smaller share of resources ๐ค with equal starting weights, C gets one third of the available resources instead of one half ๐
it's also possible for a stream to close while prioritization info that makes a dependency on that stream is still in transit ๐ if a stream named in a dependency has no associated priority info, the dependent stream gets a default priority instead (Section 5.3.5). this can lead to suboptimal prioritization, since the stream might end up with a priority that isn't what was intended ๐
to dodge these problems, an endpoint SHOULD retain stream prioritization state for a period after streams become closed ๐ the longer the state sticks around, the lower the chance that streams get wrong or default priority values.
idle streams can be given a priority or become parents of other streams too ๐ธ this lets you make a grouping node in the dependency tree, which allows for more flexible priority setups. idle streams start with a default priority (Section 5.3.5).
keeping priority info for streams that don't count toward the limit set by SETTINGS_MAX_CONCURRENT_STREAMS could make a huge state burden for an endpoint ๐ฉ so the amount of prioritization state that is retained MAY be limited.
the extra state an endpoint keeps for prioritization can depend on load. under high load, prioritization state can be thrown out to limit resource commitments ๐๏ธ in extreme cases, an endpoint could even throw out prioritization state for active or reserved streams ๐ฑ if a limit is applied, endpoints SHOULD maintain state for at least as many streams as allowed by their setting for SETTINGS_MAX_CONCURRENT_STREAMS. implementations SHOULD also attempt to retain state for streams that are in active use in the priority tree ๐
if it has kept enough state to do so, an endpoint that receives a PRIORITY frame changing the priority of a closed stream SHOULD alter the dependencies of the streams that depend on it โจ
5.3.5. Default Priorities ๐
all streams start out with a non-exclusive dependency on stream 0x0 ๐ฑ pushed streams (Section 8.2) initially depend on their associated stream instead. in both cases, streams get a default weight of 16 ๐
5.4. Error Handling ๐จ
HTTP/2 framing allows two classes of error ๐
- An error condition that makes the entire connection unusable is a connection error. ๐
- An error in an individual stream is a stream error. ๐ฉน
a list of error codes is included in Section 7 ๐
5.4.1. Connection Error Handling ๐
a connection error is any error that stops further processing of the frame layer or corrupts any connection state ๐ต
an endpoint that encounters a connection error SHOULD first send a GOAWAY frame (Section 6.8) with the stream identifier of the last stream it successfully received from its peer ๐จ the GOAWAY frame includes an error code that says why the connection is ending. after sending the GOAWAY frame for an error condition, the endpoint MUST close the TCP connection ๐
it's possible the GOAWAY won't be reliably received by the other endpoint ([RFC7230], Section 6.6 describes how an immediate connection close can result in data loss) ๐ฅบ so in the event of a connection error, GOAWAY is only a best-effort attempt to tell the peer why the connection is getting terminated ๐ค
an endpoint can end a connection at any time ๐ in particular, an endpoint MAY choose to treat a stream error as a connection error. endpoints SHOULD send a GOAWAY frame when ending a connection, providing that circumstances permit it ๐ซก
5.4.2. Stream Error Handling ๐งฏ
a stream error is an error related to one specific stream that doesn't affect processing of other streams ๐ฏ
an endpoint that detects a stream error sends a RST_STREAM frame (Section 6.4) containing the stream identifier of the stream where the error happened. the RST_STREAM frame includes an error code that tells you what kind of error it was ๐งพ
a RST_STREAM is the last frame an endpoint can send on a stream ๐ the peer that sends the RST_STREAM frame MUST be prepared to receive any frames that were sent or enqueued for sending by the remote peer ๐ซฃ those frames can be ignored, except where they modify connection state (such as the state maintained for header compression (Section 4.3) or flow control) ๐
normally, an endpoint SHOULD NOT send more than one RST_STREAM frame for any stream ๐ โโ๏ธ however, an endpoint MAY send additional RST_STREAM frames if it receives frames on a closed stream after more than a round-trip time ๐ this is allowed to deal with misbehaving implementations ๐งน
to avoid looping, an endpoint MUST NOT send a RST_STREAM in response to a RST_STREAM frame ๐
5.4.3. Connection Termination ๐ฅ
if the TCP connection is closed or reset while streams are still in the "open" or "half-closed" state, then the affected streams cannot be automatically retried (see Section 8.1.4 for details) ๐
5.5. Extending HTTP/2 ๐งฉ
HTTP/2 allows the protocol to be extended โจ within the limits described in this section, protocol extensions can be used to provide extra services or change any aspect of the protocol ๐ช extensions only work within the scope of a single HTTP/2 connection ๐ฆ
this applies to the protocol elements defined in this document ๐ it doesn't affect the existing ways of extending HTTP, like defining new methods, status codes, or header fields ๐
extensions are allowed to use new frame types (Section 4.1), new settings (Section 6.5.2), or new error codes (Section 7) ๐ registries have been set up to manage these extension points: frame types (Section 11.2), settings (Section 11.3), and error codes (Section 11.4) ๐๏ธ
implementations MUST ignore unknown or unsupported values in all extensible protocol elements ๐ implementations MUST discard frames that have unknown or unsupported types ๐๏ธ this means any of these extension points can be used safely by extensions without prior arrangement or negotiation ๐ค however, extension frames that show up in the middle of a header block (Section 4.3) are not permitted ๐ซ these MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐
extensions that could change the semantics of existing protocol components MUST be negotiated before being used ๐ง for example, an extension that changes the layout of the HEADERS frame can't be used until the peer has given a positive signal that this is okay ๐ฆ in this case, it could also be necessary to coordinate when the revised layout takes effect โฐ note that treating any frames other than DATA frames as flow controlled is that kind of semantic change, so it can only be done through negotiation ๐
this document doesn't mandate one specific way to negotiate an extension, but it does note that a setting (Section 6.5.2) could be used for that purpose ๐ ๏ธ if both peers set a value showing they're willing to use the extension, then the extension can be used ๐ if a setting is used for extension negotiation, the initial value MUST be defined in such a fashion that the extension is initially disabled ๐
6. Frame Definitions ๐
this specification defines a number of frame types, each identified by a unique 8-bit type code ๐งฉ each frame type serves its own distinct purpose in setting up and managing either the connection as a whole or individual streams ๐ธ
the transmission of specific frame types can change the state of a connection ๐ฌ if endpoints fail to keep a synchronized view of the connection state, successful communication within the connection won't be possible anymore ๐ so it's super important that endpoints share an understanding of how the state is affected by using any given frame ๐ซถ
6.1. DATA ๐
okay so DATA frames (type=0x0) are how we send arbitrary, variable-length chunks of octets tied to a stream โจ One or more DATA frames can carry things like HTTP request or response payloads ๐ฆ
DATA frames MAY also contain padding ๐ซถ Padding can be added to DATA frames to obscure the size of messages, which is lowkey iconic for privacy. Padding is a security feature, so check out Section 10.7 for the full tea.
+---------------+
|Pad Length? (8)|
+---------------+-----------------------------------------------+
| Data (*) ...
+---------------------------------------------------------------+
| Padding (*) ...
+---------------------------------------------------------------+
Figure 6: DATA Frame Payload
the DATA frame has these fields, bestie ๐
- Pad Length: an 8-bit field holding the length of the frame padding in units of octets. it's conditional (that's what the "?" in the diagram means) and only shows up if the
PADDEDflag is set ๐ธ - Data: the actual application data. the amount is whatever's left of the frame payload after you subtract the length of the other fields that are present ๐
- Padding: padding octets with zero application semantic value ๐ Padding octets MUST be set to zero when sending. a receiver is not obligated to verify padding, but it MAY treat non-zero padding as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. the receiver has the option, not the duty, which is giving chill but also a little dramatic ๐
the DATA frame defines these flags:
- END_STREAM (0x1): when set, bit 0 says this frame is the last one the endpoint will send for that stream ๐ฆ Setting this flag pushes the stream into one of the "half-closed" states or the "closed" state (Section 5.1). it's the big goodbye ๐
- PADDED (0x8): when set, bit 3 says the Pad Length field and any padding it describes are present ๐ง
DATA frames MUST be associated with a stream ๐ฅ If a DATA frame shows up with a stream identifier field of 0x0, the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR. no stream zero for you, babe ๐ญ
DATA frames are subject to flow control and can only be sent when a stream is in the "open" or "half-closed (remote)" state โจ The entire DATA frame payload counts for flow control, including the Pad Length and Padding fields if they're there. If a DATA frame arrives on a stream that is not in the "open" or "half-closed (local)" state, the recipient MUST respond with a stream error (Section 5.4.2) of type STREAM_CLOSED. the stream is closed, it's over, we don't do that here ๐ซ
the total number of padding octets is set by the Pad Length field. If the length of the padding is the length of the frame payload or greater, the recipient MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. way too much padding is a no-go ๐ โโ๏ธ
Note: A frame can be increased in size by one octet by including a Pad Length field with a value of zero. tiny but mighty trick ๐
6.2. HEADERS ๐
the HEADERS frame (type=0x1) is what opens a stream (Section 5.1), and it also carries a header block fragment ๐ฆ HEADERS frames can be sent on a stream in the "idle", "reserved (local)", "open", or "half-closed (remote)" state.
+---------------+
|Pad Length? (8)|
+-+-------------+-----------------------------------------------+
|E| Stream Dependency? (31) |
+-+-------------+-----------------------------------------------+
| Weight? (8) |
+-+-------------+-----------------------------------------------+
| Header Block Fragment (*) ...
+---------------------------------------------------------------+
| Padding (*) ...
+---------------------------------------------------------------+
Figure 7: HEADERS Frame Payload
the HEADERS frame payload has these fields ๐
- Pad Length: an 8-bit field holding the length of the frame padding in units of octets. it only shows up if the
PADDEDflag is set ๐ง - E: a single-bit flag saying the stream dependency is exclusive (see Section 5.3). it only shows up if the
PRIORITYflag is set โจ - Stream Dependency: a 31-bit stream identifier for the stream this one depends on (see Section 5.3). it only shows up if the
PRIORITYflag is set ๐ - Weight: an unsigned 8-bit integer for the stream's priority weight (see Section 5.3). add one to the value to get a weight between 1 and 256 ๐
it only shows up if the
PRIORITYflag is set - Header Block Fragment: a header block fragment (Section 4.3) ๐ฆ
- Padding: padding octets ๐ซถ
the HEADERS frame defines these flags:
- END_STREAM (0x1): when set, bit 0 says the header block (Section 4.3) is the last one the endpoint will send for that stream ๐ฆ
here's the plot twist: a HEADERS frame with END_STREAM can still be followed by CONTINUATION frames on the same stream. logically, those CONTINUATION frames are part of the HEADERS frame, so the stream's end isn't really over until the whole header block is in ๐ฅ
- END_HEADERS (0x4): when set, bit 2 says this frame has an entire header block (Section 4.3) and isn't followed by any CONTINUATION frames ๐
a HEADERS frame without the END_HEADERS flag set MUST be followed by a CONTINUATION frame for the same stream. a receiver MUST treat the receipt of any other type of frame, or a frame on a different stream, as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. no interrupting the header block, it's rude ๐
- PADDED (0x8): when set, bit 3 says the Pad Length field and any padding it describes are present ๐ธ
- PRIORITY (0x20): when set, bit 5 says the Exclusive Flag (E), Stream Dependency, and Weight fields are present. see Section 5.3 for the priority deets ๐
the payload of a HEADERS frame holds a header block fragment (Section 4.3). A header block that doesn't fit in one HEADERS frame gets continued in a CONTINUATION frame (Section 6.10) ๐ง
HEADERS frames MUST be associated with a stream. If a HEADERS frame arrives with a stream identifier field of 0x0, the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR. stream zero is not the vibe, sorry not sorry ๐ญ
the HEADERS frame changes the connection state as described in Section 4.3 โจ
the HEADERS frame can include padding too ๐ซถ the padding fields and flags are identical to the ones defined for DATA frames (Section 6.1). Padding that's bigger than the room left for the header block fragment MUST be treated as a PROTOCOL_ERROR. way too much padding, again ๐ โโ๏ธ
prioritization info in a HEADERS frame is logically the same as a separate PRIORITY frame ๐ but putting it in HEADERS avoids the potential for churn in stream prioritization when new streams get created, which is so smart. prioritization fields in HEADERS frames after the first one on a stream reprioritize that stream (Section 5.3.3) ๐
6.3. PRIORITY ๐ธ
the PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream (Section 5.3) ๐ it can be sent in any stream state, including idle or closed streams. no gatekeeping here ๐ฆ
+-+-------------------------------------------------------------+
|E| Stream Dependency (31) |
+-+-------------+-----------------------------------------------+
| Weight (8) |
+-+-------------+
Figure 8: PRIORITY Frame Payload
the payload of a PRIORITY frame has these fields โจ
- E: a single-bit flag saying the stream dependency is exclusive (see Section 5.3) ๐
- Stream Dependency: a 31-bit stream identifier for the stream this one depends on (see Section 5.3) ๐
- Weight: an unsigned 8-bit integer for the stream's priority weight (see Section 5.3). add one to the value to get a weight between 1 and 256 ๐
the PRIORITY frame doesn't define any flags ๐ซถ
the PRIORITY frame always identifies a stream. If a PRIORITY frame arrives with a stream identifier of 0x0, the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR. same energy as always: stream zero, no ๐ โโ๏ธ
the PRIORITY frame can be sent on a stream in any state, though it cannot be sent between consecutive frames that make up a single header block (Section 4.3) ๐ง heads up, this frame could show up after processing or frame sending has already finished, which means it has no effect on the stream it names ๐ For a stream in the "half-closed (remote)" or "closed" state, this frame can only affect processing of the identified stream and its dependent streams. it doesn't change frame transmission on that stream ๐
the PRIORITY frame can be sent for a stream in the "idle" or "closed" state ๐ this lets you reprioritize a whole group of dependent streams by changing the priority of an unused or closed parent stream. the parent is a background character, but it runs the whole show ๐
A PRIORITY frame with a length other than 5 octets MUST be treated as a stream error (Section 5.4.2) of type FRAME_SIZE_ERROR. five octets or bust ๐ฅ
6.4. RST_STREAM ๐
the RST_STREAM frame (type=0x3) lets you immediately terminate a stream โจ RST_STREAM is sent to request cancellation of a stream or to say an error condition has happened. it's the "we're done here" frame ๐ญ
+---------------------------------------------------------------+
| Error Code (32) |
+---------------------------------------------------------------+
Figure 9: RST_STREAM Frame Payload
the RST_STREAM frame holds a single unsigned, 32-bit integer for the error code (Section 7). the error code tells you why the stream is being terminated ๐
the RST_STREAM frame doesn't define any flags ๐ซถ
the RST_STREAM frame fully terminates the stream it references and puts it into the "closed" state ๐ After receiving a RST_STREAM on a stream, the receiver MUST NOT send additional frames for that stream, with the exception of PRIORITY. however, after sending RST_STREAM, the sending endpoint MUST be prepared to receive and process additional frames that the peer might have sent before RST_STREAM arrived ๐ง things cross in the mail, it happens ๐
RST_STREAM frames MUST be associated with a stream. If a RST_STREAM frame arrives with a stream identifier of 0x0, the recipient MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. ๐ โโ๏ธ
RST_STREAM frames MUST NOT be sent for a stream in the "idle" state. If a RST_STREAM frame identifying an idle stream is received, the recipient MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. you can't cancel a stream that never existed, bestie ๐
A RST_STREAM frame with a length other than 4 octets MUST be treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR. four octets, always ๐
6.5. SETTINGS ๐
okay bestie, the SETTINGS frame (type=0x4) is where endpoints share their config preferences and any limits they want the other side to respect ๐
It's also how they say "got it" to those settings. Each individual setting is called a "setting" (very cute, very simple) โจ
Settings are not negotiated, btw ๐ โโ๏ธ They describe what the sending peer is like, and the receiving peer just uses that info. Each peer can advertise totally different values for the same parameter, and that's totally fine. Like, a client might go "give me a big initial flow-control window!!" ๐ฆ while a server goes "mm, keep it smaller so I don't run out of resources" ๐
A SETTINGS frame MUST be sent by both endpoints at the start of a connection ๐ซถ After that, either endpoint MAY send one whenever it wants for the rest of the connection. And implementations MUST support every parameter defined in this spec. No skipping, no cap ๐ฅ
Every parameter in a SETTINGS frame replaces whatever value was there before for that parameter. The params get processed in the order they show up, and the receiver doesn't have to keep track of anything beyond the current value of each param. So the value of a setting is just the last one the receiver sees ๐
SETTINGS get acknowledged by the receiving peer, and the frame has one flag to make that happen:
ACK(0x1): When this bit is set, it means "yep, I got your SETTINGS and applied them" โจ When ACK is set, the SETTINGS payload MUST be empty. And if a frame with ACK set has a length field that isn't0, that MUST be treated as a connection error (Section 5.4.1) of typeFRAME_SIZE_ERROR๐ญ For more info, check out Section 6.5.3 ("Settings Synchronization") ๐ง
SETTINGS frames always apply to the whole connection, never just one stream ๐ So the stream identifier for a SETTINGS frame MUST be zero (0x0). If an endpoint gets a SETTINGS frame where the stream identifier is anything other than 0x0, it MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐
The SETTINGS frame messes with connection state, so a badly formed or incomplete one MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ And if the length isn't a multiple of 6 octets, that MUST be treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR ๐ฉ
6.5.1. SETTINGS Format ๐ฆ
The payload is zero or more parameters, and each one is an unsigned 16-bit setting identifier plus an unsigned 32-bit value. Cute and compact ๐ธ
+-------------------------------+
| Identifier (16) |
+-------------------------------+-------------------------------+
| Value (32) |
+---------------------------------------------------------------+
Figure 10: Setting Format
6.5.2. Defined SETTINGS Parameters ๐
Here are the parameters this spec defines, bestie ๐
SETTINGS_HEADER_TABLE_SIZE(0x1): This tells the remote endpoint the maximum size, in octets, of the header compression table used to decode header blocks โจ The encoder can pick any size up to that value, using signaling that's specific to the header compression format inside a header block (see [COMPRESSION]). The initial value is 4,096 octets ๐ทSETTINGS_ENABLE_PUSH(0x2): This one lets you turn off server push (Section 8.2) ๐ โโ๏ธ An endpoint MUST NOT send a PUSH_PROMISE frame if it received this parameter set to0. And an endpoint that has set this to0and had it acknowledged MUST treat receiving a PUSH_PROMISE frame as a connection error (Section 5.4.1) of typePROTOCOL_ERROR๐
The initial value is 1, which means server push is allowed. Any value other than 0 or 1 MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ค
SETTINGS_MAX_CONCURRENT_STREAMS(0x3): This is the max number of concurrent streams the sender is cool with ๐ฆ It's directional, meaning it limits how many streams the sender lets the receiver create. At first there's no limit at all. The spec recommends this value be no smaller than 100, so you don't limit parallelism for no reason ๐โโ๏ธ
A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by endpoints. A zero does stop new streams from being made, but that can also happen with any limit once active streams have used it all up ๐ Servers SHOULD only set a zero value for short periods. If a server doesn't want to accept requests, closing the connection is the more appropriate move ๐
SETTINGS_INITIAL_WINDOW_SIZE(0x4): This is the sender's initial window size, in octets, for stream-level flow control ๐ The initial value is 2^16-1 (65,535) octets.
This setting affects the window size of all streams (see Section 6.9.2) โจ
Values above the maximum flow-control window size of 2^31-1 MUST be treated as a connection error (Section 5.4.1) of type FLOW_CONTROL_ERROR ๐จ
SETTINGS_MAX_FRAME_SIZE(0x5): This is the size, in octets, of the biggest frame payload the sender is willing to receive ๐ฆ
The initial value is 2^14 (16,384) octets. The value an endpoint advertises MUST be between this initial value and the max allowed frame size (2^24-1 or 16,777,215 octets), inclusive. Values outside that range MUST be treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐
SETTINGS_MAX_HEADER_LIST_SIZE(0x6): This is an advisory setting that tells a peer the max size of header list the sender is ready to accept, in octets ๐ง The size is based on the uncompressed header fields: the length of each name and value in octets, plus 32 octets of overhead for each header field.
For any given request, a lower limit than what's advertised MAY be enforced. The initial value of this setting is unlimited ๐
An endpoint that gets a SETTINGS frame with any unknown or unsupported identifier MUST ignore that setting ๐ซถ
6.5.3. Settings Synchronization โฐ
Most SETTINGS values benefit from (or straight up need) knowing exactly when the peer has received and applied the changed values ๐ฅน So, to give everyone synchronized timepoints, the recipient of a SETTINGS frame without the ACK flag set MUST apply the updated parameters as soon as possible after receiving it โก
The values in the SETTINGS frame MUST be processed in the order they appear, with no other frame processing in between. Unsupported parameters MUST be ignored. Once every value has been processed, the recipient MUST immediately send a SETTINGS frame with the ACK flag set ๐ When the sender of the changed parameters gets a SETTINGS frame with ACK set, it can count on the setting having been applied ๐
If the sender of a SETTINGS frame doesn't get an acknowledgement within a reasonable amount of time, it MAY issue a connection error (Section 5.4.1) of type SETTINGS_TIMEOUT ๐ญ
6.6. PUSH_PROMISE
Okay bestie, PUSH_PROMISE is the frame where the sender gives its peer a heads up: "hey, I'm about to open these streams" ๐ฆ. It carries the unsigned 31-bit identifier of the stream the endpoint plans to create, plus a set of headers that give extra context for it. Section 8.2 has the full tea on how PUSH_PROMISE frames get used โจ.
+---------------+
|Pad Length? (8)|
+-+-------------+-----------------------------------------------+
|R| Promised Stream ID (31) |
+-+-----------------------------+-------------------------------+
| Header Block Fragment (*) ...
+---------------------------------------------------------------+
| Padding (*) ...
+---------------------------------------------------------------+
Figure 11: PUSH_PROMISE Payload Format
The PUSH_PROMISE frame payload has these fields, so let's go through them ๐ :
Pad Length: an 8-bit field holding the length of the frame padding in units of octets. This field only shows up if thePADDEDflag is set ๐.R: a single reserved bit ๐ธ.Promised Stream ID: an unsigned 31-bit integer that identifies the stream being reserved by the PUSH_PROMISE. The promised stream identifier MUST be a valid choice for the next stream sent by the sender (see "new stream identifier" in Section 5.1.1). Main character rule, no exceptions ๐.Header Block Fragment: a header block fragment (Section 4.3) containing request header fields ๐.Padding: padding octets ๐ง.
The PUSH_PROMISE frame defines these flags:
END_HEADERS(0x4): when set, bit 2 says this frame contains an entire header block (Section 4.3) and is not followed by any CONTINUATION frames ๐.- A PUSH_PROMISE frame without the
END_HEADERSflag set MUST be followed by a CONTINUATION frame for the same stream. A receiver MUST treat the receipt of any other type of frame, or a frame on a different stream, as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. Not the vibe, so don't do it ๐.
- A PUSH_PROMISE frame without the
PADDED(0x8): when set, bit 3 says the Pad Length field and any padding it describes are present ๐.
PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that is in either the "open" or "half-closed (remote)" state. The stream identifier of a PUSH_PROMISE frame indicates the stream it is associated with. If the stream identifier field specifies the value 0x0, a recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐.
Promised streams are not required to be used in the order they were promised. The PUSH_PROMISE only reserves stream identifiers for later use ๐ฆ, so there's no pressure to use them right away.
PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH setting of the peer endpoint is set to 0. An endpoint that has set this setting and has received acknowledgement MUST treat the receipt of a PUSH_PROMISE frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ญ.
Recipients of PUSH_PROMISE frames can choose to reject promised streams by returning a RST_STREAM that references the promised stream identifier back to the sender of the PUSH_PROMISE. Rude, but valid ๐ .
Okay so PUSH_PROMISE does two sneaky things to the connection state. First, including a header block can change the state kept for header compression ๐. Second, it reserves a stream for later, which puts the promised stream into the "reserved" state ๐ฅ.
A sender MUST NOT send a PUSH_PROMISE on a stream unless that stream is either "open" or "half-closed (remote)". The sender MUST ensure that the promised stream is a valid choice for a new stream identifier (Section 5.1.1), which means the promised stream MUST be in the "idle" state โจ.
Since PUSH_PROMISE reserves a stream, ignoring a PUSH_PROMISE frame leaves the stream state indeterminate, and that's a mess ๐. A receiver MUST treat the receipt of a PUSH_PROMISE on a stream that is neither "open" nor "half-closed (local)" as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. However, an endpoint that has sent RST_STREAM on the associated stream MUST handle PUSH_PROMISE frames that might have been created before the RST_STREAM frame is received and processed. Second chances are iconic ๐ธ.
A receiver MUST treat the receipt of a PUSH_PROMISE that promises an illegal stream identifier (Section 5.1.1) as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. Note that an illegal stream identifier is an identifier for a stream that is not currently in the "idle" state ๐ซ.
The PUSH_PROMISE frame can include padding. Padding fields and flags are identical to those defined for DATA frames (Section 6.1) ๐.
6.7. PING
The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the sender, and for checking whether an idle connection is still functional ๐. PING frames can be sent from any endpoint ๐, so everyone gets to ping.
+---------------------------------------------------------------+
| |
| Opaque Data (64) |
| |
+---------------------------------------------------------------+
Figure 12: PING Payload Format
In addition to the frame header, PING frames MUST contain 8 octets of opaque data in the payload. A sender can include any value it chooses and use those octets in any fashion ๐ง.
Receivers of a PING frame that does not include an ACK flag MUST send a PING frame with the ACK flag set in response, with an identical payload. PING responses SHOULD be given higher priority than any other frame ๐. Honestly, reply first, gossip later ๐.
The PING frame defines the following flag:
ACK(0x1): when set, bit 0 indicates that this PING frame is a PING response. An endpoint MUST set this flag in PING responses. An endpoint MUST NOT respond to PING frames containing this flag ๐ซถ.
PING frames are not associated with any individual stream. If a PING frame is received with a stream identifier field value other than 0x0, the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐.
Receipt of a PING frame with a length field value other than 8 MUST be treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR. Eight octets, no more, no less ๐โจ
6.8. GOAWAY ๐ฏ
okay so the GOAWAY frame (type=0x7) is how an endpoint starts shutting a connection down, or sends a "something went seriously wrong" signal ๐จ. It lets an endpoint gracefully stop accepting new streams while still finishing the ones already in progress ๐งน. This is super handy for stuff like server maintenance ๐ง.
there's an inherent race condition between an endpoint starting new streams and the remote sending a GOAWAY frame ๐๐จ. To handle this, the GOAWAY contains the stream identifier of the last peer-initiated stream that was or might be processed on the sending endpoint in this connection ๐ซถ. For example, if the server sends a GOAWAY frame, the identified stream is the highest-numbered stream the client initiated.
once it's sent, the sender will ignore frames sent on streams initiated by the receiver if the stream has an identifier higher than the included last stream identifier ๐. Receivers of a GOAWAY frame MUST NOT open additional streams on the connection, although a new connection can be established for new streams ๐ง.
if the receiver of the GOAWAY has sent data on streams with a higher stream identifier than the one in the GOAWAY frame, those streams are not or will not be processed ๐. The receiver can treat those streams as though they were never created at all, which means they can be retried later on a new connection ๐ฆ.
Endpoints SHOULD always send a GOAWAY frame before closing a connection, so the remote peer can tell whether a stream was partially processed ๐. Picture this: an HTTP client sends a POST at the exact same moment a server closes the connection. If the server never sends a GOAWAY frame to say which streams it might have acted on, the client has no way to know whether that POST got started ๐ญ.
an endpoint might choose to close a connection without sending a GOAWAY for misbehaving peers ๐ .
a GOAWAY frame might not immediately precede closing the connection. Even so, a receiver of a GOAWAY that has no more use for the connection SHOULD still send a GOAWAY frame before terminating it ๐ธ.
+-+-------------------------------------------------------------+
|R| Last-Stream-ID (31) |
+-+-------------------------------------------------------------+
| Error Code (32) |
+---------------------------------------------------------------+
| Additional Debug Data (*) |
+---------------------------------------------------------------+
Figure 13: GOAWAY Payload Format ๐
the GOAWAY frame does not define any flags ๐.
the GOAWAY frame applies to the whole connection, not one specific stream ๐. An endpoint MUST treat a GOAWAY frame with a stream identifier other than 0x0 as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. no exceptions, bestie ๐ซ.
the last stream identifier in the GOAWAY frame is the highest-numbered stream identifier the sender might have taken some action on, or might still take action on โจ. Every stream up to and including that identifier might have been processed in some way. If no streams were processed, the last stream identifier can be set to 0 ๐ซง.
Note: In this context, "processed" means some data from the stream was passed up to some higher layer of software that might have taken some action because of it ๐ง .
if a connection terminates without a GOAWAY frame, the last stream identifier is effectively the highest possible stream identifier ๐ฅน.
for streams with lower or equal identifiers that weren't fully closed before the connection closed, reattempting requests, transactions, or any protocol activity is not possible ๐ โโ๏ธ. The exception is idempotent actions like HTTP GET, PUT, or DELETE. Any protocol activity on higher-numbered streams can be safely retried over a new connection ๐.
activity on streams numbered lower than or equal to the last stream identifier might still complete successfully ๐. The sender of a GOAWAY frame might gracefully shut down a connection by sending a GOAWAY frame, keeping the connection in an "open" state until all in-progress streams complete ๐๏ธ.
An endpoint MAY send multiple GOAWAY frames if circumstances change ๐ซ. For instance, an endpoint that sends GOAWAY with NO_ERROR during a graceful shutdown could later hit a condition that requires immediate termination of the connection ๐ฌ. The last stream identifier from the last GOAWAY frame received tells you which streams could have been acted upon. Endpoints MUST NOT increase the value they send in the last stream identifier, because peers might already have retried unprocessed requests on another connection ๐.
a client that can't retry requests loses every request that's in flight when the server closes the connection ๐ต. This is especially true for intermediaries that might not be serving clients using HTTP/2 ๐ฅฒ. A server trying to gracefully shut down a connection SHOULD send an initial GOAWAY frame with the last stream identifier set to 2^31-1 and a NO_ERROR code ๐. That tells the client a shutdown is coming and that starting more requests is prohibited ๐ง. After giving any in-flight stream creation time to finish (at least one round-trip time), the server can send another GOAWAY frame with an updated last stream identifier ๐ง. This way, the connection gets cleanly shut down without losing requests โจ.
after sending a GOAWAY frame, the sender can discard frames for streams initiated by the receiver with identifiers higher than the identified last stream ๐๏ธ. However, frames that alter connection state can't be totally ignored ๐ . For example, HEADERS, PUSH_PROMISE, and CONTINUATION frames MUST be minimally processed so the state maintained for header compression stays consistent (see Section 4.3). Similarly, DATA frames MUST be counted toward the connection flow-control window ๐. If these frames aren't processed, flow control or header compression state can become unsynchronized ๐.
the GOAWAY frame also contains a 32-bit error code (Section 7) that gives the reason for closing the connection ๐งพ.
Endpoints MAY append opaque data to the payload of any GOAWAY frame ๐. Additional debug data is for diagnostic purposes only and carries no semantic value ๐. Debug info could contain security- or privacy-sensitive data, so logged or otherwise persistently stored debug data MUST have adequate safeguards to prevent unauthorized access ๐๐จ.
6.9. WINDOW_UPDATE ๐ช
the WINDOW_UPDATE frame (type=0x8) is how flow control gets implemented ๐. Check out Section 5.2 for the overview โจ.
flow control works at two levels: on each individual stream, and on the entire connection ๐.
both types of flow control are hop by hop, meaning they only happen between the two endpoints ๐ค. Intermediaries do not forward WINDOW_UPDATE frames between dependent connections ๐ซ. That said, if any receiver throttles its data transfer, that can indirectly push flow-control information back toward the original sender ๐.
flow control only applies to frames identified as subject to it. Of the frame types defined in this document, that's only DATA frames ๐ฐ. Frames that are exempt from flow control MUST be accepted and processed, unless the receiver can't assign resources to handle the frame ๐งฏ. A receiver MAY respond with a stream error (Section 5.4.2) or a connection error (Section 5.4.1) of type FLOW_CONTROL_ERROR if it can't accept a frame ๐ค.
+-+-------------------------------------------------------------+
|R| Window Size Increment (31) |
+-+-------------------------------------------------------------+
Figure 14: WINDOW_UPDATE Payload Format ๐ท
the payload of a WINDOW_UPDATE frame is one reserved bit plus an unsigned 31-bit integer. That integer tells you how many octets the sender can transmit on top of the existing flow-control window ๐ธ. The legal range for the increment is 1 to 2^31-1 (2,147,483,647) octets ๐ข.
the WINDOW_UPDATE frame does not define any flags ๐ซง.
a WINDOW_UPDATE frame can target a specific stream or the whole connection ๐ฏ. In the first case, the frame's stream identifier is the affected stream. In the second, the value "0" means the entire connection is the subject of the frame ๐.
A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a flow-control window increment of 0 as a stream error (Section 5.4.2) of type PROTOCOL_ERROR. Errors on the connection flow-control window MUST be treated as a connection error (Section 5.4.1) ๐จ.
WINDOW_UPDATE can be sent by a peer that has already sent a frame bearing the END_STREAM flag ๐. That means a receiver could get a WINDOW_UPDATE frame on a "half-closed (remote)" or "closed" stream. A receiver MUST NOT treat this as an error (see Section 5.1) ๐ฅฐ.
a receiver that gets a flow-controlled frame MUST always count its contribution against the connection flow-control window, unless the receiver treats it as a connection error (Section 5.4.1) ๐. This is necessary even if the frame is in error โ ๏ธ. The sender counts the frame toward the flow-control window, so if the receiver doesn't, the flow-control windows at the sender and receiver can end up different ๐.
A WINDOW_UPDATE frame with a length other than 4 octets MUST be treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR ๐๐.
6.9.1. The Flow-Control Window โจ
okay so flow control in HTTP/2 works by having each sender keep a window on every stream ๐ธ The window is just a simple integer that says how many octets of data the sender is allowed to send right now. Basically, its size tells you how much buffer room the receiver has got ๐ซถ
There are two flow-control windows in play: the stream flow-control window and the connection flow-control window ๐ The sender MUST NOT send a flow-controlled frame with a length bigger than the space left in either of the flow-control windows the receiver advertised. The one exception is frames with zero length that have the END_STREAM flag set (aka an empty DATA frame). Those MAY be sent even if there's no space left in either window ๐
For flow-control math, the 9-octet frame header doesn't count ๐งฎ
After the sender sends a flow-controlled frame, it takes the length of that frame off the space left in both windows ๐
When the receiver consumes data and frees up space, it sends a WINDOW_UPDATE frame to give that room back. Stream-level and connection-level windows each get their own WINDOW_UPDATE frames ๐ฆ
When a sender gets a WINDOW_UPDATE frame, it bumps the matching window up by the amount in the frame. Simple as that ๐
Now the important bit: a sender MUST NOT let a flow-control window go over 2^31-1 octets ๐ญ If a sender gets a WINDOW_UPDATE that pushes a window past that max, it MUST terminate either the stream or the connection, depending on which one it is. For a stream, the sender sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR. For the whole connection, it sends a GOAWAY frame with an error code of FLOW_CONTROL_ERROR. Dramatic, but iconic ๐
Also, flow-controlled frames from the sender and WINDOW_UPDATE frames from the receiver are totally asynchronous with each other ๐ That's the whole point, because it lets a receiver update the sender's window aggressively so streams don't stall. Main character energy for receivers ๐
6.9.2. Initial Flow-Control Window Size ๐ง
When an HTTP/2 connection is first set up, new streams start with an initial flow-control window size of 65,535 octets. The connection flow-control window also starts at 65,535 octets ๐ Either endpoint can change the initial window size for new streams by putting a value for SETTINGS_INITIAL_WINDOW_SIZE in the SETTINGS frame that's part of the connection preface. The connection flow-control window, though, can only be changed with WINDOW_UPDATE frames. Not the SETTINGS frame, bestie ๐ โโ๏ธ
Before a sender has received a SETTINGS frame that sets SETTINGS_INITIAL_WINDOW_SIZE, it can only use the default initial window size when sending flow-controlled frames. Same deal for the connection window: it stays at the default until a WINDOW_UPDATE frame shows up ๐ซ
A SETTINGS frame can also change the initial window size for streams that already have active windows (so streams in the "open" or "half-closed (remote)" state), not just streams that haven't started yet ๐ฅ When the value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust the size of every stream flow-control window it keeps by the difference between the new value and the old one ๐ง
Here's the spicy part: changing SETTINGS_INITIAL_WINDOW_SIZE can make the available space in a window go negative ๐ณ A sender MUST track that negative window, and it MUST NOT send any new flow-controlled frames until WINDOW_UPDATE frames bring the window back to positive. Ngl that's a very real plot twist.
Example time ๐ Say the client sends 60 KB right when the connection is set up, and the server sets the initial window size to 16 KB. When the client gets that SETTINGS frame, it recalculates its available flow-control window as -44 KB. It stays negative until WINDOW_UPDATE frames push it back to positive, and only then can it keep sending ๐ธ
A SETTINGS frame cannot change the connection flow-control window ๐
Finally, an endpoint MUST treat any change to SETTINGS_INITIAL_WINDOW_SIZE that makes any flow-control window go over the maximum size as a connection error (Section 5.4.1) of type FLOW_CONTROL_ERROR. Serious business, periodt ๐
6.9.3. Reducing the Stream Window Size ๐ฆ
Sometimes a receiver wants a smaller flow-control window than the current one, so it can send a new SETTINGS frame to do that. But the receiver MUST be prepared for data that goes past that smaller window, because the sender might already have sent data over the lower limit before it processed the SETTINGS frame ๐ญ Bestie, plan for chaos.
After sending a SETTINGS frame that shrinks the initial flow-control window size, a receiver MAY keep processing streams that go over their flow-control limits. Letting those streams continue doesn't let the receiver instantly shrink the space it's reserving for flow-control windows, though ๐งพ Progress on those streams can also stall, since the sender needs WINDOW_UPDATE frames before it can resume sending. Instead, the receiver MAY send a RST_STREAM with an error code of FLOW_CONTROL_ERROR for the affected streams ๐ฅ
6.10. CONTINUATION ๐
The CONTINUATION frame (type=0x9) is used to keep going with a sequence of header block fragments (Section 4.3) ๐งต You can send as many CONTINUATION frames as you need, as long as the frame before it is on the same stream and is a HEADERS, PUSH_PROMISE, or CONTINUATION frame that doesn't have the END_HEADERS flag set ๐
+---------------------------------------------------------------+
| Header Block Fragment (*) ...
+---------------------------------------------------------------+
Figure 15: CONTINUATION Frame Payload ๐
The CONTINUATION frame payload carries a header block fragment (Section 4.3) ๐ซถ
The CONTINUATION frame defines one flag:
END_HEADERS(0x4): when set, bit 2 indicates that this frame ends a header block (Section 4.3) ๐
If the END_HEADERS bit is not set, this frame MUST be followed by another CONTINUATION frame. A receiver MUST treat receiving any other type of frame, or a frame on a different stream, as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. No skipping the queue, bestie ๐ซ
The CONTINUATION frame changes the connection state as defined in Section 4.3 โจ
CONTINUATION frames MUST be associated with a stream. If a CONTINUATION frame comes in with a stream identifier field of 0x0, the recipient MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ โโ๏ธ
A CONTINUATION frame MUST be preceded by a HEADERS, PUSH_PROMISE or CONTINUATION frame that doesn't have the END_HEADERS flag set. A recipient that spots a violation of this rule MUST respond with a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ค
7. Error Codes ๐จ
Error codes are 32-bit fields used in RST_STREAM and GOAWAY frames to explain the reason for a stream or connection error ๐ง
Error codes share one common code space. Some of them only apply to streams or to the whole connection, and they have no defined meaning in the other context. Context is everything, babe ๐
These are the error codes that are defined:
NO_ERROR(0x0): the condition isn't the result of an error. For example, a GOAWAY might include this code to signal a graceful shutdown of a connection ๐ธPROTOCOL_ERROR(0x1): the endpoint detected an unspecific protocol error. Use this when no more specific error code is available ๐คทโโ๏ธINTERNAL_ERROR(0x2): the endpoint ran into an unexpected internal error ๐ฅFLOW_CONTROL_ERROR(0x3): the endpoint detected that its peer violated the flow-control protocol ๐งSETTINGS_TIMEOUT(0x4): the endpoint sent a SETTINGS frame but didn't get a response in a timely manner. See Section 6.5.3 ("Settings Synchronization") โฐSTREAM_CLOSED(0x5): the endpoint received a frame after a stream was half-closed ๐ชFRAME_SIZE_ERROR(0x6): the endpoint received a frame with an invalid size ๐REFUSED_STREAM(0x7): the endpoint refused the stream before doing any application processing (see Section 8.1.4 for details) ๐ โโ๏ธCANCEL(0x8): the endpoint uses this to say the stream isn't needed anymore ๐COMPRESSION_ERROR(0x9): the endpoint can't maintain the header compression context for the connection ๐๏ธCONNECT_ERROR(0xa): the connection set up in response to a CONNECT request (Section 8.3) got reset or closed abnormally ๐ENHANCE_YOUR_CALM(0xb): the endpoint detected that its peer is doing something that might be generating excessive load ๐งโโ๏ธINADEQUATE_SECURITY(0xc): the underlying transport has properties that don't meet minimum security requirements (see Section 9.2) ๐HTTP_1_1_REQUIRED(0xd): the endpoint needs HTTP/1.1 to be used instead of HTTP/2 ๐ฐ๏ธ
Unknown or unsupported error codes MUST NOT trigger any special behavior. They MAY be treated by an implementation as equivalent to INTERNAL_ERROR. Stay chill about the mystery codes, fr fr ๐ซง
8. HTTP Message Exchanges ๐
HTTP/2 is designed to be as compatible as possible with current uses of HTTP ๐ท From the application's point of view, the features of the protocol mostly stay the same. All request and response semantics are preserved, even though the way those semantics get expressed has changed. Same vibes, new outfit ๐
So the specification and requirements of HTTP/1.1 Semantics and Content [RFC7231], Conditional Requests [RFC7232], Range Requests [RFC7233], Caching [RFC7234], and Authentication [RFC7235] all apply to HTTP/2 ๐ Some parts of HTTP/1.1 Message Syntax and Routing [RFC7230], like the HTTP and HTTPS URI schemes, also apply in HTTP/2. But the way those semantics are expressed for this protocol gets defined in the sections below ๐โจ
8.1. HTTP Request/Response Exchange ๐
okay so a client sends an HTTP request on a brand-new stream ๐ฆ, using a stream identifier nobody has used yet (see Section 5.1.1). the server then sends its HTTP response on that same stream โจ
an HTTP message (request or response) is built out of these pieces ๐:
- for a response only, zero or more HEADERS frames (each followed by zero or more CONTINUATION frames) holding the message headers of informational (1xx) HTTP responses (see [RFC7230], Section 3.2 and [RFC7231], Section 6.2),
- one HEADERS frame (followed by zero or more CONTINUATION frames) holding the message headers (see [RFC7230], Section 3.2),
- zero or more DATA frames holding the payload body (see [RFC7230], Section 3.3), and
- optionally, one HEADERS frame, followed by zero or more CONTINUATION frames holding the trailer-part, if present (see [RFC7230], Section 4.1.2).
the last frame in the sequence has an END_STREAM flag on it. a HEADERS frame with END_STREAM can still be followed by CONTINUATION frames that carry whatever's left of the header block ๐ง
Other frames (from any stream) MUST NOT sneak in between the HEADERS frame and any CONTINUATION frames that might follow. no interrupting the header block, periodt ๐
HTTP/2 uses DATA frames to carry message payloads. the "chunked" transfer encoding from Section 4.1 of [RFC7230] MUST NOT be used in HTTP/2. no chunking here, bestie ๐
Trailing header fields ride in a header block that also ends the stream ๐ธ. that block is a sequence that starts with a HEADERS frame, followed by zero or more CONTINUATION frames, and the HEADERS frame has an END_STREAM flag. any header blocks after the first one that don't end the stream are not part of an HTTP request or response, so they don't count ๐ โโ๏ธ
A HEADERS frame (and its CONTINUATION frames) can only show up at the start or the end of a stream. if an endpoint gets a HEADERS frame without END_STREAM set after it has already received a final (non-informational) status code, it MUST treat the request or response as malformed (Section 8.1.2.6). that's a big no ๐
An HTTP request/response exchange fully uses up a single stream ๐งธ. a request starts with the HEADERS frame that puts the stream into an "open" state. the request ends with a frame bearing END_STREAM, which makes the stream "half-closed (local)" for the client and "half-closed (remote)" for the server. a response starts with a HEADERS frame and ends with a frame bearing END_STREAM, and that puts the stream in the "closed" state ๐
An HTTP response is complete once the server sends (or the client receives) a frame with the END_STREAM flag set, including any CONTINUATION frames needed to finish a header block โจ. a server can send a complete response before the client has finished sending the whole request, but only if the response doesn't depend on any part of the request that hasn't been sent and received yet ๐. when that's true, a server MAY ask the client to stop sending the request without it counting as an error, by sending a RST_STREAM with an error code of NO_ERROR after the complete response (i.e., a frame with the END_STREAM flag). Clients MUST NOT throw away responses just because they got that RST_STREAM, though clients can always toss responses at their discretion for other reasons ๐๏ธ
the tea: a RST_STREAM with NO_ERROR does not mean the response got cancelled. clients still have to keep it ๐ญ
8.1.1. Upgrading from HTTP/2
HTTP/2 drops support for the 101 (Switching Protocols) informational status code ([RFC7231], Section 6.2.2) ๐
the semantics of 101 (Switching Protocols) just don't apply to a multiplexed protocol. alternative protocols can use the same mechanisms HTTP/2 uses to negotiate their use instead (see Section 3) ๐
8.1.2. HTTP Header Fields
HTTP header fields carry information as a series of key-value pairs ๐. for a list of registered HTTP headers, check out the "Message Header Field" registry maintained at https://www.iana.org/assignments/message-headers.
just like in HTTP/1.x, header field names are strings of ASCII characters that get compared in a case-insensitive way. BUT in HTTP/2, header field names MUST be converted to lowercase before they get encoded. a request or response with uppercase header field names MUST be treated as malformed (Section 8.1.2.6). lowercase only, no exceptions, iykyk ๐
8.1.2.1. Pseudo-Header Fields
in HTTP/1.x, the message start-line (see [RFC7230], Section 3.1) carried the target URI, the request method, and the status code for responses. HTTP/2 does it differently and uses special pseudo-header fields that start with the ':' character (ASCII 0x3a) ๐งโโ๏ธ
pseudo-header fields are not HTTP header fields ๐ . Endpoints MUST NOT generate any pseudo-header fields other than the ones defined in this document ๐ซ
pseudo-header fields only work in the context they're defined for. pseudo-header fields defined for requests MUST NOT appear in responses, and pseudo-header fields defined for responses MUST NOT appear in requests. pseudo-header fields MUST NOT appear in trailers either. Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed (Section 8.1.2.6). very strict, very iconic ๐
All pseudo-header fields MUST appear in the header block before the regular header fields. any request or response that has a pseudo-header field showing up after a regular header field MUST be treated as malformed (Section 8.1.2.6). order matters, bestie ๐ซถ
8.1.2.2. Connection-Specific Header Fields
HTTP/2 doesn't use the Connection header field to signal connection-specific header fields. in this protocol, connection-specific metadata gets conveyed some other way ๐ค๏ธ. An endpoint MUST NOT generate an HTTP/2 message containing connection-specific header fields, and any message with connection-specific header fields MUST be treated as malformed (Section 8.1.2.6).
the only exception is the TE header field. it MAY be present in an HTTP/2 request, and when it is, it MUST NOT contain any value other than "trailers" ๐
this means an intermediary turning an HTTP/1.x message into HTTP/2 will need to remove any header fields nominated by the Connection header field, plus the Connection header field itself ๐งน. such intermediaries SHOULD also remove the other connection-specific header fields, like Keep-Alive, Proxy-Connection, Transfer-Encoding, and Upgrade, even if the Connection header field doesn't nominate them ๐ซง
Note: HTTP/2 purposefully does not support upgrade to another protocol. the handshake methods described in Section 3 are believed sufficient to negotiate the use of alternative protocols ๐ฆ
8.1.2.3. Request Pseudo-Header Fields
these pseudo-header fields are defined for HTTP/2 requests ๐:
- The ":method" pseudo-header field includes the HTTP method ([RFC7231], Section 4).
- The ":scheme" pseudo-header field includes the scheme portion of the target URI ([RFC3986], Section 3.1).
":scheme" isn't restricted to "http" and "https" schemed URIs ๐. a proxy or gateway can translate requests for non-HTTP schemes, which lets you use HTTP to talk to non-HTTP services. wild, right? ๐คฏ
- The ":authority" pseudo-header field includes the authority portion of the target URI ([RFC3986], Section 3.2). The authority MUST NOT include the deprecated "userinfo" subcomponent for "http" or "https" schemed URIs.
to make sure 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 origin or asterisk form (see [RFC7230], Section 5.3). Clients that generate HTTP/2 requests directly SHOULD use the ":authority" pseudo-header field instead of the Host header field ๐ฎ. An intermediary that converts an HTTP/2 request to HTTP/1.1 MUST create a Host header field if one isn't present in the request, by copying the value of the ":authority" pseudo-header field.
- The ":path" pseudo-header field includes the path and query parts of the target URI (the "path-absolute" production, and optionally a '?' character followed by the "query" production; see Sections 3.3 and 3.4 of [RFC3986]). A request in asterisk form includes the value '*' for the ":path" pseudo-header field โญ.
This pseudo-header field MUST NOT be empty for "http" or "https" URIs. "http" or "https" URIs that don't have a path component MUST include a value of '/'. the exception is an OPTIONS request for an "http" or "https" URI with no path component. those MUST include a ":path" pseudo-header field with a value of '*' (see [RFC7230], Section 5.3.4) ๐ง
All HTTP/2 requests MUST include exactly one valid value for the ":method", ":scheme", and ":path" pseudo-header fields, unless it's a CONNECT request (Section 8.3). an HTTP request that leaves out mandatory pseudo-header fields is malformed (Section 8.1.2.6) ๐
HTTP/2 doesn't define a way to carry the version identifier that shows up in the HTTP/1.1 request line ๐
8.1.2.4. Response Pseudo-Header Fields
for HTTP/2 responses, there's one ":status" pseudo-header field that carries the HTTP status code field (see [RFC7231], Section 6) ๐. This pseudo-header field MUST be included in all responses. otherwise the response is malformed (Section 8.1.2.6) ๐ฉ
HTTP/2 also doesn't define a way to carry the version or reason phrase that an HTTP/1.1 status line includes ๐ซ
8.1.2.5. Compressing the Cookie Header Field
the Cookie header field [COOKIE] uses a semicolon (";") to separate cookie-pairs (or "crumbs") ๐ช. this header field doesn't follow the list construction rules in HTTP (see [RFC7230], Section 3.2.2), so cookie-pairs can't be split into different name-value pairs. that can seriously hurt compression efficiency when individual cookie-pairs get updated ๐ค
for better compression efficiency, the Cookie header field MAY be split into separate header fields, each holding one or more cookie-pairs ๐งฉ. if there are multiple Cookie header fields after decompression, they MUST be concatenated into a single octet string using the two-octet delimiter 0x3B, 0x20 (the ASCII string "; ") before being passed into a non-HTTP/2 context, like an HTTP/1.1 connection or a generic HTTP server application ๐
so these two lists of Cookie header fields are semantically equivalent ๐ฏ:
cookie: a=b; c=d; e=f
cookie: a=b
cookie: c=d
cookie: e=f
8.1.2.6. Malformed Requests and Responses ๐ซ
okay so a malformed request or response is one that's still a valid sequence of HTTP/2 frames, but it's invalid because of extra frames, prohibited header fields, missing mandatory header fields, or uppercase header field names. bestie, no uppercase allowed, it's giving strict ๐
A request or response with a payload body can include a content-length header field. ๐ But the request or response is also malformed if the content-length value doesn't match the sum of the DATA frame payload lengths that make up the body. Math has to be mathing ๐งฎ
Here's a fun exception: a response that's defined to have no payload (see [RFC7230], Section 3.3.2) can have a non-zero content-length header field even though no content shows up in DATA frames. ๐ฆ That's allowed, so don't freak out lol
Intermediaries that process HTTP requests or responses (so, any intermediary that isn't acting as a tunnel) MUST NOT forward a malformed request or response. ๐
โโ๏ธ If a malformed request or response gets detected, it MUST be treated as a stream error (Section 5.4.2) of type PROTOCOL_ERROR. no exceptions, periodt ๐
For malformed requests, a server MAY send an HTTP response before closing or resetting the stream. ๐ธ But clients MUST NOT accept a malformed response. Honestly these rules are super strict on purpose, because being permissive can expose implementations to common HTTP attacks. the strictness is literally protecting everyone ๐ซถ
8.1.3. Examples ๐
okay so this section shows HTTP/1.1 requests and responses next to their HTTP/2 equivalents. it's so satisfying to compare them side by side โจ
An HTTP GET request has request header fields and no payload body, so it gets sent as one HEADERS frame, followed by zero or more CONTINUATION frames carrying the serialized block of request header fields. In the example below, the HEADERS frame has both the END_HEADERS and END_STREAM flags set, so no CONTINUATION frames get sent. ๐ง
GET /resource HTTP/1.1 HEADERS
Host: example.org ==> + END_STREAM
Accept: image/jpeg + END_HEADERS
:method = GET
:scheme = https
:path = /resource
host = example.org
accept = image/jpeg
Similarly, a response that only has response header fields is sent as a HEADERS frame (again, followed by zero or more CONTINUATION frames) carrying the serialized block of response header fields. ๐
HTTP/1.1 304 Not Modified HEADERS
ETag: "xyzzy" ==> + END_STREAM
Expires: Thu, 23 Jan ... + END_HEADERS
:status = 304
etag = "xyzzy"
expires = Thu, 23 Jan ...
An HTTP POST request with request header fields and payload data goes out as one HEADERS frame, then zero or more CONTINUATION frames with the request header fields, then one or more DATA frames. The last CONTINUATION (or HEADERS) frame has the END_HEADERS flag set, and the final DATA frame has the END_STREAM flag set. ๐
POST /resource HTTP/1.1 HEADERS
Host: example.org ==> - END_STREAM
Content-Type: image/jpeg - END_HEADERS
Content-Length: 123 :method = POST
:path = /resource
{binary data} :scheme = https
CONTINUATION
+ END_HEADERS
content-type = image/jpeg
host = example.org
content-length = 123
DATA
+ END_STREAM
{binary data}
Note that data for any given header field could be spread across header block fragments. The way header fields get split up between frames in this example is just for illustration. ๐
A response with header fields and payload data goes out as a HEADERS frame, then zero or more CONTINUATION frames, then one or more DATA frames. The last DATA frame in the sequence has the END_STREAM flag set. โจ
HTTP/1.1 200 OK HEADERS
Content-Type: image/jpeg ==> - END_STREAM
Content-Length: 123 + END_HEADERS
:status = 200
{binary data} content-type = image/jpeg
content-length = 123
DATA
+ END_STREAM
{binary data}
An informational response with a 1xx status code other than 101 is sent as a HEADERS frame, followed by zero or more CONTINUATION frames. ๐ฆ
Trailing header fields get sent as a header block after both the request or response header block and all the DATA frames have been sent. The HEADERS frame that starts the trailers header block has the END_STREAM flag set. ๐
The following example has both a 100 (Continue) status code, which is sent in response to a request with a "100-continue" token in the Expect header field, and trailing header fields. it's giving full package ๐ฆ
HTTP/1.1 100 Continue HEADERS
Extension-Field: bar ==> - END_STREAM
+ END_HEADERS
:status = 100
extension-field = bar
HTTP/1.1 200 OK HEADERS
Content-Type: image/jpeg ==> - END_STREAM
Transfer-Encoding: chunked + END_HEADERS
Trailer: Foo :status = 200
content-length = 123
123 content-type = image/jpeg
{binary data} trailer = Foo
0
Foo: bar DATA
- END_STREAM
{binary data}
HEADERS
+ END_STREAM
+ END_HEADERS
foo = bar
8.1.4. Request Reliability Mechanisms in HTTP/2 ๐ก๏ธ
okay so in HTTP/1.1, a client can't retry a non-idempotent request when an error happens, because there's no way to tell what kind of error it was. ๐ฌ Some server processing might have already happened before the error, and retrying could cause some seriously undesirable effects.
HTTP/2 gives clients two mechanisms that guarantee a request hasn't been processed:
- The GOAWAY frame indicates the highest stream number that might have been processed. Requests on streams with higher numbers are therefore guaranteed to be safe to retry. ๐
- The
REFUSED_STREAMerror code can be included in a RST_STREAM frame to show that the stream is being closed before any processing happened. Any request that was sent on the reset stream can be safely retried. ๐
Requests that haven't been processed haven't failed. Clients MAY automatically retry them, even ones with non-idempotent methods. ๐
A server MUST NOT indicate that a stream hasn't been processed unless it can guarantee that fact. ๐
โโ๏ธ If frames on a stream get passed to the application layer for any stream, then REFUSED_STREAM MUST NOT be used for that stream, and a GOAWAY frame MUST include a stream identifier that is greater than or equal to the given stream identifier. no shortcuts, bestie ๐ซถ
Also, the PING frame gives a client an easy way to test a connection. ๐ Connections that sit idle can break because some middleboxes (for instance, network address translators or load balancers) silently discard connection bindings. The PING frame lets a client safely check whether a connection is still active without sending a request. โญ
8.2. Server Push ๐
HTTP/2 lets a server pre-emptively send (or "push") responses, along with corresponding "promised" requests, to a client in association with a previous client-initiated request. ๐ This can be super useful when the server knows the client will need those responses to fully process the response to the original request.
A client can ask for server push to be disabled, though this is negotiated for each hop independently. ๐ The SETTINGS_ENABLE_PUSH setting can be set to 0 to indicate that server push is disabled.
Promised requests MUST be cacheable (see [RFC7231], Section 4.2.3), MUST be safe (see [RFC7231], Section 4.2.1), and MUST NOT include a request body. ๐ง Clients that receive a promised request that isn't cacheable, isn't known to be safe, or indicates a request body is present MUST reset the promised stream with a stream error (Section 5.4.2) of type PROTOCOL_ERROR. Note this could result in the promised stream being reset if the client doesn't recognize a newly defined method as safe. ๐
Pushed responses that are cacheable (see [RFC7234], Section 3) can be stored by the client, if it implements an HTTP cache. ๐พ Pushed responses are considered successfully validated on the origin server (for example, if the "no-cache" cache response directive is present ([RFC7234], Section 5.2.2)) while the stream identified by the promised stream ID is still open. โ
Pushed responses that aren't cacheable MUST NOT be stored by any HTTP cache. They MAY be made available to the application separately. ๐ท
The server MUST include a value in the ":authority" pseudo-header field for which the server is authoritative (see Section 10.1). ๐ A client MUST treat a PUSH_PROMISE for which the server isn't authoritative as a stream error (Section 5.4.2) of type PROTOCOL_ERROR.
An intermediary can receive pushes from the server and choose not to forward them to the client. In other words, how to make use of the pushed information is up to that intermediary. ๐ง Equally, the intermediary might choose to make additional pushes to the client, without any action taken by the server.
A client cannot push, so servers MUST treat receiving a PUSH_PROMISE frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. ๐จ Clients MUST reject any attempt to change the SETTINGS_ENABLE_PUSH setting to a value other than 0, treating the message as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. ๐
8.2.1. Push Requests
okay so server push is basically the same thing as the server answering a request ๐ , except this time the server is also the one who makes up the request and sends it as a PUSH_PROMISE frame ๐
The PUSH_PROMISE frame carries a header block with a complete set of request header fields that the server attributes to the request. And no, you can't push a response to a request that has a request body ๐ โโ๏ธ
Pushed responses are always tied to an explicit request from the client. The PUSH_PROMISE frames the server sends go out on that explicit request's stream. The PUSH_PROMISE frame also includes a promised stream identifier, picked from the stream identifiers the server is allowed to use (see Section 5.1.1) โจ
The header fields in PUSH_PROMISE and any CONTINUATION frames after it MUST be a valid and complete set of request header fields (Section 8.1.2.3) ๐ The server MUST put a method in the :method pseudo-header field that is safe and cacheable ๐ If a client gets a PUSH_PROMISE that doesn't have a complete and valid set of header fields, or its :method pseudo-header field names a method that isn't safe, the client MUST respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR ๐
The server SHOULD send PUSH_PROMISE (Section 6.6) frames before it sends any frames that reference the promised responses ๐ง This avoids a race where clients fire off requests before they've even seen a PUSH_PROMISE frame ๐
Here's an example. Say the server gets a request for a doc with embedded links to a bunch of image files, and it decides to push those images. If the PUSH_PROMISE frames show up before the DATA frames with the image links, the client can see that a resource is about to be pushed before it even finds the embedded links ๐ฆ Same deal if the server pushes responses that are referenced in the header block (like in Link header fields). Sending a PUSH_PROMISE before the header block means clients won't go requesting those resources themselves ๐
PUSH_PROMISE frames MUST NOT be sent by the client. Only the server gets to do that one ๐ โโ๏ธ
The server can send PUSH_PROMISE frames in response to any client-initiated stream, but that stream MUST be in either the open or half-closed (remote) state with respect to the server ๐ฅ PUSH_PROMISE frames can be mixed in with the frames that make up a response, but they can't be wedged in between the HEADERS and CONTINUATION frames that make up a single header block ๐ซถ
Sending a PUSH_PROMISE frame creates a new stream and moves it into the reserved (local) state for the server and the reserved (remote) state for the client โญ
8.2.2. Push Responses
Once the PUSH_PROMISE frame is out, the server can start delivering the pushed response as a response (Section 8.1.2.4) on a server-initiated stream that uses the promised stream identifier ๐ It sends an HTTP response using the same sequence of frames defined in Section 8.1 ๐ After the initial HEADERS frame goes out, this stream becomes half-closed to the client (Section 5.1) ๐ฆ
Once a client gets a PUSH_PROMISE frame and decides to accept the pushed response, the client SHOULD NOT issue any requests for the promised response until the promised stream has closed ๐
If the client decides, for any reason, that it doesn't want the pushed response, or if the server takes too long to start sending the promised response, the client can send a RST_STREAM frame. It can use either the CANCEL or REFUSED_STREAM code, and it references the pushed stream's identifier ๐
โโ๏ธ
A client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting to limit how many responses a server can push at the same time ๐
If it advertises a SETTINGS_MAX_CONCURRENT_STREAMS value of zero, server push is turned off, since the server can't create the streams it needs ๐ That doesn't stop the server from sending PUSH_PROMISE frames though, so clients need to reset any promised streams they don't want ๐
Clients that receive a pushed response MUST check that either the server is authoritative (see Section 10.1) or the proxy that provided the pushed response is configured for the corresponding request ๐ฅ For example, a server whose certificate is only for the "example.com" DNS-ID or Common Name is not allowed to push a response for https://www.example.org/doc ๐ญ
The response for a PUSH_PROMISE stream starts with a HEADERS frame, which immediately puts the stream into the half-closed (remote) state for the server and the half-closed (local) state for the client ๐ธ It ends with a frame carrying END_STREAM, which puts the stream in the closed state ๐ง
Note: The client never sends a frame with the END_STREAM flag for a server push. ๐ซถ
8.3. The CONNECT Method
In HTTP/1.x, the pseudo-method CONNECT ([RFC7231], Section 4.3.6) turns an HTTP connection into a tunnel to a remote host ๐ It's mostly used with HTTP proxies to set up a TLS session with an origin server so you can talk to https resources ๐
In HTTP/2, CONNECT does the same kind of job: it sets up a tunnel to a remote host over a single HTTP/2 stream ๐ฆ The HTTP header field mapping works as defined in Section 8.1.2.3 ("Request Pseudo-Header Fields"), with a few differences ๐ Specifically:
- The
:methodpseudo-header field is set toCONNECT. ๐ - The
:schemeand:pathpseudo-header fields MUST be omitted. ๐ โโ๏ธ - The
:authoritypseudo-header field contains the host and port to connect to. This is the same as the authority-form of the request-target of CONNECT requests (see [RFC7230], Section 5.3) โจ
A CONNECT request that doesn't follow these restrictions is malformed (Section 8.1.2.6) ๐
A proxy that supports CONNECT sets up a TCP connection [TCP] to the server named in the :authority pseudo-header field ๐ Once that connection is successfully established, the proxy sends a HEADERS frame with a 2xx series status code to the client, as defined in [RFC7231], Section 4.3.6 ๐
After the initial HEADERS frame from each peer, every DATA frame that follows is data sent on the TCP connection ๐ The payload of any DATA frames the client sends gets passed along by the proxy to the TCP server, and data coming back from the TCP server gets packed into DATA frames by the proxy ๐ซถ Frame types other than DATA or the stream management frames (RST_STREAM, WINDOW_UPDATE, and PRIORITY) MUST NOT be sent on a connected stream. If one is received, it MUST be treated as a stream error (Section 5.4.2) ๐ฅ
Either peer can close the TCP connection ๐ช The END_STREAM flag on a DATA frame is treated as equivalent to the TCP FIN bit ๐ฆ A client is expected to send a DATA frame with the END_STREAM flag set after it receives a frame bearing the END_STREAM flag ๐ A proxy that gets a DATA frame with END_STREAM set sends the attached data with the FIN bit set on the last TCP segment ๐ง A proxy that gets a TCP segment with the FIN bit set sends a DATA frame with the END_STREAM flag set ๐ธ Heads up: the final TCP segment or DATA frame could be empty ๐
A TCP connection error is signaled with RST_STREAM ๐จ A proxy treats any error in the TCP connection as a stream error (Section 5.4.2) of type CONNECT_ERROR. That includes receiving a TCP segment with the RST bit set ๐ญ To match, a proxy MUST send a TCP segment with the RST bit set if it detects an error with the stream or the HTTP/2 connection ๐ฅ
9. Additional HTTP Requirements/Considerations โจ
This section lays out attributes of the HTTP protocol that improve interoperability, reduce exposure to known security vulnerabilities, or reduce the potential for implementation variation ๐ก๏ธ
9.1. Connection Management
HTTP/2 connections are persistent ๐ For best performance, clients are expected to hold on to connections until they've decided no more communication with a server is needed (for example, when a user navigates away from a particular web page), or until the server closes the connection ๐
Clients SHOULD NOT open more than one HTTP/2 connection to a given host and port pair. The host can come from a URI, a selected alternative service [ALT-SVC], or a configured proxy ๐ โโ๏ธ
A client can create additional connections as replacements. It might do this to replace connections that are close to running out of stream identifier space (Section 5.1.1), to refresh the keying material for a TLS connection, or to replace connections that have hit errors (Section 5.4.1) ๐
A client MAY open multiple connections to the same IP address and TCP port using different Server Name Indication [TLS-EXT] values, or to present different TLS client certificates. It SHOULD avoid creating multiple connections with the same configuration ๐ฆ
Servers are encouraged to keep connections open for as long as possible, but they're allowed to close idle connections if they need to ๐ง When either endpoint decides to close the transport-layer TCP connection, the endpoint that's closing SHOULD first send a GOAWAY (Section 6.8) frame. That way, both endpoints can reliably tell whether previously sent frames were processed, and they can gracefully finish or wrap up any remaining tasks ๐
9.1.1. Connection Reuse
Connections made to an origin server, either directly or through a tunnel created with the CONNECT method (Section 8.3), MAY be reused for requests with multiple different URI authority components ๐ธ A connection can be reused as long as the origin server is authoritative (Section 10.1) ๐ For TCP connections without TLS, this depends on the host having resolved to the same IP address ๐
For https resources, connection reuse also depends on having a certificate that is valid for the host in the URI ๐ The certificate the server presents MUST satisfy any checks the client would perform when forming a new TLS connection for the host in the URI ๐ฅ
An origin server might offer a certificate with multiple "subjectAltName" attributes, or names with wildcards, where one of them is valid for the authority in the URI ๐ For example, a certificate with a "subjectAltName" of *.example.com might allow the same connection to be used for requests to URIs starting with https://a.example.com/ and https://b.example.com/ ๐ฆ
In some deployments, reusing a connection for multiple origins can send requests to the wrong origin server ๐ฌ For example, TLS termination might be handled by a middlebox that uses the TLS Server Name Indication (SNI) [TLS-EXT] extension to pick an origin server. So it's possible for clients to send confidential information to servers that aren't the intended target for the request, even when the server is otherwise authoritative ๐จ
A server that doesn't want clients reusing connections can say it's not authoritative for a request by sending a 421 (Misdirected Request) status code in response to the request (see Section 9.1.2) ๐
โโ๏ธ
A client that's configured to use a proxy over HTTP/2 sends requests to that proxy through a single connection. In other words, all requests sent via a proxy reuse the connection to the proxy ๐ซถ
9.1.2. The 421 (Misdirected Request) Status Code ๐
okay so the 421 (Misdirected Request) status code is the server basically saying "wrong address, bestie ๐." It means the request was sent to a server that can't produce a response for it. This can happen when a server isn't set up to answer for the combination of scheme and authority that shows up in the request URI ๐.
Clients that get a 421 (Misdirected Request) response from a server MAY retry the request over a different connection, whether the request method is idempotent or not ๐ฆ. This is possible if a connection is reused (Section 9.1.1) or if an alternative service is selected [ALT-SVC] โจ.
This status code MUST NOT be generated by proxies ๐ซ.
A 421 response is cacheable by default, unless the method definition or explicit cache controls say otherwise (see Section 4.2.2 of [RFC7234]) ๐.
9.2. Use of TLS Features ๐
Implementations of HTTP/2 MUST use TLS version 1.2 [TLS12] or higher for HTTP/2 over TLS ๐ฅ. The general TLS usage guidance in [TLSBCP] SHOULD be followed, with some extra restrictions that are specific to HTTP/2 ๐ซถ.
The TLS implementation MUST support the Server Name Indication (SNI) [TLS-EXT] extension to TLS ๐ธ. HTTP/2 clients MUST indicate the target domain name when negotiating TLS ๐.
Deployments of HTTP/2 that negotiate TLS 1.3 or higher only need to support and use the SNI extension โจ. Deployments of TLS 1.2 are subject to the requirements in the following sections. Implementations are encouraged to provide defaults that comply, but it's recognized that deployments are ultimately responsible for compliance ๐ .
9.2.1. TLS 1.2 Features ๐ง
This section describes restrictions on the TLS 1.2 feature set that can be used with HTTP/2 ๐. Due to deployment limitations, it might not be possible to fail TLS negotiation when these restrictions aren't met. An endpoint MAY immediately terminate an HTTP/2 connection that doesn't meet these TLS requirements with a connection error (Section 5.4.1) of type INADEQUATE_SECURITY โญ.
A deployment of HTTP/2 over TLS 1.2 MUST disable compression ๐ โโ๏ธ. TLS compression can lead to the exposure of information that wouldn't otherwise be revealed [RFC3749]. Generic compression is unnecessary since HTTP/2 has compression features that are more aware of context, and so are likely to be more appropriate for performance, security, or other reasons ๐.
A deployment of HTTP/2 over TLS 1.2 MUST disable renegotiation ๐ซ. An endpoint MUST treat a TLS renegotiation as a connection error (Section 5.4.1) of type PROTOCOL_ERROR ๐ญ. Heads up: disabling renegotiation can make long-lived connections unusable, because of limits on the number of messages the underlying cipher suite can encipher ๐ฅบ.
An endpoint MAY use renegotiation to protect the confidentiality of client credentials offered in the handshake, but any renegotiation MUST occur before the connection preface is sent ๐. A server SHOULD request a client certificate if it sees a renegotiation request immediately after establishing a connection ๐ชช.
This basically rules out using renegotiation in response to a request for a specific protected resource ๐. A future specification might provide a way to support this use case. Alternatively, a server might use an error (Section 5.4) of type HTTP_1_1_REQUIRED to ask the client to use a protocol that supports renegotiation ๐.
Implementations MUST support ephemeral key exchange sizes of at least 2048 bits for cipher suites that use ephemeral finite field Diffie-Hellman (DHE) [TLS12], and 224 bits for cipher suites that use ephemeral elliptic curve Diffie-Hellman (ECDHE) [RFC4492] ๐ซง. Clients MUST accept DHE sizes of up to 4096 bits ๐. Endpoints MAY treat negotiation of key sizes smaller than these lower limits as a connection error (Section 5.4.1) of type INADEQUATE_SECURITY โ ๏ธ.
9.2.2. TLS 1.2 Cipher Suites ๐
A deployment of HTTP/2 over TLS 1.2 SHOULD NOT use any of the cipher suites listed in the cipher suite black list (Appendix A) ๐ซ๐ .
Endpoints MAY choose to generate a connection error (Section 5.4.1) of type INADEQUATE_SECURITY if one of the cipher suites from the black list is negotiated. A deployment that chooses to use a black-listed cipher suite risks triggering a connection error, unless the set of potential peers is known to accept that cipher suite ๐ฌ.
Implementations MUST NOT generate this error in reaction to the negotiation of a cipher suite that isn't on the black list ๐ โโ๏ธ. So when clients offer a cipher suite that isn't on the black list, they have to be prepared to use that cipher suite with HTTP/2 ๐ซถ.
The black list includes the cipher suite that TLS 1.2 makes mandatory, which means TLS 1.2 deployments could end up with non-intersecting sets of permitted cipher suites ๐งฉ. To keep this from causing TLS handshake failures, deployments of HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] with the P-256 elliptic curve [FIPS186] ๐.
Clients might advertise support for cipher suites that are on the black list so they can connect to servers that don't support HTTP/2 ๐ธ. This lets servers select HTTP/1.1 with a cipher suite that's on the HTTP/2 black list. However, this can result in HTTP/2 being negotiated with a black-listed cipher suite if the application protocol and cipher suite are selected independently ๐.
10. Security Considerations ๐จ
10.1. Server Authority ๐
HTTP/2 relies on the HTTP/1.1 definition of authority to decide whether a server is authoritative for a given response (see [RFC7230], Section 9.1). For the http URI scheme this relies on local name resolution, and for the https scheme it relies on the authenticated server identity (see [RFC2818], Section 3) ๐.
10.2. Cross-Protocol Attacks ๐
In a cross-protocol attack, an attacker causes a client to start a transaction in one protocol toward a server that understands a different protocol ๐จ. The attacker might be able to make the transaction look like a valid transaction in the second protocol. Combined with the capabilities of the web context, this can be used to interact with poorly protected servers in private networks ๐.
Completing a TLS handshake with an ALPN identifier for HTTP/2 can be considered sufficient protection against cross-protocol attacks ๐ก๏ธ. ALPN gives a positive indication that a server is willing to proceed with HTTP/2, which prevents attacks on other TLS-based protocols โจ.
The encryption in TLS makes it hard for attackers to control the data that could be used in a cross-protocol attack on a cleartext protocol ๐.
The cleartext version of HTTP/2 has minimal protection against cross-protocol attacks ๐ญ. The connection preface (Section 3.5) contains a string designed to confuse HTTP/1.1 servers, but no special protection is offered for other protocols. A server that is willing to ignore parts of an HTTP/1.1 request containing an Upgrade header field, in addition to the client connection preface, could be exposed to a cross-protocol attack ๐ฉ.
10.3. Intermediary Encapsulation Attacks ๐ต๏ธโโ๏ธ
The HTTP/2 header field encoding allows the expression of names that aren't valid field names in the Internet Message Syntax used by HTTP/1.1 ๐. Requests or responses containing invalid header field names MUST be treated as malformed (Section 8.1.2.6). So an intermediary can't translate an HTTP/2 request or response with an invalid field name into an HTTP/1.1 message ๐ โโ๏ธ.
HTTP/2 also allows header field values that aren't valid ๐ฌ. Most of the values that can be encoded won't change header field parsing, but carriage return (CR, ASCII 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII 0x0) might be exploited by an attacker if they're translated verbatim ๐ฅ. Any request or response that contains a character not permitted in a header field value MUST be treated as malformed (Section 8.1.2.6). Valid characters are defined by the field-content ABNF rule in Section 3.2 of [RFC7230] ๐.
10.4. Cacheability of Pushed Responses ๐๏ธ
Pushed responses don't have an explicit request from the client. The request is provided by the server in the PUSH_PROMISE frame ๐.
Caching pushed responses is possible based on the guidance the origin server gives in the Cache-Control header field. However, this can cause issues if a single server hosts more than one tenant ๐ต. For example, a server might offer multiple users each a small portion of its URI space ๐ .
Where multiple tenants share space on the same server, that server MUST ensure that tenants can't push representations of resources they don't have authority over ๐. Failing to enforce this would let a tenant provide a representation that gets served out of cache, overriding the actual representation the authoritative tenant provides ๐ค.
Pushed responses for which an origin server is not authoritative (see Section 10.1) MUST NOT be used or cached ๐ซ.
10.5. Denial-of-Service Considerations ๐
An HTTP/2 connection can demand a bigger commitment of resources to operate than an HTTP/1.1 connection ๐ฅน. Header compression and flow control depend on committing resources to store a larger amount of state. Settings for these features make sure that memory commitments for them are strictly bounded ๐.
The number of PUSH_PROMISE frames isn't constrained in the same way ๐. A client that accepts server push SHOULD limit the number of streams it allows to be in the reserved (remote) state. An excessive number of server push streams can be treated as a stream error (Section 5.4.2) of type ENHANCE_YOUR_CALM ๐ค.
Processing capacity can't be guarded as effectively as state capacity ๐ง .
The SETTINGS frame can be abused to make a peer spend extra processing time ๐. This might be done by pointlessly changing SETTINGS parameters, setting multiple undefined parameters, or changing the same setting several times in the same frame. WINDOW_UPDATE or PRIORITY frames can be abused to waste resources unnecessarily ๐๏ธ.
Large numbers of small or empty frames can be abused to make a peer spend time processing frame headers ๐. Note, though, that some uses are totally legitimate, like sending an empty DATA or CONTINUATION frame at the end of a stream โ .
Header compression also offers some chances to waste processing resources. See Section 7 of [COMPRESSION] for more details on potential abuses ๐งฉ.
Limits in SETTINGS parameters can't be reduced instantly, which leaves an endpoint exposed to behavior from a peer that could exceed the new limits โณ. Specifically, right after a connection is established, the limits a server sets aren't known to clients, and they could be exceeded without it being an obvious protocol violation ๐ณ.
All of these features (SETTINGS changes, small frames, header compression) have legitimate uses ๐. They only become a burden when they're used unnecessarily or to excess ๐ .
An endpoint that doesn't monitor this behavior is exposing itself to a risk of denial-of-service attack ๐จ. Implementations SHOULD track the use of these features and set limits on their use. An endpoint MAY treat suspicious activity as a connection error (Section 5.4.1) of type ENHANCE_YOUR_CALM ๐ซ .
10.5.1. Limits on Header Block Size โจ
okay so a big header block (see Section 4.3) can make an implementation hold onto a LOT of state ๐ญ. routing-critical header fields can show up near the very end of a block, which means you can't stream them on to their ultimate destination ๐ซ. that ordering, plus other stuff like keeping caches correct, means an endpoint might have to buffer the entire header block. and since there's no hard limit on how big a header block can get, some endpoints could be forced to commit a huge chunk of their memory just for header fields ๐
an endpoint can use SETTINGS_MAX_HEADER_LIST_SIZE to give its peers a heads-up about limits that might apply to header block size ๐ซถ. but this setting is only advisory, so endpoints MAY choose to send header blocks bigger than the limit and risk the request or response getting treated as malformed ๐. it's specific to a connection, so any request or response could run into a hop with a lower, unknown limit. an intermediary can try to avoid that by passing on values from different peers, but they aren't obligated to ๐คทโโ๏ธ
a server that gets a header block it isn't willing to handle can send an HTTP 431 (Request Header Fields Too Large) status code [RFC6585]. a client can discard responses it can't process. the header block MUST be processed to keep the connection state consistent, unless the connection is closed ๐ฅ
10.5.2. CONNECT Issues ๐
the CONNECT method can be used to create disproportionate load on a proxy, since making a stream is pretty cheap compared to creating and maintaining a TCP connection ๐ค. a proxy might also keep some resources around for a TCP connection even after the stream carrying the CONNECT request is closed, because the outgoing TCP connection stays in the TIME_WAIT state. so a proxy can't rely on SETTINGS_MAX_CONCURRENT_STREAMS alone to limit the resources CONNECT requests consume ๐ง
10.6. Use of Compression ๐๏ธ
compression can let an attacker recover secret data when it's compressed in the same context as data the attacker controls ๐ฑ. HTTP/2 enables compression of header fields (Section 4.3), and the following concerns also apply to the use of HTTP compressed content-codings ([RFC7231], Section 3.1.2.1).
there are demonstrable attacks on compression that exploit the characteristics of the web (e.g., [BREACH]) ๐. the attacker induces multiple requests containing varying plaintext, then observes the length of the resulting ciphertext in each one. it reveals a shorter length when a guess about the secret is correct.
implementations communicating on a secure channel MUST NOT compress content that includes both confidential and attacker-controlled data, unless separate compression dictionaries are used for each source of data ๐ซ. compression MUST NOT be used if the source of data cannot be reliably determined. and generic stream compression, like the kind provided by TLS, MUST NOT be used with HTTP/2 (see Section 9.2) ๐ โโ๏ธ
further considerations regarding the compression of header fields are described in [COMPRESSION] ๐.
10.7. Use of Padding ๐
padding within HTTP/2 isn't meant to replace general-purpose padding, like the kind TLS [TLS12] can provide. redundant padding could even be counterproductive ๐. getting it right can depend on having specific knowledge of the data being padded.
to mitigate attacks that rely on compression, disabling or limiting compression might be preferable to padding as a countermeasure ๐ .
padding can be used to obscure the exact size of frame content, and it's there to mitigate specific attacks within HTTP. for example, attacks where compressed content includes both attacker-controlled plaintext and secret data (e.g., [BREACH]) ๐ฆ.
padding can give you less protection than it seems at first ๐. at best it only makes it harder for an attacker to infer length information, by increasing the number of frames the attacker has to observe. incorrectly implemented padding schemes can be easily defeated. randomized padding with a predictable distribution gives very little protection, and padding payloads to a fixed size exposes information as payload sizes cross the fixed-size boundary. that could happen if an attacker can control the plaintext ๐ญ.
Intermediaries SHOULD retain padding for DATA frames but MAY drop padding for HEADERS and PUSH_PROMISE frames. a valid reason for an intermediary to change the amount of padding on frames is to improve the protections that padding provides ๐ง.
10.8. Privacy Considerations ๐ต๏ธโโ๏ธ
several characteristics of HTTP/2 give an observer a chance to correlate the actions of a single client or server over time ๐. these include the value of settings, the way flow-control windows are managed, the way priorities are allocated to streams, the timing of reactions to stimulus, and the handling of any features that are controlled by settings.
as far as these create observable differences in behavior, they could be used as a basis for fingerprinting a specific client, as defined in Section 1.8 of [HTML5] ๐ซฃ.
HTTP/2's preference for using a single TCP connection allows correlation of a user's activity on a site. reusing connections for different origins allows tracking across those origins ๐.
because the PING and SETTINGS frames solicit immediate responses, they can be used by an endpoint to measure latency to their peer. this might have privacy implications in certain scenarios ๐.
11. IANA Considerations ๐
a string for identifying HTTP/2 is entered into the "Application-Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in [TLS-ALPN] ๐.
this document establishes a registry for frame types, settings, and error codes. these new registries appear in the new "Hypertext Transfer Protocol version 2 (HTTP/2) Parameters" section โจ.
this document registers the HTTP2-Settings header field for use in HTTP. it also registers the 421 (Misdirected Request) status code.
this document registers the "PRI" method for use in HTTP to avoid collisions with the connection preface (Section 3.5) ๐.
11.1. Registration of HTTP/2 Identification Strings ๐ท๏ธ
this document creates two registrations for the identification of HTTP/2 (see Section 3.3) in the "Application-Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in [TLS-ALPN].
the "h2" string identifies HTTP/2 when used over TLS:
Protocol: HTTP/2 over TLS
Identification Sequence: 0x68 0x32 ("h2")
Specification: This document
the "h2c" string identifies HTTP/2 when used over cleartext TCP:
Protocol: HTTP/2 over TCP
Identification Sequence: 0x68 0x32 0x63 ("h2c")
Specification: This document
11.2. Frame Type Registry ๐งฉ
this document establishes a registry for HTTP/2 frame type codes. the "HTTP/2 Frame Type" registry manages an 8-bit space. the "HTTP/2 Frame Type" registry operates under either of the "IETF Review" or "IESG Approval" policies [RFC5226] for values between 0x00 and 0xef, with values between 0xf0 and 0xff being reserved for Experimental Use.
new entries in this registry require the following information:
- Frame Type: a name or label for the frame type.
- Code: the 8-bit code assigned to the frame type.
- Specification: a reference to a specification that includes a description of the frame layout, its semantics, and flags that the frame type uses, including any parts of the frame that are conditionally present based on the value of flags.
the entries in the following table are registered by this document ๐ธ
+---------------+------+--------------+
| Frame Type | Code | Section |
+---------------+------+--------------+
| DATA | 0x0 | Section 6.1 |
| HEADERS | 0x1 | Section 6.2 |
| PRIORITY | 0x2 | Section 6.3 |
| RST_STREAM | 0x3 | Section 6.4 |
| SETTINGS | 0x4 | Section 6.5 |
| PUSH_PROMISE | 0x5 | Section 6.6 |
| PING | 0x6 | Section 6.7 |
| GOAWAY | 0x7 | Section 6.8 |
| WINDOW_UPDATE | 0x8 | Section 6.9 |
| CONTINUATION | 0x9 | Section 6.10 |
+---------------+------+--------------+
11.3. Settings Registry โ๏ธ
this document establishes a registry for HTTP/2 settings. the "HTTP/2 Settings" registry manages a 16-bit space. the "HTTP/2 Settings" registry operates under the "Expert Review" policy [RFC5226] for values in the range from 0x0000 to 0xefff, with values between and 0xf000 and 0xffff being reserved for Experimental Use.
new registrations are advised to provide the following information:
- Name: a symbolic name for the setting. Specifying a setting name is optional.
- Code: the 16-bit code assigned to the setting.
- Initial Value: an initial value for the setting.
- Specification: an optional reference to a specification that describes the use of the setting.
the entries in the following table are registered by this document ๐
+------------------------+------+---------------+---------------+
| Name | Code | Initial Value | Specification |
+------------------------+------+---------------+---------------+
| HEADER_TABLE_SIZE | 0x1 | 4096 | Section 6.5.2 |
| ENABLE_PUSH | 0x2 | 1 | Section 6.5.2 |
| MAX_CONCURRENT_STREAMS | 0x3 | (infinite) | Section 6.5.2 |
| INITIAL_WINDOW_SIZE | 0x4 | 65535 | Section 6.5.2 |
| MAX_FRAME_SIZE | 0x5 | 16384 | Section 6.5.2 |
| MAX_HEADER_LIST_SIZE | 0x6 | (infinite) | Section 6.5.2 |
+------------------------+------+---------------+---------------+
11.4. Error Code Registry ๐จ
okay so this section sets up a registry for HTTP/2 error codes ๐. The "HTTP/2 Error Code" registry manages a 32-bit space, and it runs under the "Expert Review" policy [RFC5226] ๐ .
Registrations for error codes are required to include a description of the error code ๐. An expert reviewer is advised to check new registrations for possible duplication with existing error codes ๐. Using existing registrations is to be encouraged, but not mandated ๐ซถ.
New registrations are advised to give the following info:
- Name: a name for the error code. Naming it is optional โจ.
- Code: the 32-bit error code value ๐ข.
- Description: a brief description of what the error code means, and it can be longer if there's no detailed specification ๐.
- Specification: an optional reference to a specification that defines the error code ๐.
The entries in the table below are registered by this document ๐ฆ.
+---------------------+------+----------------------+---------------+
| Name | Code | Description | Specification |
+---------------------+------+----------------------+---------------+
| NO_ERROR | 0x0 | Graceful shutdown | Section 7 |
| PROTOCOL_ERROR | 0x1 | Protocol error | Section 7 |
| | | detected | |
| INTERNAL_ERROR | 0x2 | Implementation fault | Section 7 |
| FLOW_CONTROL_ERROR | 0x3 | Flow-control limits | Section 7 |
| | | exceeded | |
| SETTINGS_TIMEOUT | 0x4 | Settings not | Section 7 |
| | | acknowledged | |
| STREAM_CLOSED | 0x5 | Frame received for | Section 7 |
| | | closed stream | |
| FRAME_SIZE_ERROR | 0x6 | Frame size incorrect | Section 7 |
| REFUSED_STREAM | 0x7 | Stream not processed | Section 7 |
| CANCEL | 0x8 | Stream cancelled | Section 7 |
| COMPRESSION_ERROR | 0x9 | Compression state | Section 7 |
| | | not updated | |
| CONNECT_ERROR | 0xa | TCP connection error | Section 7 |
| | | for CONNECT method | |
| ENHANCE_YOUR_CALM | 0xb | Processing capacity | Section 7 |
| | | exceeded | |
| INADEQUATE_SECURITY | 0xc | Negotiated TLS | Section 7 |
| | | parameters not | |
| | | acceptable | |
| HTTP_1_1_REQUIRED | 0xd | Use HTTP/1.1 for the | Section 7 |
| | | request | |
+---------------------+------+----------------------+---------------+
11.5. HTTP2-Settings Header Field Registration ๐
This section registers the HTTP2-Settings header field in the "Permanent Message Header Field Names" registry [BCP90] ๐ฎ.
- Header field name:
HTTP2-Settings - Applicable protocol:
http - Status:
standard - Author/Change controller:
IETF - Specification document(s): Section 3.2.1 of this document
- Related information: this header field is only used by an HTTP/2 client for Upgrade-based negotiation ๐ค.
11.6. PRI Method Registration ๐ธ
This section registers the "PRI" method in the "HTTP Method Registry" ([RFC7231], Section 8.1) ๐.
- Method Name:
PRI - Safe: Yes
- Idempotent: Yes
- Specification document(s): Section 3.5 of this document
- Related information: this method is never used by an actual client ๐ . It will only look like it's being used when an HTTP/1.1 server or intermediary tries to parse an HTTP/2 connection preface ๐.
11.7. The 421 (Misdirected Request) HTTP Status Code ๐ฆฉ
This document registers the 421 (Misdirected Request) HTTP status code in the "HTTP Status Codes" registry ([RFC7231], Section 8.2) ๐ง.
- Status Code:
421 - Short Description: Misdirected Request
- Specification: Section 9.1.2 of this document
11.8. The h2c Upgrade Token ๐
This document registers the "h2c" upgrade token in the "HTTP Upgrade Tokens" registry ([RFC7230], Section 8.6) ๐ซง.
- Value:
h2c - Description: Hypertext Transfer Protocol version 2 (HTTP/2)
- Expected Version Tokens: None
- Reference: Section 3.2 of this document
12. References ๐
12.1. Normative References ๐
[COMPRESSION]Peon, R. and H. Ruellan, "HPACK: Header Compression for HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015, <http://www.rfc-editor.org/info/rfc7541>.[COOKIE]Barth, A., "HTTP State Management Mechanism", RFC 6265, DOI 10.17487/RFC6265, April 2011, <http://www.rfc-editor.org/info/rfc6265>.[FIPS186]NIST, "Digital Signature Standard (DSS)", FIPS PUB 186-4, July 2013, <http://dx.doi.org/10.6028/NIST.FIPS.186-4>.[RFC2119]Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <http://www.rfc-editor.org/info/rfc2119>.[RFC2818]Rescorla, E., "HTTP Over TLS", RFC 2818, DOI 10.17487/RFC2818, May 2000, <http://www.rfc-editor.org/info/rfc2818>.[RFC3986]Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <http://www.rfc-editor.org/info/rfc3986>.[RFC4648]Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, <http://www.rfc-editor.org/info/rfc4648>.[RFC5226]Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 5226, DOI 10.17487/RFC5226, May 2008, <http://www.rfc-editor.org/info/rfc5226>.[RFC5234]Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <http://www.rfc-editor.org/info/rfc5234>.[RFC7230]Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing", RFC 7230, DOI 10.17487/RFC7230, June 2014, <http://www.rfc-editor.org/info/rfc7230>.[RFC7231]Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content", RFC 7231, DOI 10.17487/RFC7231, June 2014, <http://www.rfc-editor.org/info/rfc7231>.[RFC7232]Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests", RFC 7232, DOI 10.17487/RFC7232, June 2014, <http://www.rfc-editor.org/info/rfc7232>.[RFC7233]Fielding, R., Ed., Lafon, Y., Ed., and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Range Requests", RFC 7233, DOI 10.17487/RFC7233, June 2014, <http://www.rfc-editor.org/info/rfc7233>.[RFC7234]Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Caching", RFC 7234, DOI 10.17487/RFC7234, June 2014, <http://www.rfc-editor.org/info/rfc7234>.[RFC7235]Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Authentication", RFC 7235, DOI 10.17487/RFC7235, June 2014, <http://www.rfc-editor.org/info/rfc7235>.[TCP]Postel, J., "Transmission Control Protocol", STD 7, RFC 793, DOI 10.17487/RFC0793, September 1981, <http://www.rfc-editor.org/info/rfc793>.[TLS-ALPN]Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301, July 2014, <http://www.rfc-editor.org/info/rfc7301>.[TLS-ECDHE]Rescorla, E., "TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM)", RFC 5289, DOI 10.17487/RFC5289, August 2008, <http://www.rfc-editor.org/info/rfc5289>.[TLS-EXT]Eastlake 3rd, D., "Transport Layer Security (TLS) Extensions: Extension Definitions", RFC 6066, DOI 10.17487/RFC6066, January 2011, <http://www.rfc-editor.org/info/rfc6066>.[TLS12]Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, DOI 10.17487/RFC5246, August 2008, <http://www.rfc-editor.org/info/rfc5246>.
12.2. Informative References ๐
[ALT-SVC]Nottingham, M., McManus, P., and J. Reschke, "HTTP Alternative Services", Work in Progress, draft-ietf-httpbis-alt-svc-06, February 2015.[BCP90]Klyne, G., Nottingham, M., and J. Mogul, "Registration Procedures for Message Header Fields", BCP 90, RFC 3864, September 2004, <http://www.rfc-editor.org/info/bcp90>.[BREACH]Gluck, Y., Harris, N., and A. Prado, "BREACH: Reviving the CRIME Attack", July 2013, <http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf>.[HTML5]Hickson, I., Berjon, R., Faulkner, S., Leithead, T., Doyle Navara, E., O'Connor, E., and S. Pfeiffer, "HTML5", W3C Recommendation REC-html5-20141028, October 2014, <http://www.w3.org/TR/2014/REC-html5-20141028/>.[RFC3749]Hollenbeck, S., "Transport Layer Security Protocol Compression Methods", RFC 3749, DOI 10.17487/RFC3749, May 2004, <http://www.rfc-editor.org/info/rfc3749>.[RFC4492]Blake-Wilson, S., Bolyard, N., Gupta, V., Hawk, C., and B. Moeller, "Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)", RFC 4492, DOI 10.17487/RFC4492, May 2006, <http://www.rfc-editor.org/info/rfc4492>.[RFC6585]Nottingham, M. and R. Fielding, "Additional HTTP Status Codes", RFC 6585, DOI 10.17487/RFC6585, April 2012, <http://www.rfc-editor.org/info/rfc6585>.[RFC7323]Borman, D., Braden, B., Jacobson, V., and R. Scheffenegger, Ed., "TCP Extensions for High Performance", RFC 7323, DOI 10.17487/RFC7323, September 2014, <http://www.rfc-editor.org/info/rfc7323>.[TALKING]Huang, L., Chen, E., Barth, A., Rescorla, E., and C. Jackson, "Talking to Yourself for Fun and Profit", 2011, <http://w2spconf.com/2011/papers/websocket.pdf>.[TLSBCP]Sheffer, Y., Holz, R., and P. Saint-Andre, "Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May 2015, <http://www.rfc-editor.org/info/rfc7525>.
Appendix A. TLS 1.2 Cipher Suite Black List ๐ค
okay bestie, so an HTTP/2 implementation is allowed to MAY treat negotiating any of these cipher suites with TLS 1.2 as a connection error (Section 5.4.1) of type INADEQUATE_SECURITY ๐ it's giving "no thank you" energy ๐
โโ๏ธ here's the whole sus list:
TLS_NULL_WITH_NULL_NULLTLS_RSA_WITH_NULL_MD5TLS_RSA_WITH_NULL_SHATLS_RSA_EXPORT_WITH_RC4_40_MD5TLS_RSA_WITH_RC4_128_MD5TLS_RSA_WITH_RC4_128_SHATLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5TLS_RSA_WITH_IDEA_CBC_SHATLS_RSA_EXPORT_WITH_DES40_CBC_SHATLS_RSA_WITH_DES_CBC_SHATLS_RSA_WITH_3DES_EDE_CBC_SHATLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHATLS_DH_DSS_WITH_DES_CBC_SHATLS_DH_DSS_WITH_3DES_EDE_CBC_SHATLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHATLS_DH_RSA_WITH_DES_CBC_SHATLS_DH_RSA_WITH_3DES_EDE_CBC_SHATLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHATLS_DHE_DSS_WITH_DES_CBC_SHATLS_DHE_DSS_WITH_3DES_EDE_CBC_SHATLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHATLS_DHE_RSA_WITH_DES_CBC_SHATLS_DHE_RSA_WITH_3DES_EDE_CBC_SHATLS_DH_anon_EXPORT_WITH_RC4_40_MD5TLS_DH_anon_WITH_RC4_128_MD5TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHATLS_DH_anon_WITH_DES_CBC_SHATLS_DH_anon_WITH_3DES_EDE_CBC_SHATLS_KRB5_WITH_DES_CBC_SHATLS_KRB5_WITH_3DES_EDE_CBC_SHATLS_KRB5_WITH_RC4_128_SHATLS_KRB5_WITH_IDEA_CBC_SHATLS_KRB5_WITH_DES_CBC_MD5TLS_KRB5_WITH_3DES_EDE_CBC_MD5TLS_KRB5_WITH_RC4_128_MD5TLS_KRB5_WITH_IDEA_CBC_MD5TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHATLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHATLS_KRB5_EXPORT_WITH_RC4_40_SHATLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5TLS_KRB5_EXPORT_WITH_RC4_40_MD5TLS_PSK_WITH_NULL_SHATLS_DHE_PSK_WITH_NULL_SHATLS_RSA_PSK_WITH_NULL_SHATLS_RSA_WITH_AES_128_CBC_SHATLS_DH_DSS_WITH_AES_128_CBC_SHATLS_DH_RSA_WITH_AES_128_CBC_SHATLS_DHE_DSS_WITH_AES_128_CBC_SHATLS_DHE_RSA_WITH_AES_128_CBC_SHATLS_DH_anon_WITH_AES_128_CBC_SHATLS_RSA_WITH_AES_256_CBC_SHATLS_DH_DSS_WITH_AES_256_CBC_SHATLS_DH_RSA_WITH_AES_256_CBC_SHATLS_DHE_DSS_WITH_AES_256_CBC_SHATLS_DHE_RSA_WITH_AES_256_CBC_SHATLS_DH_anon_WITH_AES_256_CBC_SHATLS_RSA_WITH_NULL_SHA256TLS_RSA_WITH_AES_128_CBC_SHA256TLS_RSA_WITH_AES_256_CBC_SHA256TLS_DH_DSS_WITH_AES_128_CBC_SHA256TLS_DH_RSA_WITH_AES_128_CBC_SHA256TLS_DHE_DSS_WITH_AES_128_CBC_SHA256TLS_RSA_WITH_CAMELLIA_128_CBC_SHATLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHATLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHATLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHATLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHATLS_DH_anon_WITH_CAMELLIA_128_CBC_SHATLS_DHE_RSA_WITH_AES_128_CBC_SHA256TLS_DH_DSS_WITH_AES_256_CBC_SHA256TLS_DH_RSA_WITH_AES_256_CBC_SHA256TLS_DHE_DSS_WITH_AES_256_CBC_SHA256TLS_DHE_RSA_WITH_AES_256_CBC_SHA256TLS_DH_anon_WITH_AES_128_CBC_SHA256TLS_DH_anon_WITH_AES_256_CBC_SHA256TLS_RSA_WITH_CAMELLIA_256_CBC_SHATLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHATLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHATLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHATLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHATLS_DH_anon_WITH_CAMELLIA_256_CBC_SHATLS_PSK_WITH_RC4_128_SHATLS_PSK_WITH_3DES_EDE_CBC_SHATLS_PSK_WITH_AES_128_CBC_SHATLS_PSK_WITH_AES_256_CBC_SHATLS_DHE_PSK_WITH_RC4_128_SHATLS_DHE_PSK_WITH_3DES_EDE_CBC_SHATLS_DHE_PSK_WITH_AES_128_CBC_SHATLS_DHE_PSK_WITH_AES_256_CBC_SHATLS_RSA_PSK_WITH_RC4_128_SHATLS_RSA_PSK_WITH_3DES_EDE_CBC_SHATLS_RSA_PSK_WITH_AES_128_CBC_SHATLS_RSA_PSK_WITH_AES_256_CBC_SHATLS_RSA_WITH_SEED_CBC_SHATLS_DH_DSS_WITH_SEED_CBC_SHATLS_DH_RSA_WITH_SEED_CBC_SHATLS_DHE_DSS_WITH_SEED_CBC_SHATLS_DHE_RSA_WITH_SEED_CBC_SHATLS_DH_anon_WITH_SEED_CBC_SHATLS_RSA_WITH_AES_128_GCM_SHA256TLS_RSA_WITH_AES_256_GCM_SHA384TLS_DH_RSA_WITH_AES_128_GCM_SHA256TLS_DH_RSA_WITH_AES_256_GCM_SHA384TLS_DH_DSS_WITH_AES_128_GCM_SHA256TLS_DH_DSS_WITH_AES_256_GCM_SHA384TLS_DH_anon_WITH_AES_128_GCM_SHA256TLS_DH_anon_WITH_AES_256_GCM_SHA384TLS_PSK_WITH_AES_128_GCM_SHA256TLS_PSK_WITH_AES_256_GCM_SHA384TLS_RSA_PSK_WITH_AES_128_GCM_SHA256TLS_RSA_PSK_WITH_AES_256_GCM_SHA384TLS_PSK_WITH_AES_128_CBC_SHA256TLS_PSK_WITH_AES_256_CBC_SHA384TLS_PSK_WITH_NULL_SHA256TLS_PSK_WITH_NULL_SHA384TLS_DHE_PSK_WITH_AES_128_CBC_SHA256TLS_DHE_PSK_WITH_AES_256_CBC_SHA384TLS_DHE_PSK_WITH_NULL_SHA256TLS_DHE_PSK_WITH_NULL_SHA384TLS_RSA_PSK_WITH_AES_128_CBC_SHA256TLS_RSA_PSK_WITH_AES_256_CBC_SHA384TLS_RSA_PSK_WITH_NULL_SHA256TLS_RSA_PSK_WITH_NULL_SHA384TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256TLS_EMPTY_RENEGOTIATION_INFO_SCSVTLS_ECDH_ECDSA_WITH_NULL_SHATLS_ECDH_ECDSA_WITH_RC4_128_SHATLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHATLS_ECDH_ECDSA_WITH_AES_128_CBC_SHATLS_ECDH_ECDSA_WITH_AES_256_CBC_SHATLS_ECDHE_ECDSA_WITH_NULL_SHATLS_ECDHE_ECDSA_WITH_RC4_128_SHATLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHATLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHATLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHATLS_ECDH_RSA_WITH_NULL_SHATLS_ECDH_RSA_WITH_RC4_128_SHATLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHATLS_ECDH_RSA_WITH_AES_128_CBC_SHATLS_ECDH_RSA_WITH_AES_256_CBC_SHATLS_ECDHE_RSA_WITH_NULL_SHATLS_ECDHE_RSA_WITH_RC4_128_SHATLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHATLS_ECDHE_RSA_WITH_AES_128_CBC_SHATLS_ECDHE_RSA_WITH_AES_256_CBC_SHATLS_ECDH_anon_WITH_NULL_SHATLS_ECDH_anon_WITH_RC4_128_SHATLS_ECDH_anon_WITH_3DES_EDE_CBC_SHATLS_ECDH_anon_WITH_AES_128_CBC_SHATLS_ECDH_anon_WITH_AES_256_CBC_SHATLS_SRP_SHA_WITH_3DES_EDE_CBC_SHATLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHATLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHATLS_SRP_SHA_WITH_AES_128_CBC_SHATLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHATLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHATLS_SRP_SHA_WITH_AES_256_CBC_SHATLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHATLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHATLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384TLS_ECDHE_PSK_WITH_RC4_128_SHATLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHATLS_ECDHE_PSK_WITH_AES_128_CBC_SHATLS_ECDHE_PSK_WITH_AES_256_CBC_SHATLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384TLS_ECDHE_PSK_WITH_NULL_SHATLS_ECDHE_PSK_WITH_NULL_SHA256TLS_ECDHE_PSK_WITH_NULL_SHA384TLS_RSA_WITH_ARIA_128_CBC_SHA256TLS_RSA_WITH_ARIA_256_CBC_SHA384TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384TLS_DH_anon_WITH_ARIA_128_CBC_SHA256TLS_DH_anon_WITH_ARIA_256_CBC_SHA384TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384TLS_RSA_WITH_ARIA_128_GCM_SHA256TLS_RSA_WITH_ARIA_256_GCM_SHA384TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384TLS_DH_anon_WITH_ARIA_128_GCM_SHA256TLS_DH_anon_WITH_ARIA_256_GCM_SHA384TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384TLS_PSK_WITH_ARIA_128_CBC_SHA256TLS_PSK_WITH_ARIA_256_CBC_SHA384TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384TLS_PSK_WITH_ARIA_128_GCM_SHA256TLS_PSK_WITH_ARIA_256_GCM_SHA384TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384TLS_RSA_WITH_AES_128_CCMTLS_RSA_WITH_AES_256_CCMTLS_RSA_WITH_AES_128_CCM_8TLS_RSA_WITH_AES_256_CCM_8TLS_PSK_WITH_AES_128_CCMTLS_PSK_WITH_AES_256_CCMTLS_PSK_WITH_AES_128_CCM_8TLS_PSK_WITH_AES_256_CCM_8
Okay bestie, the cipher suite list wraps up with a super important note ๐ซถ This list was put together from the TLS cipher suites that were registered at the time of writing ๐ It includes the suites that don't offer an ephemeral key exchange ๐ โโ๏ธ and the ones built on TLS null, stream, or block cipher types (see Section 6.2.3 of [TLS12]) ๐ Other suites with these same properties could be defined later โจ and they wouldn't be explicitly banned, so keep that in mind ๐
Acknowledgements ๐
This document includes substantial input from the following individuals:
- Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham, Alyssa Wilk, Costin Manolache, William Chan, Vitaliy Lvin, Joe Chan, Adam Barth, Ryan Hamilton, Gavin Peters, Kent Alstad, Kevin Lindsay, Paul Amer, Fan Yang, and Jonathan Leighton (SPDY contributors) ๐ธ
- Gabriel Montenegro and Willy Tarreau (Upgrade mechanism) ๐ฆ
- William Chan, Salvatore Loreto, Osama Mazahir, Gabriel Montenegro, Jitu Padhye, Roberto Peon, and Rob Trace (Flow control) ๐
- Mike Bishop (Extensibility) ๐ง
- Mark Nottingham, Julian Reschke, James Snell, Jeff Pinner, Mike Bishop, and Herve Ruellan (Substantial editorial contributions) ๐
- Kari Hurtta, Tatsuhiro Tsujikawa, Greg Wilkins, Poul-Henning Kamp, and Jonathan Thackray ๐
- Alexey Melnikov, who was an editor of this document in 2013 ๐
A substantial proportion of Martin's contribution was supported by Microsoft during his employment there ๐
The Japanese HTTP/2 community provided invaluable contributions, including a number of implementations as well as numerous technical and editorial contributions ๐ iykyk, they were absolutely essential ๐ญ
Authors' Addresses ๐ฆ
Mike Belshe
BitGo
EMail: mike@belshe.com
Roberto Peon
Google, Inc
EMail: fenix@google.com
Martin Thomson (editor)
Mozilla
331 E Evelyn Street
Mountain View, CA 94041
United States
EMail: martin.thomson@gmail.com
And that's the whole spec, periodt โจ๐ Thanks for riding along with me through all 19 parts, you're literally the best ๐๐ซถ
๐ฆ where this page comes from
- ietf: rfc7540 2015-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms