use actix_web::dev::ServerHandle;
use awc::{Client, Connector, SendClientRequest, http::header::HeaderValue};
use flate2::read::GzDecoder;
use log::error;
use rustls::{RootCertStore, client::ClientConfig, crypto::ring::default_provider};
use rustls_acme::caches::TestCache;
use rustls_pemfile::certs;
use std::{
error::Error,
fs::{File, read},
io::{BufReader, Cursor, Read},
sync::{
Arc,
mpsc::{Sender, channel},
},
};
use vacuna::{Config, Vacuna, read_config, server_internal};
fn get_host(c: &Client, path: &str) -> SendClientRequest {
c.get(path).insert_header(("Host", "example.com")).send()
}
fn get_host_no_compression(c: &Client, path: &str) -> SendClientRequest {
c.get(path)
.insert_header(("Host", "example.com"))
.insert_header(("Accept-Encoding", "identity"))
.send()
}
fn get_with_host(c: &Client, path: &str, host: &str) -> SendClientRequest {
c.get(path).insert_header(("Host", host)).send()
}
fn get(c: &Client, path: &str) -> SendClientRequest {
c.get(path).send()
}
fn ssl_client(cert_store: RootCertStore) -> Client {
let rls = ClientConfig::builder_with_provider(Arc::new(default_provider()))
.with_safe_default_protocol_versions()
.expect("go safe versions")
.with_root_certificates(cert_store)
.with_no_client_auth();
let connector = Connector::new().rustls_0_23(Arc::new(rls));
Client::builder().connector(connector).finish()
}
#[actix_rt::test]
async fn test_simple() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/simple_site/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9000/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/simple_site/files/index.html").unwrap()
);
let mut result = get_host(&c, "http://127.0.0.1:9000/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/simple_site/files/index.html").unwrap()
);
vacuna.stop().await;
}
fn read_gz(vf: &str) -> Vec<u8> {
let mut expected_output = Vec::new();
GzDecoder::new(File::open(vf).expect("can open the file"))
.read_to_end(&mut expected_output)
.unwrap();
expected_output
}
#[actix_rt::test]
async fn test_simple_pre_compressed() {
let _ = pretty_env_logger::try_init();
let gzh = HeaderValue::from_str("gzip").unwrap();
let vacuna = Vacuna::start_background_from_file("./fixtures/simple_site_pre_compressed/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9009/default/").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&gzh));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/index.html.gz");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host(&c, "http://127.0.0.1:9009/default/index.html").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&gzh));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/index.html.gz");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host(&c, "http://127.0.0.1:9009/default/other.html").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&gzh));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/other.html.gz");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host(&c, "http://127.0.0.1:9009/gzx/").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&gzh));
let expected = read_gz("./fixtures/simple_site_pre_compressed/gzx/index.html.gzx");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host(&c, "http://127.0.0.1:9009/gzx/other.html").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&gzh));
let expected = read_gz("./fixtures/simple_site_pre_compressed/gzx/other.html.gzx");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let identity = HeaderValue::from_str("identity").unwrap();
result = get_host_no_compression(&c, "http://127.0.0.1:9009/default/")
.await
.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&identity));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/index.html.gz");
let current = result.body().await.unwrap().to_vec();
assert_eq!(expected.len(), current.len());
assert_eq!(String::from_utf8(expected), String::from_utf8(current));
let mut result = get_host_no_compression(&c, "http://127.0.0.1:9009/default/index.html")
.await
.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&identity));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/index.html.gz");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host_no_compression(&c, "http://127.0.0.1:9009/default/other.html")
.await
.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&identity));
let expected = read_gz("./fixtures/simple_site_pre_compressed/files/other.html.gz");
let content = result.body().await.unwrap().to_vec();
assert_eq!(String::from_utf8(expected), String::from_utf8(content));
let mut result = get_host_no_compression(&c, "http://127.0.0.1:9009/gzx/").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&identity));
let expected = read_gz("./fixtures/simple_site_pre_compressed/gzx/index.html.gzx");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host_no_compression(&c, "http://127.0.0.1:9009/gzx/other.html")
.await
.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
assert_eq!(result.headers().get("Content-Encoding"), Some(&identity));
let expected = read_gz("./fixtures/simple_site_pre_compressed/gzx/other.html.gzx");
assert_eq!(expected, result.body().await.unwrap().to_vec());
let mut result = get_host(&c, "http://127.0.0.1:9009/list/").await.unwrap();
assert!(result.status().is_success(), "failed status {}", result.status());
let resp = String::from_utf8(result.body().await.unwrap().to_vec()).unwrap();
assert!(resp.contains("other.html"));
assert!(!resp.contains("other.html.gz"), "invalid content:{}", &resp);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_multiple_folder() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/multiple_folder/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9001/first/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(result.headers().get("Access-Control-Allow-Origin"), None);
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/multiple_folder/first/index.html").unwrap()
);
let mut result = get_host(&c, "http://127.0.0.1:9001/second/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.headers().get("Access-Control-Allow-Origin"),
Some(&HeaderValue::from_static("*"))
);
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/multiple_folder/second/index.html").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_header_set() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/header_config/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9010/first/index.html").await.unwrap();
assert!(result.status().is_success(), "Not success status: {}", result.status());
assert_eq!(result.headers().get("Access-Control-Allow-Origin"), None);
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/header_config/first/index.html").unwrap()
);
assert!(result.headers().get("Access-Control-Allow-Origin").is_none());
let mut result = get_host(&c, "http://127.0.0.1:9010/second/index.html").await.unwrap();
assert!(result.status().is_success());
assert!(result.headers().get("Access-Control-Allow-Origin").is_none());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/header_config/second/index.html").unwrap()
);
let mut result = get_host(&c, "http://127.0.0.1:9010/second/third/afile").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.headers().get("Access-Control-Allow-Origin"),
Some(&HeaderValue::from_static("*"))
);
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/header_config/second/third/afile").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_simple_ssl() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/simple_ssl/conf.kdl").unwrap();
let mut cert_store = RootCertStore::empty();
let cert_file = &mut BufReader::new(File::open("./fixtures/simple_ssl/CA.pem").unwrap());
let mut cert_chain: Vec<_> = certs(cert_file).filter_map(|x| x.ok()).collect();
cert_store.add(cert_chain.pop().unwrap()).unwrap();
let c = ssl_client(cert_store);
let mut result = get(&c, "https://localhost:9002/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/simple_ssl/files/index.html").unwrap()
);
let mut result = get(&c, "https://localhost:9002/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/simple_ssl/files/index.html").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_ssl_folders() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/ssl_sites_folder/conf.kdl").unwrap();
let mut cert_store = RootCertStore::empty();
let cert_file = &mut BufReader::new(File::open("./fixtures/ssl_sites_folder/certs/localhost/CA.pem").unwrap());
let mut cert_chain: Vec<_> = certs(cert_file).filter_map(|x| x.ok()).collect();
cert_store.add(cert_chain.pop().unwrap()).unwrap();
let c = ssl_client(cert_store);
let mut result = get(&c, "https://localhost:9007/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder/files/index.html").unwrap()
);
let mut result = get(&c, "https://localhost:9007/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder/files/index.html").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_ssl_folders_acme_redirect() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/ssl_sites_folder_acme_redirect/conf.kdl").unwrap();
let mut cert_store = RootCertStore::empty();
let cert_file =
&mut BufReader::new(File::open("./fixtures/ssl_sites_folder_acme_redirect/certs/localhost/CA.pem").unwrap());
let mut cert_chain: Vec<_> = certs(cert_file).filter_map(|x| x.ok()).collect();
cert_store.add(cert_chain.pop().unwrap()).unwrap();
let c = ssl_client(cert_store);
let mut result = get(&c, "https://localhost:9008/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder_acme_redirect/files/index.html").unwrap()
);
let mut result = get(&c, "https://localhost:9008/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder_acme_redirect/files/index.html").unwrap()
);
vacuna.stop().await;
}
pub fn test_start_background(config: Config, test_cache: TestCache) -> Result<ServerHandle, Box<dyn Error>> {
let (started_tx, started_rx) = channel();
std::thread::spawn(move || {
actix_rt::System::new().block_on(async move {
if let Err(e) = test_background_start(config, test_cache, started_tx).await {
error!("fail background start {}", e)
}
});
});
let handle = started_rx.recv()?;
Ok(handle)
}
async fn test_background_start(
config: Config,
test_cache: TestCache,
started_tx: Sender<ServerHandle>,
) -> Result<(), Box<dyn Error>> {
let mut parsed_config = read_config(&config);
parsed_config.set_ssl_test_cache(test_cache);
let server = server_internal(parsed_config)?;
started_tx.send(server.handle())?;
server.await?;
Ok(())
}
#[actix_rt::test]
#[ignore]
async fn test_ssl_folders_acme() {
let _ = pretty_env_logger::try_init();
let config = Config::read("./fixtures/ssl_sites_folder_acme/conf.kdl").unwrap();
let test_cache = TestCache::default();
let cert = test_cache.ca_pem();
let reader = Cursor::new(cert.as_bytes().to_vec());
let vacuna = test_start_background(config, test_cache).unwrap();
let mut cert_store = RootCertStore::empty();
let cert_file = &mut BufReader::new(reader);
let mut cert_chain: Vec<_> = certs(cert_file).filter_map(|x| x.ok()).collect();
cert_store.add(cert_chain.pop().unwrap()).unwrap();
let c = ssl_client(cert_store);
let mut result = get(&c, "https://localhost:9011/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder_acme/files/index.html").unwrap()
);
let mut result = get(&c, "https://localhost:9011/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/ssl_sites_folder_acme/files/index.html").unwrap()
);
vacuna.stop(true).await;
}
#[actix_rt::test]
async fn test_simple_proxy() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/simple_proxy/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9003/home/index.html?abc=dd")
.await
.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/simple_proxy/files/index.html").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_log() {
let _ = pretty_env_logger::try_init();
{
let vacuna = Vacuna::start_background_from_file("./fixtures/logging/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9005/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/logging/files/index.html").unwrap()
);
vacuna.stop().await;
}
}
#[actix_rt::test]
async fn test_auto() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/auto_sites/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9004/index.html").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/auto_sites/example.com/index.html").unwrap()
);
let mut result = get_with_host(&c, "http://127.0.0.1:9004/index.html", "example.org")
.await
.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/auto_sites/example.org/index.html").unwrap()
);
vacuna.stop().await;
}
#[actix_rt::test]
async fn test_auto_config() {
let _ = pretty_env_logger::try_init();
let vacuna = Vacuna::start_background_from_file("./fixtures/auto_sites_config/conf.kdl").unwrap();
let c = Client::default();
let mut result = get_host(&c, "http://127.0.0.1:9006/").await.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/auto_sites_config/example.com/other.html").unwrap()
);
let mut result = get_with_host(&c, "http://127.0.0.1:9006/", "example.org")
.await
.unwrap();
assert!(result.status().is_success());
assert_eq!(
result.body().await.unwrap().to_vec(),
read("./fixtures/auto_sites_config/example.org/other.html").unwrap()
);
vacuna.stop().await;
}