From 44061caead90d66dd36af02acbcb7a38bb7a04d5 Mon Sep 17 00:00:00 2001 From: Erik Mackdanz Date: Fri, 27 Oct 2023 00:21:56 -0500 Subject: [PATCH] Allow env overrides of socket path and mime types (based on regex matches) --- Cargo.lock | 45 +++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 113 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fad405..7ac8b78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -49,6 +58,7 @@ dependencies = [ "log", "mime", "new_mime_guess", + "regex", "signal", "simplelog", ] @@ -71,6 +81,12 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + [[package]] name = "mime" version = "0.3.17" @@ -133,6 +149,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "serde" version = "1.0.190" diff --git a/Cargo.toml b/Cargo.toml index 7fa08c1..58eb72f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ fastcgi = "1.0.0" log = "0.4.20" mime = "0.3.17" new_mime_guess = "4.0.1" +regex = "1.10.2" signal = "0.7.0" simplelog = "0.12.1" diff --git a/src/main.rs b/src/main.rs index 2dd686a..4bb6e7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,11 @@ use fastcgi::{run_raw,Request}; use log::{debug,info,error}; use mime; use new_mime_guess::from_path; -use simplelog::{SimpleLogger,LevelFilter,Config}; +use regex::Regex; +use simplelog::{SimpleLogger,LevelFilter}; +use std::collections::BTreeMap; use std::error::Error; +use std::env; use std::fs::{File,metadata,remove_file}; use std::io::{Read,Write}; use std::os::unix::net::UnixListener; @@ -13,6 +16,7 @@ use signal::Signal; const BUFSZ: usize = 4096; +// Write a validation 4XX or 5XX back to the user macro_rules! write_err_resp { ($req:expr,$status:expr,$statusmess:expr,$body:expr) => { if let Err(e) = @@ -28,11 +32,16 @@ macro_rules! write_err_resp { } } -fn handle_req(mut req: Request) { +fn handle_req(conf: &Config, mut req: Request) { // for (k,v) in req.params() { - // error!("key {} has value {}",k,v); + // info!("key {} has value {}",k,v); // } + let Some(docroot) = req.param("DOCUMENT_ROOT") else { + write_err_resp!(req,"400","Bad Request","No document root was set"); + return; + }; + // require a method let Some(method) = req.param("REQUEST_METHOD") else { write_err_resp!(req,"405","Method not allowed","No method"); @@ -56,7 +65,16 @@ fn handle_req(mut req: Request) { // determine content-type let guess = from_path(filename.clone()); let guessed_mime = guess.first().unwrap_or(mime::TEXT_PLAIN); - let mimestr = guessed_mime.essence_str(); + let mut mimestr = guessed_mime.essence_str(); + + // check for a mime type override in config + let short_filename = &filename[docroot.len()..]; + for idx in conf.mime_matches.keys() { + let (conf_mime_match,conf_mime_value) = &conf.mime_matches[idx]; + if conf_mime_match.is_match(short_filename) { + mimestr = conf_mime_value; + } + } // read std::fs::metadata including size let Ok(metadata) = metadata(filename.clone()) else { @@ -106,23 +124,62 @@ fn handle_req(mut req: Request) { } +struct Config { + socket_path: String, + mime_matches: BTreeMap, + // cors_origin_matches: BTreeMap, +} + +impl Config { + fn init() -> Result> { + let mut socket_path = "/tmp/fcgisocket".to_string(); + let mut mime_matches = BTreeMap::new(); + // let mut cors_origin_matches = BTreeMap::new(); + + for (k,v) in env::vars() { + if k == "FCGI_SRV_SOCKET_PATH" { + info!("config: found socket_path {}",v); + socket_path = v; + } else if k.starts_with("FCGI_SRV_MIME_MATCH_") { + let index = u8::from_str_radix(&k[20..],10)?; + info!("config: found mime match index {}",index); + let re = Regex::new(&v)?; + if let Ok(mtype) = env::var(format!("FCGI_SRV_MIME_TYPE_{}",index)) { + mime_matches.insert(index,(re,mtype)); + }; + } + } + + let conf = Config { + socket_path: socket_path, + mime_matches: mime_matches, + // cors_origin_matches: cors_origin_matches, + }; + + Ok(conf) + } +} + + fn main() -> Result<(),Box> { // init logging - SimpleLogger::init(LevelFilter::Info,Config::default())?; + SimpleLogger::init(LevelFilter::Info,simplelog::Config::default())?; - let socketpath = "/tmp/fcgisocket"; + let conf = Config::init()?; // handle Ctrl+C - set_command_line("/bin/rm",["-f",socketpath],[("FOO","")]); + set_command_line("/bin/rm",["-f",&conf.socket_path],[("FOO","")]); let _ = set_handler(&[Signal::SIGINT],false); // remove socket file - let _ = remove_file(socketpath); + let _ = remove_file(&conf.socket_path); info!("Entering main loop"); - let listener = UnixListener::bind(socketpath).unwrap(); - run_raw(handle_req,listener.as_raw_fd()); + let listener = UnixListener::bind(&conf.socket_path).unwrap(); + run_raw( + move |req| {handle_req(&conf,req)}, + listener.as_raw_fd()); // Nothing after this is called -- 2.52.0