//! An HTTP+TLS server based on `hyper` and `async-native-tls`.
//!
//! Run with:
//!
//! ```
//! cargo run --example hyper-server
//! ```
//!
//! Open in the browser any of these addresses:
//!
//! - http://localhost:8000/
//! - https://localhost:8001/ (accept the security prompt in the browser)
//!
//! Refer to `README.md` to see how to the TLS certificate was generated.
use std::net::{Shutdown, TcpListener, TcpStream};
use std::pin::Pin;
use std::task::{Context, Poll};
use anyhow::{Error, Result};
use async_native_tls::{Identity, TlsAcceptor, TlsStream};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use smol::{future, io, prelude::*, Async};
/// Serves a request and returns a response.
async fn serve(req: Request
, host: String) -> Result> {
println!("Serving {}{}", host, req.uri());
Ok(Response::new(Body::from("Hello from hyper!")))
}
/// Listens for incoming connections and serves them.
async fn listen(listener: Async, tls: Option) -> Result<()> {
// Format the full host address.
let host = &match tls {
None => format!("http://{}", listener.get_ref().local_addr()?),
Some(_) => format!("https://{}", listener.get_ref().local_addr()?),
};
println!("Listening on {}", host);
// Start a hyper server.
Server::builder(SmolListener::new(&listener, tls))
.executor(SmolExecutor)
.serve(make_service_fn(move |_| {
let host = host.clone();
async { Ok::<_, Error>(service_fn(move |req| serve(req, host.clone()))) }
}))
.await?;
Ok(())
}
fn main() -> Result<()> {
// Initialize TLS with the local certificate, private key, and password.
let identity = Identity::from_pkcs12(include_bytes!("identity.pfx"), "password")?;
let tls = TlsAcceptor::from(native_tls::TlsAcceptor::new(identity)?);
// Start HTTP and HTTPS servers.
smol::block_on(async {
let http = listen(Async::::bind(([127, 0, 0, 1], 8000))?, None);
let https = listen(
Async::::bind(([127, 0, 0, 1], 8001))?,
Some(tls),
);
future::try_zip(http, https).await?;
Ok(())
})
}
/// Spawns futures.
#[derive(Clone)]
struct SmolExecutor;
impl hyper::rt::Executor for SmolExecutor {
fn execute(&self, fut: F) {
smol::spawn(async { drop(fut.await) }).detach();
}
}
/// Listens for incoming connections.
struct SmolListener<'a> {
tls: Option,
incoming: Pin>> + Send + 'a>>,
}
impl<'a> SmolListener<'a> {
fn new(listener: &'a Async, tls: Option) -> Self {
Self {
incoming: Box::pin(listener.incoming()),
tls,
}
}
}
impl hyper::server::accept::Accept for SmolListener<'_> {
type Conn = SmolStream;
type Error = Error;
fn poll_accept(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll