From eaf76dfe29cc87d8eebae5e5b8c5b9517b940ff4 Mon Sep 17 00:00:00 2001 From: 12hydrogen Date: Thu, 20 Aug 2026 00:44:24 +0800 Subject: [PATCH] Add further impl for mainloop --- .vscode/extensions.json | 9 ++++ .vscode/settings.json | 7 +++ src/lib.rs | 100 ++++++++++++++++++++++------------------ src/request.rs | 20 +++++--- src/response.rs | 30 +++++++----- 5 files changed, 102 insertions(+), 64 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..00a3a80 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "rust-lang.rust-analyzer", + "vadimcn.vscode-lldb", + "tamasfe.even-better-toml", + "vscodevim.vim", + "streetsidesoftware.code-spell-checker" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d15e403 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "color", + "conn", + "resp" + ] +} diff --git a/src/lib.rs b/src/lib.rs index 1bf6ea7..a33d29a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,63 +1,24 @@ mod request; mod response; -use request::{Header, ReqLine}; +use color_eyre::eyre; +use request::{Request, Header, ReqLine}; use response::{Response, Version, Status}; -use std::io::{BufReader, BufWriter, Read, Write}; +use std::io::{BufReader, BufWriter, ErrorKind, Read, Write}; use std::net::TcpStream; use std::fs::File; use std::path::{Path, PathBuf}; use log::{debug, info}; -pub fn handle_connection(conn: TcpStream) -> color_eyre::Result<()> { - info!("Reveiced new connection from {}", conn.peer_addr()?); +pub fn handle_connection(conn: TcpStream) -> eyre::Result<()> { + info!("Received new connection from {}", conn.peer_addr()?); - let reader = BufReader::new(conn.try_clone()?); + let mut reader = BufReader::new(conn.try_clone()?); let mut writer = BufWriter::new(conn); - let mut req = Vec::::with_capacity(0x10); - loop { - let mut buffer = String::with_capacity(0x100); - for byte in reader.get_ref().bytes() { - buffer.push(byte? as char); - if buffer.ends_with("\r\n") { - break; - } - } - if buffer.trim().is_empty() { - break; - } - buffer.shrink_to_fit(); - req.push(buffer); - } - let req_line: ReqLine = req - .get(0) - .ok_or(std::io::Error::other("Missing request line."))? - .trim() - .parse()?; - - let headers: std::io::Result> = - req.iter().skip(1).map(|line| line.parse()).collect(); - - debug!( - "{} {} {}", - req_line.method, req_line.route, req_line.version - ); - for line in headers? { - debug!("{}: {}", line.key, line.value); - } - - let file_path: Option = req_line.route.starts_with("/").then(|| { - req_line.route.split("/").map(|s| Path::new(a)).collect() - }); - - let file_path = file_path.map(|p_buf| p_buf.canonicalize()); - - let file = file_path.map(|f_path| { - f_path.map(|f_path| File::open(f_path)) - }); + let resp = handle_request(reader.by_ref()); let count: Result = resp.as_str_list().into_iter() .map(|s| writer.write(s.as_bytes())) @@ -68,3 +29,50 @@ pub fn handle_connection(conn: TcpStream) -> color_eyre::Result<()> { Ok(()) } + +fn handle_request(reader: &mut BufReader) -> Response { + let mut req = Vec::::with_capacity(0x10); + loop { + let mut buffer = String::with_capacity(0x100); + for byte in reader.bytes() { + match byte { + Err(err) if err.kind() == ErrorKind::Interrupted => continue, + Ok(byte) => { + buffer.push(byte as char); + if buffer.ends_with("\r\n") { + break; + } + } + Err(_) => return Response::invalid_request() + + } + } + if buffer.trim().is_empty() { + break; + } + buffer.shrink_to_fit(); + req.push(buffer); + } + + let req_line = if let Some(req_line) = req.get(0) { + if let Ok(req_line) = req_line.parse::() { + req_line + } else { + return Response::invalid_request(); + } + } else { + return Response::invalid_request(); + }; + + let mut headers: Vec
= Vec::with_capacity(req.len() - 1); + + for line in req.iter().skip(1) { + if let Ok(header) = line.parse() { + headers.push(header); + } else { + return Response::invalid_request(); + } + } + + Response::valid_request() +} diff --git a/src/request.rs b/src/request.rs index 73cf53a..64333f2 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,10 +1,10 @@ use std::str::FromStr; #[derive(Debug)] -pub(crate) struct ReqLine { - pub(crate) method: String, - pub(crate) route: String, - pub(crate) version: String, +pub struct ReqLine { + pub method: String, + pub route: String, + pub version: String, } impl FromStr for ReqLine { @@ -26,9 +26,9 @@ impl FromStr for ReqLine { } #[derive(Debug)] -pub(crate) struct Header { - pub(crate) key: String, - pub(crate) value: String, +pub struct Header { + pub key: String, + pub value: String, } impl FromStr for Header { @@ -44,3 +44,9 @@ impl FromStr for Header { }) } } + +#[derive(Debug)] +pub struct Request { + pub req_line: ReqLine, + pub headers: Vec
, +} diff --git a/src/response.rs b/src/response.rs index 9adbe20..044ca97 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,11 +1,11 @@ #[derive(Debug, Default)] -pub(crate) enum Version { +pub enum Version { #[default] V11, } #[derive(Debug, Default)] -pub(crate) enum Status { +pub enum Status { #[default] OK, NotFound, @@ -37,26 +37,26 @@ impl AsStaticStr for Status { } #[derive(Debug, Default)] -pub(crate) struct Header { - pub(crate) key: String, - pub(crate) value: String, +pub struct Header { + pub key: String, + pub value: String, } impl Header { - pub(crate) fn as_str(&self) -> (&str, &str) { + pub fn as_str(&self) -> (&str, &str) { (self.key.as_str(), self.value.as_str()) } } #[derive(Debug, Default)] -pub(crate) struct Response { - pub(crate) version: Version, - pub(crate) status: Status, - pub(crate) headers: Vec
, +pub struct Response { + pub version: Version, + pub status: Status, + pub headers: Vec
, } impl Response { - pub(crate) fn as_str_list(&self) -> Vec<&str> { + pub fn as_str_list(&self) -> Vec<&str> { let mut ret = vec!( self.version.as_str(), " ", @@ -76,4 +76,12 @@ impl Response { ret.push("\r\n"); ret } + + pub fn valid_request() -> Self { + Self { ..Default::default() } + } + + pub fn invalid_request() -> Self { + Self { version: Version::V11, status: Status::BadRequest, ..Default::default() } + } }