Add further impl for mainloop
This commit is contained in:
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"vadimcn.vscode-lldb",
|
||||
"tamasfe.even-better-toml",
|
||||
"vscodevim.vim",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
]
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"color",
|
||||
"conn",
|
||||
"resp"
|
||||
]
|
||||
}
|
||||
+54
-46
@@ -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
@@ -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
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user