about summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..72abb0e
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,131 @@
+use core::panic;
+use std::{net::SocketAddr, pin::Pin};
+
+use http_body_util::{BodyExt, Full};
+use hyper::{
+	Request, Response, StatusCode,
+	body::{Body, Bytes, Incoming},
+	server::conn::http1,
+	service::Service,
+};
+use hyper_util::rt::TokioIo;
+use tokio::{net::TcpListener, process::Command, runtime::Runtime};
+
+fn main() {
+	let rt = Runtime::new().unwrap();
+	rt.block_on(async { run().await });
+}
+
+async fn run() {
+	let addr = SocketAddr::from(([0, 0, 0, 0], 2562));
+	let listen = TcpListener::bind(addr).await.unwrap();
+
+	let svc = Svc {};
+
+	loop {
+		let (stream, _caddr) = listen.accept().await.unwrap();
+		let io = TokioIo::new(stream);
+		let svc_clone = svc.clone();
+		tokio::task::spawn(
+			async move { http1::Builder::new().serve_connection(io, svc_clone).await },
+		);
+	}
+}
+
+#[derive(Clone, Debug)]
+struct Svc {}
+
+impl Service<Request<Incoming>> for Svc {
+	type Response = Response<Full<Bytes>>;
+	type Error = hyper::Error;
+	type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
+
+	fn call(&self, req: Request<Incoming>) -> Self::Future {
+		fn make<B: Into<Bytes>>(b: B) -> Result<Response<Full<Bytes>>, hyper::Error> {
+			Ok(Response::builder().body(Full::new(b.into())).unwrap())
+		}
+
+		Box::pin(async { Ok(Self::handle(req).await) })
+	}
+}
+
+impl Svc {
+	async fn handle(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);
+
+		for (header, value) in headers {
+			if let Some(header) = header {
+				let hname = header.as_str();
+				let hvalue = value.to_str().unwrap();
+				cmd.env(hname.to_ascii_uppercase(), hvalue);
+
+				if hname.to_ascii_lowercase() == "user-agent" {
+					println!("USER_AGENT: {hvalue}");
+				}
+			}
+		}
+
+		/*if content_length > 0 {
+			cmd.env("CONTENT_LENGTH", content_length.to_string());
+		}*/
+
+		let output = cmd.output().await.unwrap();
+		let response_raw = output.stdout;
+		let mut response = Response::builder();
+
+		println!("{}", String::from_utf8_lossy(&response_raw));
+
+		let mut curr = response_raw.as_slice();
+		let mut status = None;
+		let mut headers = vec![];
+		let body = loop {
+			let nl = curr.iter().position(|b| *b == b'\n').expect("no nl in header");
+			let line = &curr[..nl];
+
+			let colon = line.iter().position(|b| *b == b':').expect("no colon in header");
+			let key = &line[..colon];
+			let value = &line[colon + 1..];
+			headers.push((key, value));
+
+			let key_string = String::from_utf8_lossy(key);
+			if key_string == "Status" {
+				let value_string = String::from_utf8_lossy(value);
+				if let Some((raw_code, raw_msg)) = value_string.trim().split_once(' ') {
+					let code: usize = raw_code.parse().unwrap();
+					status = Some((code, raw_msg.to_owned()));
+				}
+			}
+
+			// Body next
+			if curr[nl + 1] == b'\n' || (curr[nl + 1] == b'\r' && curr[nl + 2] == b'\n') {
+				break &curr[nl + 2..];
+			} else {
+				curr = &curr[nl + 1..];
+			}
+		};
+
+		match status {
+			None => response = response.status(StatusCode::OK),
+			Some((code, _status)) => {
+				response = response.status(StatusCode::from_u16(code as u16).unwrap());
+			}
+		}
+
+		for (key, value) in headers {
+			response = response.header(key.to_vec(), value.to_vec());
+		}
+
+		response.body(Full::new(Bytes::from(body.to_vec()))).unwrap()
+	}
+
+	fn make<B: Into<Bytes>>(b: B) -> Response<Full<Bytes>> {
+		Response::builder().body(Full::new(b.into())).unwrap()
+	}
+}