From af4ab2e39df8ba1d49209303095bfcf3c969d0d9 Mon Sep 17 00:00:00 2001 From: Darius Auding <Darius.auding@gmx.de> Date: Fri, 23 Jun 2023 14:41:15 +0200 Subject: [PATCH] refactoring the request module, add cookie functionality --- core/http/src/handlers/handlers.rs | 4 +- core/http/src/handling/request/cookies.rs | 54 ++++++++++++ core/http/src/handling/request/datatypes.rs | 73 ++++++++++++++++ core/http/src/handling/request/mod.rs | 5 ++ .../{request.rs => request/request_impl.rs} | 84 ++----------------- 5 files changed, 141 insertions(+), 79 deletions(-) create mode 100644 core/http/src/handling/request/cookies.rs create mode 100644 core/http/src/handling/request/datatypes.rs create mode 100644 core/http/src/handling/request/mod.rs rename core/http/src/handling/{request.rs => request/request_impl.rs} (84%) diff --git a/core/http/src/handlers/handlers.rs b/core/http/src/handlers/handlers.rs index df6ec34..32376bc 100755 --- a/core/http/src/handlers/handlers.rs +++ b/core/http/src/handlers/handlers.rs @@ -4,7 +4,7 @@ use tokio::{io::{AsyncReadExt, BufReader, AsyncBufReadExt, AsyncWriteExt}, net:: use crate::handling::{ file_handlers::NamedFile, - request::Request, + request::{Request, extract_cookies_from_vec}, response::{Outcome, Response, ResponseBody, Status}, routes::Data, methods::Method, }; @@ -42,7 +42,7 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin eprintln!("\x1b[31mAborting due to invalid status line\x1b[0m"); return; }, - cookies: None, + cookies: extract_cookies_from_vec(&mut http_request), headers: http_request, method: if let Some(method) = request_status_line .split(" ") diff --git a/core/http/src/handling/request/cookies.rs b/core/http/src/handling/request/cookies.rs new file mode 100644 index 0000000..c9d0fcd --- /dev/null +++ b/core/http/src/handling/request/cookies.rs @@ -0,0 +1,54 @@ +use std::collections::HashMap; + +pub fn extract_cookies_from_vec(headers: &mut Vec<String>) -> Option<HashMap<String, String>> { + let mut cookies: HashMap<String, String> = HashMap::new(); + let mut cookies_string = if let Some(index) = headers + .iter() + .position(|header| header.starts_with("Cookie: ")) + { + headers.remove(index) + } else { + return None; + }; + cookies_string = cookies_string + .strip_prefix("Cookie: ") + .unwrap() + .trim() + .to_string(); + for cookie in cookies_string.split(';') { + let Some((name, cookie)) = cookie.split_once('=') else { + return None; + }; + cookies + .entry(name.trim().to_string()) + .or_insert(cookie.trim().to_string()); + } + Some(cookies) +} + +#[cfg(test)] +mod test { + use crate::handling::request::extract_cookies_from_vec; + + #[test] + fn test_cookies() { + let mut request_vec = vec![ + "GET / HTTP/1.1".to_string(), + "Accept: sdf".to_string(), + "Cookie: io=23; f=as".to_string(), + "Format: gzip".to_string(), + ]; + let right_finished_vec = vec![ + "GET / HTTP/1.1".to_string(), + "Accept: sdf".to_string(), + "Format: gzip".to_string(), + ]; + + let mut wrong = vec!["GET / HTTP/1.1".to_string()]; + assert_eq!(None, extract_cookies_from_vec(&mut wrong)); + let cookies = extract_cookies_from_vec(&mut request_vec); + assert_eq!(right_finished_vec, request_vec); + assert_eq!("23", cookies.clone().unwrap().get("io").unwrap()); + assert_eq!("as", cookies.unwrap().get("f").unwrap()); + } +} diff --git a/core/http/src/handling/request/datatypes.rs b/core/http/src/handling/request/datatypes.rs new file mode 100644 index 0000000..68e32d5 --- /dev/null +++ b/core/http/src/handling/request/datatypes.rs @@ -0,0 +1,73 @@ +use std::{collections::HashMap, error::Error, fmt::Display}; + +use crate::handling::{methods::Method, routes::Uri}; + +pub trait FromRequest: Send { + fn get_data(&self) -> &Self; + fn set_data(&mut self, data: &Self); + fn append(&mut self, data: &Self); +} + +impl FromRequest for Vec<u8> { + fn get_data(&self) -> &Self { + &self + } + + fn set_data(&mut self, data: &Self) { + *self = data.to_vec(); + } + fn append(&mut self, data: &Self) { + self.extend_from_slice(data); + } +} + +type HeaderMap = Vec<String>; + +#[derive(Clone)] +pub struct Request<'a> { + pub uri: Uri<'a>, + pub headers: HeaderMap, + pub method: Method, + pub cookies: Option<HashMap<String, String>>, + // pub connection: ConnectionMeta, +} + +// struct ConnectionMeta { +// remote: Option<SocketAddr>, +// // certificates +// } + +#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum MediaType { + Json, + Plain, + Html, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ParseErrors { + NoData, + BadData, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct ParseFormError { + pub error: ParseErrors, +} + +impl Display for ParseFormError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.error) + } +} + +impl Display for ParseErrors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParseErrors::NoData => write!(f, "No Data at key"), + ParseErrors::BadData => write!(f, "Bad Data at key"), + } + } +} + +impl Error for ParseFormError {} diff --git a/core/http/src/handling/request/mod.rs b/core/http/src/handling/request/mod.rs new file mode 100644 index 0000000..23c9f1a --- /dev/null +++ b/core/http/src/handling/request/mod.rs @@ -0,0 +1,5 @@ +mod cookies; +mod datatypes; +mod request_impl; +pub use cookies::extract_cookies_from_vec; +pub use datatypes::{MediaType, ParseFormError, Request}; diff --git a/core/http/src/handling/request.rs b/core/http/src/handling/request/request_impl.rs similarity index 84% rename from core/http/src/handling/request.rs rename to core/http/src/handling/request/request_impl.rs index 8841901..2c582ea 100644 --- a/core/http/src/handling/request.rs +++ b/core/http/src/handling/request/request_impl.rs @@ -1,85 +1,15 @@ // use std::net::SocketAddr; -use std::{collections::HashMap, error::Error, fmt::Display}; +use std::collections::HashMap; -use crate::utils::mime::mime_enum::Mime; - -static TWO_NEWLINES: u8 = 3; - -use super::{ - methods::Method, - routes::{Data, Uri}, +use crate::{ + handling::{methods::Method, routes::Data}, + utils::mime::mime_enum::Mime, }; -pub trait FromRequest: Send { - fn get_data(&self) -> &Self; - fn set_data(&mut self, data: &Self); - fn append(&mut self, data: &Self); -} - -impl FromRequest for Vec<u8> { - fn get_data(&self) -> &Self { - &self - } - - fn set_data(&mut self, data: &Self) { - *self = data.to_vec(); - } - fn append(&mut self, data: &Self) { - self.extend_from_slice(data); - } -} - -type HeaderMap = Vec<String>; - -#[derive(Clone)] -pub struct Request<'a> { - pub uri: Uri<'a>, - pub headers: HeaderMap, - pub method: Method, - pub cookies: Option<Vec<&'a str>>, - // pub connection: ConnectionMeta, -} - -// struct ConnectionMeta { -// remote: Option<SocketAddr>, -// // certificates -// } +use super::datatypes::{ParseErrors, ParseFormError, Request}; -#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum MediaType { - Json, - Plain, - Html, -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum ParseErrors { - NoData, - BadData, -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct ParseFormError { - pub error: ParseErrors, -} - -impl Display for ParseFormError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.error) - } -} - -impl Display for ParseErrors { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ParseErrors::NoData => write!(f, "No Data at key"), - ParseErrors::BadData => write!(f, "Bad Data at key"), - } - } -} - -impl Error for ParseFormError {} +static TWO_NEWLINES: u8 = 3; impl Request<'_> { pub fn can_have_body(&self) -> bool { @@ -98,7 +28,7 @@ impl Request<'_> { &'a self, keys: &'a [&str], ) -> Result<HashMap<&str, Result<&str, ParseFormError>>, ParseFormError> { - let data = if let Some(val) = self.uri.split_once("?") { + let data = if let Some(val) = self.uri.split_once('?') { val } else { return Err(ParseFormError { -- GitLab