about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2025-04-02 12:36:48 -0500
committergennyble <gen@nyble.dev>2025-04-02 12:36:48 -0500
commitff02aba40dd599373380631a1d0e87ecbed3f8b5 (patch)
tree41aa5ca73fbf59b72f6ee92a7d33c7b76f9c7db4
parent10925e207a28635e207459c5b78581385c9dbe9e (diff)
downloadcorgi-ff02aba40dd599373380631a1d0e87ecbed3f8b5.tar.gz
corgi-ff02aba40dd599373380631a1d0e87ecbed3f8b5.zip
mutex on modules so only one request can be handled at a time
-rw-r--r--corgi/src/caller.rs15
-rw-r--r--corgi/src/main.rs4
2 files changed, 18 insertions, 1 deletions
diff --git a/corgi/src/caller.rs b/corgi/src/caller.rs
index aef6bc3..7014d22 100644
--- a/corgi/src/caller.rs
+++ b/corgi/src/caller.rs
@@ -213,6 +213,20 @@ unsafe fn module_thread(script: Script, req: HttpRequest, tx: Sender<CgiResponse
 		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();
@@ -240,5 +254,6 @@ unsafe fn module_thread(script: Script, req: HttpRequest, tx: Sender<CgiResponse
 		free(response);
 	};
 
+	drop(lock);
 	tx.send(cgi).unwrap()
 }
diff --git a/corgi/src/main.rs b/corgi/src/main.rs
index fb6915b..3923084 100644
--- a/corgi/src/main.rs
+++ b/corgi/src/main.rs
@@ -2,7 +2,7 @@ use std::{
 	net::{IpAddr, SocketAddr},
 	path::PathBuf,
 	pin::Pin,
-	sync::Arc,
+	sync::{Arc, Mutex},
 	time::Instant,
 };
 
@@ -40,6 +40,7 @@ pub enum ScriptKind {
 pub struct Script {
 	name: String,
 	kind: ScriptKind,
+	module_lock: Arc<Mutex<()>>,
 	regex: Option<Regex>,
 	filename: String,
 	env: Vec<(String, String)>,
@@ -107,6 +108,7 @@ fn parse_script_conf(conf: &Value) -> Script {
 	Script {
 		name,
 		kind,
+		module_lock: Arc::new(Mutex::new(())),
 		regex,
 		filename,
 		env: env.unwrap_or_default(),