From 6c90900d4933b4f84463dbfcfb80d973b502425b Mon Sep 17 00:00:00 2001
From: Darius Auding <Darius.auding@gmx.de>
Date: Mon, 3 Jul 2023 14:57:00 +0200
Subject: [PATCH] prototyping for cookies further, working on UrlEncoded text

---
 core/http/src/handling/file_handlers.rs       |   2 +-
 core/http/src/handling/request/cookies.rs     |   1 +
 core/http/src/handling/request/datatypes.rs   |   4 +-
 core/http/src/handling/request/form_utils.rs  |   4 +-
 .../http/src/handling/request/request_mime.rs |   4 +-
 .../response/cookie_management/cookie.rs      |  18 +++
 .../cookie_management/cookie_builder.rs       |   5 +
 core/http/src/handling/response/traits.rs     |   2 +-
 core/http/src/handling/routes.rs              |   2 +-
 core/http/src/utils/mime/mod.rs               |   5 +-
 core/http/src/utils/mod.rs                    |   1 +
 core/http/src/utils/urlencoded/datatypes.rs   |  26 ++++
 core/http/src/utils/urlencoded/endecode.rs    | 140 ++++++++++++++++++
 core/http/src/utils/urlencoded/mod.rs         |   2 +
 14 files changed, 206 insertions(+), 10 deletions(-)
 create mode 100644 core/http/src/utils/urlencoded/datatypes.rs
 create mode 100644 core/http/src/utils/urlencoded/endecode.rs
 create mode 100644 core/http/src/utils/urlencoded/mod.rs

diff --git a/core/http/src/handling/file_handlers.rs b/core/http/src/handling/file_handlers.rs
index 8ca0019..7a0b080 100644
--- a/core/http/src/handling/file_handlers.rs
+++ b/core/http/src/handling/file_handlers.rs
@@ -2,7 +2,7 @@ use std::{fs, path::PathBuf};
 
 use crate::{
     handling::response::{ResponseBody, Status},
-    utils::mime::mime_enum::Mime,
+    utils::mime::Mime,
 };
 
 #[derive(Debug)]
diff --git a/core/http/src/handling/request/cookies.rs b/core/http/src/handling/request/cookies.rs
index b386086..cd3c4ca 100644
--- a/core/http/src/handling/request/cookies.rs
+++ b/core/http/src/handling/request/cookies.rs
@@ -52,6 +52,7 @@ impl Request<'_> {
             .strip_prefix("Cookie: ")
             .unwrap()
             .trim()
+            .trim_matches('"')
             .to_string();
         for cookie in cookies_string.split(';') {
             let Some((name, cookie)) = cookie.split_once('=') else {
diff --git a/core/http/src/handling/request/datatypes.rs b/core/http/src/handling/request/datatypes.rs
index acde6d8..df96177 100644
--- a/core/http/src/handling/request/datatypes.rs
+++ b/core/http/src/handling/request/datatypes.rs
@@ -1,8 +1,8 @@
-use std::{borrow::Cow, collections::HashMap, error::Error, fmt::Display};
+use std::{collections::HashMap, error::Error, fmt::Display};
 
 use crate::{
     handling::{methods::Method, routes::Uri},
-    utils::mime::mime_enum::Mime,
+    utils::mime::Mime,
 };
 
 pub trait FromRequest: Send {
diff --git a/core/http/src/handling/request/form_utils.rs b/core/http/src/handling/request/form_utils.rs
index cab16eb..9aa300c 100644
--- a/core/http/src/handling/request/form_utils.rs
+++ b/core/http/src/handling/request/form_utils.rs
@@ -1,6 +1,6 @@
 use std::collections::HashMap;
 
-use crate::{handling::routes::Data, utils::mime::mime_enum::Mime};
+use crate::{handling::routes::Data, utils::mime::Mime};
 
 use super::{datatypes::ParseErrors, ParseFormError, Request};
 static TWO_NEWLINES: u8 = 3;
@@ -239,7 +239,7 @@ mod test {
             request::{datatypes::ParseErrors, ParseFormError},
             routes::Data,
         },
-        utils::mime::mime_enum::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData},
+        utils::mime::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData},
     };
 
     use super::Request;
