]> Humopery - fcgisrv.git/commitdiff
Allow env overrides of socket path and mime types (based on regex matches)
authorErik Mackdanz <erikmack@gmail.com>
Fri, 27 Oct 2023 05:21:56 +0000 (00:21 -0500)
committerErik Mackdanz <erikmack@gmail.com>
Fri, 27 Oct 2023 05:21:56 +0000 (00:21 -0500)
Cargo.lock
Cargo.toml
src/main.rs

index 4fad405029c7a3e8506e62bd335a348197f3a84a..7ac8b789223d9c6fa9d5463f3a4e0ddb9796c5f7 100644 (file)
@@ -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"
index 7fa08c1c73c9bf2111aaeb545e0fc9e8d2741a6d..58eb72fea8d2eaa74e337e95e5942f49de483b21 100644 (file)
@@ -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"
index 2dd686a9cc0202bf55babaef17bf29238e9bd7c4..4bb6e7dc503c84e1741a634e39e1e0ae260ee04c 100644 (file)
@@ -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<u8,(Regex,String)>,
+    // cors_origin_matches: BTreeMap<u8,(Regex,String)>,
+}
+
+impl Config {
+    fn init() -> Result<Config,Box<dyn Error>> {
+       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<dyn Error>> {
 
     // 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