HAProxy 2.0.5 accepting strict http2 request when bind line does not have proto h2

I tested with HAProxy 2.0.5 with following basic configuration using curl
curl -v --http2-prior-knowledge http://IP

global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
#maxconn 65536

defaults
log global
mode http
http-reuse never
no log
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http

frontend test
bind :80
mode http
maxconn 65536
default_backend nginx

backend nginx
mode http
balance leastconn
server <IP> <IP>:81 weight 255

When tested with HAProxy 1.9.8, I get the following error:
http2 error: Remote peer returned unexpected data while we expected SETTINGS frame. Perhaps, peer does not support HTTP/2 properly.

Is this the expected behaviour?

So you did not enable H2 in haproxy, run a H2 request against haproxy and it does not work. How can this not be expected behavior?

With HAProxy 2.0, it works without giving proto h2 in bind line. With HAProxy 1.9, it does not work with the same configuration.
With the following command:
curl -v --http2-prior-knowledge http://IP

Ok, I guess that’s because 2.0 by default enables HTX mode, and this likely changes how the request is parsed, accepting H2 message.

You can confirm that by putting option http-use-htx into a default section covering both front and backend in 1.9, and the reverse test, no option http-use-htx into a default section covering both front and backend in 2.0.

I’d say the behavior in this case is simply undefined. Is this causing any issues?

In fact, it is expected. An implicit upgrade from h1 to h2 is performed when an H2 preface is detected during the parsing of the first request of an HTTP connection. Once upgraded to h2, there is no way to come back in h1. So, on a non-TLS HTTP connection, it is possible to handle h1 or h2 requests (not mixed). Of course, if proto h2 is mentioned on the bind line, only h2 requests are accepted.

So, that said, I found a bug, there is no check to be sure it’s the first request. I will fix that quickly.