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 request;
|
||||||
mod response;
|
mod response;
|
||||||
|
|
||||||
use request::{Header, ReqLine};
|
use color_eyre::eyre;
|
||||||
|
use request::{Request, Header, ReqLine};
|
||||||
use response::{Response, Version, Status};
|
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::net::TcpStream;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
|
|
||||||
pub fn handle_connection(conn: TcpStream) -> color_eyre::Result<()> {
|
pub fn handle_connection(conn: TcpStream) -> eyre::Result<()> {
|
||||||
info!("Reveiced new connection from {}", conn.peer_addr()?);
|
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 writer = BufWriter::new(conn);
|
||||||
|
|
||||||
let mut req = Vec::<String>::with_capacity(0x10);
|
let resp = handle_request(reader.by_ref());
|
||||||
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 count: Result<usize, _> = resp.as_str_list().into_iter()
|
let count: Result<usize, _> = resp.as_str_list().into_iter()
|
||||||
.map(|s| writer.write(s.as_bytes()))
|
.map(|s| writer.write(s.as_bytes()))
|
||||||
@@ -68,3 +29,50 @@ pub fn handle_connection(conn: TcpStream) -> color_eyre::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
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;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ReqLine {
|
pub struct ReqLine {
|
||||||
pub(crate) method: String,
|
pub method: String,
|
||||||
pub(crate) route: String,
|
pub route: String,
|
||||||
pub(crate) version: String,
|
pub version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for ReqLine {
|
impl FromStr for ReqLine {
|
||||||
@@ -26,9 +26,9 @@ impl FromStr for ReqLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Header {
|
pub struct Header {
|
||||||
pub(crate) key: String,
|
pub key: String,
|
||||||
pub(crate) value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Header {
|
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)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) enum Version {
|
pub enum Version {
|
||||||
#[default]
|
#[default]
|
||||||
V11,
|
V11,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) enum Status {
|
pub enum Status {
|
||||||
#[default]
|
#[default]
|
||||||
OK,
|
OK,
|
||||||
NotFound,
|
NotFound,
|
||||||
@@ -37,26 +37,26 @@ impl AsStaticStr for Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct Header {
|
pub struct Header {
|
||||||
pub(crate) key: String,
|
pub key: String,
|
||||||
pub(crate) value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
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())
|
(self.key.as_str(), self.value.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct Response {
|
pub struct Response {
|
||||||
pub(crate) version: Version,
|
pub version: Version,
|
||||||
pub(crate) status: Status,
|
pub status: Status,
|
||||||
pub(crate) headers: Vec<Header>,
|
pub headers: Vec<Header>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
pub(crate) fn as_str_list(&self) -> Vec<&str> {
|
pub fn as_str_list(&self) -> Vec<&str> {
|
||||||
let mut ret = vec!(
|
let mut ret = vec!(
|
||||||
self.version.as_str(),
|
self.version.as_str(),
|
||||||
" ",
|
" ",
|
||||||
@@ -76,4 +76,12 @@ impl Response {
|
|||||||
ret.push("\r\n");
|
ret.push("\r\n");
|
||||||
ret
|
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