#![cfg(all(feature = "tls", feature = "server", feature = "client"))]
use oxihttp::Router;
use oxihttp::Server;
use oxihttp_server::TlsConfig;
use oxitls::rcgen_bridge::{generate_self_signed_ed25519, CertifiedKey};
use std::fs;
fn make_localhost_cert() -> CertifiedKey {
generate_self_signed_ed25519(&["localhost"]).expect("cert gen")
}
#[tokio::test]
async fn test_client_key_log_file_written() {
let ck = make_localhost_cert();
let tls_cfg = TlsConfig::from_pem(ck.cert_pem.as_bytes(), ck.key_pem().as_bytes())
.expect("server TlsConfig");
let router = Router::new().get("/ping", |_req| async {
oxihttp::response::text_response("pong")
});
let (addr, server_handle) = Server::bind("127.0.0.1:0")
.with_tls(tls_cfg)
.serve_with_addr(router)
.await
.expect("server bind");
let key_log_path = std::env::temp_dir().join(format!(
"oxihttp_client_keylog_{}.log",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.subsec_nanos())
.unwrap_or(0)
));
let _ = fs::remove_file(&key_log_path);
let client = oxihttp::Client::builder()
.with_trusted_cert_der(ck.cert_der.clone())
.with_key_log_file(key_log_path.clone())
.build_https()
.expect("build_https");
let url = format!("https://localhost:{}/ping", addr.port());
let resp = client.get(&url).expect("GET").send().await.expect("send");
assert_eq!(resp.status(), oxihttp::StatusCode::OK);
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
let contents = fs::read_to_string(&key_log_path)
.expect("key-log file should have been created by the TLS handshake");
let has_tls13_labels = contents.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET")
|| contents.contains("CLIENT_TRAFFIC_SECRET_0");
let has_tls12_label = contents.contains("CLIENT_RANDOM");
assert!(
has_tls13_labels || has_tls12_label,
"key-log file should contain NSS key-log entries (CLIENT_HANDSHAKE_TRAFFIC_SECRET \
or CLIENT_RANDOM), got:\n{contents}"
);
for line in contents.lines().filter(|l| !l.is_empty()) {
let parts: Vec<&str> = line.split_whitespace().collect();
assert_eq!(
parts.len(),
3,
"expected 3 whitespace-separated fields per key-log line, got: {line:?}"
);
}
let _ = fs::remove_file(&key_log_path);
server_handle.abort();
}
#[tokio::test]
async fn test_server_key_log_file_written() {
let ck = make_localhost_cert();
let key_log_path = std::env::temp_dir().join(format!(
"oxihttp_server_keylog_{}.log",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.subsec_nanos())
.unwrap_or(0)
));
let _ = fs::remove_file(&key_log_path);
let tls_cfg = TlsConfig::from_pem_with_key_log(
ck.cert_pem.as_bytes(),
ck.key_pem().as_bytes(),
key_log_path.clone(),
)
.expect("server TlsConfig with key log");
let router = Router::new().get("/ping", |_req| async {
oxihttp::response::text_response("pong")
});
let (addr, server_handle) = Server::bind("127.0.0.1:0")
.with_tls(tls_cfg)
.serve_with_addr(router)
.await
.expect("server bind");
let client = oxihttp::Client::builder()
.with_trusted_cert_der(ck.cert_der.clone())
.build_https()
.expect("build_https");
let url = format!("https://localhost:{}/ping", addr.port());
let resp = client.get(&url).expect("GET").send().await.expect("send");
assert_eq!(resp.status(), oxihttp::StatusCode::OK);
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
let contents = fs::read_to_string(&key_log_path)
.expect("server key-log file should have been created by the TLS handshake");
let has_tls13_labels = contents.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET")
|| contents.contains("CLIENT_TRAFFIC_SECRET_0");
let has_tls12_label = contents.contains("CLIENT_RANDOM");
assert!(
has_tls13_labels || has_tls12_label,
"server key-log file should contain NSS key-log entries, got:\n{contents}"
);
let _ = fs::remove_file(&key_log_path);
server_handle.abort();
}