use core::ffi; use std::{borrow::Cow, ffi::CStr, ptr, sync::Mutex}; #[repr(C)] pub struct ModuleRequest<'req> { pub headers_len: ffi::c_ulong, pub headers: &'req [[*const ffi::c_char; 2]], pub body_len: ffi::c_ulong, pub body: *const u8, } pub struct Request<'req> { headers: Vec<(Cow<'req, str>, Cow<'req, str>)>, body: Option<&'req [u8]>, } impl<'req> Request<'req> { 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![]; for idx in 0..reqref.headers_len as usize { let kvarr = reqref.headers[idx as usize]; let k = unsafe { CStr::from_ptr(kvarr[0]) }.to_string_lossy(); let v = unsafe { CStr::from_ptr(kvarr[1]) }.to_string_lossy(); headers.push((k, v)); } let body = if reqref.body.is_null() { None } else { Some(unsafe { std::slice::from_raw_parts(reqref.body, reqref.body_len as usize) }) }; Self { headers, body } } pub fn header(&self, key: &str) -> Option<&str> { for (hkey, hval) in &self.headers { if hkey == key { return Some(hval); } } None } pub fn headers(&self) -> &[(Cow, Cow)] { &self.headers } pub fn body(&self) -> Option<&[u8]> { self.body } } #[repr(C)] pub struct ModuleResponse { pub status: ffi::c_ushort, pub headers_len: ffi::c_ulong, pub headers: &'static [[*const ffi::c_char; 2]], pub body_len: ffi::c_ulong, pub body: *const u8, } 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); pub struct Response { headers: Vec<(Cow<'static, CStr>, Cow<'static, CStr>)>, body: Vec, } impl Response { pub fn new() -> Self { Self { headers: vec![], 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().take(HEADERS_LEN) { unsafe { HEADERS[idx][0] = key.as_ptr(); HEADERS[idx][1] = value.as_ptr(); } } 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: 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 { self.headers.push((key.into(), value.into())); self } pub fn body(&mut self, vec: Vec) -> &mut Self { self.body = vec; self } pub fn cleanup(response: *const ModuleResponse) { let mut lock = RESPONSE.lock().unwrap(); match lock.take() { Some(response) => drop(response), None => (), } let boxed = unsafe { Box::from_raw(response as *mut ModuleResponse) }; drop(boxed); } }