diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-10 13:11:11 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-10 13:11:11 -0600 |
| commit | 01959b16a21b22b5df5f16569c2a8e8f92beecef (patch) | |
| tree | 32afa5d747c5466345c59ec52161a7cba3d6d755 /vendor/hyper-rustls/examples/server.rs | |
| parent | ff30574117a996df332e23d1fb6f65259b316b5b (diff) | |
chore: vendor dependencies
Diffstat (limited to 'vendor/hyper-rustls/examples/server.rs')
| -rw-r--r-- | vendor/hyper-rustls/examples/server.rs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/vendor/hyper-rustls/examples/server.rs b/vendor/hyper-rustls/examples/server.rs new file mode 100644 index 00000000..8f7803fa --- /dev/null +++ b/vendor/hyper-rustls/examples/server.rs @@ -0,0 +1,138 @@ +//! Simple HTTPS echo service based on hyper_util and rustls +//! +//! First parameter is the mandatory port to use. +//! Certificate and private key are hardcoded to sample files. +//! hyper will automatically use HTTP/2 if a client starts talking HTTP/2, +//! otherwise HTTP/1.1 will be used. + +use std::net::{Ipv4Addr, SocketAddr}; +use std::sync::Arc; +use std::{env, fs, io}; + +use http::{Method, Request, Response, StatusCode}; +use http_body_util::{BodyExt, Full}; +use hyper::body::{Bytes, Incoming}; +use hyper::service::service_fn; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use hyper_util::server::conn::auto::Builder; +use pki_types::{CertificateDer, PrivateKeyDer}; +use rustls::ServerConfig; +use tokio::net::TcpListener; +use tokio_rustls::TlsAcceptor; + +fn main() { + // Serve an echo service over HTTPS, with proper error handling. + if let Err(e) = run_server() { + eprintln!("FAILED: {}", e); + std::process::exit(1); + } +} + +fn error(err: String) -> io::Error { + io::Error::new(io::ErrorKind::Other, err) +} + +#[tokio::main] +async fn run_server() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { + // Set a process wide default crypto provider. + #[cfg(feature = "ring")] + let _ = rustls::crypto::ring::default_provider().install_default(); + #[cfg(feature = "aws-lc-rs")] + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + + // First parameter is port number (optional, defaults to 1337) + let port = match env::args().nth(1) { + Some(ref p) => p.parse()?, + None => 1337, + }; + let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port); + + // Load public certificate. + let certs = load_certs("examples/sample.pem")?; + // Load private key. + let key = load_private_key("examples/sample.rsa")?; + + println!("Starting to serve on https://{}", addr); + + // Create a TCP listener via tokio. + let incoming = TcpListener::bind(&addr).await?; + + // Build TLS configuration. + let mut server_config = ServerConfig::builder() + .with_no_client_auth() + .with_single_cert(certs, key) + .map_err(|e| error(e.to_string()))?; + server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()]; + let tls_acceptor = TlsAcceptor::from(Arc::new(server_config)); + + let service = service_fn(echo); + + loop { + let (tcp_stream, _remote_addr) = incoming.accept().await?; + + let tls_acceptor = tls_acceptor.clone(); + tokio::spawn(async move { + let tls_stream = match tls_acceptor.accept(tcp_stream).await { + Ok(tls_stream) => tls_stream, + Err(err) => { + eprintln!("failed to perform tls handshake: {err:#}"); + return; + } + }; + if let Err(err) = Builder::new(TokioExecutor::new()) + .serve_connection(TokioIo::new(tls_stream), service) + .await + { + eprintln!("failed to serve connection: {err:#}"); + } + }); + } +} + +// Custom echo service, handling two different routes and a +// catch-all 404 responder. +async fn echo(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> { + let mut response = Response::new(Full::default()); + match (req.method(), req.uri().path()) { + // Help route. + (&Method::GET, "/") => { + *response.body_mut() = Full::from("Try POST /echo\n"); + } + // Echo service route. + (&Method::POST, "/echo") => { + *response.body_mut() = Full::from( + req.into_body() + .collect() + .await? + .to_bytes(), + ); + } + // Catch-all 404. + _ => { + *response.status_mut() = StatusCode::NOT_FOUND; + } + }; + Ok(response) +} + +// Load public certificate from file. +fn load_certs(filename: &str) -> io::Result<Vec<CertificateDer<'static>>> { + // Open certificate file. + let certfile = fs::File::open(filename) + .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?; + let mut reader = io::BufReader::new(certfile); + + // Load and return certificate. + rustls_pemfile::certs(&mut reader).collect() +} + +// Load private key from file. +fn load_private_key(filename: &str) -> io::Result<PrivateKeyDer<'static>> { + // Open keyfile. + let keyfile = fs::File::open(filename) + .map_err(|e| error(format!("failed to open {}: {}", filename, e)))?; + let mut reader = io::BufReader::new(keyfile); + + // Load and return a single private key. + rustls_pemfile::private_key(&mut reader).map(|key| key.unwrap()) +} |
