HTTP/2 Server Push
HTTP/2 Push allows a web server to send resources to a web browser before the browser gets to request them. It is,for the most part, a performance technique that can help some websites load faster.
HTTP/2 Push[1] is not a mechanism for the server to notify things to the browser. Instead, pushed contents are used by the browser when it may have otherwise produced a request to get the resource anyway. But if the browser does not request the resource, the pushed contents become wasted bandwidth.
High level example
Let's think about a hypotetical website with three resources: index.html, styles.css and script.js. Say that one user, through his browser, connects to the home page of this website and retrieves index.html. As soon as the browser gets index.html, it discovers that it will also need styles.css and script.js. Only then the browser will issue requests to get the other two files. Therefore, to assemble this webpage the browser will stack network round-trips as it gradually discovers the site's composition. With HTTP/2 PUSH, the server can take the initiative by having some rules that trigger push at certain moments. For example, when the server receives a request to index.html, it can also push styles.css and script.js without waiting for the respective request from the browser. If done correctly, by the time the browser finishes parsing index.html, the transfer of styles.css and script.js would have already started in "push mode" and the browser will simply sit back and relax while the files end their transfer.
How HTTP/2 PUSH works at a protocol level
PUSH works over HTTP/2, which at its core is a frames protocol, meaning that information is exchanged in groups of bytes called frames. Additionally, frames are part of streams, and streams are identified by a number. The stream number is present in each frame as a binary field. Streams allow to match requests and responses, e.g. the response to request GET /index.html at stream 3 must also be at stream 3.
There are different types of frames, and each has a different function. HTTP/2 has only a bunch of these types, and we don't need all of them to explain the basics. Here are the ones interesting for this description:
- HEADERS frame. As its name implies, this type of frame carries HTTP headers . When sent by the browser to the server, it signals that a request is being made. When sent by the server to the browser, it signals that a response to a previous request or push promise is being sent.
- PUSH_PROMISE frame. This frame is sent by the server to the browser to start pushing a resource. It also contains HTTP headers. However, the kind of headers present in a PUSH_PROMISE frame are headers that would normally be present in a request . This is different of the response headers that a server would normally send. The request URL, for example, is present in the PUSH_PROMISE frame as the HTTP/2-specific :path pseudo-header, as it is the :authority pseudo-header to indicate a host. Other headers that may be present a PUSH_PROMISE and that some browsers use are cache headers, for example, if-none-match.
- DATA frames. These frames are sent in either direction to carry the actual of a resource or the contents that the browser POSTs or PUTs to the server.
- RST_STREAM frames. These frames are handy in a variety of conditions, one of them is having the browser signal to the server that a pushed stream is not needed.
When the server wants to push a resource, it prepares a PUSH_PROMISE frame, architecting it in the best way possible to seduce the browser into using the pushed contents. Then the server annexes the PUSH_PROMISE frame to the response part of a normal, browser-initiated stream. However, the actual data for the pushed resource is sent in a fresh stream started by the server—and thus with an even number.
The browser holds the pushed data in a temporary "quarantine" zone until it decides to use it. Later, every time the browser is going to make an actual request, it examines the contents of any received push promises to see if it is similar enough to the request it wants to make. However, the server needs not wait until that moment to start sending data for the promised resource. After the PUSH_PROMISE frame has been sent on the browser-initiated stream, the server can send the would be response headers using a HEADERS frame in the new server-initiated stream, and later it can send the data of the resource using DATA frames. And at any point in time, the browser can interrupt any transfer by using RST_STREAM.
Here is how this would work in the previous example. If the server is HTTP/2 PUSH ready, when it receives a request to index.html it can forecast that requests to styles.css and script.js are following close in tail. So it issues push promises to get a bit ahead of events. Here is how things could look, in order of occurrence and making up the stream numbers:
- Server receives HEADERS frame asking for index.html in stream 3, and it can forecast the need for styles.css and script.js.
- Server sends a PUSH_PROMISE for styles.css and a PUSH_PROMISE for script.js, again in stream 3. These frames are roughly equivalent to a browser's request.
- Server sends a HEADERS frame in stream 3 for responding to the request for index.html.
- Server sends DATA frame(s) with the contents of index.html, still in stream 3.
- Server sends HEADERS frame for the response to styles.css in stream 4 -- notice the even stream number-- , and then for the response to script.js in stream 6.
- Server sends DATA frames for the contents of styles.css and script.js, using their respective stream numbers.
Push promises are sent as early as possible so that the browser have them well ahead of any discoveries. Notice that some HTTP headers can reveal URLs that the browser needs to fetch, and an eager browser would start asking for the resources upon seeing those headers. Therefore push promises are best sent before even the response headers of the stream where they are attached.[2]
References
- ↑ Hypertext Transfer Protocol Version 2 (HTTP/2). IETF. May 2015. p. 60. sec. 8.2. RFC 7540. https://tools.ietf.org/html/rfc7540#section-8.2. Retrieved May 6th, 2015.
- ↑ "A closer look to HTTP/2 Push". ShimmerCat.