//! Small TCP and TLS servers for tests, using the TEST-ONLY certificates in `fixtures/tls/`. //! Each serves connections on its own thread with a function of the connection. Do not edit. #![allow(dead_code)] // each test file uses a different part of this module use std::io::{Read, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; use std::path::PathBuf; use std::sync::Arc; use rustls::pki_types::pem::PemObject; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use rustls::{ServerConfig, ServerConnection, StreamOwned}; pub fn fixture(name: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests/fixtures/tls") .join(name) } /// A server certificate (`server`, `wrong-name`, `other-server`) and its key. pub fn server_config(which: &str) -> Arc { let certs: Vec> = CertificateDer::pem_file_iter(fixture(&format!("{which}.pem"))) .unwrap() .collect::>() .unwrap(); let key = PrivateKeyDer::from_pem_file(fixture(&format!("{which}.key"))).unwrap(); let provider = Arc::new(rustls::crypto::ring::default_provider()); let config = ServerConfig::builder_with_provider(provider) .with_safe_default_protocol_versions() .unwrap() .with_no_client_auth() .with_single_cert(certs, key) .unwrap(); Arc::new(config) } /// Anything a test server can serve: plain TCP, or TLS over it. pub trait Conn: Read + Write + Send {} impl Conn for T {} /// Serve every connection on 127.0.0.1 with `handle`, in plain TCP (`tls` None) or TLS. pub fn serve(tls: Option>, handle: F) -> SocketAddr where F: Fn(Box) + Send + Sync + 'static, { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let handle = Arc::new(handle); std::thread::spawn(move || { for stream in listener.incoming() { let Ok(stream) = stream else { continue }; let handle = Arc::clone(&handle); let tls = tls.clone(); std::thread::spawn(move || match tls { None => handle(Box::new(stream)), Some(config) => { let conn = ServerConnection::new(config).unwrap(); let tls_stream: StreamOwned = StreamOwned::new(conn, stream); handle(Box::new(tls_stream)); } }); } }); addr } /// A handler that reads one line and writes it back. pub fn echo_line(mut conn: Box) { let mut line = Vec::new(); let mut byte = [0u8; 1]; while conn.read(&mut byte).map(|n| n == 1).unwrap_or(false) { line.push(byte[0]); if byte[0] == b'\n' { break; } } let _ = conn.write_all(&line); let _ = conn.flush(); }