From 6d7ddee9ae3bffc63ec1d9da3cea351326a783a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Er=C3=A8be=20-=20Romain=20Gerard?= Date: Wed, 29 Nov 2023 09:52:16 +0100 Subject: [PATCH] Update example low-level-rustls to axum 0.7 (#2375) --- examples/low-level-rustls/Cargo.toml | 8 +- examples/low-level-rustls/src/main.rs | 209 ++++++++++++++------------ 2 files changed, 114 insertions(+), 103 deletions(-) diff --git a/examples/low-level-rustls/Cargo.toml b/examples/low-level-rustls/Cargo.toml index 08e28230c3..3975fcb917 100644 --- a/examples/low-level-rustls/Cargo.toml +++ b/examples/low-level-rustls/Cargo.toml @@ -6,11 +6,13 @@ publish = false [dependencies] axum = { path = "../../axum" } -futures-util = { version = "0.3", default-features = false, features = ["alloc"] } +futures-util = { version = "0.3", default-features = false } hyper = { version = "1.0.0", features = ["full"] } -rustls-pemfile = "0.3" +hyper-util = { version = "0.1" } +rustls-pemfile = "1.0.4" tokio = { version = "1", features = ["full"] } -tokio-rustls = "0.23" +tokio-rustls = "0.24.1" tower = { version = "0.4", features = ["make"] } +tower-service = "0.3.2" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/examples/low-level-rustls/src/main.rs b/examples/low-level-rustls/src/main.rs index 01514b4802..0a28e979fe 100644 --- a/examples/low-level-rustls/src/main.rs +++ b/examples/low-level-rustls/src/main.rs @@ -4,105 +4,114 @@ //! cargo run -p example-low-level-rustls //! ``` -// TODO -fn main() { - eprint!("this example has not yet been updated to hyper 1.0"); +use axum::{extract::Request, routing::get, Router}; +use futures_util::pin_mut; +use hyper::body::Incoming; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use rustls_pemfile::{certs, pkcs8_private_keys}; +use std::{ + fs::File, + io::BufReader, + path::{Path, PathBuf}, + sync::Arc, +}; +use tokio::net::TcpListener; +use tokio_rustls::{ + rustls::{Certificate, PrivateKey, ServerConfig}, + TlsAcceptor, +}; +use tower_service::Service; +use tracing::{error, info, warn}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[tokio::main] +async fn main() { + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "example_low_level_rustls=debug".into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + let rustls_config = rustls_server_config( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("self_signed_certs") + .join("key.pem"), + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("self_signed_certs") + .join("cert.pem"), + ); + + let tls_acceptor = TlsAcceptor::from(rustls_config); + let bind = "[::1]:3000"; + let tcp_listener = TcpListener::bind(bind).await.unwrap(); + info!("HTTPS server listening on {bind}. To contact curl -k https://localhost:3000"); + let app = Router::new().route("/", get(handler)); + + pin_mut!(tcp_listener); + loop { + let tower_service = app.clone(); + let tls_acceptor = tls_acceptor.clone(); + + // Wait for new tcp connection + let (cnx, addr) = tcp_listener.accept().await.unwrap(); + + tokio::spawn(async move { + // Wait for tls handshake to happen + let Ok(stream) = tls_acceptor.accept(cnx).await else { + error!("error during tls handshake connection from {}", addr); + return; + }; + + // Hyper has its own `AsyncRead` and `AsyncWrite` traits and doesn't use tokio. + // `TokioIo` converts between them. + let stream = TokioIo::new(stream); + + // Hyper has also its own `Service` trait and doesn't use tower. We can use + // `hyper::service::service_fn` to create a hyper `Service` that calls our app through + // `tower::Service::call`. + let hyper_service = hyper::service::service_fn(move |request: Request| { + // We have to clone `tower_service` because hyper's `Service` uses `&self` whereas + // tower's `Service` requires `&mut self`. + // + // We don't need to call `poll_ready` since `Router` is always ready. + tower_service.clone().call(request) + }); + + let ret = hyper_util::server::conn::auto::Builder::new(TokioExecutor::new()) + .serve_connection_with_upgrades(stream, hyper_service) + .await; + + if let Err(err) = ret { + warn!("error serving connection from {}: {}", addr, err); + } + }); + } } -// use axum::{extract::Request, routing::get, Router}; -// use futures_util::future::poll_fn; -// use hyper::server::{ -// accept::Accept, -// conn::{AddrIncoming, Http}, -// }; -// use rustls_pemfile::{certs, pkcs8_private_keys}; -// use std::{ -// fs::File, -// io::BufReader, -// path::{Path, PathBuf}, -// pin::Pin, -// sync::Arc, -// }; -// use tokio::net::TcpListener; -// use tokio_rustls::{ -// rustls::{Certificate, PrivateKey, ServerConfig}, -// TlsAcceptor, -// }; -// use tower::make::MakeService; -// use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - -// #[tokio::main] -// async fn main() { -// tracing_subscriber::registry() -// .with( -// tracing_subscriber::EnvFilter::try_from_default_env() -// .unwrap_or_else(|_| "example_tls_rustls=debug".into()), -// ) -// .with(tracing_subscriber::fmt::layer()) -// .init(); - -// let rustls_config = rustls_server_config( -// PathBuf::from(env!("CARGO_MANIFEST_DIR")) -// .join("self_signed_certs") -// .join("key.pem"), -// PathBuf::from(env!("CARGO_MANIFEST_DIR")) -// .join("self_signed_certs") -// .join("cert.pem"), -// ); - -// let acceptor = TlsAcceptor::from(rustls_config); - -// let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap(); -// let mut listener = AddrIncoming::from_listener(listener).unwrap(); - -// let protocol = Arc::new(Http::new()); - -// let mut app = Router::<()>::new() -// .route("/", get(handler)) -// .into_make_service(); - -// loop { -// let stream = poll_fn(|cx| Pin::new(&mut listener).poll_accept(cx)) -// .await -// .unwrap() -// .unwrap(); - -// let acceptor = acceptor.clone(); - -// let protocol = protocol.clone(); - -// let svc = MakeService::<_, Request>::make_service(&mut app, &stream); - -// tokio::spawn(async move { -// if let Ok(stream) = acceptor.accept(stream).await { -// let _ = protocol.serve_connection(stream, svc.await.unwrap()).await; -// } -// }); -// } -// } - -// async fn handler() -> &'static str { -// "Hello, World!" -// } - -// fn rustls_server_config(key: impl AsRef, cert: impl AsRef) -> Arc { -// let mut key_reader = BufReader::new(File::open(key).unwrap()); -// let mut cert_reader = BufReader::new(File::open(cert).unwrap()); - -// let key = PrivateKey(pkcs8_private_keys(&mut key_reader).unwrap().remove(0)); -// let certs = certs(&mut cert_reader) -// .unwrap() -// .into_iter() -// .map(Certificate) -// .collect(); - -// let mut config = ServerConfig::builder() -// .with_safe_defaults() -// .with_no_client_auth() -// .with_single_cert(certs, key) -// .expect("bad certificate/key"); - -// config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - -// Arc::new(config) -// } +async fn handler() -> &'static str { + "Hello, World!" +} + +fn rustls_server_config(key: impl AsRef, cert: impl AsRef) -> Arc { + let mut key_reader = BufReader::new(File::open(key).unwrap()); + let mut cert_reader = BufReader::new(File::open(cert).unwrap()); + + let key = PrivateKey(pkcs8_private_keys(&mut key_reader).unwrap().remove(0)); + let certs = certs(&mut cert_reader) + .unwrap() + .into_iter() + .map(Certificate) + .collect(); + + let mut config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(certs, key) + .expect("bad certificate/key"); + + config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; + + Arc::new(config) +}