work done in school
This commit is contained in:
parent
320a93118f
commit
860ddc7cf4
37 changed files with 146 additions and 18 deletions
119
src/request.rs
119
src/request.rs
|
|
@ -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",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue