HTTP & HTTP/2 are both application level protocols that utilize a lower level protocol like TCP to actually talk on the Internet. The protocol of the Internet is generally TCP over IP over Ethernet. HTTP can use other transports too such as UDP. An example of this is node-httpp. HTTP/2 is a new protocol, intended as a higher performance alternative to HTTP/1.1. HTTP/2’s overriding objective is to improve the experience of web application users. This is a significant release to HTTP 1.0. HTTP 1.0 introduced as an IEFT standard in 1996 ( RFC 1945 ) and HTTP 1.1 was published in 1999 ( RFC 2616 ). HTTP/2 was formalized by the httpbis working group. The HTTP2 protocol recommendations included solutions for header compression, server push and the ‘Head of line blocking’ problem. HTTP2 is comprised of two specifications Hypertext Transfer Protocol version 2 – RFC7540 and HPACK – Header Compression for HTTP2 – RFC7541
HTTP2 is currently supported by almost all the major browsers and Web servers. caniuse indicates that 84% of all users are currently on HTTP2.
1. Binary Protocol
HTTP2 is binary, instead of textual. Known as the binary framing layer, this protocol is compatible with the HTTP/1.1 version. Status codes, methods, and headers have not undergone any changes.
Binary protocols are more simpler, efficient to parse and less error-prone compared to textual protocols. This also means that it is much more efficient on the wire. Textual protocols have a lot of implementation complexity. They have to cover issues like string delimiters, whitespace handling , extra characters etc. These have also been the source of a number of security issues. A binary protocol avoids all these issues. Another advantage of the binary protocol is that it breaks communication down into frames. This helps carry all communication over a single TCP connection, which remains open throughout a conversation. This open up oppurtunities to optimize the communication channel further. However, with this change, it is no longer human readable without using tools like wireshark to decode the protocol. You cannot simply telnet to port 80 and fire out manually formed requests anymore. If you are an Ops person this will not make you happy. However the other features allow you to detect TCP congestion control and other issues quickly.
HTTP 1.1 introduced the concept of pipelining. HTTP pipelining allows the browser to make multiple requests immediately without waiting for the previous request’s response to return. However the responses will will need to be ordered in the same sequnce as the requests and have to be returned in full. HTTP/1.1 pipelining never really took off and browser and server support is limited. None of the major browers support pipelining due to ‘Head of line queueing’ issues, buggy proxies, incorrect server support and performance issues. Sample these issues from chrome and Safari.
HTTP2 supports multiplexing several streams over a single connection. Multiplexing allows your browser to fire off multiple requests at once on the same connection and receive the requests back in any order. HTTP/2 allows you to use a single connection to send multiple requests parallelly on this single connection. So, now you can open a single connection and fire off requests to get the HTML, CSS, fonts, images etc. on this single connection without waiting for a response before firing the next request. While this in itself is a major optimization what makes it even better is that the server can respond to these requests in any order, send back files in different order, or even break each file requested into chunks and intermingle the chunks together. This prevents the ‘Head of line blocking’ problem, where a single resource heavy request hogs the pipeline and blocks all subsequent requests until it is complete.
3. One Connection per Origin
A client opens a connection to talk to a server. Every TCP connection requires a round trip to set up. If you’re using encryption, the TLS handshake takes another 1-2 round trips. All this happens before the first byte of the first response can be sent. By reusing an existing connection instead of setting up a new one, this overhead can be shared by many requests. HTTP2 sharply reduces the need for a request to wait while a new connection is established, or wait for an existing connection to become idle. Since a single connection is multiplexed between many requests, the request can usually be sent immediately without waiting for other requests to finish.
4. Header Compression
Each HTTP transfer carries a set of headers that describe the transferred resource and its properties. In HTTP/1.x, this metadata is always sent as plain text and adds a lot of overhead per transfer. To reduce this overhead and improve performance, HTTP2 supports a new dedicated header compression algorithm, called HPACK. Across multiple subsequent HTTP requests, there is a lot of information in the HTTP header that is repeated across these requests. For e.g in the below illustration the only difference in HTTP headers between request 1 and 2 is the path. There is no need to send redundant information over and over again?. Instead of sending the data over and over again, We use HPACK header compression. HPACK keeps a table of the headers on the client and servers, then when the second and subsequent headers are sent across it just references the header number on the header table.
HPACK uses three methods of compression
- Static Dictionary: A predefined dictionary of 61 commonly used header fields, some with predefined values.The static table is defined in the specification and provides a list of common HTTP header fields that all connections are likely to use.
- Dynamic Dictionary: A list of actual headers that were encountered during the connection. The dynamic table is initially empty and is updated based on exchanged values within a particular connection. This dictionary has limited size, and when new entries are added, old entries might be evicted.
- Huffman Encoding: A static Huffman code can be used to encode any string: name or value. This code was computed specifically for HTTP Response/Request headers – ASCII digits and lowercase letters are given shorter encodings. The shortest encoding possible is 5 bits long, therefore the highest compression ratio achievable is 8:5 (or 37.5% smaller).
When HPACK needs to encode a header in the format name:value, it will first look in the static and dynamic dictionaries. If the full name:value is present, it will simply reference the entry in the dictionary using one or two bytes in most cases.Since many headers are repetitive, this strategy has a very high success rate.
When HPACK can’t match a whole header in a dictionary, it will attempt to find a header with the same name. Most of the popular header names are present in the static table. If the name was found, it can again be expressed in one or two bytes in most cases, otherwise the name will be encoded using either raw encoding or the Huffman encoding which ever is the shorter of the two.
HPACK delivers a 85%–88% reduction in the size of the transferred header data, and a significant improvement in page load time latency.
5. Server Push
How is a Server Push implemented technically ? When a HTTP2 server pushes a resource, it generates a PUSH_PROMISE frame to send to the client, for each resource that it wants to send. This helps the client needs to know which resources the server intends to push to avoid creating own and duplicate requests for these resources.The client can also reject the push (for instance, if the resource is already in the browser’s cache) by responding back with an RST_STREAM frame. It’s important that all the PUSH_PROMISE’s are sent before the response data, so the client knows what resources it needs to request.The client has complete control of how server push is used and can limit the number of concurrently pushed streams, control how much data is pushed and even disable server push entirely.
Windows Support for HTTP2
Windows 10, Windows 10 Server, Windows Server 2016 and IIS support HTTP/2 out of the box. If the client and server configuration supports HTTP2, then IIS will use HTTP2 (or fallback to HTTP/1.1 if not possible).
.Net core Support for HTTP2
At the time of writing this post, Kestrel doesn’t support some features of HTTP2, such as server push and stream prioritization. So, while the client can send a prioritization tag with its requests, Kestrel simply won’t act on that request. Another caveat to HTTP/2 support is that your hosting environment’s native cryptography library must support Application Layer Protocol Negotiation (ALPN) to establish the secure connection necessary for HTTP/2. That means HTTP2 is supported only for .NET Core apps deployed to either Windows environments or Linux hosts with OpenSSL 1.0.2 or higher. Thankfully, though, if your environment doesn’t support HTTP/2, Kestrel will silently fall back to using standard HTTP 1.1 request processing. If you want to support HTTP/2 using .net core you can simply leverage the ConfigureKestrel() method on your WebHostBuilder, like so