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