diff options
Diffstat (limited to 'corgi/src')
-rw-r--r-- | corgi/src/caller.rs | 112 | ||||
-rw-r--r-- | corgi/src/main.rs | 43 |
2 files changed, 5 insertions, 150 deletions
diff --git a/corgi/src/caller.rs b/corgi/src/caller.rs index 7014d22..29be5ca 100644 --- a/corgi/src/caller.rs +++ b/corgi/src/caller.rs @@ -1,20 +1,8 @@ -use std::{ - ffi::{self, CString}, - marker::PhantomData, - net::IpAddr, - process::Stdio, - ptr, - str::FromStr, -}; +use std::{net::IpAddr, process::Stdio}; -use smalldog::ffi::{ModuleRequest, ModuleResponse}; -use tokio::{ - io::AsyncWriteExt, - process::Command, - sync::oneshot::{self, Sender}, -}; +use tokio::{io::AsyncWriteExt, process::Command}; -use crate::{Script, ScriptKind}; +use crate::Script; pub struct HttpRequest { pub content_type: String, @@ -63,12 +51,6 @@ impl HttpRequest { } pub async fn call_and_parse_cgi(script: Script, http: HttpRequest) -> CgiResponse { - if script.kind != ScriptKind::Executable { - eprintln!("Somehow made it to executable path with module script"); - eprintln!("Script: {}", script.name); - panic!("TODO: recover") - } - let mut cmd = Command::new(&script.filename); // Set env specified in the conf. Be sure we do this after we @@ -169,91 +151,3 @@ pub struct CgiResponse { /// CGI response body pub body: Option<Vec<u8>>, } - -type HandleFn = unsafe extern "C" fn(*const ModuleRequest) -> *const ModuleResponse; -type CleanupFn = unsafe extern "C" fn(*const ModuleResponse); - -pub async fn call_and_parse_module(script: Script, req: HttpRequest) -> CgiResponse { - let (tx, rx) = oneshot::channel(); - std::thread::spawn(move || unsafe { module_thread(script, req, tx) }); - - rx.await.unwrap() -} - -unsafe fn module_thread(script: Script, req: HttpRequest, tx: Sender<CgiResponse>) { - let env: Vec<(String, String)> = req - .build_kv() - .into_iter() - .chain(req.http_headers.into_iter()) - .chain(script.env.into_iter()) - .collect(); - - let mut headers_owned = vec![]; - for (k, v) in env { - headers_owned.push([ - CString::from_str(k.as_str()).unwrap(), - CString::from_str(v.as_str()).unwrap(), - ]); - } - - let headers: Vec<[*const ffi::c_char; 2]> = - headers_owned.iter().map(|kvarr| [kvarr[0].as_ptr(), kvarr[1].as_ptr()]).collect(); - - let modreq = ModuleRequest { - headers_len: headers.len() as u64, - headers: headers[..].as_ptr(), - body_len: req.body.as_ref().map(|v| v.len()).unwrap_or(0) as u64, - body: req.body.as_ref().map(|v| v.as_ptr()).unwrap_or(ptr::null()), - _phantom: PhantomData::default(), - }; - - let mut cgi = CgiResponse { - status: 200, - headers: vec![], - body: None, - }; - - // Since we can only load a dynamic library once, block other requests so - // they do not return the same handle. per dlopen docs: - // > If the same shared object is opened again with dlopen(), - // > the same object handle is returned. - let lock = match script.module_lock.lock() { - Ok(lock) => lock, - Err(poison) => { - eprintln!("!!! mutex for {} was poisoned!", script.name); - - // get the guard - poison.into_inner() - } - }; - - unsafe { - let lib = libloading::Library::new(script.filename).unwrap(); - let handle: libloading::Symbol<HandleFn> = lib.get(b"cgi_handle").unwrap(); - let free: libloading::Symbol<CleanupFn> = lib.get(b"cgi_cleanup").unwrap(); - - let response = handle((&modreq) as *const ModuleRequest); - let response_ref = response.as_ref().unwrap(); - - let headers_ffi = - std::slice::from_raw_parts(response_ref.headers, response_ref.headers_len as usize); - - for pair in headers_ffi { - let k = ffi::CStr::from_ptr(pair[0]).to_string_lossy(); - let v = ffi::CStr::from_ptr(pair[1]).to_string_lossy(); - - cgi.headers.push((k.as_bytes().to_vec(), v.as_bytes().to_vec())); - } - - let maybe_body: Option<Vec<u8>> = response_ref - .body - .as_ref() - .map(|b| std::slice::from_raw_parts(b, response_ref.body_len as usize).to_vec()); - cgi.body = maybe_body; - - free(response); - }; - - drop(lock); - tx.send(cgi).unwrap() -} diff --git a/corgi/src/main.rs b/corgi/src/main.rs index fb6b75a..b8b23de 100644 --- a/corgi/src/main.rs +++ b/corgi/src/main.rs @@ -2,9 +2,7 @@ use std::{ net::{IpAddr, SocketAddr}, path::PathBuf, pin::Pin, - sync::{Arc, Mutex}, - thread::JoinHandle, - time::Instant, + sync::Arc, }; use caller::HttpRequest; @@ -32,25 +30,8 @@ pub struct Settings { } #[derive(Clone, Debug)] -pub enum ScriptKind { - Executable, - Module { thread: Arc<Option<JoinHandle<()>>> }, -} - -impl ScriptKind { - pub fn is_executable(&self) -> bool { - if let ScriptKind::Executable = self { - true - } else { - false - } - } -} - -#[derive(Clone, Debug)] pub struct Script { name: String, - kind: ScriptKind, regex: Option<Regex>, filename: String, env: Vec<(String, String)>, @@ -105,21 +86,8 @@ fn parse_script_conf(conf: &Value) -> Script { }, }; - let kind = match conf.get("Type") { - None => ScriptKind::Executable, - Some("executable") => ScriptKind::Executable, - Some("object") => ScriptKind::Module { - thread: Arc::new(None), - }, - Some(kind) => { - eprintln!("'{kind}' is not a valid script type"); - std::process::exit(1) - } - }; - Script { name, - kind, regex, filename, env: env.unwrap_or_default(), @@ -176,8 +144,6 @@ impl Svc { caddr: SocketAddr, req: Request<Incoming>, ) -> Response<Full<Bytes>> { - let start = Instant::now(); - // Collect things we need from the request before we eat it's body let method = req.method().as_str().to_ascii_uppercase(); let version = req.version(); @@ -251,12 +217,7 @@ impl Svc { body: if content_length > 0 { Some(body) } else { None }, }; - let cgi_response = match script.kind { - ScriptKind::Executable => { - caller::call_and_parse_cgi(script.clone(), http_request).await - } - ScriptKind::Object => caller::call_and_parse_module(script.clone(), http_request).await, - }; + let cgi_response = caller::call_and_parse_cgi(script.clone(), http_request).await; let status = StatusCode::from_u16(cgi_response.status).unwrap(); let mut response = Response::builder().status(status); |