4 ms·
This really seems like overkill to me. We've made HTTP/2 that much more complex to implement (a custom compression and dictionary not used anywhere else) to com
by byuu 10y ago
This really seems like overkill to me. We've made HTTP/2 that much more complex to implement (a custom compression and dictionary not used anywhere else) to compress headers. And complexity always leads to fun new vulnerabilities. I guarantee at some point we'll see at least a DoS come out of this.
I would add that it also consumes more resources to compress these headers (I know huffman is fast; but it's not as fast as plaintext), but you can probably cache a good portion of it, and then just encode the per-connection values at the end. Although I'd be surprised if Cloudflare has nginx doing that.
Right now, my domain's HTTP header is 192 bytes:
Content-Type: text/html; charset=utf-8
Content-Length: 3884
Connection: keep-alive
Content-Security-Policy: upgrade-insecure-requests
X-Content-Type-Options: nosniff
X-Frame-Options: deny
And more than half of it is just optional security enhancements.
So now I'm going to compress that header so that it's ... what, 100 bytes? Even on my site that's incredibly lean and lacks images, it's around 20-30 KiB per page of content. Modern web pages now average being larger than the original DOOM video game (2301 KiB.)
So we're doing all of this to chase roughly a 0.05% reduction in bandwidth per page? We're worrying about the spot on the carpet while ignoring the elephant in the room.
- jgrahamc 10y agoFrom the article: It is difficult to see, but we get 1.4% savings in the total egress HTTP/2 traffic. Header compression is cutting our overall bandwidth for HTTP/2. While it does not look like much, it is still more than increasing the compression level for data would give in many cases. So, better to do this than try to further compress pages.
- byuu 10y agoThere's a pretty big disconnect between 0.05% and 1.4%. Believing their numbers would indicate their average page sizes end up being around 7 KiB, or their headers end up being gigantic 4 KiB+ monstrosities, both of which I have trouble believing. But it's still small. Instead of adding a large chunk of complexity to HTTP/2, how much of that 1.4% do you suppose could be gleaned by removing unnecessary headers like Date, Server, X-Powered-By, cf-ray (on Cloudflare), etc? I understand that for Cloudflare hosting/proxying others' sites, their options are limited and they have to forward their customers' headers along. But I still think adding all of this is a bad idea. Not that it matters of course, it's already done. The IETF basically rubber stamped SPDY.
- tehbeard 10y agoI've only glanced at the HTTP/2 spec, but doesn't it allow reuse of headers between requests? e.g. The security headers wouldn't need to be sent with each file, only the first? This could be where the bandwidth savings are coming from.
- niftich 10y agoYes, it allows re-use. Access-Control-Allow-Origin is in the static table, and so is Strict-Transport-Security. The rest go into the dynamic table [1], which would be beneficial if they don't change. Most security headers are hardcodeable, while C-S-P is designed to be a function of the selected resource representation, not some site-wide global. But it's often used in such a way. [1] https://tools.ietf.org/html/rfc7541#section-2.4 https://tools.ietf.org/html/rfc7541#section-2.4
- Matthias247 10y agoThat's what HPACK (which is described in the article) and it's dynamic header table is for. However as soon as you exceed a certain amount of headers (the size which you can store in the dynamic table - typically 4kB) the header table might no longer work as good as possible. That's because the newer headers will always lead to the eviction of older headers in the table, and therefore headers will no longer be cached for the duration of the connection.
- raptium 10y agoThere are more gigantic monstrosities than expected. `content-security-policy` on inbox.google.com is 1.4K and my `cookie` sent to inbox is around 900B. :-(
- niftich 10y agoSecurity headers are worthy of a different [1], lengthy conversation, but they were borne out of need to override defaults about a browser's security features. Sometimes, for different features, those defaults are permissive, and sometimes they're restrictive, provided the browser supports that header -- and most of them were designed to be backward-compatible so that their truth tables are complicated. But realistically, consider C-S-P as metadata about the resource representation about to be delivered in the body, instead of a property of the HTTP response itself. In fact, the naming of the header 'Content-[...]' is consistent with the semantics of RFC 7231 [2] which defines a number of different 'Content-[...]' headers, like 'Content-Type' and 'Content-Language'. You can mentally move C-S-P from the HTTP headers into a meta tag (you can do this actually [3]). [1] https://hn.algolia.com/?query=niftich%20"damn%20header"&type=comment https://hn.algolia.com/?query=niftich%20"damn%20header"&type... [2] https://tools.ietf.org/html/rfc7231#section-3.1 https://tools.ietf.org/html/rfc7231#section-3.1 [3] https://w3c.github.io/webappsec-csp/#meta-element https://w3c.github.io/webappsec-csp/#meta-element
- raptium 10y agoYou get 192 -> 100 bytes reduction if there's only one response. The compression dictionary(dynamic table) is shared, therefore much more bytes can be saved in the following responses(assuming they contain similar headers).
- JoshTriplett 10y agoMany of your responses should be "304 Not Modified", in which case you don't send anything back but the headers. Or, for API calls, you may have a tiny response, or no response other than headers. In all of those cases, going from 192 bytes to (checking) 148 bytes the first time, or 6 bytes for a subsequent request, might make the difference between fitting entirely in the initial response packet or requiring an additional packet. In addition, hpack also allows the client to compress their request headers, which decreases your incoming traffic. And in that case, the majority of requests will have very little data in them; ideally, only the path will change between requests.
- philsnow 10y agoI think the most important gain is that client requests can fit in fewer packets -> fewer RTTs (critical on poor networks) -> lower latency to first paint -> better UX.
- niftich 10y agoDon't forget If-None-Match, If-Modified-Since, Origin, Referer
- byuu 10y ago> Many of your responses should be "304 Not Modified", in which case you don't send anything back but the headers. A 304 should be able to fit into a single frame, unless you're doing things very wrong. You don't even need headers in that case. > In addition, hpack also allows the client to compress their request headers, which decreases your incoming traffic. Yeah, that was the DoS concern I had. Lots of web server software checks the incoming header sizes don't exceed a certain length. But with huffman expansion, you can't quite make an INFLATE bomb, but if the implementation doesn't have a backout function during the decompression, you could consume a huge amount of memory by abusing this. > ideally, only the path will change between requests. Can you put the path at the bottom of an HTTP/2 request? Otherwise it would be tricky with lots of bit-shifting to reuse existing compressed headers but insert new paths onto the top of each one.
- pornel 10y agoHPACK on request headers does have a significant impact due to TCP/IP slow start and high latency of mobile networks. 100 requests per page is common (http://httparchive.org/interesting.php http://httparchive.org/interesting.php), so it quickly adds up, especially for sites that use lots of cookies (well, sites shouldn't use tons of cookies, but in the end it was easier to change HTTP than the sites). Relatively large request overhead of HTTP/1 caused headaches with icon fonts, sprite maps, and gigantic compiled JS bundles. The aim of HTTP/2 was to make requests so cheap that we could go back to having individual icon files and unbundled ES6 modules.
- byuu 10y agoYou know, I think this is my real disconnect with HTTP/2. To me, I see the problems that make HTTP/1 slow, and so I say, "okay let's address those issues." So I'll inline my includes, use spriting if I have a bunch of icons to display, cache things where possible, perform keep alive where I can, drop the use of giant JS libraries, don't use webfonts, use subdomains to avoid cookie pollution, etc. Doesn't take long. HTTP/2 seems more like, "how can we let people keep their bad practices the same yet try and speed their stuff up a bit?" And that's fine and I'm okay with the latter existing to make web sites easier and faster. But I don't like the presumption that HTTP/2 is inherently superior to HTTP/1, which is what 99% of these HTTP/2 explanatory articles promote. Complexity adds a dark cost. I think there's a lot of value in someone being able to write a client that can interact with my site in 200 lines of C code with no library dependencies. I feel like we could have put more effort into our libraries and web packages to make HTTP/1 operate much better instead, and kept the wonderful simplicity of HTTP/1.
- kevincox 10y agoWhile it does make (previous) bad practices perform better (not necessarily a bad thing) it also improves the performance of highly optimized site. For example it enabled far more granular caching. While you might convince people to bundle their assets they aren't going to reduce the amount of content on their site. They will try to optimize it but there is a certain amount of entropy they want to present to the user. If all of this is inlined you will have to request it on every page load. Sure you can be very clever and have a small number of customized bundles where you load a subset for every page, but that is very non-trivial and when we can make that both more trivial and more granular with changes we already needed in the protocol I don't see why we wouldn't do it. We already needed multiple requests on the same connection because not even the top sites are one request to load (they are very, very few of these). So all of these "bad practice" improvements are essentially "free". Also I see no reason to try to enforce habits that were formed to work around an insufficient protocol when we are designing that protocols replacement.