From cfebf65b706be63e0531b62bc03034ec870a0fad Mon Sep 17 00:00:00 2001 From: gennyble Date: Sat, 31 May 2025 10:31:17 -0500 Subject: initial commit; support for text/plain --- src/main.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/main.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..61203f6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,104 @@ +use std::{net::SocketAddr, sync::Arc}; + +use httparse::{Request, Status}; +use smol::{ + LocalExecutor, future, + io::{AsyncReadExt, AsyncWriteExt}, + net::{TcpListener, TcpStream}, +}; + +fn main() { + let exec = LocalExecutor::new(); + let arxc = Arc::new(exec); + + let moving_arxc = Arc::clone(&arxc); + future::block_on(arxc.run(async move { async_main(moving_arxc).await })); +} + +async fn async_main(ex: Arc>) { + let addr = SocketAddr::from(([0, 0, 0, 0], 12345)); + let listen = TcpListener::bind(addr).await.unwrap(); + + loop { + let (stream, caddr) = listen.accept().await.unwrap(); + println!("accepted!"); + ex.spawn(async move { handle_request(stream, caddr).await }) + .detach(); + } +} + +async fn handle_request(mut stream: TcpStream, caddr: SocketAddr) { + let mut buffer = vec![0; 1024]; + let mut data_end = 0; + loop { + println!("Waiting on read"); + match stream.read(&mut buffer).await { + Err(_err) => { + eprintln!("Error in handle_request during read. Bailing."); + return; + } + Ok(bytes_read) => { + data_end += bytes_read; + println!("read {bytes_read}"); + } + } + + let mut headers = [httparse::EMPTY_HEADER; 64]; + let mut req = Request::new(&mut headers); + + match req.parse(&buffer[..data_end]) { + Err(err) => { + eprintln!("Error in handle_request during parsing. Bailing.\nerror: {err}"); + return; + } + Ok(Status::Partial) => { + // Going around again. + // Make sure we have room in the buffer. 512 seems good :) + if buffer.len() == data_end { + buffer.resize(buffer.len() + 512, 0); + } + println!("partial!"); + + continue; + } + Ok(Status::Complete(body_offset)) => { + println!("Got entire request!"); + println!("method: {}", req.method.unwrap()); + println!("path: {}", req.path.unwrap()); + println!("body_offset: {body_offset}"); + } + } + + let minor = req.version.unwrap(); + let status = 200; + let message = "Gotcha"; + + // Fall through the match. We should guarantee that, if we end up here, + // we got a Status::Complete from the parser + let mut response = format!("HTTP/1.{minor} {status} {message}\n"); + + let body = format!("{}", caddr.ip()); + let length = body.len(); + + macro_rules! header { + ($content:expr) => { + response.push_str(&format!($content)); + response.push('\n'); + }; + } + + header!("Content-Length: {length}"); + header!("Content-Type: text/plain"); + header!("Cache-Control: no-store"); + + response.push('\n'); + response.push_str(&body); + + if let Err(err) = stream.write_all(response.as_bytes()).await { + eprintln!("Error in handle_request sending response back. Bailing.\nError: {err}"); + return; + } else { + return; + } + } +} -- cgit 1.4.1-3-g733a5