feat(serve_tls): NodeLayAcceptor + serve_tls_with_nodelay (deploy-C §5.4)

axum_server 0.8's Server builder exposes no tcp_nodelay method (verified
in source: src/axum_server/server.rs:32-360). Plan A made TCP_NODELAY
unconditional on the plaintext path; this slice extends parity to the TLS
path via a custom Accept<TcpStream, S> impl that calls set_nodelay(true)
BEFORE the inner RustlsAcceptor runs the TLS handshake. TLS does not undo
the option (kernel persists it on the fd across the bytes the TLS layer
writes); axum-server's own examples/rustls_session.rs documents this
wrapping pattern for a different reason.

serve_tls_with_nodelay is the production TLS serve path: axum_server::bind
+ NodeLayAcceptor + Handle::graceful_shutdown. main.rs switches to it
when RUTSTER_TLS_CERT + RUTSTER_TLS_KEY are both set (Task 4). Hot-reload
via RustlsConfig::reload_from_pem_file lands in Task 4's e2e reload test.

Signed-off-by: Aaron D. Lee <himself@adlee.work>
This commit is contained in:
2026-07-06 01:26:19 -04:00
parent 5d14215053
commit 55065c569d
7 changed files with 472 additions and 0 deletions

View File

@@ -80,6 +80,15 @@ ipnet = "2"
# at 0.23.41 / 0.26.4 — verified). The tls-rustls feature enables
# axum_server::tls_rustls::{RustlsConfig, RustlsAcceptor}. MIT license — cargo-deny-clean.
axum-server = { version = "0.8", features = ["tls-rustls"] }
# rustls 0.23: TLS implementation consumed transitively by axum-server's tls-rustls
# feature. Already in Cargo.lock at 0.23.41 via str0m → aws-lc-rs; this surfaces the
# direct edge for the integration test's ClientConfig. Apache-2.0 / MIT / ISC,
# cargo-deny clean.
rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs", "ring"] }
# tokio-rustls 0.26: tokio integration for rustls. Already in Cargo.lock at 0.26.4
# (transitive once Task 1's Cargo.lock resolves). Used by the serve_tls integration
# test's TLS client handshake.
tokio-rustls = { version = "0.26", default-features = false, features = ["aws-lc-rs", "ring"] }
# rcgen NOTE: rcgen 0.14.8 bumped MSRV to Rust 1.88, breaking the 1.85
# toolchain matrix. rcgen is a transitive dep via dimpl → str0m 0.21 →
# rutster-media. Cargo.lock pins it to 0.14.7 (the minimum satisfying