diff --git a/xks-axum/Cargo.toml b/xks-axum/Cargo.toml index 7e8fc13..fef491e 100644 --- a/xks-axum/Cargo.toml +++ b/xks-axum/Cargo.toml @@ -65,9 +65,6 @@ serial_test_derive = "0.9" # https://github.com/mheese/rust-pkcs11/issues/50 pkcs11 = { path = "rust-pkcs11" } -# Patch to enable configuration of full TCP keepalive parameters -axum-server = { path = "axum-server" } - [profile.dev] panic = "abort" diff --git a/xks-axum/axum-server/.gitignore b/xks-axum/axum-server/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/xks-axum/axum-server/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/xks-axum/axum-server/CHANGELOG.md b/xks-axum/axum-server/CHANGELOG.md deleted file mode 100644 index 711ba60..0000000 --- a/xks-axum/axum-server/CHANGELOG.md +++ /dev/null @@ -1,115 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to -[Semantic Versioning]. - -# Unreleased - -None. - -# 0.4.2 (5. August 2022) - -- **added:** Added `Server::from_tcp`, `axum_server::from_tcp` and - `axum_server::from_tcp_rustls` methods to create `Server` from - `std::net::TcpListener`. - -# 0.4.1 (29. July 2022) - -- **added:** Added `map`, `get` and `get_mut` methods to access the acceptor - of `Server`. - -# 0.4.0 (18. April 2022) - -- Added TLS handshake timeout(10 seconds). -- In `RustlsConfig`: `from_pem` and `from_pem_file` methods now accept EC - keys. -- **added:** Added `AddrIncomingConfig` to allow configuration of - `hyper::server::conn::AddrIncoming`. -- **added:** Added `HttpConfig::http1_header_read_timeout`. -- **breaking:** Changed `Handle::listening` return type to - `Option`. If binding fails, `Option::None` will be returned. - -# 0.3.2 (17. November 2021) - -- **added:** Added `HttpConfig` to allow more configuration. - -# 0.3.1 (10. November 2021) - -- **fixed:** `tls-rustls` feature doesn't compile if `fs` feature in `tokio` - is not enabled. - -# 0.3.0 (10. November 2021) - -- **Total rewrite of source code.** -- **Major api changes:** - - **breaking:** Removed `bind_rustls`, `certificate`, `certificate_file`, - `loader`, `new`, `private_key`, `private_key_file`, `serve_and_record`, - `tls_config` methods from `Server`. - - **breaking:** Removed `tls` module. - - **breaking:** Removed `record` module and feature. - - **breaking:** Removed `Handle::listening_addrs` method. - - **breaking:** `Server::bind` method doesn't take `self` anymore and - creates an `Server`. - - **breaking:** `bind` method now takes a `SocketAddr`. - - **breaking:** `bind_rustls` method now takes a `SocketAddr` and an - `tls_rustls::RustlsConfig`. - - **breaking:** `Server::serve` method now takes a `MakeService`. - - **breaking:** `Handle::listening` method now returns `SocketAddr`. - - **added:** Added `Handle::connection_count` that can be used to get alive - connection count. - - **added:** Added `service` module. - - **added:** Added `service::MakeServiceRef` and `service::SendService` - traits aliases for convenience. - - **added:** Added `accept` module. - - **added:** Added `accept::Accept` trait that can be implemented to modify - io stream and service. - - **added:** Added `accept::DefaultAcceptor` struct that implements - `accept::Accept` to be used as a default 'Accept' for 'Server'. - - **added:** Added `Server::acceptor` method that can be used to provide a - custom `accept::Accept`. - - **added:** Added `tls_rustls` module. - - **added:** Added `tls_rustls::RustlsAcceptor` that can be used with - `Server::acceptor` to make a tls `Server`. - - **added:** Added `tls_rustls::RustlsConfig` to create rustls utilities and - to provide reload functionality. - - **added:** Added `tls_rustls::bind_rustls` which is same as `bind_rustls` - function. - -# 0.2.5 (5. October 2021) - -- Compile on rust `1.51`. - -# 0.2.4 (17. September 2021) - -- Reduced `futures-util` features to improve compile times. - -# 0.2.3 (14. September 2021) - -- Fixed `bind` and `bind_rustls` not working on some types. - -# 0.2.2 (6. September 2021) - -- Added uri `Scheme` in `Request` extensions. -- Fixed memory leak that happens as connections are accepted. - -# 0.2.1 (30. August 2021) - -- Fixed `serve_and_record` not recording independently for each connection. - -# 0.2.0 (29. August 2021) - -- Added `TlsLoader` to reload tls configuration. -- Added `Handle` to provide additional utilities for server. - -# 0.1.2 (24. August 2021) - -- Fixed an import issue when using `tls-rustls` feature. - -# 0.1.0 (23. August 2021) - -- Initial release. - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[Semantic Versioning]: https://semver.org/spec/v2.0.0.html diff --git a/xks-axum/axum-server/Cargo.toml b/xks-axum/axum-server/Cargo.toml deleted file mode 100644 index fcb9239..0000000 --- a/xks-axum/axum-server/Cargo.toml +++ /dev/null @@ -1,67 +0,0 @@ -[package] -authors = ["Programatik "] -categories = ["asynchronous", "network-programming", "web-programming"] -description = "High level server designed to be used with axum framework." -edition = "2018" -homepage = "https://github.com/programatik29/axum-server" -keywords = ["http", "https", "web", "server"] -license = "MIT" -name = "axum-server" -readme = "README.md" -repository = "https://github.com/programatik29/axum-server" -version = "0.4.2" - -[features] -default = [] -tls-rustls = ["arc-swap", "pin-project-lite", "rustls", "rustls-pemfile", "tokio/fs", "tokio/time", "tokio-rustls"] - -[dependencies] -bytes = "1" -futures-util = { version = "0.3", default-features = false, features = ["alloc"] } -http = "0.2" -http-body = "0.4" -hyper = { version = "0.14.16", features = ["http1", "http2", "server", "runtime"] } -tokio = { version = "1", features = ["macros", "net", "sync"] } -tower-service = "0.3" - -# optional dependencies -arc-swap = { version = "1", optional = true } -pin-project-lite = { version = "0.2", optional = true } -rustls = { version = "0.20", features = ["dangerous_configuration"], optional = true } -rustls-pemfile = { version = "1", optional = true } -tokio-rustls = { version = "0.23", optional = true } - -[dev-dependencies] -axum = "0.5" -hyper = { version = "0.14", features = ["full"] } -tokio = { version = "1", features = ["full"] } -tower = { version = "0.4", features = ["util"] } -tower-http = { version = "0.3", features = ["add-extension"] } - -[package.metadata.docs.rs] -all-features = true -cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"] -rustdoc-args = ["--cfg", "docsrs"] - -[[example]] -name = "from_std_listener_rustls" -required-features = ["tls-rustls"] - -[[example]] -name = "http_and_https" -required-features = ["tls-rustls"] - -[[example]] -name = "rustls_reload" -required-features = ["tls-rustls"] - -[[example]] -name = "rustls_server" -required-features = ["tls-rustls"] - -[[example]] -name = "rustls_session" -required-features = ["tls-rustls"] - -[patch.crates-io] -hyper = { git = "https://github.com/hyperium/hyper", branch = "0.14.x" } diff --git a/xks-axum/axum-server/LICENSE b/xks-axum/axum-server/LICENSE deleted file mode 100644 index cd5a49f..0000000 --- a/xks-axum/axum-server/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2021 Axum Server Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/xks-axum/axum-server/README.md b/xks-axum/axum-server/README.md deleted file mode 100644 index 1c9cd30..0000000 --- a/xks-axum/axum-server/README.md +++ /dev/null @@ -1,58 +0,0 @@ -[![License](https://img.shields.io/crates/l/axum-server)](https://choosealicense.com/licenses/mit/) -[![Crates.io](https://img.shields.io/crates/v/axum-server)](https://crates.io/crates/axum-server) -[![Docs - Master](https://img.shields.io/badge/docs-master-blue)](https://programatik29.github.io/axum-server/axum_server/) -[![Docs - Stable](https://img.shields.io/crates/v/axum-server?color=blue&label=docs)](https://docs.rs/axum-server/) - -# axum-server - -axum-server is a [hyper] server implementation designed to be used with [axum] framework. - -This project is maintained by community independently from [axum]. - -## Features - -- HTTP/1 and HTTP/2 -- HTTPS through [rustls]. -- High performance through [hyper]. -- Using [tower] make service API. -- Very good [axum] compatibility. Likely to work with future [axum] releases. - -## Usage Example - -A simple hello world application can be served like: - -```rust -use axum::{routing::get, Router}; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .serve(app.into_make_service()) - .await - .unwrap(); -} -``` - -You can find more examples [here](/examples). - -## Minimum Supported Rust Version - -axum-server's MSRV is `1.49`. - -## Safety - -This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% safe Rust. - -## License - -This project is licensed under the [MIT license](LICENSE). - -[axum]: https://crates.io/crates/axum -[hyper]: https://crates.io/crates/hyper -[rustls]: https://crates.io/crates/rustls -[tower]: https://crates.io/crates/tower diff --git a/xks-axum/axum-server/examples/configure_addr_incoming.rs b/xks-axum/axum-server/examples/configure_addr_incoming.rs deleted file mode 100644 index f4287d3..0000000 --- a/xks-axum/axum-server/examples/configure_addr_incoming.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Run with `cargo run --example configure_http` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use axum::{routing::get, Router}; -use axum_server::AddrIncomingConfig; -use std::net::SocketAddr; -use std::time::Duration; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = AddrIncomingConfig::new() - .tcp_nodelay(true) - .tcp_sleep_on_accept_errors(true) - .tcp_keepalive(Some(Duration::from_secs(32))) - .tcp_keepalive_interval(Some(Duration::from_secs(1))) - .tcp_keepalive_retries(Some(1)) - .build(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .addr_incoming_config(config) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/configure_http.rs b/xks-axum/axum-server/examples/configure_http.rs deleted file mode 100644 index bb1991b..0000000 --- a/xks-axum/axum-server/examples/configure_http.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Run with `cargo run --example configure_http` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use axum::{routing::get, Router}; -use axum_server::HttpConfig; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = HttpConfig::new() - .http1_only(true) - .http2_only(false) - .max_buf_size(8192) - .build(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .http_config(config) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/from_std_listener.rs b/xks-axum/axum-server/examples/from_std_listener.rs deleted file mode 100644 index 150b384..0000000 --- a/xks-axum/axum-server/examples/from_std_listener.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Run with `cargo run --example from_std_listener` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use axum::{routing::get, Router}; -use std::net::{SocketAddr, TcpListener}; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - let listener = TcpListener::bind(addr).unwrap(); - println!("listening on {}", addr); - axum_server::from_tcp(listener) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/from_std_listener_rustls.rs b/xks-axum/axum-server/examples/from_std_listener_rustls.rs deleted file mode 100644 index fa8d961..0000000 --- a/xks-axum/axum-server/examples/from_std_listener_rustls.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Run with `cargo run --all-features --example from_std_listener_rustls` -//! command. -//! -//! To connect through browser, navigate to "https://localhost:3000" url. - -use axum::{routing::get, Router}; -use axum_server::tls_rustls::RustlsConfig; -use std::net::{SocketAddr, TcpListener}; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - let listener = TcpListener::bind(addr).unwrap(); - println!("listening on {}", addr); - axum_server::from_tcp_rustls(listener, config) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/graceful_shutdown.rs b/xks-axum/axum-server/examples/graceful_shutdown.rs deleted file mode 100644 index 07b9ca1..0000000 --- a/xks-axum/axum-server/examples/graceful_shutdown.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Run with `cargo run --example graceful_shutdown` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. -//! -//! After 10 seconds: -//! - If there aren't any connections alive, server will shutdown. -//! - If there are connections alive, server will wait until deadline is elapsed. -//! - Deadline is 30 seconds. Server will shutdown anyways when deadline is elapsed. - -use axum::{routing::get, Router}; -use axum_server::Handle; -use std::{net::SocketAddr, time::Duration}; -use tokio::time::sleep; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let handle = Handle::new(); - - // Spawn a task to gracefully shutdown server. - tokio::spawn(graceful_shutdown(handle.clone())); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .handle(handle) - .serve(app.into_make_service()) - .await - .unwrap(); - - println!("server is shut down"); -} - -async fn graceful_shutdown(handle: Handle) { - // Wait 10 seconds. - sleep(Duration::from_secs(10)).await; - - println!("sending graceful shutdown signal"); - - // Signal the server to shutdown using Handle. - handle.graceful_shutdown(Some(Duration::from_secs(30))); - - // Print alive connection count every second. - loop { - sleep(Duration::from_secs(1)).await; - - println!("alive connections: {}", handle.connection_count()); - } -} diff --git a/xks-axum/axum-server/examples/hello_world.rs b/xks-axum/axum-server/examples/hello_world.rs deleted file mode 100644 index 32d94c7..0000000 --- a/xks-axum/axum-server/examples/hello_world.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Run with `cargo run --example hello_world` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use axum::{routing::get, Router}; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/http_and_https.rs b/xks-axum/axum-server/examples/http_and_https.rs deleted file mode 100644 index d320838..0000000 --- a/xks-axum/axum-server/examples/http_and_https.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Run with `cargo run --all-features --example http_and_https` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url which should redirect to -//! "https://localhost:3443". - -use axum::{http::uri::Uri, response::Redirect, routing::get, Router}; -use axum_server::tls_rustls::RustlsConfig; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let http = tokio::spawn(http_server()); - let https = tokio::spawn(https_server()); - - // Ignore errors. - let _ = tokio::join!(http, https); -} - -async fn http_server() { - let app = Router::new().route("/", get(http_handler)); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("http listening on {}", addr); - axum_server::bind(addr) - .serve(app.into_make_service()) - .await - .unwrap(); -} - -async fn http_handler(uri: Uri) -> Redirect { - let uri = format!("https://127.0.0.1:3443{}", uri.path()); - - Redirect::temporary(&uri) -} - -async fn https_server() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3443)); - println!("https listening on {}", addr); - axum_server::bind_rustls(addr, config) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/remote_address.rs b/xks-axum/axum-server/examples/remote_address.rs deleted file mode 100644 index f48ea02..0000000 --- a/xks-axum/axum-server/examples/remote_address.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Run with `cargo run --example remote_address` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use axum::{extract::ConnectInfo, routing::get, Router}; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let app = Router::new() - .route("/", get(handler)) - .into_make_service_with_connect_info::(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - - axum_server::bind(addr).serve(app).await.unwrap(); -} - -async fn handler(ConnectInfo(addr): ConnectInfo) -> String { - format!("your ip address is: {}", addr) -} diff --git a/xks-axum/axum-server/examples/remote_address_using_tower.rs b/xks-axum/axum-server/examples/remote_address_using_tower.rs deleted file mode 100644 index 00857b8..0000000 --- a/xks-axum/axum-server/examples/remote_address_using_tower.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! Run with `cargo run --example remote_address_using_tower` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. - -use hyper::{server::conn::AddrStream, Body, Request, Response}; -use std::{convert::Infallible, net::SocketAddr}; -use tower::service_fn; -use tower_http::add_extension::AddExtension; - -#[tokio::main] -async fn main() { - let service = service_fn(|mut req: Request| async move { - let addr: SocketAddr = req.extensions_mut().remove().unwrap(); - let body = Body::from(format!("IP Address: {}", addr)); - - Ok::<_, Infallible>(Response::new(body)) - }); - - axum_server::bind(SocketAddr::from(([127, 0, 0, 1], 3000))) - .serve(service_fn(|addr: &AddrStream| { - let addr = addr.remote_addr(); - - async move { Ok::<_, Infallible>(AddExtension::new(service, addr)) } - })) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/rustls_reload.rs b/xks-axum/axum-server/examples/rustls_reload.rs deleted file mode 100644 index 08c2a85..0000000 --- a/xks-axum/axum-server/examples/rustls_reload.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Run with `cargo run --all-features --example rustls_reload` command. -//! -//! To connect through browser, navigate to "https://localhost:3000" url. -//! -//! Certificate common name will be "localhost". -//! -//! After 20 seconds, certificate common name will be "reloaded". - -use axum::{routing::get, Router}; -use axum_server::tls_rustls::RustlsConfig; -use std::{net::SocketAddr, time::Duration}; -use tokio::time::sleep; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - // Spawn a task to reload tls. - tokio::spawn(reload(config.clone())); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind_rustls(addr, config) - .serve(app.into_make_service()) - .await - .unwrap(); -} - -async fn reload(config: RustlsConfig) { - // Wait for 20 seconds. - sleep(Duration::from_secs(20)).await; - - println!("reloading rustls configuration"); - - // Reload rustls configuration from new files. - config - .reload_from_pem_file( - "examples/self-signed-certs/reload/cert.pem", - "examples/self-signed-certs/reload/key.pem", - ) - .await - .unwrap(); - - println!("rustls configuration reloaded"); -} diff --git a/xks-axum/axum-server/examples/rustls_server.rs b/xks-axum/axum-server/examples/rustls_server.rs deleted file mode 100644 index 44ea023..0000000 --- a/xks-axum/axum-server/examples/rustls_server.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Run with `cargo run --all-features --example rustls_server` command. -//! -//! To connect through browser, navigate to "https://localhost:3000" url. - -use axum::{routing::get, Router}; -use axum_server::tls_rustls::RustlsConfig; -use std::net::SocketAddr; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind_rustls(addr, config) - .serve(app.into_make_service()) - .await - .unwrap(); -} diff --git a/xks-axum/axum-server/examples/rustls_session.rs b/xks-axum/axum-server/examples/rustls_session.rs deleted file mode 100644 index 2697d9d..0000000 --- a/xks-axum/axum-server/examples/rustls_session.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! Run with `cargo run --all-features --example rustls_session` command. -//! -//! To connect through browser, navigate to "https://localhost:3000" url. - -use axum::{middleware::AddExtension, routing::get, Extension, Router}; -use axum_server::{ - accept::Accept, - tls_rustls::{RustlsAcceptor, RustlsConfig}, -}; -use futures_util::future::BoxFuture; -use std::{io, net::SocketAddr, sync::Arc}; -use tokio::io::{AsyncRead, AsyncWrite}; -use tokio_rustls::server::TlsStream; -use tower::Layer; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(handler)); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - - println!("listening on {}", addr); - - let acceptor = CustomAcceptor::new(RustlsAcceptor::new(config)); - let server = axum_server::bind(addr).acceptor(acceptor); - - server.serve(app.into_make_service()).await.unwrap(); -} - -async fn handler(tls_data: Extension) -> String { - format!("{:?}", tls_data) -} - -#[derive(Debug, Clone)] -struct TlsData { - _hostname: Option>, -} - -#[derive(Debug, Clone)] -struct CustomAcceptor { - inner: RustlsAcceptor, -} - -impl CustomAcceptor { - fn new(inner: RustlsAcceptor) -> Self { - Self { inner } - } -} - -impl Accept for CustomAcceptor -where - I: AsyncRead + AsyncWrite + Unpin + Send + 'static, - S: Send + 'static, -{ - type Stream = TlsStream; - type Service = AddExtension; - type Future = BoxFuture<'static, io::Result<(Self::Stream, Self::Service)>>; - - fn accept(&self, stream: I, service: S) -> Self::Future { - let acceptor = self.inner.clone(); - - Box::pin(async move { - let (stream, service) = acceptor.accept(stream, service).await?; - let server_conn = stream.get_ref().1; - let sni_hostname = TlsData { - _hostname: server_conn.sni_hostname().map(From::from), - }; - let service = Extension(sni_hostname).layer(service); - - Ok((stream, service)) - }) - } -} diff --git a/xks-axum/axum-server/examples/self-signed-certs/cert.pem b/xks-axum/axum-server/examples/self-signed-certs/cert.pem deleted file mode 100644 index 8227f32..0000000 --- a/xks-axum/axum-server/examples/self-signed-certs/cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFkzCCA3ugAwIBAgIUQZiKeBISKUZoglT8J8CCPpGbgTkwDQYJKoZIhvcNAQEL -BQAwWTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X -DTIxMDgyOTEyMDE0NVoXDTIyMDgyOTEyMDE0NVowWTELMAkGA1UEBhMCVVMxEzAR -BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 -IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAoeDJnuh1lhcpKCt5VEBqO9JcSoz2wqD3SLj4i2qrEOvqb4X0ZZeN -5GQXQlOG2N6+9FOxTzaTTigTecYzI3hqKn1fiuvaS4EeTC7E1sVOj7tY0yVySjXM -pC/3t1n1s3B25m7eQ0G2JypZFCobGqY0kaRoO+mCTjI4bdCd769shIerCO4Z8FD5 -uj1+hBC7ZY/sqmRkGTLX1ZzkXzaeNeWGlkXKU8/V3qdveFQ/sGe+KoZpOPXb0yR7 -H8zf6NE2CFCNJDhytOkYLOsnvCJOvibJ3kbM2GfI9iCd0/QhQAOcrVhcOgI4aIxr -wP3zvF4PFUhFKEWHqK5IFq41xKyMYu2fw3bmKXg4zsQGcB0avBD7z+7ENEBvLkNI -7O20wKJp8u0RfjStNHWPmWLXPjkadVB5JHJjsktvgNZkbs9ugxhZWW2AzrrIuqwR -NOWnjHE7J3jvcHP6jE5O9LHpnlh6BMoKPsQuRu/bkrD34rNzwH7IX1To1CyDazMR -yhUiARYh43gg6hrrQdVjDFMHd51mgWHtOPzSLb0uzToglAa3FClGlCeaiacu4H2V -EfJrlCbVlftmIub9/EILZ6XpyYWMxt2mm4mCcMtXmBsHolP4lU3keK8AGNFOr3PC -B7NHLNp1RHgx8+Q3kzobJ1Lk+zEjraWPb5gyByUvZySbd/JTGgNCmZsCAwEAAaNT -MFEwHQYDVR0OBBYEFGsIv6GsbDS+dEWwWlA/3TG5Oi88MB8GA1UdIwQYMBaAFGsI -v6GsbDS+dEWwWlA/3TG5Oi88MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggIBAHhjzP8WtkLJVfZXXUPAAekR7kaqk2hb3hIgDABBJ7xNxcktLOH7V/ng -nhbnwSH5mCkHHXx78TOhWqokHp5wru8K3de5wvAD8uz0UwNDHK5EzqtjYLzxbxAr -ht89WoXGPEZIz6MuOxVYx/HHXdgNEXUcujzfpAfvznVxvzBVqpHNgc7qO8wJd0cG -nit1XubxKoIVTEUjDfxGa2TsmBI7CZ8MLjIyztp/b3txpVl36hPC/uFLwKC780Jc -eO9saA5ISbJh7EaISRr8MKpBpJcraL+055bMjM+kzRFA18NWuuo9Y8fXnXE8e/af -k8FvclVdH/YyezaLkjW7lXjo7QoSXHhAuSzvsGmIsh+HuH+3Fs22AN3aGdmimOmp -7JiNe42mwEpJydwgGlKOysw4ht6MA6yOcQJw73QAYYwusOmNjFZtfCUqJx/JO7mn -Sb1/PW58xYSJhDxdGhoh6Rd3xPMW1T4YwpapkAC/htciK3XkwCcG1VKSmCIErkXf -vllmdahH/QkNooNAHMZl/ipYMik8pp5eRjVjCvpQTDBOI97U0+bgXydHVowP9ExE -dGcm6pP8FU1LyBZdYTdlMRC5Z0L0ltcZn7bqKcyzZB3UcWJv7Uhn3MYbmqGsUVly -a/e3kH2t5pEWRTsrNrRD94LzEYKvcNHy6PYkrgpGjh2G2VBZgNzh ------END CERTIFICATE----- diff --git a/xks-axum/axum-server/examples/self-signed-certs/key.pem b/xks-axum/axum-server/examples/self-signed-certs/key.pem deleted file mode 100644 index c329a2d..0000000 --- a/xks-axum/axum-server/examples/self-signed-certs/key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -HUGWsrhnzvWoCOV+9+MdApoim8FI ------END PRIVATE KEY----- diff --git a/xks-axum/axum-server/examples/self-signed-certs/reload/cert.pem b/xks-axum/axum-server/examples/self-signed-certs/reload/cert.pem deleted file mode 100644 index 545c0ae..0000000 --- a/xks-axum/axum-server/examples/self-signed-certs/reload/cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFkTCCA3mgAwIBAgIUXN/Uw2uyZ6/Uj4LRuuK0/RdRHRswDQYJKoZIhvcNAQEL -BQAwWDELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDERMA8GA1UEAwwIcmVsb2FkZWQwHhcN -MjEwODI5MTI1NjU2WhcNMjIwODI5MTI1NjU2WjBYMQswCQYDVQQGEwJVUzETMBEG -A1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg -THRkMREwDwYDVQQDDAhyZWxvYWRlZDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC -AgoCggIBAL/OR5KG8PqJgZSDza1lBVpZjW3jw1MA9eegePoK/4dYjd0Mdw+DeYOu -J/UmXoLHUDi/YWwZSmeY3YW0Wimwo1C5VqQL3GapSyFibvyTFE2fpoK0QtlgTKJ4 -G0mzdZ9NjibhvK23UOW5VbzlBujrYAaF2ynUha/cgVZ9uzvdwd6ooi+1i6XfHnkG -AQqGi6u/SIB+eHXn0w+tTYXmMp44jqIkjsK2vPNeifWj3MQxvgg7JTR/AKTmFCMm -BJIEP62BTFEnHJF+pRd2Hj0GIAiNBq1uA1F+HoUhxyX3OWHYCkRwPMnrSbPQOyxO -g4oFaUzAvMd2lHN/GjJS0kLwDy7WF/iXZuFxdEsmEmH62fE7N4P2uEnNw5OcHS82 -8Mc2EoMrV8zUBl4ZJ2eFo6w9lAx2bzMZyGXdOHsZWnJ5+1co6gfRfv51TeJGQx8f -JaHWFrn55qKBQmgQpKmCt/sG3HrqTviw1PtecsrzTliEXPoWdx6AhYaV+I4u8c8S -Q0NfdfjXx+5EMFDe5CvfWp/D5C1AQIV5E0Ao3Q+VfjoU/2tz9WcE5voHfyl3mBMI -FHvAPCZC18E+ZpiYyhRJLxP4z0MzTiuxp25lRi0Yt/5QTzEzFfH1UNQYe2xljPtf -syg5RtHoijcL+MncE1NUXz+B/qC4uJm8llPjFoL94Yg3/dwWOPtPAgMBAAGjUzBR -MB0GA1UdDgQWBBThri9Jq8CLFMEHJ+wE7WsCODVRwjAfBgNVHSMEGDAWgBThri9J -q8CLFMEHJ+wE7WsCODVRwjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA -A4ICAQCiR8yJ2YQyJfYDd9BT9eb9H8/S+Yz/9ayNS3zSJk4StQZaS1V6XjexzDBr -MRSr/hHGtO9G2qeocuJ/ArUJS5yYsf69g9AjuB+b41k0E4BVpiB/lENAhMbMbl+D -+ysRifUR2svHnZzKnL7DRrpS3vEUQhO37GXwbEi192rXAr2N6VE0LhxGyE7EwCzw -7gNkzoB3/Y4Fb+6zCYZorg3PmPZHrfu9vGFiP9nh+JVos9aq2JHZgZJ2N5Hcdh1H -Bci372+i1SHKfYutXrcSnUcPd4UgGQt6F63fOFHJEGsSVbHpJujqjpIscuPqgfn8 -DSkm9SEyVEV8MrY2vtwtVFOre4yjsaZ2fHDU7rCXOO88kIBBdvIpdIO4mBKV14ug -k9M1xzqK/KvgMUztuw/oLxOp7Vnii9sQ9bjzjbFEMiJ07V5Egr88Zh+VnN3ED1MH -Ri6Ho/CI/ttAwzZVhrKumOb6AprPVUteZFedpV80UaYmIthkeW0i9QcUOMkr4bL3 -gCghJeBSETTGEYCKOpcIFbvXwlc8d3KlL0Fa4EbQiw5vlPY28UChnxuZ3I0Vtetf -2F+3bLoVxfZD2Gc7p5bjGHgzUbGLFM4GgqQ6EbRh261Om9/bUxBao7mhKa23XWna -3Y4qISAqus6OolerflYJCCuWUF4N6e6fES5bqnZD49qAaIEg0A== ------END CERTIFICATE----- diff --git a/xks-axum/axum-server/examples/self-signed-certs/reload/key.pem b/xks-axum/axum-server/examples/self-signed-certs/reload/key.pem deleted file mode 100644 index bc7dccf..0000000 --- a/xks-axum/axum-server/examples/self-signed-certs/reload/key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -85DaC33fAFuevGxpS147+sAiW6doqQ== ------END PRIVATE KEY----- diff --git a/xks-axum/axum-server/examples/shutdown.rs b/xks-axum/axum-server/examples/shutdown.rs deleted file mode 100644 index d84d5a2..0000000 --- a/xks-axum/axum-server/examples/shutdown.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Run with `cargo run --example shutdown` command. -//! -//! To connect through browser, navigate to "http://localhost:3000" url. -//! -//! Server will shutdown in 20 seconds. - -use axum::{routing::get, Router}; -use axum_server::Handle; -use std::{net::SocketAddr, time::Duration}; -use tokio::time::sleep; - -#[tokio::main] -async fn main() { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let handle = Handle::new(); - - // Spawn a task to shutdown server. - tokio::spawn(shutdown(handle.clone())); - - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); - axum_server::bind(addr) - .handle(handle) - .serve(app.into_make_service()) - .await - .unwrap(); - - println!("server is shut down"); -} - -async fn shutdown(handle: Handle) { - // Wait 20 seconds. - sleep(Duration::from_secs(20)).await; - - println!("sending shutdown signal"); - - // Signal the server to shutdown using Handle. - handle.shutdown(); -} diff --git a/xks-axum/axum-server/src/accept.rs b/xks-axum/axum-server/src/accept.rs deleted file mode 100644 index 702337a..0000000 --- a/xks-axum/axum-server/src/accept.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! [`Accept`] trait and utilities. - -use std::{ - future::{Future, Ready}, - io, -}; - -/// An asynchronous function to modify io stream and service. -pub trait Accept { - /// IO stream produced by accept. - type Stream; - - /// Service produced by accept. - type Service; - - /// Future return value. - type Future: Future>; - - /// Process io stream and service asynchronously. - fn accept(&self, stream: I, service: S) -> Self::Future; -} - -/// A no-op acceptor. -#[derive(Clone, Copy, Debug, Default)] -pub struct DefaultAcceptor; - -impl DefaultAcceptor { - /// Create a new default acceptor. - pub fn new() -> Self { - Self::default() - } -} - -impl Accept for DefaultAcceptor { - type Stream = I; - type Service = S; - type Future = Ready>; - - fn accept(&self, stream: I, service: S) -> Self::Future { - std::future::ready(Ok((stream, service))) - } -} diff --git a/xks-axum/axum-server/src/addr_incoming_config.rs b/xks-axum/axum-server/src/addr_incoming_config.rs deleted file mode 100644 index b75aed2..0000000 --- a/xks-axum/axum-server/src/addr_incoming_config.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::time::Duration; - -/// A configuration for [`AddrIncoming`](hyper::server::conn::AddrIncoming). -#[derive(Debug, Clone)] -pub struct AddrIncomingConfig { - pub(crate) tcp_sleep_on_accept_errors: bool, - pub(crate) tcp_keepalive: Option, - pub(crate) tcp_keepalive_interval: Option, - pub(crate) tcp_keepalive_retries: Option, - pub(crate) tcp_nodelay: bool, -} - -impl Default for AddrIncomingConfig { - fn default() -> Self { - Self::new() - } -} - -impl AddrIncomingConfig { - /// Creates a default [`AddrIncoming`](hyper::server::conn::AddrIncoming) config. - pub fn new() -> AddrIncomingConfig { - Self { - tcp_sleep_on_accept_errors: true, - tcp_keepalive: None, - tcp_keepalive_interval: None, - tcp_keepalive_retries: None, - tcp_nodelay: false, - } - } - - /// Builds the config, creating an owned version of it. - pub fn build(&mut self) -> Self { - self.clone() - } - - /// Set whether to sleep on accept errors, to avoid exhausting file descriptor limits. - /// - /// Default is `true`. - pub fn tcp_sleep_on_accept_errors(&mut self, val: bool) -> &mut Self { - self.tcp_sleep_on_accept_errors = val; - self - } - - /// Set how often to send TCP keepalive probes. - /// - /// By default TCP keepalive probes is disabled. - pub fn tcp_keepalive(&mut self, val: Option) -> &mut Self { - self.tcp_keepalive = val; - self - } - - /// Set the duration between two successive TCP keepalive retransmissions, - /// if acknowledgement to the previous keepalive transmission is not received. - /// - /// Default is no interval. - pub fn tcp_keepalive_interval(&mut self, val: Option) -> &mut Self { - self.tcp_keepalive_interval = val; - self - } - - /// Set the number of retransmissions to be carried out before declaring that remote end is not available. - /// - /// Default is no retry. - pub fn tcp_keepalive_retries(&mut self, val: Option) -> &mut Self { - self.tcp_keepalive_retries = val; - self - } - - /// Set the value of `TCP_NODELAY` option for accepted connections. - /// - /// Default is `false`. - pub fn tcp_nodelay(&mut self, val: bool) -> &mut Self { - self.tcp_nodelay = val; - self - } -} diff --git a/xks-axum/axum-server/src/handle.rs b/xks-axum/axum-server/src/handle.rs deleted file mode 100644 index 9171fa2..0000000 --- a/xks-axum/axum-server/src/handle.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::notify_once::NotifyOnce; -use std::{ - net::SocketAddr, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, Mutex, - }, - time::Duration, -}; -use tokio::{sync::Notify, time::sleep}; - -/// A handle for [`Server`](crate::server::Server). -#[derive(Clone, Debug, Default)] -pub struct Handle { - inner: Arc, -} - -#[derive(Debug, Default)] -struct HandleInner { - addr: Mutex>, - addr_notify: Notify, - conn_count: AtomicUsize, - shutdown: NotifyOnce, - graceful: NotifyOnce, - graceful_dur: Mutex>, - conn_end: NotifyOnce, -} - -impl Handle { - /// Create a new handle. - pub fn new() -> Self { - Self::default() - } - - /// Get the number of connections. - pub fn connection_count(&self) -> usize { - self.inner.conn_count.load(Ordering::SeqCst) - } - - /// Shutdown the server. - pub fn shutdown(&self) { - self.inner.shutdown.notify_waiters(); - } - - /// Gracefully shutdown the server. - pub fn graceful_shutdown(&self, duration: Option) { - *self.inner.graceful_dur.lock().unwrap() = duration; - - self.inner.graceful.notify_waiters(); - } - - /// Returns local address and port when server starts listening. - /// - /// Returns `None` if server fails to bind. - pub async fn listening(&self) -> Option { - let notified = self.inner.addr_notify.notified(); - - if let Some(addr) = *self.inner.addr.lock().unwrap() { - return Some(addr); - } - - notified.await; - - *self.inner.addr.lock().unwrap() - } - - pub(crate) fn notify_listening(&self, addr: Option) { - *self.inner.addr.lock().unwrap() = addr; - - self.inner.addr_notify.notify_waiters(); - } - - pub(crate) fn watcher(&self) -> Watcher { - Watcher::new(self.clone()) - } - - pub(crate) async fn wait_shutdown(&self) { - self.inner.shutdown.notified().await; - } - - pub(crate) async fn wait_graceful_shutdown(&self) { - self.inner.graceful.notified().await; - } - - pub(crate) async fn wait_connections_end(&self) { - if self.inner.conn_count.load(Ordering::SeqCst) == 0 { - return; - } - - let deadline = *self.inner.graceful_dur.lock().unwrap(); - - match deadline { - Some(duration) => tokio::select! { - biased; - _ = sleep(duration) => self.shutdown(), - _ = self.inner.conn_end.notified() => (), - }, - None => self.inner.conn_end.notified().await, - } - } -} - -pub(crate) struct Watcher { - handle: Handle, -} - -impl Watcher { - fn new(handle: Handle) -> Self { - handle.inner.conn_count.fetch_add(1, Ordering::SeqCst); - - Self { handle } - } - - pub(crate) async fn wait_shutdown(&self) { - self.handle.wait_shutdown().await - } -} - -impl Drop for Watcher { - fn drop(&mut self) { - let count = self.handle.inner.conn_count.fetch_sub(1, Ordering::SeqCst) - 1; - - if count == 0 && self.handle.inner.graceful.is_notified() { - self.handle.inner.conn_end.notify_waiters(); - } - } -} diff --git a/xks-axum/axum-server/src/http_config.rs b/xks-axum/axum-server/src/http_config.rs deleted file mode 100644 index 87ff3b2..0000000 --- a/xks-axum/axum-server/src/http_config.rs +++ /dev/null @@ -1,215 +0,0 @@ -use hyper::server::conn::Http; -use std::time::Duration; - -/// A configuration for [`Http`]. -#[derive(Debug, Clone)] -pub struct HttpConfig { - pub(crate) inner: Http, -} - -impl Default for HttpConfig { - fn default() -> Self { - Self::new() - } -} - -impl HttpConfig { - /// Creates a default [`Http`] config. - pub fn new() -> HttpConfig { - Self { inner: Http::new() } - } - - /// Builds the config, creating an owned version of it. - pub fn build(&mut self) -> Self { - self.clone() - } - - /// Sets whether HTTP1 is required. - /// - /// Default is `false`. - pub fn http1_only(&mut self, val: bool) -> &mut Self { - self.inner.http1_only(val); - self - } - - /// Set whether HTTP/1 connections should support half-closures. - /// - /// Clients can chose to shutdown their write-side while waiting - /// for the server to respond. Setting this to `true` will - /// prevent closing the connection immediately if `read` - /// detects an EOF in the middle of a request. - /// - /// Default is `false`. - pub fn http1_half_close(&mut self, val: bool) -> &mut Self { - self.inner.http1_half_close(val); - self - } - - /// Enables or disables HTTP/1 keep-alive. - /// - /// Default is true. - pub fn http1_keep_alive(&mut self, val: bool) -> &mut Self { - self.inner.http1_keep_alive(val); - self - } - - /// Set whether HTTP/1 connections will write header names as title case at - /// the socket level. - /// - /// Note that this setting does not affect HTTP/2. - /// - /// Default is false. - pub fn http1_title_case_headers(&mut self, enabled: bool) -> &mut Self { - self.inner.http1_title_case_headers(enabled); - self - } - - /// Set whether HTTP/1 connections will write header names as provided - /// at the socket level. - /// - /// Note that this setting does not affect HTTP/2. - /// - /// Default is false. - pub fn http1_preserve_header_case(&mut self, enabled: bool) -> &mut Self { - self.inner.http1_preserve_header_case(enabled); - self - } - - /// Set a timeout for reading client request headers. If a client does not - /// transmit the entire header within this time, the connection is closed. - /// - /// Default is None. - pub fn http1_header_read_timeout(&mut self, val: Duration) -> &mut Self { - self.inner.http1_header_read_timeout(val); - self - } - - /// Set whether HTTP/1 connections should try to use vectored writes, - /// or always flatten into a single buffer. - /// - /// Note that setting this to false may mean more copies of body data, - /// but may also improve performance when an IO transport doesn't - /// support vectored writes well, such as most TLS implementations. - /// - /// Setting this to true will force hyper to use queued strategy - /// which may eliminate unnecessary cloning on some TLS backends - /// - /// Default is `auto`. In this mode hyper will try to guess which - /// mode to use - pub fn http1_writev(&mut self, val: bool) -> &mut Self { - self.inner.http1_writev(val); - self - } - - /// Sets whether HTTP2 is required. - /// - /// Default is false - pub fn http2_only(&mut self, val: bool) -> &mut Self { - self.inner.http2_only(val); - self - } - - /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2 - /// stream-level flow control. - /// - /// Passing `None` will do nothing. - /// - /// If not set, hyper will use a default. - /// - /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_INITIAL_WINDOW_SIZE - pub fn http2_initial_stream_window_size(&mut self, sz: impl Into>) -> &mut Self { - self.inner.http2_initial_stream_window_size(sz); - self - } - - /// Sets the max connection-level flow control for HTTP2. - /// - /// Passing `None` will do nothing. - /// - /// If not set, hyper will use a default. - pub fn http2_initial_connection_window_size( - &mut self, - sz: impl Into>, - ) -> &mut Self { - self.inner.http2_initial_connection_window_size(sz); - self - } - - /// Sets whether to use an adaptive flow control. - /// - /// Enabling this will override the limits set in - /// `http2_initial_stream_window_size` and - /// `http2_initial_connection_window_size`. - pub fn http2_adaptive_window(&mut self, enabled: bool) -> &mut Self { - self.inner.http2_adaptive_window(enabled); - self - } - - /// Sets the maximum frame size to use for HTTP2. - /// - /// Passing `None` will do nothing. - /// - /// If not set, hyper will use a default. - pub fn http2_max_frame_size(&mut self, sz: impl Into>) -> &mut Self { - self.inner.http2_max_frame_size(sz); - self - } - - /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2 - /// connections. - /// - /// Default is no limit (`std::u32::MAX`). Passing `None` will do nothing. - /// - /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS - pub fn http2_max_concurrent_streams(&mut self, max: impl Into>) -> &mut Self { - self.inner.http2_max_concurrent_streams(max); - self - } - - /// Sets an interval for HTTP2 Ping frames should be sent to keep a - /// connection alive. - /// - /// Pass `None` to disable HTTP2 keep-alive. - /// - /// Default is currently disabled. - pub fn http2_keep_alive_interval( - &mut self, - interval: impl Into>, - ) -> &mut Self { - self.inner.http2_keep_alive_interval(interval); - self - } - - /// Sets a timeout for receiving an acknowledgement of the keep-alive ping. - /// - /// If the ping is not acknowledged within the timeout, the connection will - /// be closed. Does nothing if `http2_keep_alive_interval` is disabled. - /// - /// Default is 20 seconds. - pub fn http2_keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self { - self.inner.http2_keep_alive_timeout(timeout); - self - } - - /// Set the maximum buffer size for the connection. - /// - /// Default is ~400kb. - /// - /// # Panics - /// - /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum. - pub fn max_buf_size(&mut self, max: usize) -> &mut Self { - self.inner.max_buf_size(max); - self - } - - /// Aggregates flushes to better support pipelined responses. - /// - /// Experimental, may have bugs. - /// - /// Default is false. - pub fn pipeline_flush(&mut self, enabled: bool) -> &mut Self { - self.inner.pipeline_flush(enabled); - self - } -} diff --git a/xks-axum/axum-server/src/lib.rs b/xks-axum/axum-server/src/lib.rs deleted file mode 100644 index 1c3a6ed..0000000 --- a/xks-axum/axum-server/src/lib.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! axum-server is a [hyper] server implementation designed to be used with [axum] framework. -//! -//! # Features -//! -//! - HTTP/1 and HTTP/2 -//! - HTTPS through [rustls]. -//! - High performance through [hyper]. -//! - Using [tower] make service API. -//! - Very good [axum] compatibility. Likely to work with future [axum] releases. -//! -//! # Guide -//! -//! axum-server can [`serve`] items that implement [`MakeService`] with some additional [trait -//! bounds](crate::service::MakeServiceRef). Make services that are [created] using [`axum`] -//! complies with those trait bounds out of the box. Therefore it is more convenient to use this -//! crate with [`axum`]. -//! -//! All examples in this crate uses [`axum`]. If you want to use this crate without [`axum`] it is -//! highly recommended to learn how [tower] works. -//! -//! [`Server::bind`] or [`bind`] function can be called to create a server that will bind to -//! provided [`SocketAddr`] when [`serve`] is called. -//! -//! A [`Handle`] can be passed to [`Server`](Server::handle) for additional utilities like shutdown -//! and graceful shutdown. -//! -//! [`bind_rustls`] can be called by providing [`RustlsConfig`] to create a HTTPS [`Server`] that -//! will bind on provided [`SocketAddr`]. [`RustlsConfig`] can be cloned, reload methods can be -//! used on clone to reload tls configuration. -//! -//! # Example -//! -//! A simple hello world application can be served like: -//! -//! ```rust,no_run -//! use axum::{routing::get, Router}; -//! use std::net::SocketAddr; -//! -//! #[tokio::main] -//! async fn main() { -//! let app = Router::new().route("/", get(|| async { "Hello, world!" })); -//! -//! let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); -//! println!("listening on {}", addr); -//! axum_server::bind(addr) -//! .serve(app.into_make_service()) -//! .await -//! .unwrap(); -//! } -//! ``` -//! -//! You can find more examples in [repository]. -//! -//! [axum]: https://crates.io/crates/axum -//! [bind]: crate::bind -//! [bind_rustls]: crate::bind_rustls -//! [created]: https://docs.rs/axum/0.3/axum/struct.Router.html#method.into_make_service -//! [hyper]: https://crates.io/crates/hyper -//! [repository]: https://github.com/programatik29/axum-server/tree/v0.3.0/examples -//! [rustls]: https://crates.io/crates/rustls -//! [tower]: https://crates.io/crates/tower -//! [`axum`]: https://docs.rs/axum/0.3 -//! [`serve`]: crate::server::Server::serve -//! [`MakeService`]: https://docs.rs/tower/0.4/tower/make/trait.MakeService.html -//! [`RustlsConfig`]: crate::tls_rustls::RustlsConfig -//! [`SocketAddr`]: std::net::SocketAddr - -#![forbid(unsafe_code)] -#![warn( - clippy::await_holding_lock, - clippy::cargo_common_metadata, - clippy::dbg_macro, - clippy::doc_markdown, - clippy::empty_enum, - clippy::enum_glob_use, - clippy::inefficient_to_string, - clippy::mem_forget, - clippy::mutex_integer, - clippy::needless_continue, - clippy::todo, - clippy::unimplemented, - clippy::wildcard_imports, - future_incompatible, - missing_docs, - missing_debug_implementations, - unreachable_pub -)] -#![cfg_attr(docsrs, feature(doc_cfg))] - -mod addr_incoming_config; -mod handle; -mod http_config; -mod notify_once; -mod server; - -pub mod accept; -pub mod service; - -pub use self::{ - addr_incoming_config::AddrIncomingConfig, - handle::Handle, - http_config::HttpConfig, - server::{bind, from_tcp, Server}, -}; - -#[cfg(feature = "tls-rustls")] -#[cfg_attr(docsrs, doc(cfg(feature = "tls-rustls")))] -pub mod tls_rustls; - -#[doc(inline)] -#[cfg(feature = "tls-rustls")] -pub use self::tls_rustls::export::{bind_rustls, from_tcp_rustls}; diff --git a/xks-axum/axum-server/src/notify_once.rs b/xks-axum/axum-server/src/notify_once.rs deleted file mode 100644 index 452906e..0000000 --- a/xks-axum/axum-server/src/notify_once.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; -use tokio::sync::Notify; - -#[derive(Debug, Default)] -pub(crate) struct NotifyOnce { - notified: AtomicBool, - notify: Notify, -} - -impl NotifyOnce { - pub(crate) fn notify_waiters(&self) { - self.notified.store(true, Ordering::SeqCst); - - self.notify.notify_waiters(); - } - - pub(crate) fn is_notified(&self) -> bool { - self.notified.load(Ordering::SeqCst) - } - - pub(crate) async fn notified(&self) { - let future = self.notify.notified(); - - if !self.notified.load(Ordering::SeqCst) { - future.await; - } - } -} diff --git a/xks-axum/axum-server/src/server.rs b/xks-axum/axum-server/src/server.rs deleted file mode 100644 index dc4da0a..0000000 --- a/xks-axum/axum-server/src/server.rs +++ /dev/null @@ -1,407 +0,0 @@ -use crate::{ - accept::{Accept, DefaultAcceptor}, - addr_incoming_config::AddrIncomingConfig, - handle::Handle, - http_config::HttpConfig, - service::{MakeServiceRef, SendService}, -}; -use futures_util::future::poll_fn; -use http::Request; -use hyper::server::{ - accept::Accept as HyperAccept, - conn::{AddrIncoming, AddrStream}, -}; -use std::{ - io::{self, ErrorKind}, - net::SocketAddr, - pin::Pin, -}; -use tokio::{ - io::{AsyncRead, AsyncWrite}, - net::TcpListener, -}; - -/// HTTP server. -#[derive(Debug)] -pub struct Server { - acceptor: A, - listener: Listener, - addr_incoming_conf: AddrIncomingConfig, - handle: Handle, - http_conf: HttpConfig, -} - -#[derive(Debug)] -enum Listener { - Bind(SocketAddr), - Std(std::net::TcpListener), -} - -/// Create a [`Server`] that will bind to provided address. -pub fn bind(addr: SocketAddr) -> Server { - Server::bind(addr) -} - -/// Create a [`Server`] from existing `std::net::TcpListener`. -pub fn from_tcp(listener: std::net::TcpListener) -> Server { - Server::from_tcp(listener) -} - -impl Server { - /// Create a server that will bind to provided address. - pub fn bind(addr: SocketAddr) -> Self { - let acceptor = DefaultAcceptor::new(); - let handle = Handle::new(); - - Self { - acceptor, - listener: Listener::Bind(addr), - addr_incoming_conf: AddrIncomingConfig::default(), - handle, - http_conf: HttpConfig::default(), - } - } - - /// Create a server from existing `std::net::TcpListener`. - pub fn from_tcp(listener: std::net::TcpListener) -> Self { - let acceptor = DefaultAcceptor::new(); - let handle = Handle::new(); - - Self { - acceptor, - listener: Listener::Std(listener), - addr_incoming_conf: AddrIncomingConfig::default(), - handle, - http_conf: HttpConfig::default(), - } - } -} - -impl Server { - /// Overwrite acceptor. - pub fn acceptor(self, acceptor: Acceptor) -> Server { - Server { - acceptor, - listener: self.listener, - addr_incoming_conf: self.addr_incoming_conf, - handle: self.handle, - http_conf: self.http_conf, - } - } - - /// Map acceptor. - pub fn map(self, acceptor: F) -> Server - where - F: FnOnce(A) -> Acceptor, - { - Server { - acceptor: acceptor(self.acceptor), - listener: self.listener, - addr_incoming_conf: self.addr_incoming_conf, - handle: self.handle, - http_conf: self.http_conf, - } - } - - /// Returns a reference to the acceptor. - pub fn get_ref(&self) -> &A { - &self.acceptor - } - - /// Returns a mutable reference to the acceptor. - pub fn get_mut(&mut self) -> &mut A { - &mut self.acceptor - } - - /// Provide a handle for additional utilities. - pub fn handle(mut self, handle: Handle) -> Self { - self.handle = handle; - self - } - - /// Overwrite http configuration. - pub fn http_config(mut self, config: HttpConfig) -> Self { - self.http_conf = config; - self - } - - /// Overwrite addr incoming configuration. - pub fn addr_incoming_config(mut self, config: AddrIncomingConfig) -> Self { - self.addr_incoming_conf = config; - self - } - - /// Serve provided [`MakeService`]. - /// - /// To create [`MakeService`] easily, `Shared` from [`tower`] can be used. - /// - /// # Errors - /// - /// An error will be returned when: - /// - /// - Binding to an address fails. - /// - `make_service` returns an error when `poll_ready` is called. This never happens on - /// [`axum`] make services. - /// - /// [`axum`]: https://docs.rs/axum/0.3 - /// [`tower`]: https://docs.rs/tower - /// [`MakeService`]: https://docs.rs/tower/0.4/tower/make/trait.MakeService.html - pub async fn serve(self, mut make_service: M) -> io::Result<()> - where - M: MakeServiceRef>, - A: Accept + Clone + Send + Sync + 'static, - A::Stream: AsyncRead + AsyncWrite + Unpin + Send, - A::Service: SendService> + Send, - A::Future: Send, - { - let acceptor = self.acceptor; - let addr_incoming_conf = self.addr_incoming_conf; - let handle = self.handle; - let http_conf = self.http_conf; - - let mut incoming = match bind_incoming(self.listener, addr_incoming_conf).await { - Ok(v) => v, - Err(e) => { - handle.notify_listening(None); - return Err(e); - } - }; - - handle.notify_listening(Some(incoming.local_addr())); - - let accept_loop_future = async { - loop { - let addr_stream = tokio::select! { - biased; - result = accept(&mut incoming) => result?, - _ = handle.wait_graceful_shutdown() => return Ok(()), - }; - - poll_fn(|cx| make_service.poll_ready(cx)) - .await - .map_err(io_other)?; - - let service = match make_service.make_service(&addr_stream).await { - Ok(service) => service, - Err(_) => continue, - }; - - let acceptor = acceptor.clone(); - let watcher = handle.watcher(); - let http_conf = http_conf.clone(); - - tokio::spawn(async move { - if let Ok((stream, send_service)) = acceptor.accept(addr_stream, service).await - { - let service = send_service.into_service(); - - let serve_future = http_conf - .inner - .serve_connection(stream, service) - .with_upgrades(); - - tokio::select! { - biased; - _ = watcher.wait_shutdown() => (), - _ = serve_future => (), - } - } - }); - } - }; - - let result = tokio::select! { - biased; - _ = handle.wait_shutdown() => return Ok(()), - result = accept_loop_future => result, - }; - - if let Err(e) = result { - return Err(e); - } - - handle.wait_connections_end().await; - - Ok(()) - } -} - -async fn bind_incoming( - listener: Listener, - addr_incoming_conf: AddrIncomingConfig, -) -> io::Result { - let listener = match listener { - Listener::Bind(addr) => TcpListener::bind(addr).await?, - Listener::Std(std_listener) => { - std_listener.set_nonblocking(true)?; - TcpListener::from_std(std_listener)? - } - }; - let mut incoming = AddrIncoming::from_listener(listener).map_err(io_other)?; - - incoming.set_sleep_on_errors(addr_incoming_conf.tcp_sleep_on_accept_errors); - incoming.set_keepalive(addr_incoming_conf.tcp_keepalive); - incoming.set_keepalive_interval(addr_incoming_conf.tcp_keepalive_interval); - incoming.set_keepalive_retries(addr_incoming_conf.tcp_keepalive_retries); - incoming.set_nodelay(addr_incoming_conf.tcp_nodelay); - - Ok(incoming) -} - -pub(crate) async fn accept(incoming: &mut AddrIncoming) -> io::Result { - let mut incoming = Pin::new(incoming); - - // Always [`Option::Some`]. - // https://docs.rs/hyper/0.14.14/src/hyper/server/tcp.rs.html#165 - poll_fn(|cx| incoming.as_mut().poll_accept(cx)) - .await - .unwrap() -} - -type BoxError = Box; - -pub(crate) fn io_other>(error: E) -> io::Error { - io::Error::new(ErrorKind::Other, error) -} - -#[cfg(test)] -mod tests { - use crate::{handle::Handle, server::Server}; - use axum::{routing::get, Router}; - use bytes::Bytes; - use http::{response, Request}; - use hyper::{ - client::conn::{handshake, SendRequest}, - Body, - }; - use std::{io, net::SocketAddr, time::Duration}; - use tokio::{net::TcpStream, task::JoinHandle, time::timeout}; - use tower::{Service, ServiceExt}; - - #[tokio::test] - async fn start_and_request() { - let (_handle, _server_task, addr) = start_server().await; - - let (mut client, _conn) = connect(addr).await; - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - } - - #[tokio::test] - async fn test_shutdown() { - let (handle, _server_task, addr) = start_server().await; - - let (mut client, conn) = connect(addr).await; - - handle.shutdown(); - - let response_future_result = client - .ready() - .await - .unwrap() - .call(Request::new(Body::empty())) - .await; - - assert!(response_future_result.is_err()); - - // Connection task should finish soon. - let _ = timeout(Duration::from_secs(1), conn).await.unwrap(); - } - - #[tokio::test] - async fn test_graceful_shutdown() { - let (handle, server_task, addr) = start_server().await; - - let (mut client, conn) = connect(addr).await; - - handle.graceful_shutdown(None); - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - - // Disconnect client. - conn.abort(); - - // Server task should finish soon. - let server_result = timeout(Duration::from_secs(1), server_task) - .await - .unwrap() - .unwrap(); - - assert!(server_result.is_ok()); - } - - #[ignore] - #[tokio::test] - async fn test_graceful_shutdown_timed() { - let (handle, server_task, addr) = start_server().await; - - let (mut client, _conn) = connect(addr).await; - - handle.graceful_shutdown(Some(Duration::from_millis(250))); - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - - // Don't disconnect client. - // conn.abort(); - - // Server task should finish soon. - let server_result = timeout(Duration::from_secs(1), server_task) - .await - .unwrap() - .unwrap(); - - assert!(server_result.is_ok()); - } - - async fn start_server() -> (Handle, JoinHandle>, SocketAddr) { - let handle = Handle::new(); - - let server_handle = handle.clone(); - let server_task = tokio::spawn(async move { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let addr = SocketAddr::from(([127, 0, 0, 1], 0)); - - Server::bind(addr) - .handle(server_handle) - .serve(app.into_make_service()) - .await - }); - - let addr = handle.listening().await.unwrap(); - - (handle, server_task, addr) - } - - async fn connect(addr: SocketAddr) -> (SendRequest, JoinHandle<()>) { - let stream = TcpStream::connect(addr).await.unwrap(); - - let (send_request, connection) = handshake(stream).await.unwrap(); - - let task = tokio::spawn(async move { - let _ = connection.await; - }); - - (send_request, task) - } - - async fn send_empty_request(client: &mut SendRequest) -> (response::Parts, Bytes) { - let (parts, body) = client - .ready() - .await - .unwrap() - .call(Request::new(Body::empty())) - .await - .unwrap() - .into_parts(); - let body = hyper::body::to_bytes(body).await.unwrap(); - - (parts, body) - } -} diff --git a/xks-axum/axum-server/src/service.rs b/xks-axum/axum-server/src/service.rs deleted file mode 100644 index e2f335f..0000000 --- a/xks-axum/axum-server/src/service.rs +++ /dev/null @@ -1,156 +0,0 @@ -//! Service traits. - -use http::Response; -use http_body::Body; -use std::{ - future::Future, - task::{Context, Poll}, -}; -use tower_service::Service; - -/// Trait alias for [`Service`] with bounds required for [`serve`](crate::server::Server::serve). -/// -/// This trait is sealed and cannot be implemented for types outside this crate. -#[allow(missing_docs)] -pub trait SendService: send_service::Sealed { - type Service: Service< - Request, - Response = Response, - Error = Self::Error, - Future = Self::Future, - > + Send - + 'static; - - type Body: Body + Send + 'static; - type BodyData: Send + 'static; - type BodyError: Into>; - - type Error: Into>; - - type Future: Future, Self::Error>> + Send + 'static; - - fn into_service(self) -> Self::Service; -} - -impl send_service::Sealed for T -where - T: Service>, - T::Error: Into>, - T::Future: Send + 'static, - B: Body + Send + 'static, - B::Data: Send + 'static, - B::Error: Into>, -{ -} - -impl SendService for T -where - T: Service> + Send + 'static, - T::Error: Into>, - T::Future: Send + 'static, - B: Body + Send + 'static, - B::Data: Send + 'static, - B::Error: Into>, -{ - type Service = T; - - type Body = B; - type BodyData = B::Data; - type BodyError = B::Error; - - type Error = T::Error; - - type Future = T::Future; - - fn into_service(self) -> Self::Service { - self - } -} - -/// Modified version of [`MakeService`] that takes a `&Target` and has required trait bounds for -/// [`serve`](crate::server::Server::serve). -/// -/// This trait is sealed and cannot be implemented for types outside this crate. -/// -/// [`MakeService`]: https://docs.rs/tower/0.4/tower/make/trait.MakeService.html -#[allow(missing_docs)] -pub trait MakeServiceRef: make_service_ref::Sealed<(Target, Request)> { - type Service: Service< - Request, - Response = Response, - Error = Self::Error, - Future = Self::Future, - > + Send - + 'static; - - type Body: Body + Send + 'static; - type BodyData: Send + 'static; - type BodyError: Into>; - - type Error: Into>; - - type Future: Future, Self::Error>> + Send + 'static; - - type MakeError: Into>; - type MakeFuture: Future>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll>; - - fn make_service(&mut self, target: &Target) -> Self::MakeFuture; -} - -impl make_service_ref::Sealed<(Target, Request)> for T -where - T: for<'a> Service<&'a Target, Response = S, Error = E, Future = F>, - S: Service> + Send + 'static, - S::Error: Into>, - S::Future: Send + 'static, - B: Body + Send + 'static, - B::Data: Send + 'static, - B::Error: Into>, - E: Into>, - F: Future>, -{ -} - -impl MakeServiceRef for T -where - T: for<'a> Service<&'a Target, Response = S, Error = E, Future = F>, - S: Service> + Send + 'static, - S::Error: Into>, - S::Future: Send + 'static, - B: Body + Send + 'static, - B::Data: Send + 'static, - B::Error: Into>, - E: Into>, - F: Future>, -{ - type Service = S; - - type Body = B; - type BodyData = B::Data; - type BodyError = B::Error; - - type Error = S::Error; - - type Future = S::Future; - - type MakeError = E; - type MakeFuture = F; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.poll_ready(cx) - } - - fn make_service(&mut self, target: &Target) -> Self::MakeFuture { - self.call(target) - } -} - -mod send_service { - pub trait Sealed {} -} - -mod make_service_ref { - pub trait Sealed {} -} diff --git a/xks-axum/axum-server/src/tls_rustls/future.rs b/xks-axum/axum-server/src/tls_rustls/future.rs deleted file mode 100644 index 5b7594b..0000000 --- a/xks-axum/axum-server/src/tls_rustls/future.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! Future types. - -use crate::tls_rustls::RustlsConfig; -use pin_project_lite::pin_project; -use std::io::{Error, ErrorKind}; -use std::time::Duration; -use std::{ - fmt, - future::Future, - io, - pin::Pin, - task::{Context, Poll}, -}; -use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::time::{timeout, Timeout}; -use tokio_rustls::{server::TlsStream, Accept, TlsAcceptor}; - -pin_project! { - /// Future type for [`RustlsAcceptor`](crate::tls_rustls::RustlsAcceptor). - pub struct RustlsAcceptorFuture { - #[pin] - inner: AcceptFuture, - config: Option, - } -} - -impl RustlsAcceptorFuture { - pub(crate) fn new(future: F, config: RustlsConfig, handshake_timeout: Duration) -> Self { - let inner = AcceptFuture::Inner { - future, - handshake_timeout, - }; - let config = Some(config); - - Self { inner, config } - } -} - -impl fmt::Debug for RustlsAcceptorFuture { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RustlsAcceptorFuture").finish() - } -} - -pin_project! { - #[project = AcceptFutureProj] - enum AcceptFuture { - Inner { - #[pin] - future: F, - handshake_timeout: Duration, - }, - Accept { - #[pin] - future: Timeout>, - service: Option, - }, - } -} - -impl Future for RustlsAcceptorFuture -where - F: Future>, - I: AsyncRead + AsyncWrite + Unpin, -{ - type Output = io::Result<(TlsStream, S)>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut this = self.project(); - - loop { - match this.inner.as_mut().project() { - AcceptFutureProj::Inner { - future, - handshake_timeout, - } => { - match future.poll(cx) { - Poll::Ready(Ok((stream, service))) => { - let server_config = this.config - .take() - .expect("config is not set. this is a bug in axum-server, please report") - .get_inner(); - - let acceptor = TlsAcceptor::from(server_config); - let future = acceptor.accept(stream); - - let service = Some(service); - let handshake_timeout = *handshake_timeout; - - this.inner.set(AcceptFuture::Accept { - future: timeout(handshake_timeout, future), - service, - }); - } - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - Poll::Pending => return Poll::Pending, - } - } - AcceptFutureProj::Accept { future, service } => match future.poll(cx) { - Poll::Ready(Ok(Ok(stream))) => { - let service = service.take().expect("future polled after ready"); - - return Poll::Ready(Ok((stream, service))); - } - Poll::Ready(Ok(Err(e))) => return Poll::Ready(Err(e)), - Poll::Ready(Err(timeout)) => { - return Poll::Ready(Err(Error::new(ErrorKind::TimedOut, timeout))) - } - Poll::Pending => return Poll::Pending, - }, - } - } - } -} diff --git a/xks-axum/axum-server/src/tls_rustls/mod.rs b/xks-axum/axum-server/src/tls_rustls/mod.rs deleted file mode 100644 index 898588e..0000000 --- a/xks-axum/axum-server/src/tls_rustls/mod.rs +++ /dev/null @@ -1,578 +0,0 @@ -//! Tls implementation using [`rustls`]. -//! -//! # Example -//! -//! ```rust,no_run -//! use axum::{routing::get, Router}; -//! use axum_server::tls_rustls::RustlsConfig; -//! use std::net::SocketAddr; -//! -//! #[tokio::main] -//! async fn main() { -//! let app = Router::new().route("/", get(|| async { "Hello, world!" })); -//! -//! let config = RustlsConfig::from_pem_file( -//! "examples/self-signed-certs/cert.pem", -//! "examples/self-signed-certs/key.pem", -//! ) -//! .await -//! .unwrap(); -//! -//! let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); -//! println!("listening on {}", addr); -//! axum_server::bind_rustls(addr, config) -//! .serve(app.into_make_service()) -//! .await -//! .unwrap(); -//! } -//! ``` - -use self::future::RustlsAcceptorFuture; -use crate::{ - accept::{Accept, DefaultAcceptor}, - server::{io_other, Server}, -}; -use arc_swap::ArcSwap; -use rustls::{Certificate, PrivateKey, ServerConfig}; -use std::time::Duration; -use std::{fmt, io, net::SocketAddr, path::Path, sync::Arc}; -use tokio::{ - io::{AsyncRead, AsyncWrite}, - task::spawn_blocking, -}; -use tokio_rustls::server::TlsStream; - -pub(crate) mod export { - use super::*; - - /// Create a tls server that will bind to provided address. - #[cfg_attr(docsrs, doc(cfg(feature = "tls-rustls")))] - pub fn bind_rustls(addr: SocketAddr, config: RustlsConfig) -> Server { - super::bind_rustls(addr, config) - } - - /// Create a tls server from existing `std::net::TcpListener`. - #[cfg_attr(docsrs, doc(cfg(feature = "tls-rustls")))] - pub fn from_tcp_rustls( - listener: std::net::TcpListener, - config: RustlsConfig, - ) -> Server { - let acceptor = RustlsAcceptor::new(config); - - Server::from_tcp(listener).acceptor(acceptor) - } -} - -pub mod future; - -/// Create a tls server that will bind to provided address. -pub fn bind_rustls(addr: SocketAddr, config: RustlsConfig) -> Server { - let acceptor = RustlsAcceptor::new(config); - - Server::bind(addr).acceptor(acceptor) -} - -/// Create a tls server from existing `std::net::TcpListener`. -pub fn from_tcp_rustls( - listener: std::net::TcpListener, - config: RustlsConfig, -) -> Server { - let acceptor = RustlsAcceptor::new(config); - - Server::from_tcp(listener).acceptor(acceptor) -} - -/// Tls acceptor using rustls. -#[derive(Clone)] -pub struct RustlsAcceptor { - inner: A, - config: RustlsConfig, - handshake_timeout: Duration, -} - -impl RustlsAcceptor { - /// Create a new rustls acceptor. - pub fn new(config: RustlsConfig) -> Self { - let inner = DefaultAcceptor::new(); - - #[cfg(not(test))] - let handshake_timeout = Duration::from_secs(10); - - // Don't force tests to wait too long. - #[cfg(test)] - let handshake_timeout = Duration::from_secs(1); - - Self { - inner, - config, - handshake_timeout, - } - } - - /// Override the default TLS handshake timeout of 10 seconds, except during testing. - pub fn handshake_timeout(mut self, val: Duration) -> Self { - self.handshake_timeout = val; - self - } -} - -impl RustlsAcceptor { - /// Overwrite inner acceptor. - pub fn acceptor(self, acceptor: Acceptor) -> RustlsAcceptor { - RustlsAcceptor { - inner: acceptor, - config: self.config, - handshake_timeout: self.handshake_timeout, - } - } -} - -impl Accept for RustlsAcceptor -where - A: Accept, - A::Stream: AsyncRead + AsyncWrite + Unpin, -{ - type Stream = TlsStream; - type Service = A::Service; - type Future = RustlsAcceptorFuture; - - fn accept(&self, stream: I, service: S) -> Self::Future { - let inner_future = self.inner.accept(stream, service); - let config = self.config.clone(); - - RustlsAcceptorFuture::new(inner_future, config, self.handshake_timeout) - } -} - -impl fmt::Debug for RustlsAcceptor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RustlsAcceptor").finish() - } -} - -/// Rustls configuration. -#[derive(Clone)] -pub struct RustlsConfig { - inner: Arc>, -} - -impl RustlsConfig { - /// Create config from `Arc<`[`ServerConfig`]`>`. - pub fn from_config(config: Arc) -> Self { - let inner = Arc::new(ArcSwap::new(config)); - - Self { inner } - } - - /// Create config from DER-encoded data. - /// - /// The certificate must be DER-encoded X.509. - /// - /// The private key must be DER-encoded ASN.1 in either PKCS#8 or PKCS#1 format. - pub async fn from_der(cert: Vec>, key: Vec) -> io::Result { - let server_config = spawn_blocking(|| config_from_der(cert, key)) - .await - .unwrap()?; - let inner = Arc::new(ArcSwap::from_pointee(server_config)); - - Ok(Self { inner }) - } - - /// Create config from PEM formatted data. - /// - /// Certificate and private key must be in PEM format. - pub async fn from_pem(cert: Vec, key: Vec) -> io::Result { - let server_config = spawn_blocking(|| config_from_pem(cert, key)) - .await - .unwrap()?; - let inner = Arc::new(ArcSwap::from_pointee(server_config)); - - Ok(Self { inner }) - } - - /// Create config from PEM formatted files. - /// - /// Contents of certificate file and private key file must be in PEM format. - pub async fn from_pem_file(cert: impl AsRef, key: impl AsRef) -> io::Result { - let server_config = config_from_pem_file(cert, key).await?; - let inner = Arc::new(ArcSwap::from_pointee(server_config)); - - Ok(Self { inner }) - } - - /// Get inner `Arc<`[`ServerConfig`]`>`. - pub fn get_inner(&self) -> Arc { - self.inner.load_full() - } - - /// Reload config from `Arc<`[`ServerConfig`]`>`. - pub fn reload_from_config(&self, config: Arc) { - self.inner.store(config); - } - - /// Reload config from DER-encoded data. - /// - /// The certificate must be DER-encoded X.509. - /// - /// The private key must be DER-encoded ASN.1 in either PKCS#8 or PKCS#1 format. - pub async fn reload_from_der(&self, cert: Vec>, key: Vec) -> io::Result<()> { - let server_config = spawn_blocking(|| config_from_der(cert, key)) - .await - .unwrap()?; - let inner = Arc::new(server_config); - - self.inner.store(inner); - - Ok(()) - } - - /// Reload config from PEM formatted data. - /// - /// Certificate and private key must be in PEM format. - pub async fn reload_from_pem(&self, cert: Vec, key: Vec) -> io::Result<()> { - let server_config = spawn_blocking(|| config_from_pem(cert, key)) - .await - .unwrap()?; - let inner = Arc::new(server_config); - - self.inner.store(inner); - - Ok(()) - } - - /// Reload config from PEM formatted files. - /// - /// Contents of certificate file and private key file must be in PEM format. - pub async fn reload_from_pem_file( - &self, - cert: impl AsRef, - key: impl AsRef, - ) -> io::Result<()> { - let server_config = config_from_pem_file(cert, key).await?; - let inner = Arc::new(server_config); - - self.inner.store(inner); - - Ok(()) - } -} - -impl fmt::Debug for RustlsConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RustlsConfig").finish() - } -} - -fn config_from_der(cert: Vec>, key: Vec) -> io::Result { - let cert = cert.into_iter().map(Certificate).collect(); - let key = PrivateKey(key); - - let mut config = ServerConfig::builder() - .with_safe_defaults() - .with_no_client_auth() - .with_single_cert(cert, key) - .map_err(io_other)?; - - config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - - Ok(config) -} - -fn config_from_pem(cert: Vec, key: Vec) -> io::Result { - use rustls_pemfile::Item; - - let cert = rustls_pemfile::certs(&mut cert.as_ref())?; - let key = match rustls_pemfile::read_one(&mut key.as_ref())? { - Some(Item::RSAKey(key)) | Some(Item::PKCS8Key(key)) | Some(Item::ECKey(key)) => key, - _ => return Err(io_other("private key format not supported")), - }; - - config_from_der(cert, key) -} - -async fn config_from_pem_file( - cert: impl AsRef, - key: impl AsRef, -) -> io::Result { - let cert = tokio::fs::read(cert.as_ref()).await?; - let key = tokio::fs::read(key.as_ref()).await?; - - config_from_pem(cert, key) -} - -#[cfg(test)] -mod tests { - use crate::{ - handle::Handle, - tls_rustls::{self, RustlsConfig}, - }; - use axum::{routing::get, Router}; - use bytes::Bytes; - use http::{response, Request}; - use hyper::{ - client::conn::{handshake, SendRequest}, - Body, - }; - use rustls::{ - client::{ServerCertVerified, ServerCertVerifier}, - Certificate, ClientConfig, ServerName, - }; - use std::{ - convert::TryFrom, - io, - net::SocketAddr, - sync::Arc, - time::{Duration, SystemTime}, - }; - use tokio::time::sleep; - use tokio::{net::TcpStream, task::JoinHandle, time::timeout}; - use tokio_rustls::TlsConnector; - use tower::{Service, ServiceExt}; - - #[tokio::test] - async fn start_and_request() { - let (_handle, _server_task, addr) = start_server().await; - - let (mut client, _conn) = connect(addr).await; - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - } - - #[ignore] - #[tokio::test] - async fn tls_timeout() { - let (handle, _server_task, addr) = start_server().await; - assert_eq!(handle.connection_count(), 0); - - // We intentionally avoid driving a TLS handshake to completion. - let _stream = TcpStream::connect(addr).await.unwrap(); - - sleep(Duration::from_millis(500)).await; - assert_eq!(handle.connection_count(), 1); - - tokio::time::sleep(Duration::from_millis(1000)).await; - // Timeout defaults to 1s during testing, and we have waited 1.5 seconds. - assert_eq!(handle.connection_count(), 0); - } - - #[tokio::test] - async fn test_reload() { - let handle = Handle::new(); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - let server_handle = handle.clone(); - let rustls_config = config.clone(); - tokio::spawn(async move { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let addr = SocketAddr::from(([127, 0, 0, 1], 0)); - - tls_rustls::bind_rustls(addr, rustls_config) - .handle(server_handle) - .serve(app.into_make_service()) - .await - }); - - let addr = handle.listening().await.unwrap(); - - let cert_a = get_first_cert(addr).await; - let mut cert_b = get_first_cert(addr).await; - - assert_eq!(cert_a, cert_b); - - config - .reload_from_pem_file( - "examples/self-signed-certs/reload/cert.pem", - "examples/self-signed-certs/reload/key.pem", - ) - .await - .unwrap(); - - cert_b = get_first_cert(addr).await; - - assert_ne!(cert_a, cert_b); - - config - .reload_from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await - .unwrap(); - - cert_b = get_first_cert(addr).await; - - assert_eq!(cert_a, cert_b); - } - - #[tokio::test] - async fn test_shutdown() { - let (handle, _server_task, addr) = start_server().await; - - let (mut client, conn) = connect(addr).await; - - handle.shutdown(); - - let response_future_result = client - .ready() - .await - .unwrap() - .call(Request::new(Body::empty())) - .await; - - assert!(response_future_result.is_err()); - - // Connection task should finish soon. - let _ = timeout(Duration::from_secs(1), conn).await.unwrap(); - } - - #[tokio::test] - async fn test_graceful_shutdown() { - let (handle, server_task, addr) = start_server().await; - - let (mut client, conn) = connect(addr).await; - - handle.graceful_shutdown(None); - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - - // Disconnect client. - conn.abort(); - - // Server task should finish soon. - let server_result = timeout(Duration::from_secs(1), server_task) - .await - .unwrap() - .unwrap(); - - assert!(server_result.is_ok()); - } - - #[ignore] - #[tokio::test] - async fn test_graceful_shutdown_timed() { - let (handle, server_task, addr) = start_server().await; - - let (mut client, _conn) = connect(addr).await; - - handle.graceful_shutdown(Some(Duration::from_millis(250))); - - let (_parts, body) = send_empty_request(&mut client).await; - - assert_eq!(body.as_ref(), b"Hello, world!"); - - // Don't disconnect client. - // conn.abort(); - - // Server task should finish soon. - let server_result = timeout(Duration::from_secs(1), server_task) - .await - .unwrap() - .unwrap(); - - assert!(server_result.is_ok()); - } - - async fn start_server() -> (Handle, JoinHandle>, SocketAddr) { - let handle = Handle::new(); - - let server_handle = handle.clone(); - let server_task = tokio::spawn(async move { - let app = Router::new().route("/", get(|| async { "Hello, world!" })); - - let config = RustlsConfig::from_pem_file( - "examples/self-signed-certs/cert.pem", - "examples/self-signed-certs/key.pem", - ) - .await?; - - let addr = SocketAddr::from(([127, 0, 0, 1], 0)); - - tls_rustls::bind_rustls(addr, config) - .handle(server_handle) - .serve(app.into_make_service()) - .await - }); - - let addr = handle.listening().await.unwrap(); - - (handle, server_task, addr) - } - - async fn get_first_cert(addr: SocketAddr) -> Certificate { - let stream = TcpStream::connect(addr).await.unwrap(); - let tls_stream = tls_connector().connect(dns_name(), stream).await.unwrap(); - - let (_io, client_connection) = tls_stream.into_inner(); - - client_connection.peer_certificates().unwrap()[0].clone() - } - - async fn connect(addr: SocketAddr) -> (SendRequest, JoinHandle<()>) { - let stream = TcpStream::connect(addr).await.unwrap(); - let tls_stream = tls_connector().connect(dns_name(), stream).await.unwrap(); - - let (send_request, connection) = handshake(tls_stream).await.unwrap(); - - let task = tokio::spawn(async move { - let _ = connection.await; - }); - - (send_request, task) - } - - async fn send_empty_request(client: &mut SendRequest) -> (response::Parts, Bytes) { - let (parts, body) = client - .ready() - .await - .unwrap() - .call(Request::new(Body::empty())) - .await - .unwrap() - .into_parts(); - let body = hyper::body::to_bytes(body).await.unwrap(); - - (parts, body) - } - - fn tls_connector() -> TlsConnector { - struct NoVerify; - - impl ServerCertVerifier for NoVerify { - fn verify_server_cert( - &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _server_name: &ServerName, - _scts: &mut dyn Iterator, - _ocsp_response: &[u8], - _now: SystemTime, - ) -> Result { - Ok(ServerCertVerified::assertion()) - } - } - - let mut client_config = ClientConfig::builder() - .with_safe_defaults() - .with_custom_certificate_verifier(Arc::new(NoVerify)) - .with_no_client_auth(); - - client_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; - - TlsConnector::from(Arc::new(client_config)) - } - - fn dns_name() -> ServerName { - ServerName::try_from("localhost").unwrap() - } -}