//! To run this example, you'll need to compile cgi-tick first: //! //! ```bash //! cargo build --example cgi-tick //! cargo run --example cgi //! ``` //! //! Then connect to localhost:7000: //! //! ```bash //! nc localhost 7000 //! ``` extern crate libuv; use libuv::prelude::*; use libuv::{ exepath, ProcessHandle, ProcessOptions, StdioContainer, StdioFlags, StdioType, TcpBindFlags, TcpHandle, }; use std::net::Ipv4Addr; use std::path::PathBuf; fn invoke_cgi_script(client: TcpHandle) -> Result<(), Box> { let mut path: PathBuf = exepath()?.into(); if cfg!(windows) { path.set_file_name("cgi-tick.exe"); } else { path.set_file_name("cgi-tick"); } let child_stdio = [ Default::default(), StdioContainer { flags: StdioFlags::INHERIT_STREAM, data: StdioType::Stream(client.to_stream()), }, Default::default(), ]; let path = path.to_string_lossy().into_owned(); let args: [&str; 1] = [&path]; let mut options = ProcessOptions::new(&args); options.stdio = &child_stdio; let mut client_clone = client.clone(); options.exit_cb = (move |mut handle: ProcessHandle, exit_status: i64, term_signal: i32| { println!( "Process exited with status {}, signal {}", exit_status, term_signal ); handle.close(()); client_clone.close(()); }) .into(); client.get_loop().spawn_process(options)?; Ok(()) } fn on_new_connection(mut server: StreamHandle, status: libuv::Result) { if let Err(e) = status { eprintln!("New connection error: {}", e); return; } if let Ok(mut client) = server.get_loop().tcp() { match server.accept(&mut client.to_stream()) { Ok(_) => { if let Err(e) = invoke_cgi_script(client) { eprintln!("Error invoking CGI script: {}", e); } } Err(_) => { client.close(()); } } } } fn main() -> Result<(), Box> { let mut r#loop = Loop::default()?; let mut server = r#loop.tcp()?; let addr = (Ipv4Addr::UNSPECIFIED, 7000).into(); server.bind(&addr, TcpBindFlags::empty())?; server.listen(128, on_new_connection)?; r#loop.run(RunMode::Default)?; Ok(()) }