Speeding up HTTP with minimal protocol changes
blog.jgc.org
blog.jgc.org
"
Your premise seems to be that SPDY is a complex binary protocol and we don't need that achieve mux. I don't see much evidence for your complexity assertion - especially when compared with HTTP/1.
Consider the difference in finding the message boundaries of a SPDY message with an HTTP/1.1 one.
To process the SPDY message you
* buffer 8 bytes of data
* determine that it is a data packet by confirming (buf[0] & 0x80 == 0)
* determine the length of the data by ntohl(((uint32_t)buf)[1)& 0x00ffffff
* find out if there are more chunks to come by looking at (buf[4] & 1).
All done. It is very straightforward, efficient, well bounded, and testable.
Contrast that with parsing a HTTP/1 message.
* read "enough" data from the network. You don't know how much that is and if you read too much you have to implement some facility for "putting it back" so the next message can use it. This inevitably leads to streaming parsers and their inherent complexity and lack of efficiency.
* parse the headers so you can determine which message delimiter is being used. To parse the header you have to implement line folding, implement a tokenizer aware of various rules around quotation marks and colons, and adopt to a number of real-world variations in the use of line endings other than just CRLF. To do this you have to run a state machine against every byte of input rather than directly address fixed offsets.
* Implement strategies to deal with conflicts such "Content-Length: 42, 17" and "Content-Length: 95\r\nTransfer-Encoding: chunked\r\n"
* you need to implement an ascii to integer conversion routine to determine the status code because some status codes implicitly impact message delimiters (e.g. 304).
* now you have to implement no less than 5 message delimiting schemes - chunked encodings, EOF, content-length, implicit (304), and everyone's favorite multibyte/ranges.
* If you have content-length or a chunk you'll need to convert a text string to an integer again.. and http/1 doesn't bound the size of the text string so you'll either have a common bug with an overflow or you'll implement an undiscoverable constraint in your implementation leading to cases of failing interop.
* you'll still have exposure to a whole class of CRLF injection attacks inherent in the text format.
The binary framing is so much less complex and significant improvement. Sure, to the naked eye in a log it may not look that way but that is optimizing for all the wrong things and can be quite misleading - do you really interpret a HTTP header with line folding or \n\r instead of \r\n sequences correctly when eyeballing it?)
Now there certainly is some complexity in SPDY but it doesn't come, in my opinion, from the binary framing that you're talking about here. That is a a significant simplification over HTTP/1.
"
[1] https://hacks.mozilla.org/2012/02/spdy-brings-responsive-and...
This is in the same vein as TCP, TLS, or DNS. Developers use these technologies all the time, and it exposes a simple interface to them, but all of them are quite complicated under the covers. I don't believe that Nagle's algorithm or the UDP framing for DNS is common knowledge amongst the majority of developers.
Similarly, SPDY or HTTP/2.0 will expose a simple interface to developers, but internally transport the content in an efficient, if somewhat inscrutable, manner.
While I appreciate the sentiment that HTTP is easy to understand as it stands, I'd rather not optimize for "developers of almost any skill level". While it would be totally OK for you to write a HTTP/1.1 parser as a toy, it would be somewhat crazy for you to use that implementation in a production scenario.
There, everybody uses a small set of implementations that have been vetted: Firefox, Chrome, Apache, Nginx, etc. These guys work extremely hard to make sure that their implementation is solid not merely "compatible-ish". I'd rather optimize for them, rather than the beginners. I'd rather make it easy for them to write correct implementations. I'd rather jettison the "fault tolerant enough that compatible-ish is ok" design of HTTP/1.1 that makes their life so difficult.
What would an existing proxy server (i.e. doesn't understand HMURR) do with a connection that looked like this?
The world is full of proxies and html-consuming tools that do not bother to check the version number, which would get horribly confused by this, and probably mangle the stream.
I was under the impression one of the reasons SPDY is so different is precisely to try to avoid problems with bad proxies. I'm not an expert on this unfortunately, but I'm sure that quite a few bits of the web-proxy standard involved getting around badly behaving proxies, and they had to do a few strange things.
Edit: Or also add an "Upgrade: slices" to the initial request, and if the expected response to the Upgrade: request is missing, continue with HTTP 1.1.
So that leaves the standard HTTP proxying. The HTTP proxy might treat the 2nd to nth request as being the payload of the HTTP request and may insert Content-Length headers. The HTTP proxy might filter out unknown HTTP headers (would be pretty bad; it's like the common example of where strict firewall admins tend to drop all ICMP packets). There will be security issues related to colliding Request-ID's and to the caching of it.
Also I don't see why we would need the Slice-Length. Just re-use the Content-Range header, that's what it's for right? (http://www.greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-r...).
The standard HTTP pipelining is quite old and very well specified but afaik none of the major browsers implement it; I'm not sure why though. Maybe it depends on the lack of server support.
Interesting attempt I must say but I think it will be hard to actually get it out there. Too much legacy stuff in the way.
It's a bit like how for a really long time a lot of fancy new VOIP protocols were really hindered by the lack of proper NAT support leading to all these horrible workarounds to do NAT hole punching or more RFC's like STUN and TURN.
They would be right to do so. 206 implies that the request is done. It is a very fundamental difference for 206 to stop meaning that. One can not just gloss over the fact that one of the connection may very well have closed the TCP stream. That's not a theoretical objection, that's a very pragmatic one.
It seems like the main reason to prefer this proposal is if you do not want to write another parser for HTTP/2.0 and think that new features afforded by a different wire level representation are not worthwhile.
Another thing to note is that this proposal effectively adds on multiplexing without prioritization. Prioritization is fairly important, otherwise the client application has to do application layer throttling in order to reduce contention. Adding prioritization would help obviate the need to make the link utilization vs contention tradeoff.
Can you give an example of prioritization in practice?
Prioritization: Generally speaking, documents (HTML) > script/stylesheets (JS&CSS) > subresources (e.g. images). https://insouciant.org/tech/resource-prioritization-in-chrom... https://insouciant.org/tech/throttling-subresources-before-f...
Some binary layers are helpful: TLS, for example, adds a nice generic encryption layer to connections. SPDY, on the other hand, has intimate knowledge of the operation of HTTP (which it needs to do header compression, for example). For example, the header compression dictionary is based on today's usage of HTTP with no provision for it to change over time.
It is a shame that features that are important to HTTP (multiplexing and priority) are not being added within HTTP itself.
I'd like to comment on your statement on the header compression dictionary. Firstly, your statement is only true for the initial header compression dictionary. Most of the improvement is achieved strictly through the use of compression at all, with very marginal gains from different compression algorithms or better initial dictionaries. If your implication is that intimate knowledge of HTTP is required for SPDY compression to work well, that is false. Please note the research at http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf with the following conclusion: "This result suggests that zlib’s adaptive dictionary evolves to roughly an equivalent state after compressing the first header regardless of the content of the initial dictionary."
Can you clarify what you mean about features not being added within HTTP itself? Where are you drawing the line for "HTTP itself"? I'm curious, since the ideas behind SPDY have already been proposed for HTTP/2.0, and indeed the starting point for the HTTP/2.0 proposal used the SPDY draft, so I don't know what it means that important features aren't being added to HTTP itself.
When I think of HTTP I think of a text-based protocol not binary. I fully understand that SPDY has essentially been ratified as HTTP 2.0 given that the charter has been updated to be so close to SPDY itself. Thus at some point what I think if as HTTP will need updating to simply include SPDY and what I currently think of HTTP will be moot.
In sum, why can't we uncouple features that each may have merit on their own?
Chunked requests and pipelines are good examples. They are rarely used but absolutely supported by the spec. But because they are rarely used they break a lot in practice and are not realistically deployable on Internet scale.
I understand that no one wants to define a new format, but I don't see how it is more difficult than defining a new protocol.
In short, SPDY does not imply combining resources. Application level combining of resources is a common hack to work around lack of parallelization at the HTTP/1 protocol level, but as noted, it has deficiencies.
Then again, I don't know much about HTTP, so maybe I'm missing something obvious.
Edit: Hmm, just learned about SPDY's server hinting, which is pretty similar to my idea.