I tried to convert the "Getting Started with a Server" guide for hyper
1.0 from HTTP1 to HTTP2.
I first tried this:
@@ -3,7 +3,7 @@
use http_body_util::Full;
use hyper::body::Bytes;
-use hyper::server::conn::http1;
+use hyper::server::conn::http2;
use hyper::service::service_fn;
use hyper::{Request, Response};
use tokio::net::TcpListener;
@@ -26,7 +26,7 @@
// Spawn a tokio task to serve multiple connections concurrently
tokio::task::spawn(async move {
// Finally, we bind the incoming connection to our `hello` service
- if let Err(err) = http1::Builder::new()
+ if let Err(err) = http2::Builder::new()
// `service_fn` converts our function in a `Service`
.serve_connection(stream, service_fn(hello))
.await
But apparently hyper::server::conn::http2::Builder
has a different function signature than http1::Builder
.
Looking into the http2::Builder
docs, I have to implement an…
[…] executor which is a type that implements
Http2ConnExec
trait.
Checking out the docs for that Http2ConnExec
trait, I learned that:
[
Http2ConnExec
] is sealed and cannot be implemented for types outside this crate.
Too bad the docs don't show any implementors. But to the rescue:
[
Http2ConnExec
] is implemented for any type that implementsExecutor
trait for any future.
Okay, lets head to the documentation of Executor
, and I find that example:
struct TokioExecutor;
impl<F> Executor<F> for TokioExecutor
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
fn execute(&self, future: F) {
tokio::spawn(future);
}
}
Adding that to my code, and changing…
- if let Err(err) = http2::Builder::new()
+ if let Err(err) = http2::Builder::new(TokioExecutor)
… it complains about TokioExecutor
not being Clone
. Okay, I'm adding that too:
+#[derive(Clone)]
struct TokioExecutor;
Now the program runs! But when I dare to use my webbrowser to connect to the running server with http://localhost:3000/
, I get…
��������������@�����
…shown on a blank page. Network inspector doesn't show a status code. Weird.
That is in Mozilla Firefox. I tried Chrome/Chromium, and get:
This page isn’t working
localhost sent an invalid response.
ERR_INVALID_HTTP_RESPONSE
Oh, and using curl
, I get:
% curl -v http://localhost:3000/
* Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.87.0
> Accept: */*
>
* Received HTTP/0.9 when not allowed
* Closing connection 0
curl: (1) Received HTTP/0.9 when not allowed
So what's going on here? Does it have to do with HTTP2 only being supported with TLS?
The output in the console where I run cargo run
gives me:
Error serving connection: hyper::Error(Http2, Error { kind: GoAway(b"", PROTOCOL_ERROR, Library) })
I just tested to use https://localhost:3000/
instead of http://localhost:3000
. But it doesn't work either.
On Firefox:
Secure Connection Failed
An error occurred during a connection to localhost:3000. PR_END_OF_FILE_ERROR
Error code: PR_END_OF_FILE_ERROR
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.
Please contact the website owners to inform them of this problem.
On Chrome:
This site can’t provide a secure connection
localhost sent an invalid response.
ERR_SSL_PROTOCOL_ERROR
And with curl
:
% curl -v https://localhost:3000/
* Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* CAfile: none
* CApath: /etc/ssl/certs/
* [CONN-0-0][CF-SSL] TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL/1.1.1o: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
* Closing connection 0
curl: (35) OpenSSL/1.1.1o: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
And on the server side the same error:
Error serving connection: hyper::Error(Http2, Error { kind: GoAway(b"", PROTOCOL_ERROR, Library) })