Add further impl for mainloop

This commit is contained in:
2026-08-20 00:47:52 +08:00
parent 137028ac03
commit eaf76dfe29
5 changed files with 102 additions and 64 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"recommendations": [
"rust-lang.rust-analyzer",
"vadimcn.vscode-lldb",
"tamasfe.even-better-toml",
"vscodevim.vim",
"streetsidesoftware.code-spell-checker"
]
}
+7
View File
@@ -0,0 +1,7 @@
{
"cSpell.words": [
"color",
"conn",
"resp"
]
}
+54 -46
View File
@@ -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::<String>::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<Vec<Header>> =
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<PathBuf> = 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<usize, _> = 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<TcpStream>) -> Response {
let mut req = Vec::<String>::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::<ReqLine>() {
req_line
} else {
return Response::invalid_request();
}
} else {
return Response::invalid_request();
};
let mut headers: Vec<Header> = 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()
}
+13 -7
View File
@@ -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<Header>,
}
+19 -11
View File
@@ -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<Header>,
pub struct Response {
pub version: Version,
pub status: Status,
pub headers: Vec<Header>,
}
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() }
}
}