diff --git a/core/http/src/handling/request/request_mime.rs b/core/http/src/handling/request/request_mime.rs
index 7551bb7..56188d1 100644
--- a/core/http/src/handling/request/request_mime.rs
+++ b/core/http/src/handling/request/request_mime.rs
@@ -9,7 +9,7 @@ impl<'a> Request<'a> {
     /// ```
     /// use http::{
     ///     handling::{methods::Method, request::Request},
-    ///     utils::mime::mime_enum::Mime,
+    ///     utils::mime::Mime,
     /// };
     ///
     /// let mut request = Request {
@@ -71,7 +71,7 @@ impl<'a> Request<'a> {
 mod test {
     use crate::{
         handling::{methods::Method, request::Request},
-        utils::mime::mime_enum::Mime,
+        utils::mime::Mime,
     };
 
     #[test]
diff --git a/core/http/src/handling/response/cookie_management/cookie.rs b/core/http/src/handling/response/cookie_management/cookie.rs
index cfe3501..4e072eb 100644
--- a/core/http/src/handling/response/cookie_management/cookie.rs
+++ b/core/http/src/handling/response/cookie_management/cookie.rs
@@ -19,10 +19,28 @@ pub struct Cookie<'a> {
     /// The draft `SameSite` attribute.
     pub(crate) same_site: Option<SameSite>,
     pub(crate) expires: Option<&'a str>,
+    pub(crate) partitioned: Option<bool>,
 }
 
+#[derive(Debug)]
 pub enum SameSite {
     None,
     Lax,
     Strict,
 }
+
+impl std::fmt::Display for SameSite {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::None => write!(f, "SameSite=None; Secure"),
+            Self::Lax => write!(f, "SameSite=Lax"),
+            Self::Strict => write!(f, "SameSite=Strict"),
+        }
+    }
+}
+
+impl std::fmt::Display for Cookie<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        todo!()
+    }
+}
diff --git a/core/http/src/handling/response/cookie_management/cookie_builder.rs b/core/http/src/handling/response/cookie_management/cookie_builder.rs
index ead2df0..431160a 100644
--- a/core/http/src/handling/response/cookie_management/cookie_builder.rs
+++ b/core/http/src/handling/response/cookie_management/cookie_builder.rs
@@ -20,6 +20,7 @@ impl<'a> CookieBuilder<'a> {
                 http_only: None,
                 same_site: None,
                 expires: None,
+                partitioned: None,
             },
         }
     }
@@ -54,6 +55,10 @@ impl<'a> CookieBuilder<'a> {
         self.inner.expires = Some(expire);
         self
     }
