use std::ffi::{self, CStr, CString}; #[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, } const HEADERS: &'static [[*const ffi::c_char; 2]] = &[[c"Content-Type".as_ptr(), c"text/plain".as_ptr()]]; #[unsafe(no_mangle)] extern "C" fn cgi_handle(req: *const ModuleRequest) -> *const ModuleResponse { let mut ret = String::new(); // unwrap is bad here let reqref = unsafe { req.as_ref() }.unwrap(); for idx in 0..reqref.headers_len { 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(); // While debugging I removed the format!() because it was SIGSEGVing // as the String it allocated freed, and now that this is here it can stay ret.push_str(&k); ret.push(':'); ret.push(' '); ret.push_str(&v); ret.push('\n') } let body = CString::new(ret).unwrap(); let resp = ModuleResponse { status: 200, headers_len: 1, headers: HEADERS, body_len: body.as_bytes().len() as u64, body: body.into_raw() as *const u8, }; let boxed = Box::new(resp); Box::::into_raw(boxed) } #[unsafe(no_mangle)] extern "C" fn cgi_cleanup(req: *const ModuleResponse) { // from_raw what we need to here so that these get dropped let boxed = unsafe { Box::from_raw(req as *mut ModuleResponse) }; let body = unsafe { CString::from_raw(boxed.body as *mut i8) }; // Explicitly calling drop here to feel good about myself drop(body); drop(boxed); }