- Cargo.tmol
- src/main.rs
cargo run を実行します。 ブラウザーや curl でアクセスします。
curl -kv https://localhost:3000
HTTP のバージョンを指定する場合
curl -kv --http1.1 https://localhost:3000
| [package] | |
| name = "warp-project" | |
| version = "0.1.0" | |
| edition = "2021" | |
| [dependencies] | |
| hyper = { version = "1", features = ["full"] } | |
| tokio = { version = "1", features = ["full"] } | |
| hyper-util = { version = "0.1", features = ["full"] } | |
| warp = { version = "0.4", default-features = false } | |
| tokio-rustls = "0.26" | |
| rustls = "0.23" | |
| rustls-pemfile = "2" |
| use std::{fs::File, io::BufReader, net::SocketAddr, sync::Arc}; | |
| use tokio::net::TcpListener; | |
| use tokio_rustls::TlsAcceptor; | |
| use warp::Filter; | |
| use hyper_util::rt::{TokioExecutor, TokioIo}; | |
| use hyper_util::server::conn::auto; | |
| use hyper_util::service::TowerToHyperService; | |
| use rustls::ServerConfig; | |
| use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; | |
| use rustls_pemfile::{certs, pkcs8_private_keys}; | |
| type Error = Box<dyn std::error::Error + Send + Sync>; | |
| fn load_tls_config() -> Result<Arc<ServerConfig>, Error> { | |
| let cert_file = &mut BufReader::new(File::open("localhost.pem")?); | |
| let key_file = &mut BufReader::new(File::open("localhost-key.pem")?); | |
| let cert_chain: Vec<CertificateDer<'static>> = | |
| certs(cert_file).collect::<Result<Vec<_>, _>>()?; | |
| let mut keys: Vec<PrivatePkcs8KeyDer<'static>> = | |
| pkcs8_private_keys(key_file).collect::<Result<Vec<_>, _>>()?; | |
| if keys.is_empty() { | |
| return Err("no private key found in certs/key.pem".into()); | |
| } | |
| let key_der: PrivateKeyDer<'static> = PrivateKeyDer::from(keys.remove(0)); | |
| let mut config = ServerConfig::builder() | |
| .with_no_client_auth() | |
| .with_single_cert(cert_chain, key_der)?; | |
| config.alpn_protocols = vec![ | |
| b"h2".to_vec(), | |
| b"http/1.1".to_vec(), | |
| ]; | |
| Ok(Arc::new(config)) | |
| } | |
| #[tokio::main] | |
| async fn main() -> Result<(), Error> { | |
| // rustls::crypto::aws_lc_rs::default_provider().install_default(); | |
| // ★ Reply を String にする | |
| let routes = warp::path::end().map(|| { | |
| "Hello from warp over TLS (HTTP/1 & HTTP/2 auto)!".to_string() | |
| }); | |
| let warp_service = warp::service(routes); | |
| let hyper_service = TowerToHyperService::new(warp_service); | |
| let tls_config = load_tls_config()?; | |
| let tls_acceptor = TlsAcceptor::from(tls_config); | |
| let addr: SocketAddr = ([127, 0, 0, 1], 3000).into(); | |
| let listener = TcpListener::bind(addr).await?; | |
| println!("Listening on https://{addr} (HTTP/1 & HTTP/2 via ALPN)"); | |
| loop { | |
| let (tcp_stream, peer_addr) = listener.accept().await?; | |
| let svc = hyper_service.clone(); | |
| let acceptor = tls_acceptor.clone(); | |
| tokio::spawn(async move { | |
| println!("accepted connection from {peer_addr}"); | |
| let tls_stream = match acceptor.accept(tcp_stream).await { | |
| Ok(s) => s, | |
| Err(e) => { | |
| eprintln!("TLS accept error: {e}"); | |
| return; | |
| } | |
| }; | |
| let io = TokioIo::new(tls_stream); | |
| if let Err(err) = auto::Builder::new(TokioExecutor::new()) | |
| .serve_connection(io, svc) | |
| .await | |
| { | |
| eprintln!("server connection error: {err}"); | |
| } | |
| }); | |
| } | |
| } |