How to use hyper server with unencrypted HTTP/2 (H2C)?

120 views Asked by At

Couldn't find working examples for this (that can be checked with curl -v --http2-prior-knowledge http://localhost:8081 command), so asking here.

curl -v --http2-prior-knowledge http://localhost:8081
*   Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: http]
* h2h3 [:authority: localhost:8081]
* h2h3 [user-agent: curl/7.88.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x56425e0e6c80)
> GET / HTTP/2
> Host: localhost:8081
> user-agent: curl/7.88.1
> accept: */*
>
* HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Connection #0 to host localhost left intact
curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)

I tried using https://github.com/hyperium/tonic/blob/master/examples/src/h2c/server.rs but it just fails with

called `Result::unwrap()` on an `Err` value: hyper::Error(User(NoUpgrade))

on this line

let upgraded_io = hyper::upgrade::on(&mut req).await.unwrap();

When trying to connect with Postman, it fails when using TLS (of course), and without it, it shows a Received RST_STREAM with code 1

1

There are 1 answers

0
bk2204 On

This server is designed to accept HTTP/2 after receiving an HTTP/1.1 response with the Upgrade header, so the command line argument to curl that you want is --http2, not --http2-prior-knowledge.

In general, the problem is that HTTP/1.1 and HTTP/2 use completely different syntax and framing, so unless your server is completely HTTP/2 only and does absolutely no HTTP/1.1, you need some way to determine what syntax you're using. With TLS, you negotiate HTTP/2 with ALPN, but without that, you generally need to use the Upgrade approach. Using --http2-prior-knowledge indicates that that isn't required, but in this case, it is.