/// A simple handler for disk based files. Will optionally chop off a prefix. use super::{Handler as MajHandler, Request, Result}; use crate::Response; use crate::{route, seg, split}; use async_trait::async_trait; use std::collections::HashMap; use std::io::Cursor; use std::path::PathBuf; use std::process::Command; pub struct Handler { base_dir: PathBuf, } const APPLICATION_NAME: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); #[async_trait] impl MajHandler for Handler { async fn handle(&self, r: Request) -> Result { route!(r.url.path(), { (/"cgi-bin"/[prog_name: String][/rest..]) => self.do_cgi(prog_name, rest.to_string(), r).await; }); Ok(Response::not_found()) } } impl Handler { pub fn new(base_dir: PathBuf) -> Self { Handler { base_dir: base_dir } } async fn do_cgi(&self, prog_name: String, rest: String, r: Request) -> Result { let mut path = PathBuf::from(&self.base_dir); path.push(&prog_name); log::debug!("path: {:?}", path); let query = { match r.url.query() { Some(q) => q.clone(), None => "", } }; let filtered_env: HashMap = std::env::vars() .filter(|&(ref k, _)| k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH") .collect(); let output = Command::new(path.clone()) .env_clear() .envs(filtered_env) .env("GATEWAY_INTERFACE", "CGI/1.1") .env("SERVER_PROTOCOL", "GEMINI") .env("SERVER_SOFTWARE", APPLICATION_NAME) .env("GEMINI_URL", format!("{}", r.url)) .env("SCRIPT_NAME", path) .env("PATH_INFO", rest) .env("QUERY_STRING", query) .env("SERVER_NAME", r.url.host_str().unwrap()) .env("SERVER_HOSTNAME", r.url.host_str().unwrap()) .env("SERVER_PORT", format!("{}", r.url.port().unwrap_or(1965))) .env("REMOTE_HOST", "127.0.0.1") .env("REMOTE_ADDR", "127.0.0.1") .env("TLS_CIPHER", "Secure") .env("TLS_VERSION", "TLSv1.3") .output()?; let resp = Response::parse(&mut Cursor::new(output.stdout))?; Ok(resp) } }