diff --git a/Cargo.lock b/Cargo.lock index 0484ac9..bcc8b19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "17cbf58e19f2bda088d8c4c95a46b41895375e15a2d63dd686a4273f8c43d46b" [[package]] name = "herb" -version = "0.8.2" +version = "0.9.0-develop" dependencies = [ "frostwalker", "packeteer", diff --git a/Cargo.toml b/Cargo.toml index 492bb56..ea823de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "herb" -version = "0.8.2" +version = "0.9.0-develop" edition = "2018" [dependencies] diff --git a/README.md b/README.md index 4db6c26..96d193f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ herb is able to send all types of data to clients, including text, video, audio, ## Features * Dynamic websites through CGI -* Only one external dependency (packeteer) +* Only two external dependencies ([packeteer](https://git.colean.cc/threeoh6000/packeteer), [frostwalker](https://git.colean.cc/threeoh6000/frostwalker)) * Directory index generation * Primitive media type detection * Supports text and raw data, including PNGs and MP3s diff --git a/src/main.rs b/src/main.rs index 89dee32..51ae5d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use std::net::{TcpListener, TcpStream}; use std::fs; use std::fs::File; use std::string::{String}; -use std::process::Command; +use std::process::{Command, Stdio}; use packeteer::http1::*; use frostwalker; use packeteer::{generate_kvheader, unwrap_url_into_segments}; @@ -30,15 +30,17 @@ struct Settings { index_generation: bool, address: String, logging: bool, + server_header: bool, + time_header: bool, } impl Settings { fn new() -> Settings { - return Settings { cgi: true, index_generation: true, address: "0.0.0.0:8080".to_string(), logging: false}; + return Settings { cgi: true, index_generation: true, address: "0.0.0.0:8080".to_string(), logging: false, server_header: true, time_header: false}; } } -fn process_cgi(filename: String) -> Option> { +fn process_cgi(filename: String, post_data: Option) -> Option> { // This is gonna be the bodgiest implementation of CGI that anyone // has ever seen in the history of the fucking world @@ -56,7 +58,35 @@ fn process_cgi(filename: String) -> Option> { } let output; - if query != "" { + if query != "".to_string() && post_data.is_some() { + let mut child = Command::new(format!("./{}", script)) + .env("GATEWAY_INTERFACE", "CGI/1.1") + .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) + .env("REQUEST_METHOD", "POST") + .env("QUERY_STRING", query) + .env("SCRIPT_NAME", script) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(post_data.unwrap().as_bytes()).unwrap(); + output = child.wait_with_output(); + } else if query == "".to_string() && post_data.is_some() { + let mut child = Command::new(format!("./{}", script)) + .env("GATEWAY_INTERFACE", "CGI/1.1") + .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) + .env("REQUEST_METHOD", "POST") + .env("SCRIPT_NAME", script) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(post_data.unwrap().as_bytes()).unwrap(); + output = child.wait_with_output(); + } + else if query != "" { output = Command::new(format!("./{}", script)) .env("GATEWAY_INTERFACE", "CGI/1.1") .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) @@ -79,7 +109,7 @@ fn process_cgi(filename: String) -> Option> { } } -fn process_cgi_with_path(filename: String, segments: Vec, location: i32) -> Option> { +fn process_cgi_with_path(filename: String, segments: Vec, location: i32, post_data: Option) -> Option> { let mut query: String = "".to_string(); let script = filename; @@ -104,22 +134,52 @@ fn process_cgi_with_path(filename: String, segments: Vec, location: i32) path = format!("{}/", path); let output; - if query != "".to_string() { - output = Command::new(format!("./{}", script)) + if query != "".to_string() && post_data.is_some() { + let mut child = Command::new(format!("./{}", script.clone())) + .env("GATEWAY_INTERFACE", "CGI/1.1") + .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) + .env("REQUEST_METHOD", "POST") + .env("QUERY_STRING", query) + .env("PATH_INFO", path.clone()) + .env("SCRIPT_NAME", script.clone()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(post_data.unwrap().as_bytes()).unwrap(); + output = child.wait_with_output(); + } else if query == "".to_string() && post_data.is_some() { + let mut child = Command::new(format!("./{}", script.clone())) + .env("GATEWAY_INTERFACE", "CGI/1.1") + .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) + .env("REQUEST_METHOD", "POST") + .env("PATH_INFO", path.clone()) + .env("SCRIPT_NAME", script.clone()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(post_data.unwrap().as_bytes()).unwrap(); + output = child.wait_with_output(); + } + else if query != "".to_string() && post_data.is_none() { + output = Command::new(format!("./{}", script.clone())) .env("GATEWAY_INTERFACE", "CGI/1.1") .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) .env("REQUEST_METHOD", "GET") .env("QUERY_STRING", query) - .env("PATH_INFO", path) - .env("SCRIPT_NAME", script) + .env("PATH_INFO", path.clone()) + .env("SCRIPT_NAME", script.clone()) .output(); } else { - output = Command::new(format!("./{}", script)) + output = Command::new(format!("./{}", script.clone())) .env("GATEWAY_INTERFACE", "CGI/1.1") .env("SERVER_SOFTWARE", format!("herb/{}", env!("CARGO_PKG_VERSION"))) .env("REQUEST_METHOD", "GET") - .env("PATH_INFO", path) - .env("SCRIPT_NAME", script) + .env("PATH_INFO", path.clone()) + .env("SCRIPT_NAME", script.clone()) .output(); } if output.is_ok() { @@ -242,7 +302,7 @@ fn get_page(filename: String, settings: Settings) -> GetPageResult { return resultstruct; } - let result = process_cgi(filename); + let result = process_cgi(filename, None); if result.is_some() { resultstruct.contents = result.unwrap(); resultstruct.iscgi = true; @@ -263,7 +323,7 @@ fn get_page(filename: String, settings: Settings) -> GetPageResult { return resultstruct; } - let result = process_cgi(filename); + let result = process_cgi(filename, None); if result.is_some() { resultstruct.contents = result.unwrap(); resultstruct.iscgi = true; @@ -370,7 +430,7 @@ fn process_request(request: Vec, settings: Settings) -> Resource { return resource; } - let contents = process_cgi_with_path(cgipathraw, segclone, cgiscript); + let contents = process_cgi_with_path(cgipathraw, segclone, cgiscript, None); if contents.is_some() { let resource = Resource { contents: contents.unwrap(), status_code: 200, mime: "text/html".to_string(), iscgi: true }; return resource;