From 9e2911847edd441a82d68660b5d871e8d8d7ae67 Mon Sep 17 00:00:00 2001 From: Darius Auding <Darius.auding@gmx.de> Date: Thu, 29 Jun 2023 21:58:41 +0200 Subject: [PATCH] New Documentation and changing Request mime type to (Mime, String) for the whole data of the content-type --- core/http/src/handling/request/datatypes.rs | 9 +- core/http/src/handling/request/form_utils.rs | 117 +++++++++++++++--- .../http/src/handling/request/request_mime.rs | 25 ++-- 3 files changed, 125 insertions(+), 26 deletions(-) diff --git a/core/http/src/handling/request/datatypes.rs b/core/http/src/handling/request/datatypes.rs index 45f7b7f..f490137 100644 --- a/core/http/src/handling/request/datatypes.rs +++ b/core/http/src/handling/request/datatypes.rs @@ -26,13 +26,20 @@ impl FromRequest for Vec<u8> { type HeaderMap = Vec<String>; +/// A struct to handle Requests +/// #[derive(Clone)] pub struct Request<'a> { + /// The requested Uri pub uri: Uri<'a>, + /// All headers of the request that haven't been parsed pub headers: HeaderMap, + /// The methods Request represented with the [Method] pub method: Method, + /// An optional HashMap representation of all Cookies of the request pub cookies: Option<HashMap<String, String>>, - pub mime_type: Option<Mime>, + /// If the has a body it represents the [Mime]-type of the body + pub mime_type: Option<(Mime, String)>, // pub connection: ConnectionMeta, } diff --git a/core/http/src/handling/request/form_utils.rs b/core/http/src/handling/request/form_utils.rs index 4163710..d70b2bc 100644 --- a/core/http/src/handling/request/form_utils.rs +++ b/core/http/src/handling/request/form_utils.rs @@ -6,6 +6,55 @@ use super::{datatypes::ParseErrors, ParseFormError, Request}; static TWO_NEWLINES: u8 = 3; impl Request<'_> { + /// # Gets data from a get_form as a HashMap + /// + /// # Errors + /// Gives back a [ParseFormError], top level, if there is lacking data + /// + /// If everything is fine on the top level it gives back a HashMap of keys and Results, that + /// indicate wether the key exists with the [ParseFormError] with an error of + /// [ParseErrors::NoData] or wether the key is corrupt with the [ParseErrors::BadData]-Variant + /// + /// # Examples + /// ``` + /// let request = Request { + /// uri: "/form?name=Name&age=Age", + /// headers: vec![], + /// method: Method::Get, + /// cookies: None, + /// mime_type: None, + /// }; + /// let right = request.get_get_form_keys(&["name", "age"]).unwrap(); + /// assert_eq!(&"Name", right.get("name").unwrap().as_ref().unwrap()); + /// assert_eq!(&"Age", right.get("age").unwrap().as_ref().unwrap()); + /// + /// let wrong_request = Request { + /// uri: "/form", + /// ..request.clone() + /// }; + /// assert_eq!( + /// Err(ParseFormError { + /// error: ParseErrors::NoData + /// }), + /// wrong_request.get_get_form_keys(&["name", "age"]) + /// ); + /// + /// let bad_data = Request { + /// uri: "/form?age=", + /// ..request.clone() + /// }; + /// let wrong = bad_data.get_get_form_keys(&["name", "age"]).unwrap(); + /// assert_eq!( + /// &Err(ParseFormError { + /// error: ParseErrors::NoData + /// }), + /// wrong.get("name").unwrap() + /// ); + /// assert_eq!(&Ok(""), wrong.get("age").unwrap()); + /// ``` + /// + /// # Panics + /// No Panics pub fn get_get_form_keys<'a>( &'a self, keys: &'a [&str], @@ -59,11 +108,11 @@ impl Request<'_> { error: ParseErrors::NoData, })); } - let Some(mime_type) = self.mime_type else { + let Some(ref mime_type) = self.mime_type else { return Err(ParseFormError { error: ParseErrors::BadData }); }; - match mime_type { + match mime_type.0 { Mime::ApplicationXWwwFormUrlencoded => { let Ok(data) = String::from_utf8(data.to_vec()) else { return Err(ParseFormError { error: ParseErrors::BadData }); @@ -82,15 +131,7 @@ impl Request<'_> { } } Mime::MultipartFormData => { - let Some(post_type) = self - .headers - .iter() - .find(|header| header.contains("Content-Type: ")) else { - return Err(ParseFormError { error: ParseErrors::BadData }); - }; - - let content_type = post_type.trim().strip_prefix("Content-Type: ").unwrap(); - let Some(mut boundary) = content_type.split(';').find(|element| element.trim().starts_with("boundary=")) else { + let Some(mut boundary) = mime_type.1.split(';').find(|element| element.trim().starts_with("boundary=")) else { return Err(ParseFormError { error: ParseErrors::BadData }); }; boundary = boundary @@ -187,20 +228,61 @@ impl Request<'_> { #[cfg(test)] mod test { use crate::{ - handling::routes::Data, + handling::{ + methods::Method, + request::{datatypes::ParseErrors, ParseFormError}, + routes::Data, + }, utils::mime::mime_enum::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData}, }; use super::Request; + #[test] + fn try_get_test() { + let request = Request { + uri: "/form?name=Name&age=Age", + headers: vec![], + method: Method::Get, + cookies: None, + mime_type: None, + }; + let right = request.get_get_form_keys(&["name", "age"]).unwrap(); + assert_eq!(&"Name", right.get("name").unwrap().as_ref().unwrap()); + assert_eq!(&"Age", right.get("age").unwrap().as_ref().unwrap()); + + let wrong_request = Request { + uri: "/form", + ..request.clone() + }; + assert_eq!( + Err(ParseFormError { + error: ParseErrors::NoData + }), + wrong_request.get_get_form_keys(&["name", "age"]) + ); + + let bad_data = Request { + uri: "/form?age=", + ..request.clone() + }; + let wrong = bad_data.get_get_form_keys(&["name", "age"]).unwrap(); + assert_eq!( + &Err(ParseFormError { + error: ParseErrors::NoData + }), + wrong.get("name").unwrap() + ); + assert_eq!(&Ok(""), wrong.get("age").unwrap()); + } #[test] fn try_post_text() { let req = Request { uri: "", headers: vec!["Content-Type: application/x-www-form-urlencoded".to_string()], - method: crate::handling::methods::Method::Post, + method: Method::Post, cookies: None, - mime_type: Some(ApplicationXWwwFormUrlencoded), + mime_type: Some((ApplicationXWwwFormUrlencoded, "".into())), }; let data = Data { buffer: b"message=23&message1=24".to_vec(), @@ -218,9 +300,12 @@ mod test { let req = Request { uri: "", headers: vec!["Content-Type: multipart/form-data; boundary=\"boundary\"".to_string()], - method: crate::handling::methods::Method::Post, + method: Method::Post, cookies: None, - mime_type: Some(MultipartFormData), + mime_type: Some(( + MultipartFormData, + "charset=UTF-8; boundary=\"boundary\"".into(), + )), }; let data = Data { buffer: b"--boundary\r diff --git a/core/http/src/handling/request/request_mime.rs b/core/http/src/handling/request/request_mime.rs index 03ac55a..7551bb7 100644 --- a/core/http/src/handling/request/request_mime.rs +++ b/core/http/src/handling/request/request_mime.rs @@ -1,6 +1,6 @@ use super::datatypes::Request; -impl Request<'_> { +impl<'a> Request<'a> { /// Sets the `mime_type` of this [`Request`] from the headers. /// /// The mime_type can remain none if there isn't a `Content-Type: ` header @@ -17,7 +17,7 @@ impl Request<'_> { /// headers: vec![ /// "GET / 23".to_string(), /// "SDF:LKJSD:F".to_string(), - /// "Content-Type: text/plain".to_string(), + /// "Content-Type: text/plain; charset=UTF-8".to_string(), /// "SDF".to_string(), /// ], /// method: Method::Get, @@ -38,7 +38,7 @@ impl Request<'_> { /// request.mime_from_headers(); /// wrong.mime_from_headers(); /// assert_eq!(None, wrong.mime_type); - /// assert_eq!(Mime::TextPlain, request.mime_type.unwrap()); + /// assert_eq!((Mime::TextPlain, " charset=UTF-8".to_string()), request.mime_type.unwrap()); /// ``` /// # Panics /// No Panics @@ -48,14 +48,21 @@ impl Request<'_> { .find(|header| header.starts_with("Content-Type: ")) else { return; }; - let content_type_string = content_type_header + let content_type_string: &str = content_type_header .strip_prefix("Content-Type: ") .unwrap() - .to_string(); + .trim(); - self.mime_type = match content_type_string.split_once(';') { - Some(sub) => sub.0.trim().parse().ok(), - None => content_type_string.trim().parse().ok(), + self.mime_type = if let Some(content_type) = content_type_string.split_once(';') { + let Ok(mime) = content_type.0.trim().parse() else { + return; + }; + Some((mime, content_type.1.to_owned())) + } else { + let Ok(mime) = content_type_string.parse() else { + return; + }; + Some((mime, "".to_owned())) }; } } @@ -96,6 +103,6 @@ mod test { request.mime_from_headers(); wrong.mime_from_headers(); assert_eq!(None, wrong.mime_type); - assert_eq!(Mime::TextPlain, request.mime_type.unwrap()); + assert_eq!((Mime::TextPlain, "".to_owned()), request.mime_type.unwrap()); } } -- GitLab