From 15a864bbfdd2d437315b0808da51fb9c6b941fb0 Mon Sep 17 00:00:00 2001
From: Darius Auding <Darius.auding@gmx.de>
Date: Sat, 15 Jul 2023 22:09:50 +0200
Subject: [PATCH] Add uri , work on FromStr of cookie

---
 TODO.md                                       |   7 +
 .../response/cookie_management/cookie.rs      |  10 +-
 core/http/src/utils/mod.rs                    |   1 +
 core/http/src/utils/url_utils/datatypes.rs    |  38 ++++
 core/http/src/utils/url_utils/mod.rs          |   7 +
 core/http/src/utils/url_utils/uri.rs          | 183 ++++++++++++++++++
 core/http/src/utils/urlencoded/datatypes.rs   |   8 +-
 core/http/src/utils/urlencoded/mod.rs         |   3 +-
 8 files changed, 245 insertions(+), 12 deletions(-)
 create mode 100644 core/http/src/utils/url_utils/datatypes.rs
 create mode 100644 core/http/src/utils/url_utils/mod.rs
 create mode 100644 core/http/src/utils/url_utils/uri.rs

diff --git a/TODO.md b/TODO.md
index c15fe15..7d14bdd 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,3 +1,5 @@
+GOOD HABITS
+
 1. If you collect an iterator which you don't index in, you don't need to collect it
 2. avoid temporary hashmaps
 3. rewrite POST request stuff TICK
@@ -6,4 +8,9 @@
 6. Remove unwraps
 7. Reusable allocations
 
+TODO:
+
+1. Uri structs everywhere
+2. Cookie From String fix
+
 API design 3. No decisions for the caller
