diff options
Diffstat (limited to 'corgi/src')
-rw-r--r-- | corgi/src/caller.rs | 82 | ||||
-rw-r--r-- | corgi/src/main.rs | 7 |
2 files changed, 87 insertions, 2 deletions
diff --git a/corgi/src/caller.rs b/corgi/src/caller.rs index 1e1d138..b942849 100644 --- a/corgi/src/caller.rs +++ b/corgi/src/caller.rs @@ -1,4 +1,10 @@ -use std::{net::IpAddr, process::Stdio}; +use std::{ + ffi::{self, CString}, + net::IpAddr, + process::Stdio, + ptr, + str::FromStr, +}; use tokio::{io::AsyncWriteExt, process::Command}; @@ -156,3 +162,77 @@ pub struct CgiResponse { /// CGI response body pub body: Option<Vec<u8>>, } + +#[repr(C)] +struct ModuleRequest<'req> { + headers_len: ffi::c_ulong, + headers: &'req [[*const ffi::c_char; 2]], + body_len: ffi::c_ulong, + body: *const u8, +} + +#[repr(C)] +struct ModuleResponse { + status: ffi::c_ushort, + headers_len: ffi::c_ulong, + headers: &'static [[*const ffi::c_char; 2]], + body_len: ffi::c_ulong, + body: *const u8, +} + +type HandleFn = unsafe extern "C" fn(*const ModuleRequest) -> *const ModuleResponse; +type FreeFn = unsafe extern "C" fn(*const ModuleResponse); + +pub async fn call_and_parse_module(script: Script, req: HttpRequest) -> CgiResponse { + let env = req.build_kv(); + + let mut headers_owned = vec![]; + for (k, v) in env { + headers_owned.push([ + CString::from_str(&k).unwrap(), + CString::from_str(&v).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, + 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()), + }; + + let mut cgi = CgiResponse { + status: 200, + headers: vec![], + body: None, + }; + + unsafe { + let lib = libloading::Library::new(script.filename).unwrap(); + let handle: libloading::Symbol<HandleFn> = lib.get(b"handle").unwrap(); + let free: libloading::Symbol<FreeFn> = lib.get(b"free").unwrap(); + + let response = handle((&modreq) as *const ModuleRequest); + let response_ref = response.as_ref().unwrap(); + + for idx in 0..response_ref.headers_len { + let kvarr = response_ref.headers[idx as usize]; + let k = ffi::CStr::from_ptr(kvarr[0]).to_string_lossy(); + let v = ffi::CStr::from_ptr(kvarr[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); + }; + + cgi +} diff --git a/corgi/src/main.rs b/corgi/src/main.rs index 0338d0e..cd3b67c 100644 --- a/corgi/src/main.rs +++ b/corgi/src/main.rs @@ -227,7 +227,12 @@ impl Svc { }; let start_cgi = Instant::now(); - let cgi_response = caller::call_and_parse_cgi(script.clone(), http_request).await; + 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_time = start_cgi.elapsed(); let status = StatusCode::from_u16(cgi_response.status).unwrap(); |