From ceb1047ed6bcd45f756bc2b9b0e41ddfdd694d56 Mon Sep 17 00:00:00 2001 From: gennyble Date: Thu, 27 Mar 2025 11:48:36 -0500 Subject: improve saftey --- smalldog/src/lib.rs | 65 +++++++++++++++---------------------------------- stats_module/src/lib.rs | 20 ++++++--------- 2 files changed, 28 insertions(+), 57 deletions(-) diff --git a/smalldog/src/lib.rs b/smalldog/src/lib.rs index e1ada11..adfe9c1 100644 --- a/smalldog/src/lib.rs +++ b/smalldog/src/lib.rs @@ -21,7 +21,8 @@ pub struct Request<'req> { } impl<'req> Request<'req> { - pub fn from_mod_request(request: *const ModuleRequest) -> Self { + pub fn from_mod_request(request: *const ModuleRequest<'req>) -> Self { + // SAFTEY: corgi will never give us a null pointer let reqref = unsafe { request.as_ref() }.unwrap(); let mut headers = vec![]; @@ -61,86 +62,60 @@ pub struct ModuleResponse { pub body: *const u8, } -pub static mut HEADERS: [[*const ffi::c_char; 2]; 64] = [[ptr::null(), ptr::null()]; 64]; +const HEADERS_LEN: usize = 64; +static mut HEADERS: [[*const ffi::c_char; 2]; HEADERS_LEN] = [[ptr::null(), ptr::null()]; 64]; static RESPONSE: Mutex> = Mutex::new(None); -#[derive(Clone, Debug, PartialEq)] -enum ResponseBody { - Building(String), - Built(CString), -} - -impl ResponseBody { - pub fn get_built(&mut self) -> &CString { - match self { - ResponseBody::Building(body) => { - *self = ResponseBody::Built(CString::from_str(&body).unwrap()); - - if let ResponseBody::Built(bdy) = self { - bdy - } else { - unreachable!() - } - } - ResponseBody::Built(bdy) => bdy, - } - } -} - pub struct Response { - headers: Vec<(CString, CString)>, - body: ResponseBody, + headers: Vec<(Cow<'static, CStr>, Cow<'static, CStr>)>, + body: Vec, } impl Response { pub fn new() -> Self { Self { headers: vec![], - body: ResponseBody::Building(String::new()), + body: vec![], } } pub fn into_mod_response(self, status: u16) -> *const ModuleResponse { let mut lock = RESPONSE.lock().unwrap(); *lock = Some(self); + let this = lock.as_mut().unwrap(); - for (idx, (key, value)) in this.headers.iter().enumerate() { + for (idx, (key, value)) in this.headers.iter().enumerate().take(HEADERS_LEN) { unsafe { HEADERS[idx][0] = key.as_ptr(); HEADERS[idx][1] = value.as_ptr(); } } - let (body_len, body) = { - let built = this.body.get_built(); - (built.as_bytes().len() as u64, built.as_ptr() as *const u8) - }; - - let headers_len = this.headers.len() as u64; + let headers_len = this.headers.len().min(HEADERS_LEN) as u64; let boxed = Box::new(ModuleResponse { status, headers_len, headers: unsafe { &HEADERS[..headers_len as usize] }, - body_len, - body, + body_len: this.body.len() as u64, + body: this.body.as_ptr(), }); Box::::into_raw(boxed) } - pub fn header, V: Into>(&mut self, key: K, value: V) -> &mut Self { + pub fn header>, V: Into>>( + &mut self, + key: K, + value: V, + ) -> &mut Self { self.headers.push((key.into(), value.into())); self } - pub fn push_str(&mut self, s: &str) { - match self.body { - ResponseBody::Building(ref mut body) => { - body.push_str(s); - } - _ => (), - } + pub fn body(&mut self, vec: Vec) -> &mut Self { + self.body = vec; + self } pub fn cleanup(response: *const ModuleResponse) { diff --git a/stats_module/src/lib.rs b/stats_module/src/lib.rs index 96cbaa9..a56d22d 100644 --- a/stats_module/src/lib.rs +++ b/stats_module/src/lib.rs @@ -1,5 +1,3 @@ -use std::ffi::CStr; - use rusqlite::{Connection, params}; use smalldog::{ModuleRequest, ModuleResponse, Request, Response}; use time::{Duration, OffsetDateTime}; @@ -7,6 +5,7 @@ use time::{Duration, OffsetDateTime}; #[unsafe(no_mangle)] extern "C" fn cgi_handle(req: *const ModuleRequest) -> *const ModuleResponse { let mut response = Response::new(); + let mut body = String::new(); let request = Request::from_mod_request(req); let db = if let Some(path) = request.header("CORGI_STATS_DB") { @@ -32,27 +31,24 @@ extern "C" fn cgi_handle(req: *const ModuleRequest) -> *const ModuleResponse { agents.sort_by(|a, b| a.0.cmp(&b.0).reverse()); - response.push_str("

In the last fifteen minutes:

");
-	response.push_str("total | req/m | agent\n");
+	body.push_str("

In the last fifteen minutes:

");
+	body.push_str("total | req/m | agent\n");
 	for (count, agent) in &agents {
-		response.push_str(&format!(
+		body.push_str(&format!(
 			"{count:<5} | {:<5.1} | {agent}\n",
 			*count as f32 / 15.0
 		));
 	}
-	response.push_str("

"); + body.push_str("

"); + response.body(body.into_bytes()); response.into_mod_response(200) } fn make_error>(code: u16, msg: S) -> *const ModuleResponse { - unsafe { - smalldog::HEADERS[0][0] = c"Content-Length".as_ptr(); - smalldog::HEADERS[0][1] = c"text/html".as_ptr(); - } - let mut response = Response::new(); - response.push_str(msg.as_ref()); + response.header(c"Content-Length", c"text/html"); + response.body(msg.as_ref().as_bytes().to_vec()); response.into_mod_response(code) } -- cgit 1.4.1-3-g733a5