RFC 7540

Hypertext Transfer Protocol Version 2 (HTTP/2)

๐Ÿ“… published May 2015, from ietf

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 (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 for SETTINGS_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 ID field ๐Ÿ‘€

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:

  1. 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.
  2. 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 ๐Ÿ“
  3. 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 ๐Ÿ’…
  4. The initial value for the flow-control window is 65,535 octets for both new streams and the overall connection.
  5. 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 ๐Ÿ”ฅ
  6. Flow control cannot be disabled.
  7. 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 PADDED flag 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 PADDED flag is set ๐Ÿงš
  • E: a single-bit flag saying the stream dependency is exclusive (see Section 5.3). it only shows up if the PRIORITY flag 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 PRIORITY flag 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 PRIORITY flag 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't 0, that MUST be treated as a connection error (Section 5.4.1) of type FRAME_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 to 0. And an endpoint that has set this to 0 and had it acknowledged MUST treat receiving a PUSH_PROMISE frame as a connection error (Section 5.4.1) of type PROTOCOL_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 the PADDED flag 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_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. Not the vibe, so don't do it ๐Ÿ’€.
  • 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 ๐ŸŽ€:

  1. 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),
  2. one HEADERS frame (followed by zero or more CONTINUATION frames) holding the message headers (see [RFC7230], Section 3.2),
  3. zero or more DATA frames holding the payload body (see [RFC7230], Section 3.3), and
  4. 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 ๐Ÿซ 

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_STREAM error 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 :method pseudo-header field is set to CONNECT. ๐ŸŽ€
  • The :scheme and :path pseudo-header fields MUST be omitted. ๐Ÿ™…โ€โ™€๏ธ
  • The :authority pseudo-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 ๐Ÿ’–

