Summary: a new status code that lets the server send headers early, before the main headers. This helps with optimisations like preloading. Example from the document:
The client can start preloading the CSS and JavaScript before the main headers arrive. This is a nice optimisation.
There are various security risks with sending multiple headers to non-conforming clients hence: "Therefore, a server might refrain from sending Early Hints over HTTP/1.1 unless the client is known to handle informational responses correctly."
The server is going to be slowly building up a real reply. But it also knows that most likely, the real reply is going to need a list of assets that doesn't change regardless of what the reply is.
So to save time, the server is going to spit out a few packets early that say "Hey, while you're waiting on me, go load these".
Am I understanding this right?
It's like your server at the restaurant bringing you appetizers early because they're fast to cook and you were just going to be sitting there doing nothing anyways.
Generally correct. However, the the final response won’t necessarily actually include those headers, so it’s more that the server is saying, “I think you’ll get this, but don’t quote me on it”.
In the case of a Link header, it would thus be OK to fetch the resources, and if you don’t end up needing them, c’est la vie. In the case of CSS, it’d be perfectly legitimate to load the CSS in anticipation. It would even be OK to execute JavaScript up to the point of its needing to interact with the document or HTTP. But it would be not OK to execute anything that was not safe (in the terminology of the HTTP spec on methods).
I’d extend your parallel in appetisers, but it gets mildly disturbing quite quickly.
I'd rather say: It's like the default set if knife/fork/spoon set out at the table. They might be taken away or replaced based on what you actually end up ordering. But for the most part they will work out.
the parent was implying that the server might later change their mind and ask for the water and bread back, so you shouldn't do anything irreversible with it.
In the interest of clobbering the analogy even further: It would be like the server bringing you a red wine and then serving fish - the red wine doesn't go with it, so you better hope you can get it off the table and the taste out of your mouth.
A recipe with a shopping list. Only you get the shopping list first and some of the items might be for another recipe (and you might already have them.)
i.e. only idempotent operations, such as GET. You should not perform a POST using the information obtained in these hints.
Perhaps an alternative analogy is branch prediction? Browser is permitted to run along a particular path of execution because it applies in most cases. But you end up throwing away your work in the case that the prediction turns out to be wrong.
In terms of practical application for this - most modern sites run their content over an additional layer of application logic that runs in the browser e.g. React, or Angular or something. These hints can tell the browser that such-and-such an application framework is required to display the content, and to go get it before the content is available.
No, not idempotent operations; safe operations. When speaking of HTTP methods, PUT and DELETE are both idempotent but not safe; you wouldn’t the user agent to DELETE a resource based on merely a hint—it needs to wait until the actual response comes in, at which point it can confirm whether the header is there and to be acted upon.
(Keep in mind with 103’s semantics that we’re not talking about HTTP methods, we’re merely borrowing its definition of “safe”. Speculative JavaScript execution, for example, is perfectly feasible; you’d simply have to pause execution as soon as it tried to mutate its environment or make HTTP requests or things like that. How useful it is is another question.)
I took idempotent and safe to be functionally equivalent. i.e. that which causes no state-change on the server. Thanks for the correction. Effectively a "debounced" operation.
The origin of my confusion is the definition of GET as idempotent. My understanding of this verb is it (should) cause no mutations. So the correct classification of GET is "safe".
Importantly, the server serving up the main page may not be the same one serving up static assets. You hit the main page and it sends back 103s telling your browser to then download a bunch of stuff off of a CDN ASAP even while the main page is still being transferred.
No! It's your pizza delivery service sending you menu of appetizers, because pizza is not ready yet. Oh! BTW you might not get this menu incase of traffic jam (aka buffering proxies), and pizza might arrive with menu as well :D.
So is there a default header to say 'I support 103s' or 'here are my extended capabilities'? Or are we just going to have every API ask for 'x-<company>-preload: true'?
"A client MUST be able to parse one or more 1xx responses received prior to a final response, even if the client does not expect one. A user agent MAY ignore unexpected 1xx responses."
They don't need to be requested. Supporting servers will just send them, unsupporting clients will just ignore them (barring the potential security issue with broken HTTP/1.1 implementations which is noted in the 103 spec).
> HTTP/2 ([RFC7540]) server push can accelerate the delivery of resources, but only resources for which the server is authoritative. The other limitation of server push is that the response will be transmitted regardless of whether the client has the response cached. At the cost of spending one extra round-trip compared to server push in the worst case, delivering Link header fields in a timely fashion is more flexible and might consume less bandwidth.
I use tabix.ui for Clickhouse, clickhouse generates tons of extra headers as progress bars. Chrome will just cut the connection and says header too large error.
http 103 will just be abused like that. People will make megabytes sized headers
Not likely. Megabyte sized headers would significantly degrade the loading performance of the web site since the browser can't go on to begin fetching the main content until the headers have arrived. So, operators that don't care for performance might abuse it, but then why would they bother at all?
Wouldn't that same logic mean that we can't have JavaScript, CSS, image/audio/video, etc. because some people will send too much junk? We can't prevent people from using the web badly but anyone who doesn't completely disregard the user experience will be subject to the usual feedback loop.
To explain the use case for this (as I understand it):
http/2 push sounds great at first glance for doing things like sending your CSS/JS bundles downstream with the HTML. The problem with this is that only the system that builds the HTML knows what needs to be pushed and only the system terminating the http/2 connection can send the assets. That means your app servers would need to terminate the http/2 connection and would be serving static assets. Serving static assets from your app server sucks for a lot of reasons. Instead what you want to do is tell some upstream proxy that is good at serving static assets what it should push. This is done by having the upstream proxy parse the Link HTTP headers in the response, which many services already do. But, today they can't start pushing assets until the main response is being sent since they need the headers from it to instruct them. Ideally you'd start sending assets ASAP, while the app server is building the page. This is exactly what the 103 response is most useful for.
e.g. You have a CDN front for your app servers, the app server sends an early 103 as soon as it knows what assets the page needs, the CDN intercepts this response and uses it to start pushing the assets to the client from the local edge node using http/2 push. This lets you benefit from http/2 push of your assets while processing the main response without your app server needing to serve static assets or even know about http/2 itself.
Does HTTP2 support multiple concurrent streams over a single client connection? If not, presumably your use case would require that the client has a separate HTTP2 connection opened up to the CDN already, right? Or am I missing something?
While I disagree with mbell's interpretation of the value of this header or how it could be used, to answer you're question pcl, yes HTTP 2 does support multiple streams over a single transport connection.
To me, I would say increasing efficiency (or decreasing latency) was a central design goal of HTTP2. So HTTP2 includes it's own framing, which allows multiplexing across the connection. This helps avoid the overhead of establishing multiple parallel connections to speed up page load, head of line blocking, running slow start on each connection, etc.
Sorry, I apologize for being unclear, I don't agree with you're interpretation of the use case that adds the most value.
While the RFC does state that what you described can happen at a caching intermediary, I don't believe that's where the value lies or the primary use case. To me, much of the value added is to get the 103 to the client early, and allow it to begin making decisions on whether the content is in it's local cache, or to begin making requests to third party servers.
This helps eliminate some of the weaknesses with HTTP push, mainly being that only content the server is authoritative for can be pushed, and that the server doesn't know whether the resource to be pushed already exists in a client cache.
It's a balancing act of course, but if the resource being pushed is above a certain size, pushing the resource on each request could add overhead, not reduce it.
The problem is that clients won't be supporting 103 for a long time, I would guess it'll be 3-5 years before you can realistically push the 103 to a browser and I don't thank any currently support it. It's also not a particularly safe thing to turn on. e.g. Chrome prior to 57 bombed on http/2 connections that sent a 103 which is in contrast to the RFP's theory that http/2 clients should be 'safer' in handling it than http/1 clients. We really don't know how many clients and proxies will have trouble with 103 and have to wait for the vast majority to at least ignore it / pass it along before it could be turned on externally.
> This helps eliminate some of the weaknesses with HTTP push, mainly being that only content the server is authoritative for can be pushed, and that the server doesn't know whether the resource to be pushed already exists in a client cache.
When a server sends a push to the client it first sends `PUSH_PROMISE` command to the client and the client may cancel the push, e.g. if it already has the asset in cache based on url. Assuming things move forward the server sends a HEADERS frame which can also trigger to the client to cancel the push, e.g. in response to an etag, though at this point some DATA frames may be in flight.
You are correct that you can't push assets for another domain, but I don't see this as much of a problem as there are many other benefits to having all requests go a CDN/reverse proxy that can handle the static asset serving, like regional SSL termination. There are of course third party scripts that may be needed, but it's good practice make these non-blocking for page rendering anyway so if they are a bit behind that is probably ok, if not preferable.
In my example there would be only a single connection from the client, to the CDN edge. The CDN is acting as a reverse proxy for the main request and pulling Link headers out of the response(s) to decide what static assets to push to the client over the same connection.
I don't love the idea of routing all my app traffic through the CDN edge, and I really get the willies thinking about terminating app-tier SSL at the CDN. I guess if a deployment is all-AWS or something, sure, but there's plenty of static content that I'm comfortable sharing with my CDN even though I don't want them seeing any user-generated content or metadata.
The author of this draft is also the author of H2O (an HTTP/2 webserver). IMO the cool thing about this RFC is that you can put an HTTP/2 proxy that understands Early Hints in front of an HTTP/1 application server, and give the application server HTTP/2 push without needing to "HTTP/2 enable" the application server.
Such that if you run H2O (or any webserver that supports early hints) in front of Rails, you can get asset push support for free. eileencodes wrote a great blog post about her work on this:
This is one of those optimizations where I'm ambivalent about it's usefulness.
Sure, Google might get a millisecond or two less in their apps, but who in their right mind has the engineering time to implement this very, very small optimization when there's many other things to be done that probably have a higher priority?
I could imagine it is a very good optimization for sites that take a long time to return the HTML of the page.
Take a site like reddit, where the HTTP request can take a second or 2 to return when there is a really high server load.
Reddit could return HTTP 103 hints to the clients to start downloading useful assets ahead of time so when the HTML payload finally arrives everything is ready to start execution. And if this does become a standard, it can get built into web servers and will be as simple as adding a few lines to a config file.
Obviously the "correct" solution is to reduce the time it takes to return the HTML from the server, but if it can improve load times for a nonzero amount of people for not much work, it's a win in my book (even if it's not ideal).
You are right, most people don't have the engineering time to implement this. Though there is definitely a market for this kind of optimizations in a SaaS solution (I know that because it has something to do with my job)...
Now, implementation of this by browsers is going to take a long time, and then we will see incompatibilities trickle down all the way, with Safari taking a few years after everybody else has it and IE/Edge also taking forever.... I should rather work in a farm and harvest tomatoes...
"millisecond or two" won't cut it as the only usable case would happen when there is non-trivial delay between 103 and 200 statuses.
Also I see this as more harmful than good as it'd require yet another packet sent and ack'd.
I also fail to see the usefulness. A server can already today send only the html head, flush the stream then pause before sending the body?
Most modern SPAs also have a static index.html which shouldn't take long to serve anyway.
This is going to be abused by cargo cult brogrammers who heard that "103 will make your site faster!!!1" and put every single resource as a 103 making the time to 200 even longer than the time you actually potentily gain.
With the article yesterday about the Trinet[1] I can see this optimization being used in the majority of HTTP traffic, even if it won't be used by a majority of companies/websites.
My reading of it is that it also increases the utility of centralized resources like CDNs and Google fonts relative to hosting your own resources, which HTTP/2 increases the utility of. In other words, this tends to promote the centralization of the web and is a gift to big tech companies.
What happens to hints in a redirect chain?, i.e. 301 103 301 103 200
What headers are applicable to the 103 beyond Link? If a 103 included Refresh, could this be used like a timeout (redirect after Refresh time if actual request did not respond?)
This...
> A server MAY use a 103 (Early Hints) response to indicate only some of the header fields that are expected to be found in the final response.
... implies that all possible HTTP headers from the final response may be in the 103.
RFCs need less ambiguity, lest clients and servers start to fill in the gaps and have divergent behaviour.
If the implementation decided to honor Set-Cookie in a 301, it should use the same security boundaries that it would use anywhere else. For a redirect chain and the rest, again it's up to the implementation. Since this is just an optional optimization, does it matter if there are divergent clients and servers?
It isn't yet approved. It is still a draft, not an RFC. Even if it does become an RFC, it is intended for the Experimental track, not the Standards track.
Am I wrong in thinking that these hints should include subresource integrity hashes?
Given hints with SRI hashes, the client can fetch/verify them and be ready when the HTML arrives, or even better, consult the cache and verify to avoid fetching and save bandwidth.
So I think there are a couple aspects to consider on this.
This RFC very strongly points to hints as the purpose, but to me appears to be generically implemented. So HTTP 103 can send any header, but only the final headers are authoritative. So it's really up to wherever those headers are defined to indicate what can/cannot be indicated by the headers. In other words, what a header can represent is likely a different discussion.
Subresource integrity is actually a w3c recommendation and not an IETF recommendation, so the checksum doesn't appear to be conveyed through headers. But trying to think about it logically, I don't think it's necessary to have the hashes at this stage. The web browser get's a HTTP 103, and see's the link rel and begins requesting and caching the resource. The web browser then loads the HTML, which includes the subresource integrity, that it then uses to check the result it already downloaded and cached. To validate that resource, it would need to download it anyway, the only thing HTTP 103 did was allow the the content to start downloading sooner in the process.
You don't need to download the file to verify the contents. The purpose of having a hash in the link is to allow you to cache jQuery previously downloaded from one CDN even though the link points to another.
Seems like it wouldn't really increase the speed at which the resources would be rejected, because the spec is that the resources can only be preloaded and not used: they are advisory messages only. So a compliant browser can take the hints, load the files, but only "use" them after seeing the HTML and validating the hash. Then a faster browser could compute that hash in advance, as well as precompiling the JS, etc.
Are there any prior examples of sending multiple status codes in one response? I didn't think you could, but there's not much discussion of it in the draft (a little in section 3 only) which makes me think it's not seen as controversial. Seems like it'd be a heap of work to update all the servers and clients out there if it's not supported already?
If client intends to send a POST request with request body large enough to try to avoid wasting bandwidth (in case server might reply with 3xx,4xx or 5xx), the client will send onlyheaders including "Expect: 100-continue" header, then server indenting to reply with "200 OK", will instead first reply with "100 Continue" than client will send POST body, and finally server sends "200 OK".
All 1xx responses are supposed to be sent like this - though "all" doesn't mean much as I think only two (100, 101) are defined in HTTP. Other derived protocols (e.g. WEBDAV) have additional ones though.
Also the exchange seems to be subtly different for each of them:
100 Continue:
Client sends start of request, server sends 100, client sends rest of request.
This look nice to prefetch some stuff, although i have a feeling it'll break some not-so-nicely coded HTTP 1.1 clients that expect everything after the first CR/LF to be the content or -more likely- if the response isn't 200 for the request to fail :-P.
"Aside from performance optimizations, such evaluation of the 103 (Early Hints) response's header fields MUST NOT affect how the final response is processed."
But beside, if you are in a position to insert HTTP responses, you are in a position to inject arbitrary JS.
Difference being is that one could inject 103 <download Y> for any resource, not just web pages, amplifying the outgoing traffic. Plus content doesn't need to be modified. It would be nice (I haven't read the specs) if 103 was restricted to HTTPS only for example.
Though other posters have pointed out why this is not the case, it _will_ make DDOS-by-linking much easier for "middleboxes" to orchestrate. I'm sure that there are further security issues to be found, as there are with all new technologies.
To further clarify, my intuition (having not read the spec) is that even if a middle-box sent a 103 response and had the client download a JS or CSS file, it won't get used by the client unless it is referenced by the document that is ultimately being loaded.
So yes, the file would get fetched, but no, it can't affect the page being rendered by the browser.
It literally just says "please download this into the browser cache". Nothing happens to things in the browser cache - they certainly don't get executed. Later, if a page tries to load resources, it might come from the browser cache.
> All ad-blocking tools/addons today works by parsing the webpage content
No, no they don't. They primarily work by hooking network requests through e.g. chrome.webRequest[0] and blocking certain URLs from being loaded. This continues to work with the multiple header-based mechanisms for downloading things.
This seems like it's only of interest if you need to do time consuming processing before deciding what http status code to send, because once you pick the status code, you can send it and start sending the rest of the headers.
Is it common to serve something other than http 200 and to take a long time to do it -- but also be able to send something early sooner? Most of the the slow pages I've worked on were either slow to load all the details, but I knew it was 200 near instantly, and could get all the headers and the HTML head out pretty quickly, or had some structural problems that made them terribly slow, but we couldn't get anything out quickly anyway.
The vast majority of the cases the status would be planned as 200... unless for whatever reason a timeout/error occurs during process. Then it may end up with error status and or redirect to an error handling page.
Still very dubious proposal with minimal benefit(s).
As I understand it, the status code would improve performance in situations like the following:
1. Client requests X.html (which requires Y.css and Z.js) from Proxy.
2. Proxy forwards client's X.html request to Server.
3. [Server takes a long time to respond]
4. Server sends a 200 response to Proxy with X.html.
5. Proxy, per some configuration, adds Preload headers to this response indicating that Y.css and Z.js should be immediately loaded once this response is received, and sends it to Client.
6. Client requests Y.css and Z.js.
With the 103 status code, this would look like:
1. Client requests X.html (which requires Y.css and Z.js) from Proxy.
2. Proxy forwards client's X.html request to server and, per some configuration, immediately sends a 103 response with Preload headers for Y.css and Z.js to Client.
3. [Server takes a long time to respond]
4. In parallel, Client requests Y.css and Z.js.
5. Server sends a 200 response to Proxy with X.html.
6. Proxy sends this response to Client.
Note that since Y.css and Z.js are requested sooner, the final load time should be less.
The proxy could also read preload headers from the Server, and start preemptively fetching Y.css and Z.js from the Server at the same time (step 2) it forwards the preload headers back to Client.
I read the headline and it colored my reading of the linked article. Bad headlines set up bad context. Someone also lowercased the "a" in approved in the headline since I saw it.
Browsers can learn this on their own and start prefetching likely resources before the server responds. Like a cpu's branch prediction. I wouldn't be surprised if chrome already did this.
This is actually great. I ran into this problem recently. I wanted to push out some CSS while waiting for some external response. Unfortunately, it was very important to be able to send a 404 in case it turned out the external response. This means we had to live with a higher TFFB.
Let’s hope this becomes widely adopted soon. Does anyone know how long it took till other HTTP features that were added later (not HTTP2) were widely supported?
At first, I thought, "they must limit URLs to be relative" which would solve that issue, but a lot of sites use CDNs to host static assets, so I don't know.
Nice, not sure how trivial this will be to add to frameworks and still make it not as slow as two requests. I think maybe this could be a macro in Elixir’s Phoenix framework that’s done at compilation time; would mean it isn’t changeable at runtime but would make it very fast.
The issue addressed by this spec (preloading latency) is only partially addressed by HTTP/2 push. As another user pointed out, the spec notes in its introduction that push (a) requires the replying server to be authoritative, and (b) wastes bandwidth in the case that the content is already in the client's cache. In particular, the spec also notes it is reasonable to only implement in HTTP/2 due to a specific security consideration.
one reason to dislike it, is because it is way too stateful.
and a lot of things depends on timings.
/and the spec misses some stuff, like if all my streams are done (except one long running stream, SSE, etc) and I get a new request what do do now? (there are multiple ways of doing that, one would be to just cancel the long running stream and hope that the client reconnects to the new connection).
Personally I think it is more complex than it was needed to be.
stream priority can also be a PITA.
Ah and I basically forgot, due to the state it is practically not the best protocol for mobile clients over 2G/low end 3G.
It's not the worst, I think h2 would be fine if it would be 10 years earlier, since I think we can learn a lot from the behavior of h2 in real world scenarios and than use the best things from http/1.1 and h2 to make h3.
I thought HTTP2 was born out of the experimental SPDY protocol which was used in the wild for quite some time, maybe 5 years. I think SPDY was released around 2010.
HTTP2 is like the good parts of SPDY and what was learned over that time period (I think).
SPDY wasn't in widespread use (I think it had something like 30% usage), especially not in mobile environments.
basically I also did not say that h2/spdy is bad, it actually solves some things, but makes others worse.
it actually solves head of line blocking. multiplexing is cool, but comes with the overhead of a connection state.
I think h2 is perfect for RPC like architectures, interconnection between servers is a perfect fit for something like h2. but when it comes to real world traffic it depends on too many parameters. The sad part is, is that h2 will take forever to gain that data and to have widespread usage. the hard part will be 100% h2, a lot of stuff prolly only uses h2 at the edge.
Also most flaws of h2, will probably be fixed without a new protocol, i.e. in the next 10 years I hope that _all_ mobile environments have a widespread use of 3g networks (or to say it differently, I dream of) and hopefully all network people make world wide latency better and make all networks more reliable.
There are various security risks with sending multiple headers to non-conforming clients hence: "Therefore, a server might refrain from sending Early Hints over HTTP/1.1 unless the client is known to handle informational responses correctly."