+    pub fn partitioned(mut self, partitioned: bool) -> Self {
+        self.inner.partitioned = Some(partitioned);
+        self
+    }
     pub fn name(mut self, name: &'a str) -> Self {
         self.inner.name = name;
         self
diff --git a/core/http/src/handling/response/traits.rs b/core/http/src/handling/response/traits.rs
index 96ac87c..fc7eb09 100644
--- a/core/http/src/handling/response/traits.rs
+++ b/core/http/src/handling/response/traits.rs
@@ -1,4 +1,4 @@
-use crate::{handling::routes::Body, utils::mime::mime_enum::Mime};
+use crate::{handling::routes::Body, utils::mime::Mime};
 
 pub trait ResponseBody: Send {
     fn get_data(&self) -> Vec<u8>;
diff --git a/core/http/src/handling/routes.rs b/core/http/src/handling/routes.rs
index a85261a..e4246b8 100644
--- a/core/http/src/handling/routes.rs
+++ b/core/http/src/handling/routes.rs
@@ -4,7 +4,7 @@ use crate::{
         request::{MediaType, Request},
         response::{Outcome, Response, Status},
     },
-    utils::mime::mime_enum::Mime,
+    utils::mime::Mime,
 };
 
 pub struct RoutInfo {
diff --git a/core/http/src/utils/mime/mod.rs b/core/http/src/utils/mime/mod.rs
index bbf3a87..4421654 100644
--- a/core/http/src/utils/mime/mod.rs
+++ b/core/http/src/utils/mime/mod.rs
@@ -1,2 +1,5 @@
 mod map;
-pub mod mime_enum;
+mod mime_enum;
+pub use map::MIME_MAP;
+pub use mime_enum::Mime;
+pub use mime_enum::ParseMimeError;
diff --git a/core/http/src/utils/mod.rs b/core/http/src/utils/mod.rs
index 909a531..98498d0 100644
--- a/core/http/src/utils/mod.rs
+++ b/core/http/src/utils/mod.rs
@@ -1 +1,2 @@
 pub mod mime;
+pub mod urlencoded;
diff --git a/core/http/src/utils/urlencoded/datatypes.rs b/core/http/src/utils/urlencoded/datatypes.rs
new file mode 100644
index 0000000..c370ddf
--- /dev/null
+++ b/core/http/src/utils/urlencoded/datatypes.rs
@@ -0,0 +1,26 @@
+use std::borrow::Cow;
+
+use super::endecode::EnDecodable;
+
+pub struct UrlEncodeData<'a> {
+    encoded: Cow<'a, str>,
+    raw: Cow<'a, str>,
+}
+
+impl UrlEncodeData<'_> {
+    pub fn from_raw(raw: &str) -> Self {
+        todo!()
+    }
+    pub fn from_encoded(encoded: &str) -> Self {
+        todo!()
+    }
+}
+
+impl EnDecodable for UrlEncodeData<'_> {
+    fn encode(&self) -> Cow<'_, str> {
+        self.raw.encode()
+    }
+    fn decode(&self) -> Result<Cow<'_, str>, ()> {
+        self.encoded.decode()
+    }
+}
diff --git a/core/http/src/utils/urlencoded/endecode.rs b/core/http/src/utils/urlencoded/endecode.rs
new file mode 100644
index 0000000..0e7fe2c
--- /dev/null
+++ b/core/http/src/utils/urlencoded/endecode.rs
@@ -0,0 +1,140 @@
+use std::borrow::Cow;
+
+static BASE16_HEXA_DECIMAL: u8 = 16;
+pub trait EnDecodable {
+    fn encode(&self) -> Cow<'_, str>;
+    fn decode(&self) -> Result<Cow<'_, str>, ()>;
+}
+
+impl EnDecodable for Cow<'_, str> {
+    fn encode(&self) -> Cow<'_, str> {
+        self.bytes()
+            .map(|byte| {
+                if !byte.is_ascii_alphanumeric() {
+                    format!("%{:02X}", byte)
+                } else {
+                    String::from_utf8([byte].to_vec()).unwrap()
+                }
+            })
+            .collect()
+    }
+    fn decode(&self) -> Result<Cow<'_, str>, ()> {
+        let mut first = true;
+        let mut result = String::with_capacity(self.len());
+        for i in self.split('%') {
+            if first {
+                first = false;
+                result += i;
+                continue;
+            }
+            let Ok(char) = u8::from_str_radix(i[0..2].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
+                return Err(());
+            };
+            unsafe {
+                result.as_mut_vec().push(char);
+            }
+            result = result + &i[2..];
+        }
+        Ok(result.into())
+    }
+}
+
+impl EnDecodable for &str {
+    fn encode(&self) -> Cow<'_, str> {
+        self.bytes()
+            .map(|byte| {
+                if !byte.is_ascii_alphanumeric() {
+                    format!("%{:02X}", byte)
+                } else {
+                    String::from_utf8([byte].to_vec()).unwrap()
+                }
+            })
+            .collect()
+    }
+
+    fn decode(&self) -> Result<Cow<'_, str>, ()> {
+        let mut first = true;
+        let mut result = String::with_capacity(self.len());
+        for i in self.split('%') {
+            if first {
+                first = false;
+                result += i;
+                continue;
+            }
+            let Ok(char) = u8::from_str_radix(i[0..2].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
+                return Err(());
+            };
+            unsafe {
+                result.as_mut_vec().push(char);
+            }
+            result = result + &i[2..];
+        }
+        Ok(result.into())
+    }
+}
+
+impl EnDecodable for String {
+    fn encode(&self) -> Cow<'_, str> {
+        self.bytes()
+            .map(|byte| {
+                if !byte.is_ascii_alphanumeric() {
+                    format!("%{:02X}", byte)
+                } else {
+                    String::from_utf8([byte].to_vec()).unwrap()
+                }
+            })
+            .collect()
+    }
+    fn decode(&self) -> Result<Cow<'_, str>, ()> {
+        let mut first = true;
+        let mut result = String::with_capacity(self.len());
+        for i in self.split('%') {
+            if first {
+                first = false;
+                result += i;
+                continue;
+            }
+            let Ok(char) = u8::from_str_radix(i[0..2].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
+                return Err(());
+            };
+            unsafe {
+                result.as_mut_vec().push(char);
+            }
+            result = result + &i[2..];
+        }
+        Ok(result.into())
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::borrow::Cow;
+
+    use crate::utils::urlencoded::endecode::EnDecodable;
+
+    #[test]
+    fn urlencoded_test() {
+        assert_eq!(
+            "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire",
+            Cow::Borrowed("Darius is the biggest genius/Genie/Human extraordinäire").encode()
+        )
+    }
+    #[test]
+    fn urldecoded_test() {
+        assert_eq!(
+            "Darius is the biggest genius/Genie/Human extraordinäire",
+            Cow::Borrowed(
+                "Darius%20is%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire"
+            )
+            .decode()
+            .unwrap()
+        );
+        assert_eq!(
+            Err(()),
+            Cow::Borrowed(
+                "Darius%2iis%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire"
+            )
+            .decode()
+        );
+    }
+}
diff --git a/core/http/src/utils/urlencoded/mod.rs b/core/http/src/utils/urlencoded/mod.rs
new file mode 100644
index 0000000..43ea58f
--- /dev/null
+++ b/core/http/src/utils/urlencoded/mod.rs
@@ -0,0 +1,2 @@
+mod datatypes;
+mod endecode;
-- 
GitLab