about summary refs log tree commit diff
path: root/corgi/src
diff options
context:
space:
mode:
Diffstat (limited to 'corgi/src')
-rw-r--r--corgi/src/caller.rs82
-rw-r--r--corgi/src/main.rs7
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();