12.2. Informative References ๐ŸŒˆ

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_NULL
  • TLS_RSA_WITH_NULL_MD5
  • TLS_RSA_WITH_NULL_SHA
  • TLS_RSA_EXPORT_WITH_RC4_40_MD5
  • TLS_RSA_WITH_RC4_128_MD5
  • TLS_RSA_WITH_RC4_128_SHA
  • TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
  • TLS_RSA_WITH_IDEA_CBC_SHA
  • TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
  • TLS_RSA_WITH_DES_CBC_SHA
  • TLS_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA
  • TLS_DH_DSS_WITH_DES_CBC_SHA
  • TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA
  • TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA
  • TLS_DH_RSA_WITH_DES_CBC_SHA
  • TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
  • TLS_DHE_DSS_WITH_DES_CBC_SHA
  • TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
  • TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
  • TLS_DHE_RSA_WITH_DES_CBC_SHA
  • TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_DH_anon_EXPORT_WITH_RC4_40_MD5
  • TLS_DH_anon_WITH_RC4_128_MD5
  • TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA
  • TLS_DH_anon_WITH_DES_CBC_SHA
  • TLS_DH_anon_WITH_3DES_EDE_CBC_SHA
  • TLS_KRB5_WITH_DES_CBC_SHA
  • TLS_KRB5_WITH_3DES_EDE_CBC_SHA
  • TLS_KRB5_WITH_RC4_128_SHA
  • TLS_KRB5_WITH_IDEA_CBC_SHA
  • TLS_KRB5_WITH_DES_CBC_MD5
  • TLS_KRB5_WITH_3DES_EDE_CBC_MD5
  • TLS_KRB5_WITH_RC4_128_MD5
  • TLS_KRB5_WITH_IDEA_CBC_MD5
  • TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA
  • TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA
  • TLS_KRB5_EXPORT_WITH_RC4_40_SHA
  • TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5
  • TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5
  • TLS_KRB5_EXPORT_WITH_RC4_40_MD5
  • TLS_PSK_WITH_NULL_SHA
  • TLS_DHE_PSK_WITH_NULL_SHA
  • TLS_RSA_PSK_WITH_NULL_SHA
  • TLS_RSA_WITH_AES_128_CBC_SHA
  • TLS_DH_DSS_WITH_AES_128_CBC_SHA
  • TLS_DH_RSA_WITH_AES_128_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_DH_anon_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_DH_DSS_WITH_AES_256_CBC_SHA
  • TLS_DH_RSA_WITH_AES_256_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_DH_anon_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_NULL_SHA256
  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DH_DSS_WITH_AES_128_CBC_SHA256
  • TLS_DH_RSA_WITH_AES_128_CBC_SHA256
  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_DH_DSS_WITH_AES_256_CBC_SHA256
  • TLS_DH_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DH_anon_WITH_AES_128_CBC_SHA256
  • TLS_DH_anon_WITH_AES_256_CBC_SHA256
  • TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
  • TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA
  • TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA
  • TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
  • TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
  • TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA
  • TLS_PSK_WITH_RC4_128_SHA
  • TLS_PSK_WITH_3DES_EDE_CBC_SHA
  • TLS_PSK_WITH_AES_128_CBC_SHA
  • TLS_PSK_WITH_AES_256_CBC_SHA
  • TLS_DHE_PSK_WITH_RC4_128_SHA
  • TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
  • TLS_DHE_PSK_WITH_AES_128_CBC_SHA
  • TLS_DHE_PSK_WITH_AES_256_CBC_SHA
  • TLS_RSA_PSK_WITH_RC4_128_SHA
  • TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA
  • TLS_RSA_PSK_WITH_AES_128_CBC_SHA
  • TLS_RSA_PSK_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_SEED_CBC_SHA
  • TLS_DH_DSS_WITH_SEED_CBC_SHA
  • TLS_DH_RSA_WITH_SEED_CBC_SHA
  • TLS_DHE_DSS_WITH_SEED_CBC_SHA
  • TLS_DHE_RSA_WITH_SEED_CBC_SHA
  • TLS_DH_anon_WITH_SEED_CBC_SHA
  • TLS_RSA_WITH_AES_128_GCM_SHA256
  • TLS_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DH_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DH_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DH_DSS_WITH_AES_128_GCM_SHA256
  • TLS_DH_DSS_WITH_AES_256_GCM_SHA384
  • TLS_DH_anon_WITH_AES_128_GCM_SHA256
  • TLS_DH_anon_WITH_AES_256_GCM_SHA384
  • TLS_PSK_WITH_AES_128_GCM_SHA256
  • TLS_PSK_WITH_AES_256_GCM_SHA384
  • TLS_RSA_PSK_WITH_AES_128_GCM_SHA256
  • TLS_RSA_PSK_WITH_AES_256_GCM_SHA384
  • TLS_PSK_WITH_AES_128_CBC_SHA256
  • TLS_PSK_WITH_AES_256_CBC_SHA384
  • TLS_PSK_WITH_NULL_SHA256
  • TLS_PSK_WITH_NULL_SHA384
  • TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
  • TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
  • TLS_DHE_PSK_WITH_NULL_SHA256
  • TLS_DHE_PSK_WITH_NULL_SHA384
  • TLS_RSA_PSK_WITH_AES_128_CBC_SHA256
  • TLS_RSA_PSK_WITH_AES_256_CBC_SHA384
  • TLS_RSA_PSK_WITH_NULL_SHA256
  • TLS_RSA_PSK_WITH_NULL_SHA384
  • TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256
  • TLS_EMPTY_RENEGOTIATION_INFO_SCSV
  • TLS_ECDH_ECDSA_WITH_NULL_SHA
  • TLS_ECDH_ECDSA_WITH_RC4_128_SHA
  • TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_NULL_SHA
  • TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
  • TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_RSA_WITH_NULL_SHA
  • TLS_ECDH_RSA_WITH_RC4_128_SHA
  • TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_RSA_WITH_NULL_SHA
  • TLS_ECDHE_RSA_WITH_RC4_128_SHA
  • TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_anon_WITH_NULL_SHA
  • TLS_ECDH_anon_WITH_RC4_128_SHA
  • TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDH_anon_WITH_AES_128_CBC_SHA
  • TLS_ECDH_anon_WITH_AES_256_CBC_SHA
  • TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA
  • TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
  • TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA
  • TLS_SRP_SHA_WITH_AES_128_CBC_SHA
  • TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
  • TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA
  • TLS_SRP_SHA_WITH_AES_256_CBC_SHA
  • TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA
  • TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_PSK_WITH_RC4_128_SHA
  • TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
  • TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_PSK_WITH_NULL_SHA
  • TLS_ECDHE_PSK_WITH_NULL_SHA256
  • TLS_ECDHE_PSK_WITH_NULL_SHA384
  • TLS_RSA_WITH_ARIA_128_CBC_SHA256
  • TLS_RSA_WITH_ARIA_256_CBC_SHA384
  • TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256
  • TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384
  • TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256
  • TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384
  • TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256
  • TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384
  • TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256
  • TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384
  • TLS_DH_anon_WITH_ARIA_128_CBC_SHA256
  • TLS_DH_anon_WITH_ARIA_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384
  • TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256
  • TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384
  • TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256
  • TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384
  • TLS_RSA_WITH_ARIA_128_GCM_SHA256
  • TLS_RSA_WITH_ARIA_256_GCM_SHA384
  • TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256
  • TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384
  • TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256
  • TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384
  • TLS_DH_anon_WITH_ARIA_128_GCM_SHA256
  • TLS_DH_anon_WITH_ARIA_256_GCM_SHA384
  • TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256
  • TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384
  • TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256
  • TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384
  • TLS_PSK_WITH_ARIA_128_CBC_SHA256
  • TLS_PSK_WITH_ARIA_256_CBC_SHA384
  • TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256
  • TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384
  • TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256
  • TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384
  • TLS_PSK_WITH_ARIA_128_GCM_SHA256
  • TLS_PSK_WITH_ARIA_256_GCM_SHA384
  • TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256
  • TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384
  • TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256
  • TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
  • TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
  • TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
  • TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
  • TLS_RSA_WITH_AES_128_CCM
  • TLS_RSA_WITH_AES_256_CCM
  • TLS_RSA_WITH_AES_128_CCM_8
  • TLS_RSA_WITH_AES_256_CCM_8
  • TLS_PSK_WITH_AES_128_CCM
  • TLS_PSK_WITH_AES_256_CCM
  • TLS_PSK_WITH_AES_128_CCM_8
  • TLS_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