So first Google (Chrome team) foobar'd HTTP (and HTML and CSS and ...) into overengineered crap to replace TCP with vague promises of pushed resources and multiplexing only necessary to handle absurdly bloated CSS, images, and fonts there for CDNs by Google et al to sensor your traffic and visit data in the first place, then they admitted server push, as the other touted advantage, being not well thought out after all. The effect being to derail most F/OSS HTTP libs, web servers, and TCP/IP stacks due to sheer complexity and conflicting goals. Wish we'd call Google's destructive efforts towards the web as what they are.
You are grossly misrepresenting the situation. Google has played a significant role in HTTP/2 and HTTP/3 development, and they did provide the starting point in each case, but they have not controlled it, and what has come out of IETF after collaboration with many interested parties is significantly different from what Google first proposed. And Google is far from the only party that wants, uses and will benefit from HTTP/2 and HTTP/3.
And once talking about all this, the Chrome team is one of the less important parts of Google in bringing about HTTP/2 and HTTP/3.
Yes, HTTP/2 and HTTP/3 are more complex than HTTP/1, but these are not the ways Google is harming the web—these are the good parts of what Google is helping to improve the web.
You are yearning for the simple and inefficient days of yore, but those days are gone. The internet is a part of society now, and keeping it inefficient and slow does no one any good.
Your tirade is misguided and significantly factually inaccurate.
The GP got the facts wrong, but IMO we shouldn't dismiss the sentiment. In particular:
> You are yearning for the simple and inefficient days of yore
The simpler our systems are, the more we can understand them, and the more reliable we can make them. And more often than not, a system that's simple from top to bottom, and kept as small as possible, is efficient. Yes, I do kind of miss the days when HTTP was understandable enough that I could write my own HTTP server directly on top of a TCP socket API. TLS is a necessary evil to protect users from bad actors, but I'm not so sure about HTTP/2. In one of my Rust projects, I just switched from reqwest to ureq (yes, partly prompted by this discussion), and saved ~600K in a release build (already optimized for size). That's 600K of removed code that can't cause bugs anymore. And I know that in my particular use case, HTTP/1.1 will be good enough.
It’s worth noting that HTTP/2 is only a part of the difference there—reqwest is generally designed to spend more code on better correctness and performance and starts with async, whereas ureq is designed for simplicity and is synchronous-only, which all tends to lead to less code. For the point in question, it would be interesting to compare reqwest minus HTTP/2 support, or ureq with HTTP/2 support.
On the matter of reliability: I’d honestly expect HTTP/2 and HTTP/3 to end up more reliable than HTTP/1 (my guess is that HTTP/2 probably already is, but HTTP/3 won’t be just yet), because binary protocols require more careful implementation and generally leave much less room for bad implementation, whereas text protocols are simple enough that the average quality of implementation is much lower (because barely-skilled developers can make something that mostly works without even looking at the specs).
> text protocols are simple enough that the average quality of implementation is much lower (because barely-skilled developers can make something that mostly works without even looking at the specs).
And to be fair, the HTTP server that I did in fact write as a teenager in the late 90s (in the MOO programming language) was firmly in that category. I'm sure my mild wishing for those days is just nostalgia.
Google served as a well-placed catalyst, due to their broad interests. I don’t doubt that it would have taken longer to happen had they not been involved (though what “involved” means is fiddly, given that being deliberately not-involved would act as a significant retarding force, given the popularity of their browser), but I do believe that it would still have happened eventually.
(The word catalyst isn’t quite right because Google took part in the reaction, but it’s the closest word to what I want that I can immediately think of.)
>replace TCP with vague promises of pushed resources
Server Push was introduced in HTTP/2. TCP was replaced later, in QUIC and HTTP/3. The goal of replacing TCP was not to improve Server Push. Chrome never even implemented Server Push for HTTP/3.
Even without Push, HTTP/2 is ridiculously faster than HTTP 1.1. Removing the parts that didn't work hardly seem like "overengineering". In fact, it's the opposite.
Well said. HTTP/1.1 or below is HTTP for the people, mostly developed by academia not "tech" companies or their service providers, e.g., CDNs. HTTP/2 and 3 are HTTP for "tech" companies and their service providers.
If the technical limits of HTTP/1.1 limit the amount and effectiveness of online advertising and behavourial tracking, or if it limits the amount of time people may potentially waste on the "interactive" attention-grabbing www, then that is a benefit, IMHO. To put it another way, if the technical deficiencies of HTTP/1.1 limit the viability of "tech" companies then this is a benefit, because "tech" companies are responsible for attaching surveillance to commercial and recreational web use that I would prefer not to support.
HTTP/1.1 and below were for a less commercial web not controlled by Google.
Websites "load" very fast for me because I do not use Chrome. I retreive data/information from the www without running Javascript, processing CSS or auto-loading resources. I have no trouble making online purchases, conducting online banking, etc. with a popular browser when that is necessary. The only regret is having to use a browser controlled by an advertising company (or supported by one) for those tasks. HTTP/1.1 works great for me.
I hope you realize what you do is extremely uncommon and that "the people" don't want the web to be like that where there is no styling, no images, no videos, limited interactivity, etc.
>The effect being to derail most F/OSS HTTP libs, web servers, and TCP/IP stacks due to sheer complexity and conflicting goals.
If you're trying to imply HTTP/2 and HTTP/3 have this goal, then I am glad you are not writing any HTTP libraries. I am sick and tired of everyone rolling their own shoddy, incomplete HTTP/1.1 libraries with string splitting and regex. I safely assume any HTTP library that does not support at least HTTP/2 is exactly this.
I'm glad the "complexity" of HTTP/2 and HTTP/3 means less people are trying to make a half-assed implementation. By the time you get to actually sending stuff with HTTP/3, you'll be deep enough that you won't just forget the whole 3xx series of response codes.
This seems like a weird argument to make: complexity of a spec as some kind of gatekeeper to prevent people from rolling their own implementation?
The fact of the matter is that these people will probably still not use HTTP/2, but rather stick with their broken HTTP/1.1 implementation, and therefor forever requiring browsers to support this.
Disclosure: I was a (secondary) coauthor on this work.
Vroom [1] is a research system to accelerate page loads. It identifies dependent resources for your page and uses a combination of client hints and and server push to improve network utilization. I believe that only important, non-cacheable content use server push. See the paper for results.
To be clear, web performance is not my main field and I haven't kept up with the latest happenings. I only bring it up as evidence that push can be useful, but I can't actually say whether it's worth the complexity.
Yeah, that's the thing. So very many years ago when we started using HTTP/2 at LinkedIn, we simply just couldn't find a use for server push. It was a fascinating meeting. We got this technology, no matter how much we tried to use it, couldn't come up with a use for it. I still remember how awkward that meeting was to this day.
The webserver could just parse the HTML and send http push for each dependency!
What was the problem with doing this?
To me this seem very similar to "open document format" are storing html with all its dependency in a ZIP package. So with HTTP/2 push you just push the whole package and the client tell the server if it already have some of the files.
> The webserver could just parse the HTML and send http push for each dependency! What was the problem with doing this?
Well… the client knows which resources are already in its cache. The server does not. You just suggested that the server should always send resources that client almost certainly already had cached, which is wasteful for everyone involved.
> So with HTTP/2 push you just push the whole package and the client tell the server if it already have some of the files.
That doesn’t make sense. Once the files have been pushed, the bandwidth and time has already been wasted. The client doesn’t get to tell the server anything in that scenario.
I guess the client could tell server that "I already have that file in cache", but it's still weird, might require another round-trip (server asking if client needs this file).
a push is an HTTP2 stream.
the stream header contain everything the client need to know if it already have that file.
If it does already have that file, client simply close the stream it doesn't need to download the file or send request to server to say it doesn't need the file.
Even then, the average case would still be worse because the server would be sending all these unnecessary stream headers and forcing the client to send so many unnecessary RST_STREAM frames back. Each PUSH_PROMISE is supposed to contain the full set of headers for each resource.
I guess I hadn’t realized that clients could RST_STREAM on these pushes, but it doesn’t change the outcome here.
What you describe isn’t a win for anyone except a client with a cold cache, and then they start losing immediately after that. That’s why it isn’t done. That’s why HTTP/2 Push is going away.
Even if a client does a RST_STREAM, the origin server might already have done a lot of additional work (e.g. request the pushed file from an upstream if it's a proxy/CDN), and probably stuffed min(TCP_SEND_BUFFER_SIZE, STREAM_FLOW_CONTRO_WINDOW) of data into the stream. Which then also means all of that work might get billed if the server is a managed service. It's really quite some waste of resources compared to the client sending an additional request (which might even be a conditional request).
Yeah, and unless I’m wrong, this also means the TTFB could be significantly higher, since I think the PUSH_PROMISE frames need to come before the main content. Doing that at least requires gathering up the information on those objects, which takes time.
"The server SHOULD send PUSH_PROMISE (Section 6.6) frames prior to sending any frames that reference the promised responses. This avoids a race where clients issue requests prior to receiving any PUSH_PROMISE frames."
even if a server implements that behavior, it could however just send the PUSH_PROMISE frame (containing HTTP headers) but doesn't have to send the associated data frames yet. The frames associated with the original response could follow earlier.
The http/2 stream is multiplexed over a regular tcp stream. At least some push HEADERS and data was most likely already send over the tcp stream, and is most likely already a few hops away from the actual server. By the time the server actually gets the first http/2 RST_STREAM(s) a lot of data from multiple useless pushes could be inflight already. At this point you cannot just close the http/2 stream to avoid data being send. You can only either RST the entire tcp stream and kill all multiplexed http/2 flowing over it (avoiding some data transfer), or accept the data that arrives on your closed http/2 streams and send it in the direction of /dev/null.
Server push, as opposed to preload/hints, only makes sense when you know a) a client will absolutely need the data and b) you're reasonably sure the client does not have the data yet (e.g. data that is uncacheable).
It is bad design, but more importantly, server push is a (subpar) solution to a problem we shouldn't have in the first place.
How exactly modern web ended up in a situation where, first time browser is displaying a single page (with maybe 3 pictures and 2 paragraphs of text), it has to download 300 resources from 12 different servers, including 2 megabytes of minified javascript?
How many files touches some typical desktop program to display 3 pictures and 2 paragraphs of text? How many megabytes its installation occupies? My bet is that numbers will be comparable. That's the way people write software. Standards and tools should adapt. It makes no sense to complain about it as nothing changes. Every popular JS build tool helps with good practices by building a single minified bundle. Popular JS frameworks are tiny portion of those 2 megabytes. Developers just don't care and you can't do anything about it. You can build better protocols and better tools to make those applications work faster. And developers will leverage those to make their apps even slower. Who cares about 2 MB with 5G?
As much as I agree in general, the last part affects me and many others. I only get 2.5Mb/s and I work for the WISP.
The wife's family living away from the main city have intermittent connection and slower speeds. We have only one submarine cable and poor infrastructure further out. So heavy, bloated sites eat up people's pre-paid internet packages quickly or have trouble loading altogether. Prepaid is around $1.25 for 500MB or $10 for 5.5GB.
I think lower bundle sizes should be a goal. Or lower bandwidth websites should be available such as a 'm.' Domain. IMO
Do you reinstall your OS/apps daily or even hourly?
^Who cares about 2 MB with 5G?
That's exactly how we get into current shitty situation. Network is fast, memory is cheap so let's do whatever we want. In 2004, I only had 512MB memory on my computer, it run pretty smoothly. But now I got 64GB of memory and I run of memory now and then. I'm wondering how soon I'm going to put 1TB of RAM into my computer, not going to be too far away I reckon.
Statements like this reminds me we live in different planets. I'd argue we should still care, just like we care about accessibility in general, but obviously it's indeed a lost cause. Anyone not on 1Gbps and 32 GB of RAM is to be relegated
63 for me, and most of those are libraries which should already be in memory. Which is nanoseconds away from the CPU while servers are dozens to hundreds milliseconds away.
That's not the whole story of course: there's an X server that feh is communicating with over a domain socket and usually shared memory, and X implements significant functionality on its end. Then there's drivers, and the stuff between these things.
Sure. And bloated websites aren't dropping from the race here, either. They are communicating, over HTTP (and maybe WS/SSE), with fair number of servers, that also implement significant functionality. Then, there are microservices, databases, network between those...
Ultimately, though, even the script-free HTML pages that purists generally like and do not see as a problem do all of these things just as much. The point is that people have a lot of feelings about how simple, small and self-contained different software is, but realistically if you're not on a Commodore 64 they're all nightmarishly complicated. It only feels otherwise because encapsulation can be effective.
It's a bit nitpicky to go this direction, but in general having the display server implement all of the things X does is not necessary at all, especially because most apps, certainly browsers, essentially ignore those features of the display server, because they need more functionality and better performance.
That said, I would not be surprised if XFree86 was, at some point, significantly larger than contemporary web browsers, given the enormous amount of functionality that was loaded into it. Of course, modern web browsers definitely trump any old X server, so is this really relevant? I guess it depends. I get a huge sense that what people are longing for is a return to the "good ol days" when software was simple and fast, and X is a damning counter example, though it certainly doesn't mean that there's no point to be made at all, just that it is perhaps less black and white than people suggest.
I am not trying to say that feh is as complex or as slow as a web browser, only that in general, people treat the division of "native code" and "browser code" such that code running in a browser is always more bloated and slow. Somehow though, this is demonstrably not true. Looking at only very simple software with intentionally very limited scope is not going to give the whole picture. When you look at fairly complex software, the additional burden of having a browser underneath can fade away compared to algorithmic complexity issues and poorly optimized code. Your text layout and font shaping routines are probably going to struggle to compete with a browser if you have a very heavy layout to handle, and if you're doing accidentally quadratic things it's going to matter more than JIT or GC overhead.
I think X was kind of like this, yeah - in the eighties and early nineties; it's got its own chapter in the Unix Haters Handbook. There's been an incredible amount of work done to fix/work around its problems, and some of them - like security - turned up to be not practically fixable at all. Rewriting it into a properly minimalist design 20 years ago, like Apple did, instead of just now, would save everyone a lot of time.
There is a difference: a webpage is not a program, the program is the browser. The browser is a program to display documents, just like a text editor can display text, a PDF viewer can display a PDF or a video player can play a video.
The problem is that who make websites, instead of making documents, maybe built dynamically by the server and with some interactive elements in it, doesn't sent you a document but instead sends you an application that builds the document into the browser, basically turning an application that simply displays you document into a virtual machine that runs an entire graphical environment.
The fact is that most of the websites to function doesn't need a line of JavaScript, and still are downloading Mb of libraries to do what?
I think the web is a great application framework, but I agree some sites really don't need as much JS as they use. For example, my note taking setup is a self modifying HTML file that relies heavily on JS for obvious reasons. Your typical blog or news site really doesn't need it in the same way.
I think that one of the problem of the modern web is that it's seen as an application framework, and we forgot the origin that is the browser as a document viewer, basically.
Most of the problems wouldn't be even present if we reason in terms of documents, and in terms of operations that you can do on these documents (GET, PUT, DELETE, POST). You find out that for most website you don't need JS!
One could argue that JS is an optimization because you don't load up again the whole page each time you navigate to a different URL. That is false: if you cache the assets that doesn't change between pages such as stylesheets and images correctly, downloading just the HTML of the page is something trivial. Look at the number of requests that a webpage that uses JS does: is that more efficient?
I just want to read a damn article. Why does it need to download hundreds of resources from dozens of origins? Reading a PDF article on my desktop touches exactly one file, the PDF. Ok, maybe some dylibs from the OS related to PDF rendering. But surprise! Browsers already have everything built-in for HTML rendering! No need to download an HTML rendering engine, because it’s already there: it’s the browser!
Basically because site owner wants to monetise your visit. Those who don't want to monetise you, usually don't put loads of trackers, ads and other stuff which is main reason of those hundreds of requests.
Because multiple files require multiple roundtrip times, more connections, and the total amount of data is higher because of all the waste that happens with headers.
The headers are not the wasteful part. Headers are typically in the low-hundreds of bytes. This extra data is insignificant as "waste" compared to the request/response content.
The real waste is in the time it takes to create and destroy the connection. (hence why http/3 switched to UDP, and also why multiplexing is a thing.)
Thing is, combining js and css on the server side into 1 file pretty much negates this speed benefit. I've been building sites this way forever, and performance is great. First page takes longer, but then those files are in the cache anyway.
The actual problem is Ads. They require tracking, and of course displaying. If you're looking for waste, or indeed why a server would bother with http/3 then look no further. No ads, no problem.
Unfortunately for those sites that rely on advertising for revenue, I don't have an alternative suggestion. I get it, ads pay for lots of the Internet I "browse". I'm not a fan of pay walls and subscriptions.
So http/3 is a solution to an economic reality - and really only benefits the ad-supported Web - but for them it is important.
I/O. An anecdote. A friend of mine was modding a 360/PS3 game recently. He was trying to animate a texture by cycling through an image sequence. The first attempt read every image from disk each time, and ate shit. The second attempt pre-loaded them all, and it works perfectly fine
> How exactly [has the] modern web ended up in a situation where, first time browser is displaying a single page (with maybe 3 pictures and 2 paragraphs of text), it has to download 300 resources from 12 different servers, including 2 megabytes of minified javascript?
I remember looking at a graph showing our frontend usage of various libraries. Moment was huge, because it depended on so much. At the time there's wasn't really a good alternative though.
> How exactly modern web ended up in a situation where [...]
> it has to download 300 resources from 12 different servers,
> including 2 megabytes of minified javascript?
This is "best practice" that is used widely to work around HTTP 1.1 Head of Line Blocking [1]. HTTP/2 and to a greater degree HTTP/3 (as it also alleviates TCP head of line blocking) are fixing the underlying problem making the former best practice an anti pattern (but only for those users able to use modern HTTP implementations).
“12 different servers” and “minified JavaScript” were indeed workarounds for head-of-line blocking, but I think the GP’s main point is that “300 resources” and “2 megabytes” should not be required for displaying a web page.
They are not required to display a web page. They are mostly required to make money off that web page, and, to a smaller degree, to observe how users interact with it and thus improve it (also aligns with making more money).
Fortunately, Reader Mode is available in a few user-friendly browsers.
Adobe Photoshop and Quake 3 are JS apps nowadays so depending on your use case it's completely legitimate to download hundreds of megabytes of code and data in modern browsers. I once worked on an app that was a heavily optimized tree shaken 40MB bundle of JS because it was a telephony system, video conferencing and document sharing and collaboration app. Completely ok size for that use case.
If it's just a normal non-interactive website then it shouldn't have any javascript in the first place.
Newer HTTP versions solve some some things but are not magic pixie dust.
For example:
* If you have file A requiring file B requiring file C requiring file D you still get a chain of requests.
* Compression works a lot better the more data you throw at it, especially similar data which is usually the case for JS/CSS. SDHC was supposed to solve this, but it was never adopted by any major players besides linkedin (and google itself).
HTTP/3 is pixie dust. It solves most problems that previous transport layers had and also supports 0 RTT TLS handshakes in case of QUIC. Of course the transport layer can't magically resolve application layer dependencies as you mentioned, that's not its job.
HTTP/2 was supposed to help avoid openning too many connections, but of course TCP in TCP is bad form. Now HTTP/3 is TCP in UDP, and has separate connections (more or less) per resource. I'm not sure what the big difference is between that and HTTP/1.1 with multiple TCP connections.
There is an argument for better congestion control. Which is funny coming from Google where they control the kernel on the server and the clients. Yes, it takes more time to deploy better congestion control if it needs kernel updates, but if it's really important to update congestion control without kernel updates, you could make interfaces for usermode congestion control.
Too many TCP connections is a browser limitation (for DDOS prevention reasons mostly). Inside each connection you are limited by head of line blocking, either by HTTP/1.1 itself or by TCP when using HTTP/2. You are correct that HTTP/3 can stream multiple resources over one QUIC connection via multiple channels and each channel can make progress independently from each other channel. Nowadays (assuming a modern browser in a non-udp restricted environment), you can just download hundreds of resources at the same time from the same server through one HTTP/3 connection without much overhead and transport level limitations.
Seems like all the churn could have been avoided by webservers advertising a limit on number of connections and browsers opening up to that limit if needed. Maybe in the connection header, or the keep-alive header, or some new header that Google servers and Chrome Browser could have tried out first.
Use css variables for colors, then load the relevant set with a 'prefers-color-scheme' media query. No need to serve 2 CSS assets: the difference should be minimal.
We're assuming here that the site owner wants to push the image.; Having the client request a different image as a follow-up based on the user's preferences is a different solution, and there are lots of specific ways to do that.
Nowadays absolutely. Worth keeping in mind HTTP/2 made it into browsers 4 years before that media query though. You can also request that info via header nowadays if you for some reason were really dead set on sending the minimal CSS directly.
Push would IMHO allow nice pub sub if combined with SSE. Particularly for short lived objects one could actually considerably reduce overhead. However, it has been build with the design goal to be an optional feature (as there is no client side API) : I guess it fulfilled at least that goal.
That's the idea that led to implementing server push. Lots of people it, and it turns out not to work very well. There's too much variation in what people will already have in their caches and the server is not great at predicting the order in which clients will need the resources.
First request is empty filter, server will push everything mentioned in HTML. For subsequent requests browser will fill filter with known hashes, server will push changed resources (and false positives).
I'm just still shocked that this wasn't obvious to more people before: it isn't like you even need to have implemented this feature to do the instrumentation required to know whether this would work, and it frankly had always seemed like a long shot.
I think it was something much simpler: oh, you're navigating to `index.html` without session? You're going to need this CSS, JS and PNG files as well.
And the idea is that client would already have those files by the time browsers parses `<head>` it already has them all. Except...browser cache exists, so who cares.
Ans it turns out the way this was implemented didn't really works well. There just isn't a universal format that you can generate the list and upload it to server/cdn/whatever. No one ever figure out how to actually use this list to generate a http2 server push from a common platform/cdn.
The alternative (Service worker/<meta> preferch/preload tags) on other hand are much easier to handle although have one extra round trip. Because they are just text files that you need to upload to the server.
The reason I'm a little disappointing about this, is because I was really hoping for a future where we improve sending collections of items from APIs.
One issue with the typical API formats is that all the data for each resource is shipped with the collection, which means that client caches are unaware of the 'transcluded'/'embedded' resources.
Server push, if implemented well could have allowed us to just push every collection member down the wire. Push lets you solve the Q+1 issue because all members can be generated together.
Also, at some point there were talks about a browser request header that would send the browsers' cache state as a bloom filter to the server, which would let the browser have a pretty good idea of what not to send.
Anyway, I'm disappointed this happens. I get that people had trouble putting push to good use, but in my opinion this just needed more time to brew. Once Chrome announced the removal, all of this died.
Funny thing is that I was just looking into how this software could work with APIs and now it seems like it's dead in the water if the support is removed from the browser. Sure, it's a progressive enhancement and you wouldn't break anything, but you lose all the benefit as far as I can tell and you _are_ adding an extra layer.
I'm afraid per-item responses are not very realistic, even with HTTP/2 and efficient message formats. The items then begin to be comparable, or smaller, than the client identity token sent with each request. Its size is limited by cryptography.
Caching is also notoriously hard to get right. Apps (including web apps) usually prefer to depend on their own caching: it saves them more in development and support expenses.
As usual from Chrome, 100% ignores the fact that developers have wanted to use fetch to be able to reactively hear of resources coming in, & chrome has (largely) ignored these pleas. The post focuses only around the most boring & basic capability of webpage loading, since that was the only capability developers ever got.
The article talks about Jake Archibald enumerating some problems with PUSH. Well, Jake was also author to a mini-proposal to add Push support to fetch so developers could try out other uses for push. Seemingly ignored by chrome.
Having the browser be a minimalist, picky implementation of http protocols is hard for me to reconcile & be ok with. There's well over a half decade of neglect & plugging their ears on Chrome's side around Push, not listening to users, not delivering us low-level extensibility manifesto capable apis, and this pulling the plug is sad and sorely premature.
We are stuck forever inventing new non-http transports, over SSE, over websockets/webtransport, over long polling, becayse Chrome systematically ignored the one thing that would have made http capable of satisfying many of the desires of the old HybridBidirectional working group, & has kept the page unable to understand & recieve resources coming to it. What a blasted shame.
this really strikes me as evidence that something is wrong with the http standardization process. we should know if something's a good idea before immortalizing it in a standard.
It may be removed from chrome, but it's still in the standard.
Keep in mind that the HTTP/2 standardization process really started from SPDY [1]. Before HTTP/2 the standard hadn't changed significantly in _decades_ due to lack of industry consensus and actual data.
Google then used its unique position as a) massive web server and b) massive web browser to perform real-world protocol experiments that _nobody_ else could possibly do. SPDY came out of that (really cool!) work, and had some great benefits, and the working group started with the spec and worked to evolve it.
The server-push originally comes from SPDY, and as I recall it seemed an obviously useful optimization at the time. It's a bit ironic that the same company that introduced it is now saying "we never really found a use for it".
Disclaimer: I was employed by Google and on the HTTP/2 working group at the time.
- "only google can do these huge experiments, and we've blessed the world by sharing our discoveries, so we can have confidence that our proposals are validated with real world experience."
- "That thing we standardized and got a bunch of other people to implement? yeah, i know we said it was really useful, but we meant it seemed really useful. We actually never found a use for it."
What it means is that the Google mindset of introducing and later killing off whatever services they feel like, extends to how they view the standards process, viz. that it’s theirs to tinker and butcher as well, and coupled to that the implicit belief that their implementation of the web is the reference implementation, and the rest of us simply subordinate to Google’s commercial preferences.
Other vendors do this too - the fundamental conceit at play is as old as the tech sector - but that doesn’t make it any less arrogant or reprehensible behaviour.
With that understanding, the process note above from an ex-Google employee amounts to a description of wilful abuse of market power.
So people aren't allowed to make mistakes? HTTP/2 was morphed by so many other entities besides Google and offers a host of benefits. Having one useless feature is hardly worth complaining about.
>this really strikes me as evidence that something is wrong with the http standardization process.
The overall decision-making around how the web works is insane and getting more insane by the year. We have fairly trivial and absolutely universal problems unsolved for decades, while browsers get crammed full of features that aren't used by 99.9% of websites.
Worse, some problems are finally solved in such a half-assed way that it's almost worse than having no solution at all. (Input type="date", meter element, dialog element etc.)
This is not at all what I imagined the field would look like when I entered it nearly two decades ago.
- A working element that only got half assed/ignored by one provider (Apple, but who's surprised?) which meant polyfills for years to fix it.
- A niche element, there are plenty of those?
- A relatively new element that solves a lot of issues with Z layer, accessibility etc and is a good basis for other components/libraries to use for their styled/enhanced modal dialogs.
Input for dates has many issues with styling, cross-browser compatibility and various formats/locales.
Meter has a nonsensical data model and no standard way of styling it.
Dialog is a half-assed element that's useless without large amount of styling and code. For its sake they've added an additional form method, which will likely break many older JS libraries.
Mind you, we're talking about controls that have been faked or implemented on the web by developers for at least two decades. This is pitiful.
In practice, I’m pretty happy with how dialog turned out. I certainly do not find it needing a “large amount of styling and code” to obtain immediate utility.
I’ll readily agree, however, that the meter element is trash, and date input an underspecified UX crapshoot.
My biggest beef with Apple’s standards engagement, however, is their intransigent and ill-considered refusal to implement customised built-in elements.
Your first two points are valid, and a wider issue with styling form pseudo element internals, though I'll contest letting date visualize as the user's locale is a better option than forcing American month/day/year weirdness on the rest of us.
You're wrong on dialog though.
It's not half assed, it's the core functionality needed for a dialog, no more. It makes very few assumptions abouts you want your dialogs to look, or behave with closing/opening. You only have to build atop it, rather than strip it back (e.g. Like how you have to strip/reset lists to use as nav menu elements)
I've styled them and it's usually less css than equivalent bootstrap or homegrown dialogs.
I also doubt your claims that the new form method will break older js being a real problem. The method just allows js to get a standard way of how a dialog closed. I just don't see when you'd use old js that might have issues to handle that..
>We have fairly trivial and absolutely universal problems unsolved for decades, while browsers get crammed full of features that aren't used by 99.9% of websites.
Why is this surprising? Universal problems are hard to solve otherwise it wouldn't be a universal problem in the first place. Add to that large numbers of groups will have their own set of opinions on what the best solution is, and it will conflict with some ideas.
>Universal problems are hard to solve otherwise it wouldn't be a universal problem in the first place.
This is completely backwards. Universal problems on the web are routinely solved by everyone designing a standard website. They often have fairly standard solutions. Browser vendors routinely fail to generalize the experience of run-of-the-mill web developers. It's not about engineering. It's about misaligned incentives and operating from a bad frame of reference.
> We have fairly trivial and absolutely universal problems unsolved for decades
This describes most areas of applied computer science, honestly. Language design, build systems, operating systems, etc. When standards and/or widely used systems are involved, nothing is trivial. And the web is the most widely used and most standards-based system out there.
But the only real way to be sure if something is a good idea, especially in complex distributed systems such as the web platform, is to try it out. And when you try it out at scale, standardization is very important. The alternative is to have everyone using new ActiveXObject("Microsoft.XMLHTTP") because you have a non-standardized thing that's rapidly turning out to be a good idea.
The purpose of a standardization process isn't to stamp approval on good ideas; it's to ensure interoperability. Server Push was a plausible idea. It very much could have been a good idea. It turned out not to be, after we tried it in the real world for many years, but that's okay. And we know one thing for sure - the reason it didn't work wasn't that people were afraid to use a nonstandard X-Chrome-Server-Push extension.
That kind of seems like the difference between top-down and bottom-up standards. MS added a weird extension to IE to support their proprietary webmail app, and... actually it was great so people wanted it pulled in to every browser as a standard. Many other features from Netscape's blink to IE's scrolling marquee died natural deaths.
HTTP/2 was what? Something no one wanted, imposed by Google? Is that too strong?
Agreed, it should have received much more testing.
However, in this case it being in the HTTP/2 standard is moot, since it's just a (premature) optimization and thus its removal results in a reasonable fallback, which is simply not using that particular optimization, and also because HTTP/3 is so far along already.
Not to get too tangential, but this seems similar to fetch removing support for reponse bodies for POST/PUT requests; a login POST, for example, might return information about the user's login or the state of the server, or even a per-tab/per-page token that isn't a cookie header, but fetch simply refuses to support it (even though XMLHttpRequest still does). Fetch removing this means that additional round-trips are needed, even over a multiplexed connection, and certain app designs are simply not possible. The solution seems to be to buck the trend and just use XHR instead of fetch, especially since fetch doesn't seem to be available on older Android Chrome (possibly 5-15% marketshare even now.)
> it's just a (premature) optimization and thus its removal results in a reasonable fallback, which is simply not using that particular optimization
this is a salient point. if it's just an optimization and not implementing it (or removal) doesn't change behavior of sites that have adopted it, then it's benign.
I would say what’s wrong is that Chrome decided to remove a standard feature, and due to their market share, nobody can oppose it. There was a time when a single company controlled the web. That was Microsoft. Today, it’s Google.
There was lots of public discussion, and no one made a serious case for keeping it. I think Chrome probably would have been happy to keep it if someone had been able to describe how it was improving performance on their site.
What's wrong with XHTML 1.0 or 1.1? (assuming you are speaking about this)
What significant feature in XHTML is not supported by HTML5?
if you are only speaking about the syntax (so your statement includes XHTML5), I don't follow you neither: I don't see what's wrong with the XML version of HTML5.
That issue is considered a feature by many. Don't send out broken web pages. If you don't build your pages using string concatenation you have already eliminated most problems (it's just like SQL, in that respect).
XML parsers are not that bad when you disable custom entities, which browsers could easily do.
There's nothing stopping developers from doing server-side validation before sending markup to clients.
It seems like the majority of developers have never really wanted to make that cost-benefit tradeoff, though. I ran tons of websites declaring an xhtml doctype through https://validator.w3.org/ back before HTML5 when xhtml was still trendy: almost all of the "xhtml" websites failed validation.
> That issue is considered a feature by many. Don't send out broken web pages. If you don't build your pages using string concatenation you have already eliminated most problems (it's just like SQL, in that respect).
Yes, but there weren't many tools to "correctly" compose XHTML back then.
> XML parsers are not that bad when you disable custom entities, which browsers could easily do.
Yes, but it's another thing browser developers need to think of. A lot of CVEs already originate in browser. Even if it's actually safe, people who got burnt by XML, would have bad opinions about XML in mind.
No. This is actually wrong that browser by default doesn't report errors in HTML, CSS or JS - because of this nobody notices them and you cannot understand why the button is not working. Instead, in case of any error a browser should show a big red bar above or below the page. So that the user immediately understands that the page is broken and it makes no sense to try to enter anything.
Hiding errors is always a poor choice. Only if you are low paid developer not interested in making a quality product then probably you like browser's behaviour.
Wrong or not, the point is that many websites that declared`xhtml` back in a day failed validation and the majority of developers didn't like it. Browser vendors (WHATWG) didn't like that their browsers showed dead pages (parsing errors) more often than not.
Some estimates say that 99% of HTML pages in the wild have at least one error in them. Yes, they errors would probably be fixed if it stopped browsers from rendering the page.
Browser plugins also had to speak valid XHTML and be able to modify documents correctly. In-line JavaScript was...funny looking. CSS also behaved differently in XHTML.
I, personally, liked XHTML behavior because errors in HTML were essentially Undefined Behavior. That resulted in different results from browser to browser (back when we had multiple browsers and not just Chrome). However, I also like Rust, so maybe it's a fetish? /s
We didn't really have good tools back then, and the way HTML was generated wasn't brilliant. Currently, I'm making a website in Yew, and it won't even compile if I don't have tags correctly placed and closed because everything inside `html!` macro gets turned into rust code and then HTML gets built. I think JSX behaves similarly?
> however it’s collectively considered a bad idea and no one uses it
No one uses it going forward. I'd hate to venture a guess at how many existing sites there are that use xhtml. Browsers are still expected to parse and render them properly.
HTTP/2 Server Push being impractical matches my experience on getting my game client[0] to load quickly (2.5 - 3.5 seconds via Starlink, for cold - warm cache). What slowed it down:
1. Fetching many resources simultaneously, 162 resources just for terrain data, a couple hundred more for meshes. I am currently serving with Express, so the solution here was to put Cloudflare in front of it as a reverse proxy with a short cache TTL. Cloudflare then serves them with HTTP/3. Also, requesting all of these simultaneously rather than sequentially. The header overhead isn't a problem with HTTP/3 since that uses a hash or something rather than re-sending all the same headers in each request.
2. Resource byte size. Cloudflare does Brotli but from my testing, I would need to combine terrain zones into a single binary blob for this to reduce byte size by half. (Compressing things that are a few hundred bytes achieves very little.) But combining these would mean that any change to the data of one zone would require re-compressing all zones. (Mesh compression with Draco[1] helped though.)
3. ROUNDTRIP. Especially with connection latency. This is where Server Push comes in. I actually experimented with it. But it basically only saves one roundtrip (~50-500ms depending on connection); the server establishes a connection then can push. Without server push, the server establishes a connection, then waits for the client to request resources.
The client requesting resources has a few advantages. 1) Server doesn't need to figure out what data the client needs, the client can do those calculations, and the server can simply verify (which is a lighter SQL query than discovery). 2) Client can not-request resources which it already has (in cache or storage)! 3) Resources can be cached by Cloudflare at the edge.
You've got a fairly heafty JS file on the critical rendering path (350kb), so one option to help your roundtrips 3 is to preload the other files it uses so it's not dependent on the JS download and executing before they are discovered. See: https://web.dev/preload-critical-assets/
Thanks! That JS file is the whole minified application. The application is what knows what needs to be loaded - so I would have to move that logic out into the page. It would help but I am not sure it's worth the cost of maintaining that extra logic, in this case (being indie).
As I commented yesterday[1], accelerating page loading was only one use case for http Push frames. Alas it's the only ude case Chrome ever acknowledged or cared about or have ever seemingly recognized (in spite of it under-the-hood powering Push API).
Push also could have been useful to replace theess of non-web non-resourceful ad-hoc protocols people have endlessly kept reinventing atop WebSockets/WebTransport/SSE/Long-polling to push things like new chat messages to the browser.
The author cites Jake Archibald's struggle using Push for page loading. But Jake also was interested in expanding past this incredibly limited use case, and threw together a mini-proposal to let Fetch hear of incoming Pushed resources[2]. Chrome though largely have never acknowledged this desire, even though it's been asked for for ~7 years now.
So the web is still request & response & there's still no natural obvious way for the browser to hear of new resources that are ocurring. Chrome didnt listen to developers, never let us actually use the feature, and now they're killing it, and we're stuck where we were two decades ago, scabling to figuring out what to do to get some bidirectionalism beyond request-response.
The Push API <https://w3c.github.io/push-api/> is a completely different thing with absolutely nothing in common with HTTP/2 PUSH frames (Server Push), just like Server Push is nothing to do with Server-Sent Events. PUSH frames would be unsuitable for the Push API, which is all about not having to keep a connection alive.
(The rest of your comment is still valid, though I reckon you overstate the practical usefulness/superiority of Server Push somewhat—sure, the ability to push multiple streams instead of just one is useful in some cases, helping avoid head-of-line blocking or subprotocol complexity, but in practice I suggest that most scenarios can’t actually use that power at all.)
You've listed some fine advantages of Push frames, but the one most near & dear to me is that it is supported by HTTP itself & delivers http resources. This is an incomparable advantage versus everything else: slotting nicely into the existing ecosystem.
With QUIC based semi-connectionless HTTP3, the advantagea would only have been further accelerated, no longer even needing a TCP connection to be maintained.
I see now that I misunderstood what you were speaking of by “under-the-hood”. I was thinking about the developer-facing parts of the Push API, but you actually meant the bit in the browser’s control, opaque to the developer. I retract my quibble.
They mention this in the doc, but it seems like the future solution to preloading resources will involve HTTP Status 403 [1]. That seems like a great alternative to server push.
Currently it seems like the best option is to use Transfer-Encoding: chunked and make sure you flush out an HTML header that includes the preload directives before you spend any time rendering the web page. This is a pain - especially if something in the rendering fails and you now have to figure out how to deliver...something to the client. It also limits other headers significantly - e.g. cookies.
Lol yes of course I meant 103. Though I’m ready for an http status code that’s like that: “I can’t give you what you want, but here’s something you didn’t even ask for instead.”
What really killed it was an awful implementation. It did not simply push things into browser’s cache. Instead, pushed items were held in some kind of temporary purgatory, and would be discarded if browser didn’t immediately have a need to request the pushed resource.
IIRC there were two reasons for this. One was an information-leak concern whose details I don't fully remember.
The other is flow control. A server push doesn't automatically send the entire object. It opens a new stream and fills the window, but the client must actively read / ack the stream for the remainder to be sent. To do otherwise would allow the server to de-facto violate the client's stated flow control settings and potentially DoS their network link.
This is one of the reasons HTTP/1.1 will still be reliable and workable decades from now, and every HTTP/2 and HTTP/3 client will be long gone. Google has just taken their ridiculous deprecation policies and applied them to web standards bodies.
Not all that complicated, I have some places on the interwebz where my kind of NSFW content is posted so I scrape those and maintain an SQLite database of direct urls.
Over that database I have a tiny Koa server that checks if URL is still active, processes image in memory and serves it through HTTP2 over to a Preact app that handles displaying them.
I do this so I can share this with some people, and allow them to share some stuff without exposing myself to liability for hosting.
> I do this so I can share this with some people, and allow them to share some stuff without exposing myself to liability for hosting.
I don't know what country you live in, but here where I live (in the US) you definitely aren't avoiding any legal definition of hosting by only relaying.
I'm fairly certain you are confusing Server Push with something else, because as far as I can tell Server Push is not useful for doing what you describe.
Why is everyone so mad about this feature? Maybe I do not understand Server Push in http2, but isn't it useful to e.g. send a rendered picture to the client instead of the client polling the server every 5 ms until the image is ready? What about chat applications?
What we need is somehow the ability to serve the html/js and json at the same time without having to wait for the client to get the html and then do the fetch request for that json. This will save a full round trip for loading content while keeping things simple.
If you mean avoiding the dreaded loading spinner when loading a single page app, you can add the JSON data in some script within the HTML. This is what server-side rendering frameworks like Next.JS do. In it's simplest form, just include something like:
Put the HTML/CSS inside the JS, make that whole bundle cacheable, and make your "HTML" response basically be one <script> tag starting the JS and another containing the JSON response.
Folk have been using this technique for a decade or more
An alternative is to have a minimal HTML that has basically nothing except a <script> tag that connects to a WebSocket then have all content delivered over that. I've done testing with this in the past and it definitely outperforms HTTP/1.1 but maybe not HTTP/2 or HTTP/3 (never tested against those--this was several years ago).
I even wrote a web server with bundled framework (as an academic exercise) whose whole purpose was to work like this. It was basically made for delivering any given bundles of assets over a WebSocket and had some cool features like the ability to auto-encode, auto-compress, or translate from one file type to another (say, turning a PNG into a JPEG or minifiying JS/CSS) as a simple matter of modifying the configuration.
I just generate the json when loading the page and embed it as script with a nonce. Of couse I lose the caching of the "static" page but it's worth it.
Hmm, that's an interesting idea - perhaps the browser first downloads some kind of "manifest" file, which lists the required URIs, then the browser can request them all at once?
I posted this at the Google group, though it is pending approval. So this is a shorter version of it from memory:
I have a dev http/2 server that is serving my app locally, amounting to 271 module dependencies. It takes about 400-500ms to load everything and startup the app. The implementation is trivial and without errors, every dependency can locate its assets because it sits at its real path, sourcemaps etc.
Switching to Early hints/Link: it becomes 4-5s and even with all of the modules cached, it doesn't get less than 2-3s. So this could be an implementation difficulty and might be improved, but it is still a non-trivial overhead.
Now the only viable solution becomes bundling, even with esbuild the improvement over http/2 push is marginal. But now there is an extra build step that before was handled at the HTTP layer by "push". The files are bundled to a single file, so they no longer can access their assets relatively to their path, since they have changed paths. Workers etc. have the same problem, import.meta.url no longer works and so they can't be located. Not without various steps of transformations and assets handling, and there'll always be edge cases where those are going to fail. Certainly not composable across domains/projects since by bundling they become hardwired to their environment.
Push doesn't have these problems. So, it's a step backwards IMO to remove it. Without "push", the only viable solution becomes to use 3rd party bundling tools for any non-trivial work that exceeds a handful of dependencies, where with "push" you could deploy the exact structure of the code as it was. Bundling makes source code and the web less open and less accessible and with this change there is no other solution. Early hints are fine when dependencies are less than a dozen, but it becomes much worse as they grow, leaving you with no choice than build steps/bundle steps, instead of simply uploading the directory of your source code to the http/2 push server leaving the structure intact.
Certainly not. Cache API is a useful API that can enable faster web apps by skipping network calls altogether. It also enables offline-capable web apps. I regularly use this API to speed up my web apps -- both personal and professional. I recently wrote about using Cache API to make a web app work entirely offline: [0].
Also, I think you may be mistaken about being "(kinda) server-push" - Cache API is entirely client-driven: the server can't push items into that cache; the client (usually a service worker) must choose to do so. I don't know what you mean when you say it's like server push.
Cache API being "useful" and "entirely client-driven" - both great points, but how is does it contradict my statement about same API being usable for server-push (i.e. force-feeding some objects to client it didn't ask for), may I ask?
Remember, "client" (assuming user didn't disable javascript) is a dumb machine that executes whatever (code downloaded from) server tells it to, within some (pretty generous) limits. Imagine index HTML containing this:
<script>
const cache = await caches.open('push');
cache.put('/resource.json',
new Response('{"foo": "bar"}'));
cache.put('/resource.gif',
new Response(atob('R0lGODlh...'));
</script>
That, of course, assumes that rest of code would use cache.match() instead of fetch API or XHR. Or, more realistically, a wrapper that tries both.
I don't deny that Cache API was usable from HTTP/2 push. I'm responding to your question asking whether Chrome will obsolete the Cache API because it was usable from HTTP/2 server push.
My answer is no, of course not, because Cache API is unrelated to HTTP/2 push. It's useful for storing resources regardless of whether they're HTTP/2 push'd from the server or fetched from the client. Indeed, the primary use of Cache API is storing resources fetched from a client's service worker.
We already have Server Sent Events over HTTP/1.1 so yes this was completely unneccessary.
The TCP head-of-line problem makes HTTP/2 a solution ONLY for people that abuse the bandwidth in the first place (read big centralized coorporations that have large bills of wasted eletricity) making it a non-solution across the board for the distributed (hosting HTTP from home) humanity.
The reason for "eternal growth" mindset is job security:
"What are all these people going to do now that we have the final HTTP/1.1 working perfectly across the globe on every machine?" Depreceate and "improve"...
In my mind the second version (not always named 2) is always the final version, see half-life and starcraft for other stories that tell you a similar progression: you make 1.0 as well as you could and then take a pause and realize you need some final additions so 1.1 completes the product/protocol. (both HL and SC where rewritten in a large manner after they where "done").
2.0 is often a waste of resources, see HL2+ and Starcraft 2, where the electricity prices are going now and for eternity you wont be able to play them anyway!