|
use std::{net::SocketAddr, sync::Arc}; |
|
use std::fs::File; |
|
use std::io::BufReader; |
|
|
|
use hyper::server::conn::http1; |
|
use hyper_util::rt::TokioIo; |
|
use hyper_util::service::TowerToHyperService; |
|
use tokio::net::TcpListener; |
|
use warp::Filter; |
|
|
|
use rustls::ServerConfig; |
|
use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; |
|
use rustls_pemfile::{certs, pkcs8_private_keys}; |
|
use tokio_rustls::TlsAcceptor; |
|
|
|
fn load_tls_config() -> Result<Arc<ServerConfig>, Box<dyn std::error::Error + Send + Sync>> { |
|
// 証明書と鍵ファイルを開く |
|
let cert_file = &mut BufReader::new(File::open("localhost.pem")?); |
|
let key_file = &mut BufReader::new(File::open("localhost-key.pem")?); |
|
|
|
// --- 証明書チェーンを Vec<CertificateDer> に読む --- |
|
let cert_chain: Vec<CertificateDer<'static>> = certs(cert_file) |
|
.collect::<Result<Vec<_>, _>>()?; // ← イテレータを Result<Vec<_>, _> にまとめてから ? する |
|
|
|
// --- 秘密鍵 (PKCS#8) を Vec<PrivatePkcs8KeyDer> に読む --- |
|
let mut keys: Vec<PrivatePkcs8KeyDer<'static>> = pkcs8_private_keys(key_file) |
|
.collect::<Result<Vec<_>, _>>()?; |
|
|
|
if keys.is_empty() { |
|
return Err("private key not found in key.pem".into()); |
|
} |
|
|
|
// rustls が要求する PrivateKeyDer に変換 |
|
let key_der: PrivateKeyDer<'static> = PrivateKeyDer::from(keys.remove(0)); |
|
|
|
// ServerConfig を組み立て |
|
let config = ServerConfig::builder() |
|
.with_no_client_auth() |
|
.with_single_cert(cert_chain, key_der)?; // ← ここに上の型を渡す |
|
|
|
Ok(Arc::new(config)) |
|
} |
|
|
|
#[tokio::main] |
|
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { |
|
// warp のルーティングはそのまま |
|
let routes = warp::any().map(|| "Hello, World!".to_string()); |
|
let tower_svc = warp::service(routes); |
|
let hyper_svc = TowerToHyperService::new(tower_svc); |
|
|
|
// TLS 設定読み込み |
|
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!("HTTPS server listening on https://{addr}"); |
|
|
|
loop { |
|
let (stream, _peer) = listener.accept().await?; |
|
let io = stream; |
|
let svc = hyper_svc.clone(); |
|
let acceptor = tls_acceptor.clone(); |
|
|
|
tokio::spawn(async move { |
|
// ここで TLS ハンドシェイク |
|
let tls_stream = match acceptor.accept(io).await { |
|
Ok(s) => s, |
|
Err(err) => { |
|
eprintln!("TLS accept error: {err}"); |
|
return; |
|
} |
|
}; |
|
|
|
let io = TokioIo::new(tls_stream); |
|
|
|
if let Err(err) = http1::Builder::new() |
|
.serve_connection(io, svc) |
|
.await |
|
{ |
|
eprintln!("error serving connection: {err}"); |
|
} |
|
}); |
|
} |
|
} |