diff options
author | gennyble <gen@nyble.dev> | 2025-03-11 16:34:13 -0500 |
---|---|---|
committer | gennyble <gen@nyble.dev> | 2025-03-11 16:34:13 -0500 |
commit | a3798984ad4d77ae66d28478a19fb3e50e7a64f7 (patch) | |
tree | fc141dfd17aa86028e02f1e51575f295a2a3954f | |
parent | 912ce0966c42f126d7a37c88e442e16a30308415 (diff) | |
download | corgi-a3798984ad4d77ae66d28478a19fb3e50e7a64f7.tar.gz corgi-a3798984ad4d77ae66d28478a19fb3e50e7a64f7.zip |
allow setting script path to execute
-rw-r--r-- | Cargo.lock | 7 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | TODO.md | 8 | ||||
-rw-r--r-- | corgi.conf | 1 | ||||
-rw-r--r-- | src/main.rs | 39 |
6 files changed, 51 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock index 55b19f3..25241c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,9 +45,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "confindent" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a06ecfd8e0b653f5b0a1b083f74a275d2aab7834b90bce8c66f3c0b2f53fb1" + +[[package]] name = "corgi" version = "0.1.0" dependencies = [ + "confindent", "http-body-util", "hyper", "hyper-util", diff --git a/Cargo.toml b/Cargo.toml index 206071d..77232e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +confindent = "2.2.0" http-body-util = "0.1.3" hyper-util = { version = "0.1.10", features = ["tokio"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..152c6b7 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +corgi is a CGI server. + +currently, it can handle on application. \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..862bb82 --- /dev/null +++ b/TODO.md @@ -0,0 +1,8 @@ +(1) Support Multiple CGI Scripts + This is needed even just for the cgit and git server target. + We need to be able to support the cgit executable itself, and + also git-http-backend for smart clones. + +(2) Support Matching CGI Based On Path + The other requirement for git-http-backend, which needs to + trigger on the regex `/.+/(info/refs|git-upload-pack)` \ No newline at end of file diff --git a/corgi.conf b/corgi.conf new file mode 100644 index 0000000..065d9ea --- /dev/null +++ b/corgi.conf @@ -0,0 +1 @@ +Script /usr/lib/cgit/cgit.cgi \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 72abb0e..e0f20a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use core::panic; use std::{net::SocketAddr, pin::Pin}; +use confindent::Confindent; use http_body_util::{BodyExt, Full}; use hyper::{ Request, Response, StatusCode, @@ -11,16 +12,33 @@ use hyper::{ use hyper_util::rt::TokioIo; use tokio::{net::TcpListener, process::Command, runtime::Runtime}; +#[derive(Clone, Debug)] +pub struct Settings { + script_filename: String, + env: Vec<(String, String)>, +} + +const CONF_DEFAULT: &str = "/etc/corgi.conf"; + fn main() { + let conf_path = std::env::args().nth(1).unwrap_or(String::from(CONF_DEFAULT)); + let conf = Confindent::from_file(conf_path).expect("failed to open conf"); + + let script = conf.child("Script").expect("no 'Script' key in conf"); + let settings = Settings { + script_filename: script.value_owned().expect("'Script' key has no value'"), + env: vec![], + }; + let rt = Runtime::new().unwrap(); - rt.block_on(async { run().await }); + rt.block_on(async { run(settings).await }); } -async fn run() { +async fn run(settings: Settings) { let addr = SocketAddr::from(([0, 0, 0, 0], 2562)); let listen = TcpListener::bind(addr).await.unwrap(); - let svc = Svc {}; + let svc = Svc { settings }; loop { let (stream, _caddr) = listen.accept().await.unwrap(); @@ -33,7 +51,9 @@ async fn run() { } #[derive(Clone, Debug)] -struct Svc {} +struct Svc { + settings: Settings, +} impl Service<Request<Incoming>> for Svc { type Response = Response<Full<Bytes>>; @@ -45,20 +65,23 @@ impl Service<Request<Incoming>> for Svc { Ok(Response::builder().body(Full::new(b.into())).unwrap()) } - Box::pin(async { Ok(Self::handle(req).await) }) + let settings = self.settings.clone(); + Box::pin(async { Ok(Self::handle(settings, req).await) }) } } impl Svc { - async fn handle(req: Request<Incoming>) -> Response<Full<Bytes>> { + async fn handle(settings: Settings, req: Request<Incoming>) -> Response<Full<Bytes>> { let method = req.method().as_str().to_ascii_uppercase(); let path = req.uri().path().to_owned(); let headers = req.headers().clone(); let body = req.into_body().collect().await.unwrap().to_bytes(); let content_length = body.len(); - let mut cmd = Command::new("/usr/lib/cgit/cgit.cgi"); - cmd.env("PATH_INFO", path).env("REQUEST_METHOD", method); + let mut cmd = Command::new(&settings.script_filename); + cmd.env("SCRIPT_NAME", settings.script_filename) + .env("PATH_INFO", path) + .env("REQUEST_METHOD", method); for (header, value) in headers { if let Some(header) = header { |