work done in school

This commit is contained in:
maxstrb 2025-10-06 19:10:16 +02:00
parent 320a93118f
commit 860ddc7cf4
37 changed files with 146 additions and 18 deletions

View file

@ -1,11 +1,13 @@
use crate::shared_enums::ContentType;
use std::{
io::{self, BufRead, BufReader, Read},
io::{self, BufRead, BufReader, Read, Take},
net::TcpStream,
str::FromStr,
};
const MAX_LINE_WIDTH: u64 = 4096; // 4 KiB
const MAX_BODY_LENGTH: u64 = 8388608; // 5 MiB
const MAX_HEADER_COUNT: u64 = 512;
pub struct Request {
method: Method,
@ -23,37 +25,96 @@ pub enum RequestHeader {
Other(String, String),
}
impl FromStr for RequestHeader {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let
}
}
impl Request {
pub fn from_bufreader(buffer: BufReader<&TcpStream>) -> io::Result<Self> {
let mut first_line = Vec::<u8>::new();
let mut limited_buffer = buffer.take(MAX_LINE_WIDTH);
limited_buffer.read_until(b'\n', &mut first_line)?;
println!("{}", String::from_utf8_lossy(&first_line));
first_line.clear();
limited_buffer.set_limit(MAX_LINE_WIDTH);
limited_buffer.read_until(b'\n', &mut first_line)?;
println!("{}", String::from_utf8_lossy(&first_line));
let first_line = Self::read_line(&mut limited_buffer)?;
let parsed_first_line = Self::parse_first_line(first_line)?;
Ok(Self {
method: Method::Get,
http_version: "HTTP/1.1".to_string(),
path: ServerPath {
path: vec![],
options: vec![],
},
method: parsed_first_line.0,
path: parsed_first_line.1,
http_version: parsed_first_line.2,
headers: vec![],
data: vec![],
})
}
fn read_line(buffer: &mut Take<BufReader<&TcpStream>>) -> io::Result<String> {
let mut read_buffer = vec![];
buffer.set_limit(MAX_LINE_WIDTH);
buffer.read_until(b'\n', &mut read_buffer)?;
Ok(String::from_utf8_lossy(&read_buffer).to_string())
}
fn parse_first_line(line: String) -> io::Result<(Method, ServerPath, String)> {
let splitted_line: Vec<&str> = line.split_whitespace().collect();
match splitted_line.as_slice() {
[method, path, "HTTP/1.1"] => Ok((
Method::from_str(method)?,
ServerPath::from_str(path)?,
"HTTP/1.1".to_string(),
)),
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"Incorrect HTTP first line",
)),
}
}
}
pub struct ServerPath {
path: Vec<String>,
options: Vec<(String, String)>,
query: Vec<(String, String)>,
}
impl FromStr for ServerPath {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.split("?").collect::<Vec<&str>>().as_slice() {
[path, query] => {
let mut query_hashset: std::collections::hash_set::HashSet<String> =
std::collections::hash_set::HashSet::new();
let query_parsed = query
.split('&')
.filter_map(|s| match s.split('=').collect::<Vec<&str>>().as_slice() {
[parameter, value] => {
if query_hashset.contains(*parameter) {
None
} else {
query_hashset.insert(parameter.to_string());
Some((parameter.to_string(), value.to_string()))
}
}
_ => None,
})
.collect();
Ok(Self {
path: path
.split('/')
.filter(|s| !s.is_empty() && !s.starts_with('.'))
.map(|s| s.to_string())
.collect(),
query: query_parsed,
})
}
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid path")),
}
}
}
pub enum Method {
@ -67,3 +128,25 @@ pub enum Method {
Put,
Trace,
}
impl FromStr for Method {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"GET" => Ok(Self::Get),
"POST" => Ok(Self::Post),
"CONNECT" => Ok(Self::Connect),
"DELETE" => Ok(Self::Delete),
"HEAD" => Ok(Self::Head),
"OPTIONS" => Ok(Self::Options),
"PATCH" => Ok(Self::Patch),
"PUT" => Ok(Self::Put),
"TRACE" => Ok(Self::Trace),
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid HTTP method",
)),
}
}
}