sozu
sozu copied to clipboard
Initial H2 thought by geal
In gitlab by @Geal on Jan 11, 2017, 11:15
right now, the proxy supports HTTP, HTTPS, TCP, and Websockets. It can upgrade a connection between protocols, but the condition is always that the protocol is the same for client<->proxy and proxy<->backend connections.
With HTTP/2, we want to support different use cases, like:
- client <- HTTP/2 -> proxy and proxy <- HTTP 1.1 -> backend, with possibly multiple connections to the backend that will be multiplexed for the frontend
- client <- HTTP 1.1 -> proxy and proxy <- HTTP/2 -> backend to support HTTP 1.1 for web frameworks that will only support HTTP/2
And this should be working with protocol upgrades as well.
First thoughts:
- will this only affect HTTP 1.1 and HTTP/2? The proxy does not support many protocols yet, but there might be other cases we can take inspiration from, and plan for
- this means having separate protocols for readable/writable and back_readable/back_writable functions, and a way to transform state back and forth
- the HTTP proxy tries to keep the data unparsed as much as possible. Transforming headers between HTTP 1.1 and HTTP/2 means parsing the buffer, returning a header, make it a HTTP/2 header, and write it to the output buffer if necessary
- while both protocols will probably supported by the frontend, backend servers may not support both. So we have to decide if we keep the data in the buffer for a HTTP 1.1<->HTTP 1.1 connection, or if we transform it to HTTP/2
- one HTTP/2 connection with the client, multiple HTTP 1.1 connections on the backend: this will be annoying to implement
Plan (for now):
- [ ] refactor the event loop #257
- [ ] Add protocol info to backends #258
- [ ] support ALPN extension and upgrade to a placeholder HTTP/2 implementation
- [ ] implement frame parser and serializer. nom and cookie factory should be ok
- [ ] start working on the initial messages
- [ ] integrate a HPACK implementation. It's probably not useful to write a new one from scratch
- [ ] implement the stream state machine
- [ ] implement the flow control policy (as a separate struct with lots of unit tests)
- [ ] implement the frame priority and dependency calculation (as a separate struct with lots of unit tests)
- [ ] find a new buffer abstraction, since the one currently in use will probably not be adapted to a multiplexed protocol
- [ ] end to end patterns:
- [ ] first, assume there's only one backend, and it supports HTTP/2 (needs TLS on the backend)
- [ ] then, make sure we can still connect with HTTP 1.* over TLS to that backend
- [ ] associate HTTP/2 streams to backends. We need a configurable limit for the number of streams in a connection
- [ ] check the behaviour of load balancing streams with buffer borrows
- [ ] investigate routing for protocols like gRPC
depends on #257 and #258
RFC 7540 for HTTP/2: http://httpwg.org/specs/rfc7540.html RFC 7541 for HPACK (header compression): http://httpwg.org/specs/rfc7541.html
Parsing and generating the different frames should not be too hard. Handling the ALPN dance will be ok too. The stream state machine is well defined (there are still lots of details and failure cases to handle correctly). The complex part appears to be in flow control and stream priorities. About half the mentions of proxy specific behaviour are around the CONNECT HTTP method, which may not be really interesting to handle for now.
Parts of https://github.com/carllerche/h2 might be reusable. https://github.com/mlalic/hpack-rs is not really maintained. https://github.com/carllerche/bytes would be interesting for buffer handling, since it can work correctly with multiple subsets of the data: https://carllerche.github.io/bytes/bytes/struct.Bytes.html
development has started in the h2 branch. It is only plugged into the HTTPS Openssl proxy for now.
How to test
cf https://blog.cloudflare.com/tools-for-debugging-testing-and-using-http-2/
curl
curl --http2 -kv http://lolcatho.st:8443/
h2c
~/.go/bin/h2c connect lolcatho.st:8443
~/.go/bin/h2c get /
Compliance
We will need to test with h2spec
Current version is using the hpack crate, we might need to write a new one at some point
Related issues:
- half protocol implementations #540
- Move away from BufferQueue as basic element for everything #541
- functions concerning back sockets should take a token as argument #542
- HTTP 1 client implementation #543
some things to keep in mind for this implementation: https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md
With HTTP/3 coming, it’s high time to support http/2, isn’t it? Any idea when this support will be available?