diff --git a/TODO.md b/TODO.md index c15fe15492ef30d3296d9d2eb2782ca7f4d04718..7d14bddea530e5b1f353e340271ff68fdf2c478d 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 6de43e0110acb05295b67b5e800c4cb0aef4dfa6..4bd4d2ee301217b33d1676edff2cc3b4858743a0 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 98498d0d0f9587b59d03a27eda201ca43d646500..6f54242fa58e4f066dad1846c4b4bc586b002a32 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 0000000000000000000000000000000000000000..3c4003770906612619b50904e1f2c2f15f0263b5 --- /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 0000000000000000000000000000000000000000..7a6061d096e735d42bc4f1a5508377758798e101 --- /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 0000000000000000000000000000000000000000..b9e6939e183f22df30d13df4d6d2834e24d1373b --- /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 2db1e181a567379f8adf2d98b4dc6a0bf8923c84..d48e02be890d6ef0362c6f3040006136b2a46346 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 6511cfc285082147732f8246a15cae9486bc1a12..3145200e62492c82c37385fa9aa0e1d69c48e5eb 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};