maj/src/server/cgi.rs

73 lines
2.3 KiB
Rust

/// 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<Response> {
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<Response> {
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<String, String> = 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)
}
}