Hi Lukas, On Wed, Nov 01, 2017 at 11:35:30PM +0100, Lukas Tribus wrote: > In ALPN, the client announces the supported protocols, currently for example > http1/1 and h2, and then the server picks a protocol out of that > selection, based on its own preference.
Yep. > However, with clients supporting both http/1.1 and h2 the configuration: > alpn http/1.1,h2 > > always leads to HTTP/1.1 (on both curl and Chrome) here. > > I had to turn it around, for HTTP/2 to be actually negotiated: > alpn h2,http/1.1 Hmmm I think you're right, I've been doing most of my tests with "h2" only and figured it would be good to propose h1 as well in the mail announce so that testers don't see connections rejected! > With the latter configuration, HTTP/2 is actually used. OK. > > "alpn http/1.1,h2" on a "bind" line present in an HTTP mode frontend, > > And "alpn h2,http/1.1" does work via HTTP2 in a HTTP mode frontend. > > > But when the frontend is in TCP mode, and the backend is in HTTP mode, I didn't think about this use case. > its looks like the H2 parser is not started even when ALPN negotiates h2, and > the HTTP/1.1 only backend server receives the "PRI" connection request > verbatim: That's totally true. H2 is only used if negociated by ALPN *and* the frontend is in HTTP mode, as I couldn't find any case where we would not want to use H2 there, so I preferred not to introduce another option in the frontend. > 0000000a:https_in.accept(0005)=0008 from [10.0.0.4:54737] ALPN=h2 > 0000000a:bk_testbk.clireq[0008:ffffffff]: PRI * HTTP/2.0 > 0000000a:bk_testbk.srvrep[0008:adfd]: HTTP/1.1 400 Bad Request > 0000000a:bk_testbk.srvhdr[0008:adfd]: Server: nginx/1.10.3 (Ubuntu) > 0000000a:bk_testbk.srvhdr[0008:adfd]: Date: Wed, 01 Nov 2017 21:15:41 GMT > 0000000a:bk_testbk.srvhdr[0008:adfd]: Content-Type: text/html > 0000000a:bk_testbk.srvhdr[0008:adfd]: Content-Length: 182 > 0000000a:bk_testbk.srvhdr[0008:adfd]: Connection: close > 0000000a:bk_testbk.srvcls[0008:adfd] > 0000000b:bk_testbk.clireq[0008:ffffffff]: SM > 0000000b:bk_testbk.clicls[adfd:ffffffff] > 0000000b:bk_testbk.closed[adfd:ffffffff] > > > In the HTTP/1.1 world I used to think that even if the frontend is in TCP > mode, > when haproxy selects a backend in HTTP mode, it understands that this is gonna > be a HTTP session and it turned on the HTTP hut for all intends and purposes. Yes but here we have to make the choice while installing the mux, it's important to understand that we *cannot* apply the frontend's switching rules to the preface which purposely looks like a broken request, then decide to route it to an HTTP backend. So we have to decide of the protocol in the frontend. > Of course, when both front and backend are in TCP mode and we negotiate h2 > via NPN or ALPN, we have to leave it alone (just terminate TLS). Exactly. > But in the "frontend->tcp mode; backend->http mode" case, should we be able to > start the H2 parsing and actually handle this case? Or is this something we > are > unable to cover? I don't see a way to cover it unfortunately. However I think the HTTP parser needs to detect the H2 preface and immediately reject it so that we don't end up with hung requests like this. > I'm certainly able to fix this issue here via configuration, I'm just > not sure if that is the case for all the use-cases out there? We at least need to address it in the configuration. We *may* be able to address it in the config validity checking : since we're able to detect http frontends switching to tcp backends and report an error, we might be able to check for the opposite when one of the frontend's "bind" lines is configured to support H2, and then emit a warning (since some people might very well switch to a TCP backend only when ALPN says H2 to offload the processing somewhere else). However that would leave them with an unfixable warning and I don't want this either, as TCP->HTTP setups are used when you want to support multiple protocols on the same port and ALPN is a perfect example of this. So I think the best would be to just reject the preface in the backend and report the reason in the logs. > Now, comment number 3, pretty sure this is actually a bug :) > > In my configuration, files transferred via HTTP2 are corrupted with > random content > from memory. I could spot my certificate, some HTTP headers and the content of > /etc/resolv.conf in the HTTP payload. Using HTTP/1.1 (even by a client > side change) > fixes this. Just H2 is affected. Ouch, not good. > How to reproduce? In my case I'm transferring a 150KB .svg file > through haproxy and > it gets corrupted every time. > > > The configuration is *VERY* basic (also, no filters are enabled :) ): > > lukas@dev:~/haproxy$ cat ../haproxy.cfg > defaults > timeout connect 5000 > timeout client 50000 > timeout server 50000 > #compression algo gzip > frontend http_in > bind :80 > default_backend bk_testbk > frontend https_in > mode http > bind :443 ssl crt /home/lukas/cert/certdir/cert.pem alpn h2,http/1.1 > default_backend bk_testbk > backend bk_testbk > mode http > server www www.lan.ltri.eu:80 > > lukas@dev:~/haproxy$ > > Not sure what I can do to pinpoint this issue? I don't know for now, I'll have to try to reproduce. Olivier already sent me some fixes for mistakes I did in the H2 code (wrong states in error cases) but that should not affect this. I suspect we're reading past a buffer in some cases (possibly the measurement of the contiguous payload in the buffer which occasionally fails). > BTW: tomorrow is OpenSSL release day, they will publish new releases fixing a > already disclosed low severity and a undisclosed moderate level security > issue: > > https://mta.openssl.org/pipermail/openssl-announce/2017-October/000104.html Yep, but thanks for recalling it, especially since some of the list members here probably are not subscribed. Cheers, Willy

