News for hackers. Stuff that matters.
Re:HPACK: the silent killer (feature) of HTTP/2 by byuu on Monday November 28, 2016 @10:37AM (#13056036)
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.

Re:HPACK: the silent killer (feature) of HTTP/2 by JoshTriplett on Monday November 28, 2016 @12:22PM (#13056852)
Many 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by byuu on Monday November 28, 2016 @03:59PM (#13058348)
> 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by philsnow on Monday November 28, 2016 @01:24PM (#13057313)
I 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.
Re:HPACK: the silent killer (feature) of HTTP/2 by niftich on Monday November 28, 2016 @01:33PM (#13057371)
Don't forget If-None-Match, If-Modified-Since, Origin, Referer
Re:HPACK: the silent killer (feature) of HTTP/2 by pornel on Monday November 28, 2016 @03:01PM (#13057922)
HPACK 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), 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by byuu on Monday November 28, 2016 @04:09PM (#13058439)
You 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by kevincox on Monday November 28, 2016 @04:44PM (#13058703)
While 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by byuu on Tuesday November 29, 2016 @04:15AM (#13061848)
> If all of this is inlined you will have to request it on every page load.

True, it's an interesting trade-off. If you inline your CSS and Javascript like I do, then you can't afford to have 100KiB of CSS and 2.4MiB of Javascript code. But you can at least merge all CSS to one file, all JS to one file, and use a combination of max-age and etags to only pay the cost once.

When I look at site waterfalls today ... cnn.com for example is making 20 separate Javascript file requests against its own domain. They don't have to develop their entire JS backend in a single file, but when deploying to production, they should be merging them.

There's also the corollary that trying to put everything on the same connection (both HTTP/2 stream multiplexing and HTTP/1 file merging) tends to have disastrous consequences when you start experiencing 2% packet loss or higher. Great video with charts on that here: https://www.youtube.com/watch?v=0yzJAKknE_k

> 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)

Oh yeah, it's definitely rare. cnn.com hits me with 110 connections to load their homepage.

My site (byuu.org) does it in a single connection, though. Although I'll admit I haven't won any design awards yet for it ;)

The thing is, I wanted to optimize load times, so I learned the best practices and implemented them. If other sites are concerned about HTTP/1 responsiveness, they could easily do the same. I'm actually paying a small bit due to being HTTPS-only with strong 256-bit crypto and compression necessarily disabled. Everything always seems to be a trade-off, eh?

> 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.

Well again, to me, things should be as simple as possible. People hate C++ because it has ten billion features and you need a large team of engineers to implement even a basic compiler for it. With C, a single developer can do that.

I'm not saying we should've been stuck with HTTP/1 forever, nor with C forever. But certainly we could have started with HTTP/1.2 before turning the HTTP protocol into something that needs a team of engineers to implement in a product from scratch. Server-Push would have been a very simple header to add, for instance.

Yes, the complexity is hidden to the average web developer that installs nginx, flips a switch for HTTP/2, and calls it a day. But as you and I know, that complexity leads to bugs, vulnerabilities, inconsistencies between implementations, lack of choices in software (monocultures), etc. All very bad things. Further, we're stuck with this for at least 20-40 years now. Just like we still have HTTP/1.0 servers. Every new HTTP revision is one more version your software will need to support. How fun do you think it'll be to write an alternative to cURL once we're at HTTP/7? (assuming new revisions pick up the pace as they've suggested it would.)

Re:HPACK: the silent killer (feature) of HTTP/2 by throwbsidbdk on Monday November 28, 2016 @10:16PM (#13060477)
Http was not designed for what we're using it for. The biggest problem is numerous requests, which is caused by http using TCP underneath, not by multiple requests in themselves being bad.

Bundling is not a best practice because anything about it is inherently better. It's only better because http is bad at delivering multiple responses efficiently.

I think HTTP/2 is a quite reasonable compromise compared to the ideal, which would be scrapping http and starting over. The biggest change is to multiplex requests over a single TCP socket, something that's been done by many other protocols over the years. The added complexity is needed because the alternative, running modified http over UDP, would break so much of our infrastructure that it's implausible.

Re:HPACK: the silent killer (feature) of HTTP/2 by jgrahamc on Monday November 28, 2016 @10:41AM (#13056066)
From 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.

Re:HPACK: the silent killer (feature) of HTTP/2 by byuu on Monday November 28, 2016 @11:00AM (#13056222)
There'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.

Re:HPACK: the silent killer (feature) of HTTP/2 by tehbeard on Monday November 28, 2016 @11:31AM (#13056448)
I'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.
Re:HPACK: the silent killer (feature) of HTTP/2 by niftich on Monday November 28, 2016 @01:48PM (#13057481)
Yes, 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

Re:HPACK: the silent killer (feature) of HTTP/2 by Matthias247 on Tuesday November 29, 2016 @06:14AM (#13062323)
That'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.
Re:HPACK: the silent killer (feature) of HTTP/2 by raptium on Monday November 28, 2016 @11:43AM (#13056544)
There 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. :-(

Re:HPACK: the silent killer (feature) of HTTP/2 by niftich on Monday November 28, 2016 @01:16PM (#13057260)
Security 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... [2] https://tools.ietf.org/html/rfc7231#section-3.1 [3] https://w3c.github.io/webappsec-csp/#meta-element

Re:HPACK: the silent killer (feature) of HTTP/2 by throwbsidbdk on Monday November 28, 2016 @10:21PM (#13060503)
The net effect is much larger than the smallish overall effect appears to be. The request is much smaller and this has a surprisingly large effect because modern consumer connections are asymmetrical as much as 20/1. Those requests take 5-20 times as long per byte to send over the wire. Shrinking them this much decreases total request -> response time a lot more than it looks
Re:HPACK: the silent killer (feature) of HTTP/2 by raptium on Monday November 28, 2016 @11:31AM (#13056447)
You 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).