diff --git a/examples/tls-graceful-shutdown/Cargo.toml b/examples/tls-graceful-shutdown/Cargo.toml index 7b0169ba..40e48903 100644 --- a/examples/tls-graceful-shutdown/Cargo.toml +++ b/examples/tls-graceful-shutdown/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] axum = { path = "../../axum" } -axum-server = { version = "0.3", features = ["tls-rustls"] } +axum-server = { version = "0.6", features = ["tls-rustls"] } hyper = { version = "0.14", features = ["full"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/examples/tls-graceful-shutdown/src/main.rs b/examples/tls-graceful-shutdown/src/main.rs index 13251846..cc5b6ecb 100644 --- a/examples/tls-graceful-shutdown/src/main.rs +++ b/examples/tls-graceful-shutdown/src/main.rs @@ -4,140 +4,138 @@ //! cargo run -p example-tls-graceful-shutdown //! ``` -fn main() { - // This example has not yet been updated to Hyper 1.0 +use axum::{ + extract::Host, + handler::HandlerWithoutStateExt, + http::{StatusCode, Uri}, + response::Redirect, + routing::get, + BoxError, Router, +}; +use axum_server::tls_rustls::RustlsConfig; +use std::{future::Future, net::SocketAddr, path::PathBuf, time::Duration}; +use tokio::signal; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[derive(Clone, Copy)] +struct Ports { + http: u16, + https: u16, } -//use axum::{ -// extract::Host, -// handler::HandlerWithoutStateExt, -// http::{StatusCode, Uri}, -// response::Redirect, -// routing::get, -// BoxError, Router, -//}; -//use axum_server::tls_rustls::RustlsConfig; -//use std::{future::Future, net::SocketAddr, path::PathBuf, time::Duration}; -//use tokio::signal; -//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_graceful_shutdown=debug".into()), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); -//#[derive(Clone, Copy)] -//struct Ports { -// http: u16, -// https: u16, -//} + let ports = Ports { + http: 7878, + https: 3000, + }; -//#[tokio::main] -//async fn main() { -// tracing_subscriber::registry() -// .with( -// tracing_subscriber::EnvFilter::try_from_default_env() -// .unwrap_or_else(|_| "example_tls_graceful_shutdown=debug".into()), -// ) -// .with(tracing_subscriber::fmt::layer()) -// .init(); + //Create a handle for our TLS server so the shutdown signal can all shutdown + let handle = axum_server::Handle::new(); + //save the future for easy shutting down of redirect server + let shutdown_future = shutdown_signal(handle.clone()); -// let ports = Ports { -// http: 7878, -// https: 3000, -// }; + // optional: spawn a second server to redirect http requests to this server + tokio::spawn(redirect_http_to_https(ports, shutdown_future)); -// //Create a handle for our TLS server so the shutdown signal can all shutdown -// let handle = axum_server::Handle::new(); -// //save the future for easy shutting down of redirect server -// let shutdown_future = shutdown_signal(handle.clone()); + // configure certificate and private key used by https + let config = RustlsConfig::from_pem_file( + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("self_signed_certs") + .join("cert.pem"), + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("self_signed_certs") + .join("key.pem"), + ) + .await + .unwrap(); -// // optional: spawn a second server to redirect http requests to this server -// tokio::spawn(redirect_http_to_https(ports, shutdown_future)); + let app = Router::new().route("/", get(handler)); -// // configure certificate and private key used by https -// let config = RustlsConfig::from_pem_file( -// PathBuf::from(env!("CARGO_MANIFEST_DIR")) -// .join("self_signed_certs") -// .join("cert.pem"), -// PathBuf::from(env!("CARGO_MANIFEST_DIR")) -// .join("self_signed_certs") -// .join("key.pem"), -// ) -// .await -// .unwrap(); + // run https server + let addr = SocketAddr::from(([127, 0, 0, 1], ports.https)); + tracing::debug!("listening on {addr}"); + axum_server::bind_rustls(addr, config) + .handle(handle) + .serve(app.into_make_service()) + .await + .unwrap(); +} -// let app = Router::new().route("/", get(handler)); +async fn shutdown_signal(handle: axum_server::Handle) { + let ctrl_c = async { + signal::ctrl_c() + .await + .expect("failed to install Ctrl+C handler"); + }; -// // run https server -// let addr = SocketAddr::from(([127, 0, 0, 1], ports.https)); -// tracing::debug!("listening on {addr}"); -// axum_server::bind_rustls(addr, config) -// .handle(handle) -// .serve(app.into_make_service()) -// .await -// .unwrap(); -//} + #[cfg(unix)] + let terminate = async { + signal::unix::signal(signal::unix::SignalKind::terminate()) + .expect("failed to install signal handler") + .recv() + .await; + }; -//async fn shutdown_signal(handle: axum_server::Handle) { -// let ctrl_c = async { -// signal::ctrl_c() -// .await -// .expect("failed to install Ctrl+C handler"); -// }; + #[cfg(not(unix))] + let terminate = std::future::pending::<()>(); -// #[cfg(unix)] -// let terminate = async { -// signal::unix::signal(signal::unix::SignalKind::terminate()) -// .expect("failed to install signal handler") -// .recv() -// .await; -// }; + tokio::select! { + _ = ctrl_c => {}, + _ = terminate => {}, + } -// #[cfg(not(unix))] -// let terminate = std::future::pending::<()>(); + tracing::info!("Received termination signal shutting down"); + handle.graceful_shutdown(Some(Duration::from_secs(10))); // 10 secs is how long docker will wait + // to force shutdown +} -// tokio::select! { -// _ = ctrl_c => {}, -// _ = terminate => {}, -// } +async fn handler() -> &'static str { + "Hello, World!" +} -// tracing::info!("Received termination signal shutting down"); -// handle.graceful_shutdown(Some(Duration::from_secs(10))); // 10 secs is how long docker will wait -// // to force shutdown -//} +async fn redirect_http_to_https(ports: Ports, signal: F) +where + F: Future + Send + 'static, +{ + fn make_https(host: String, uri: Uri, ports: Ports) -> Result { + let mut parts = uri.into_parts(); -//async fn handler() -> &'static str { -// "Hello, World!" -//} + parts.scheme = Some(axum::http::uri::Scheme::HTTPS); -//async fn redirect_http_to_https(ports: Ports, signal: impl Future) { -// fn make_https(host: String, uri: Uri, ports: Ports) -> Result { -// let mut parts = uri.into_parts(); + if parts.path_and_query.is_none() { + parts.path_and_query = Some("/".parse().unwrap()); + } -// parts.scheme = Some(axum::http::uri::Scheme::HTTPS); + let https_host = host.replace(&ports.http.to_string(), &ports.https.to_string()); + parts.authority = Some(https_host.parse()?); -// if parts.path_and_query.is_none() { -// parts.path_and_query = Some("/".parse().unwrap()); -// } + Ok(Uri::from_parts(parts)?) + } -// let https_host = host.replace(&ports.http.to_string(), &ports.https.to_string()); -// parts.authority = Some(https_host.parse()?); + let redirect = move |Host(host): Host, uri: Uri| async move { + match make_https(host, uri, ports) { + Ok(uri) => Ok(Redirect::permanent(&uri.to_string())), + Err(error) => { + tracing::warn!(%error, "failed to convert URI to HTTPS"); + Err(StatusCode::BAD_REQUEST) + } + } + }; -// Ok(Uri::from_parts(parts)?) -// } - -// let redirect = move |Host(host): Host, uri: Uri| async move { -// match make_https(host, uri, ports) { -// Ok(uri) => Ok(Redirect::permanent(&uri.to_string())), -// Err(error) => { -// tracing::warn!(%error, "failed to convert URI to HTTPS"); -// Err(StatusCode::BAD_REQUEST) -// } -// } -// }; - -// let addr = SocketAddr::from(([127, 0, 0, 1], ports.http)); -// //let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); -// tracing::debug!("listening on {addr}"); -// hyper::Server::bind(&addr) -// .serve(redirect.into_make_service()) -// .with_graceful_shutdown(signal) -// .await -// .unwrap(); -//} + let addr = SocketAddr::from(([127, 0, 0, 1], ports.http)); + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); + tracing::debug!("listening on {addr}"); + axum::serve(listener, redirect.into_make_service()) + .with_graceful_shutdown(signal) + .await + .unwrap(); +}