Hyper
Hyper is a fast and correct HTTP implementation written in and for Rust. Hyper is a lower-level HTTP library, meant to be a building block for libraries and applications.
Body
On top of Body
trait from http-body 1.0.0
, hyper also provides the concrete Incoming
type which implmenets Body
.
It is a stream of Bytes, used when receiving bodies from the network.
Note that Users should not instantiate this struct directly.
When working with the hyper client, Incoming
is returned to you in responses.
Similarly, when operating with the hyper server, it is provided within requests.
Bytes
Hyper uses Bytes
as a byte representation.
It is a cheaply cloneable and sliceable chunk of contiguous memory.
Client
Since hyper is a low-level HTTP library, user is in charge of everything, starting from TCP handshake.
Wraps the TCP connection(tokio::net::TcpStream
) with an adapter (hyper::rt::TokioIo
).
Then performs the TCP handshake and spawns the task to poll the connection.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Open a TCP connection to the remote host
let stream = tokio::net::TcpStream::connect(address).await?;
// Use an adapter to access something implementing `tokio::io` traits as if they implement
// `hyper::rt` IO traits.
let io = hyper_util::rt::TokioIo::new(stream);
// Perform a TCP handshake
let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;
// Spawn a task to poll the connection, driving the HTTP state
tokio::task::spawn(async move {
if let Err(err) = conn.await {
println!("Connection failed: {:?}", err);
}
});
// The authority of our URL will be the hostname of the httpbin remote
let authority = url.authority().unwrap().clone();
// Create an HTTP request with an empty body and a HOST header
let req = Request::builder()
.uri(url)
.header(hyper::header::HOST, authority.as_str())
.body(Empty::<Bytes>::new())?;
// Await the response...
let mut res = sender.send_request(req).await?;
Server
Hyper server uses tower::Service
to serve incoming HTTP connections.
Wraps the incoming connection accepted by listener(tokio::net::TcpListener
) with an adapter (hyper::rt::TokioIo
).
Then serves connection using tower::Service
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// We create a TcpListener and bind it to 127.0.0.1:3000
let listener = TcpListener::bind(addr).await?;
// We start a loop to continuously accept incoming connections
loop {
let (stream, _) = listener.accept().await?;
// Use an adapter to access something implementing `tokio::io` traits as if they implement
// `hyper::rt` IO traits.
let io = TokioIo::new(stream);
// Spawn a tokio task to serve multiple connections concurrently
tokio::task::spawn(async move {
// Finally, we bind the incoming connection to our `hello` service
// Here, `hello` is `Copy`.
if let Err(err) = http1::Builder::new()
.serve_connection(io, hello)
.await
{
println!("Error serving connection: {:?}", err);
}
});
}