diff --git a/core/http/src/handling/response/cookie_management/cookie.rs b/core/http/src/handling/response/cookie_management/cookie.rs
index 6de43e0..4bd4d2e 100644
--- a/core/http/src/handling/response/cookie_management/cookie.rs
+++ b/core/http/src/handling/response/cookie_management/cookie.rs
@@ -153,7 +153,7 @@ impl FromStr for Cookie {
 mod test {
     use std::time::Duration;
 
-    use crate::handling::response::{Cookie, CookieBuilder};
+    use crate::handling::response::CookieBuilder;
 
     use super::SameSite;
 
@@ -176,14 +176,12 @@ mod test {
             .expires("Monday")
             .finish();
         let test_cookie3_res = "Set-Cookie: ab=ss; HttpOnly; Partitioned; \
-            Max-Age=24; Domain=codecraft.com; Path=%2F; SameSite=None; Secure; Expires=Monday";
-
-        let test_cookie4_res = "ab=ss; HttpOnly; Partitioned; \
-            Max-Age=24; Domain=codecraft.com; Path=%2F; SameSite=None; Secure; Expires=Monday";
+            Max-Age=24; Domain=codecraft.com; Path=/; SameSite=None; Secure; Expires=Monday";
 
         assert_eq!(test_cookie1_res, test_cookie1);
         assert_eq!(test_cookie2_res, test_cookie2);
         assert_eq!(test_cookie3_res, test_cookie3.to_string());
-        assert_eq!(test_cookie4_res.parse::<Cookie>().unwrap(), test_cookie3);
     }
+    #[test]
+    fn cooki_from_string() {}
 }
diff --git a/core/http/src/utils/mod.rs b/core/http/src/utils/mod.rs
index 98498d0..6f54242 100644
--- a/core/http/src/utils/mod.rs
+++ b/core/http/src/utils/mod.rs
@@ -1,2 +1,3 @@
 pub mod mime;
+pub mod url_utils;
 pub mod urlencoded;
diff --git a/core/http/src/utils/url_utils/datatypes.rs b/core/http/src/utils/url_utils/datatypes.rs
new file mode 100644
index 0000000..3c40037
--- /dev/null
+++ b/core/http/src/utils/url_utils/datatypes.rs
@@ -0,0 +1,38 @@
+use std::error;
+
+use crate::utils::urlencoded::UrlEncodeData;
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
+pub struct Uri {
+    pub(super) parts: Vec<UrlEncodeData>,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct RawUri {
+    pub(super) raw_string: String,
+    pub(super) infinte_end: bool,
+    pub(super) parts: Vec<RawUriElement>,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum RawUriElement {
+    Variable,
+    Name(UrlEncodeData),
+}
+
+#[derive(Debug)]
+pub enum UriError {
+    InvalidUriEncoding,
+}
+
+#[derive(Debug)]
+pub struct ParseUriError {
+    error: UriError,
+}
+impl std::fmt::Display for ParseUriError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl error::Error for ParseUriError {}
diff --git a/core/http/src/utils/url_utils/mod.rs b/core/http/src/utils/url_utils/mod.rs
new file mode 100644
index 0000000..7a6061d
--- /dev/null
+++ b/core/http/src/utils/url_utils/mod.rs
@@ -0,0 +1,7 @@
+mod datatypes;
+mod uri;
+pub use datatypes::ParseUriError;
+pub use datatypes::RawUri;
+pub use datatypes::RawUriElement;
+pub use datatypes::Uri;
+pub use datatypes::UriError;
diff --git a/core/http/src/utils/url_utils/uri.rs b/core/http/src/utils/url_utils/uri.rs
new file mode 100644
index 0000000..b9e6939
--- /dev/null
+++ b/core/http/src/utils/url_utils/uri.rs
@@ -0,0 +1,183 @@
+use std::str::FromStr;
+
+use crate::utils::{url_utils::datatypes::RawUriElement, urlencoded::UrlEncodeData};
+
+use super::datatypes::{ParseUriError, RawUri, Uri, UriError};
+
+impl Uri {
+    pub fn new(parts: Vec<&str>) -> Self {
+        Self {
+            parts: parts
+                .into_iter()
+                .map(|part| UrlEncodeData::from_raw(part))
+                .collect(),
+        }
+    }
+}
+
+impl RawUri {
+    pub fn new(parts: Vec<&str>) -> Self {
+        let mut result = Self {
+            infinte_end: false,
+            parts: Vec::with_capacity(parts.len()),
+            raw_string: "/".to_owned() + &parts.join("/"),
+        };
+        for part in parts {
+            if part.starts_with("<") && part.ends_with("..>") {
+                result.infinte_end = true;
+                break;
+            }
+            if part.starts_with("<") && part.ends_with(">") {
+                result.parts.push(RawUriElement::Variable);
+                continue;
+            }
+            result
+                .parts
+                .push(RawUriElement::Name(UrlEncodeData::from_raw(part)))
+        }
+        result
+    }
+    pub fn compare_uri(self, uri: Uri) -> bool {
+        let mut iter_comp = uri.parts.iter();
+        let mut counter = 0;
+        for element in self.parts.iter() {
+            counter += 1;
+            let Some(compare_element) = iter_comp.next() else {
+                return false;
+            };
+
+            if *element == RawUriElement::Variable {
+                continue;
+            }
+            if let RawUriElement::Name(name) = element {
+                if name.encoded() != compare_element.encoded() {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+        if counter > self.parts.len() && !self.infinte_end {
+            return false;
+        }
+        true
+    }
+}
+
+impl std::fmt::Display for RawUri {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.raw_string)
+    }
+}
+
+impl std::fmt::Display for Uri {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let url = self
+            .parts
+            .iter()
+            .map(|part| part.encoded())
+            .collect::<Vec<_>>();
+        write!(f, "/{}", url.join("/"))
+    }
+}
+
+impl FromStr for Uri {
+    type Err = ParseUriError;
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let split = s.split('/');
+        let mut result = Vec::new();
+        for sub in split {
+            if sub.is_empty() {
+                continue;
+            }
+            result.push(if let Ok(coded) = UrlEncodeData::from_encoded(sub) {
+                coded
+            } else {
+                UrlEncodeData::from_raw(sub)
+            });
+        }
+        Ok(Self { parts: result })
+    }
+}
+
+impl FromStr for RawUri {
+    type Err = UriError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        let parts = s.split('/').collect::<Vec<&str>>();
+        let mut result = Self {
+            infinte_end: false,
+            parts: Vec::new(),
+            raw_string: parts.join("/"),
+        };
+        for part in parts {
+            if part.is_empty() {
+                continue;
+            }
+            if part.starts_with("<") && part.ends_with("..>") {
+                result.infinte_end = true;
+                break;
+            }
+            if part.starts_with("<") && part.ends_with(">") {
+                result.parts.push(RawUriElement::Variable);
+                continue;
+            }
+            result
+                .parts
+                .push(RawUriElement::Name(UrlEncodeData::from_raw(part)))
+        }
+        Ok(result)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::utils::{
+        url_utils::{
+            datatypes::{RawUri, RawUriElement},
+            Uri,
+        },
+        urlencoded::UrlEncodeData,
+    };
+
+    #[test]
+    fn uri_to_string() {
+        assert_eq!("/a/%20", Uri::new(vec!["a", " "]).to_string());
+    }
+
+    #[test]
+    fn uri_from_string() {
+        assert_eq!(Uri::new(vec!["a", " "]), "/a/%20".parse().unwrap())
+    }
+
+    #[test]
+    fn raw_uri_from_string() {
+        assert_eq!(
+            RawUri {
+                raw_string: "/<name>/a/<f..>".to_owned(),
+                infinte_end: true,
+                parts: vec![
+                    RawUriElement::Variable,
+                    RawUriElement::Name(UrlEncodeData::from_raw("a")),
+                ]
+            },
+            "/<name>/a/<f..>".parse().unwrap()
+        );
+    }
+
+    #[test]
+    fn raw_uri_to_string() {
+        assert_eq!(
+            "/<name>/a/<f..>",
+            RawUri {
+                raw_string: "/<name>/a/<f..>".to_owned(),
+                infinte_end: true,
+                parts: vec![
+                    RawUriElement::Variable,
+                    RawUriElement::Name(UrlEncodeData::from_raw("a")),
+                ]
+            }
+            .to_string()
+        )
+    }
+}
diff --git a/core/http/src/utils/urlencoded/datatypes.rs b/core/http/src/utils/urlencoded/datatypes.rs
index 2db1e18..d48e02b 100644
--- a/core/http/src/utils/urlencoded/datatypes.rs
+++ b/core/http/src/utils/urlencoded/datatypes.rs
@@ -2,15 +2,15 @@ use crate::utils::urlencoded::endecode::EnCodable;
 
 use super::endecode::DeCodable;
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
 /// A way to store UrlEncoded data
 pub struct UrlEncodeData {
     /// Encoded string
-    encoded: String,
+    pub(crate) encoded: String,
     /// raw data, unencoded
-    raw: Vec<u8>,
+    pub(crate) raw: Vec<u8>,
     /// raw string if it exists
-    raw_string: Option<String>,
+    pub(crate) raw_string: Option<String>,
 }
 
 impl UrlEncodeData {
diff --git a/core/http/src/utils/urlencoded/mod.rs b/core/http/src/utils/urlencoded/mod.rs
index 6511cfc..3145200 100644
--- a/core/http/src/utils/urlencoded/mod.rs
+++ b/core/http/src/utils/urlencoded/mod.rs
@@ -1,5 +1,4 @@
 mod datatypes;
 mod endecode;
 pub use datatypes::UrlEncodeData;
-pub use endecode::DeCodable;
-pub use endecode::EnCodable;
+pub use endecode::{DeCodable, EnCodable};
-- 
GitLab