diff --git a/README.md b/README.md index 008b3d9c8619b3be7adcb945a334e4778fd92ed4..356738042d02f94de03d0fdfb634a06fcde1d81a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ git clone https://edugit.org/codecraft/webserver ``` cd webserver -git checkout new cd site cargo run ``` diff --git a/core/codegen/.gitignore b/core/codegen/.gitignore deleted file mode 100644 index ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba..0000000000000000000000000000000000000000 --- a/core/codegen/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/core/codegen/Cargo.lock b/core/codegen/Cargo.lock deleted file mode 100644 index 0f1eef005f8d1c81cc13a0f5bf42f09a5a3d6002..0000000000000000000000000000000000000000 --- a/core/codegen/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "codegen" -version = "0.1.0" diff --git a/core/codegen/Cargo.toml b/core/codegen/Cargo.toml deleted file mode 100644 index d233c6a7725cb0527b251decf5a45134e79764aa..0000000000000000000000000000000000000000 --- a/core/codegen/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "codegen" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/core/codegen/src/lib.rs b/core/codegen/src/lib.rs deleted file mode 100644 index 7d12d9af8195bf5e19d10c7b592b359ccd014149..0000000000000000000000000000000000000000 --- a/core/codegen/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/core/html/.gitignore b/core/html/.gitignore deleted file mode 100644 index ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba..0000000000000000000000000000000000000000 --- a/core/html/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/core/html/Cargo.lock b/core/html/Cargo.lock deleted file mode 100644 index bcf40f43c0c65da86b1a12efcf54eaf4c41ed9a7..0000000000000000000000000000000000000000 --- a/core/html/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "html" -version = "0.1.0" diff --git a/core/html/Cargo.toml b/core/html/Cargo.toml deleted file mode 100644 index d593c982a62081bd847f78e12ff52bcfdbe089d6..0000000000000000000000000000000000000000 --- a/core/html/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "html" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/core/html/src/lib.rs b/core/html/src/lib.rs deleted file mode 100644 index 7d12d9af8195bf5e19d10c7b592b359ccd014149..0000000000000000000000000000000000000000 --- a/core/html/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/core/http/Cargo.toml b/core/http/Cargo.toml index 5d24dbd889e2de9c7013b930d543cecd6cbf3aed..8f14568e01b016390b4731273116d2369d6e7b23 100644 --- a/core/http/Cargo.toml +++ b/core/http/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "http" -version = "0.1.0" +version = "1.0.0" edition = "2021" [features] +default = [] secure = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/core/http/src/handlers/handler.rs b/core/http/src/handlers/handler.rs index 38315a1cea3bf365d89699c3315bb5686edcc2f7..93a556a9299851625322c7fd0fa5eadb38898241 100644 --- a/core/http/src/handlers/handler.rs +++ b/core/http/src/handlers/handler.rs @@ -1,4 +1,4 @@ -use std::{io, path::PathBuf}; +use std::{io, path::PathBuf, ops::Deref}; use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader, AsyncWrite, AsyncRead}; @@ -8,8 +8,7 @@ use crate::{handling::{ request::Request, response::{Outcome, Response, ResponseBody, Status}, routes::{Body, Data}, -}, utils::urlencoded::UrlEncodeData}; -use crate::setup::MountPoint; +}, setup::MountPoint}; /// The Maximal size of the Body of an HTTP-Message in bytes static MAX_HTTP_MESSAGE_SIZE: u16 = 4196; @@ -25,7 +24,7 @@ static MAX_HTTP_MESSAGE_SIZE: u16 = 4196; /// /// # Panics /// No Panics -pub async fn handle_connection<T: AsyncRead + AsyncWrite + std::marker::Unpin>(mut stream: T, mountpoints: Vec<MountPoint<'_>>) { +pub async fn handle_connection<T: AsyncRead + AsyncWrite + std::marker::Unpin>(mut stream: T, mountpoints: Vec<MountPoint>) { let mut buf_reader = BufReader::new(&mut stream); let mut http_request: Vec<String> = Vec::with_capacity(10); loop { @@ -49,7 +48,7 @@ pub async fn handle_connection<T: AsyncRead + AsyncWrite + std::marker::Unpin>(m let mut request = Request { uri: if let Some(uri) = &request_status_line.split(' ').nth(1) { - if let Ok(uri) = UrlEncodeData::from_encoded(uri) { + if let Ok(uri) = uri.deref().try_into() { uri } else { eprintln!("\x1b[31mAborting due to invalid uri\x1b[0m"); @@ -132,29 +131,19 @@ pub async fn handle_connection<T: AsyncRead + AsyncWrite + std::marker::Unpin>(m let mut handled_response: Option<Outcome<Response, Status, Data>> = None; for mountpoint in mountpoints { - if request.uri.raw_string().is_none() { - return; - } - if !request.uri.raw_string().unwrap().starts_with(mountpoint.mountpoint) { + if !mountpoint.compare_with_uri(&mut request.uri) { continue; } - let mounted_request_uri = request.uri.raw_string().unwrap().strip_prefix(mountpoint.mountpoint).unwrap(); for route in mountpoint.routes { if (route.method != request.method) && ((route.method != Method::Get) && (request.method == Method::Head)) { continue; } - if !route.compare_uri(mounted_request_uri) { + if !route.uri.compare_uri(&request.uri) { continue; } - handled_response = Some((route.handler)( - Request { - uri: UrlEncodeData::from_raw(mounted_request_uri), - ..request.clone() - }, - data.clone(), - )); + handled_response = Some((route.handler)(request.clone(), data.clone())); if let Some(Outcome::Forward(_)) = handled_response { continue; diff --git a/core/http/src/handling/request/datatypes.rs b/core/http/src/handling/request/datatypes.rs index 44f1cf3e1fe0083f84da94b337f167a14fece4bf..56316f54834e397f3018bafa88577c7f02258ee0 100644 --- a/core/http/src/handling/request/datatypes.rs +++ b/core/http/src/handling/request/datatypes.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, error::Error, fmt::Display}; use crate::{ handling::methods::Method, - utils::{mime::Mime, urlencoded::UrlEncodeData}, + utils::{mime::Mime, url_utils::Uri}, }; type HeaderMap = Vec<String>; @@ -12,7 +12,7 @@ type HeaderMap = Vec<String>; #[derive(Clone)] pub struct Request { /// The requested Uri - pub uri: UrlEncodeData, + pub uri: Uri, /// All headers of the request that haven't been parsed pub headers: HeaderMap, /// The methods Request represented with the [Method] diff --git a/core/http/src/handling/request/form_utils.rs b/core/http/src/handling/request/form_utils.rs index cc8999d7cc5eef4d0fa667c9c93d0dff0442572c..865da7bb19ac156d034a9720d9cb85a0162b5a2f 100644 --- a/core/http/src/handling/request/form_utils.rs +++ b/core/http/src/handling/request/form_utils.rs @@ -66,10 +66,15 @@ impl Request { &'a self, keys: &'a [&str], ) -> Result<HashMap<&str, Result<&str, ParseFormError>>, ParseFormError> { - let Some(uri) = self.uri.raw_string() else { - return Err(ParseFormError { error: ParseErrors::BadData }); - }; - let data = if let Some(val) = uri.split_once('?') { + let data = if let Some(val) = self + .uri + .parts() + .last() + .unwrap() + .raw_string() + .unwrap() + .split_once('?') + { val } else { return Err(ParseFormError { @@ -249,17 +254,14 @@ mod test { request::{datatypes::ParseErrors, ParseFormError}, routes::Data, }, - utils::{ - mime::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData}, - urlencoded::UrlEncodeData, - }, + utils::mime::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData}, }; use super::Request; #[test] fn try_get_test() { let request = Request { - uri: UrlEncodeData::from_encoded("/form?name=Name&age=Age").unwrap(), + uri: "/form?name=Name&age=Age".try_into().unwrap(), headers: vec![], method: Method::Get, cookies: None, @@ -270,7 +272,7 @@ mod test { assert_eq!(&"Age", right.get("age").unwrap().as_ref().unwrap()); let wrong_request = Request { - uri: UrlEncodeData::from_encoded("/form").unwrap(), + uri: "/form".try_into().unwrap(), ..request.clone() }; assert_eq!( @@ -281,7 +283,7 @@ mod test { ); let bad_data = Request { - uri: UrlEncodeData::from_encoded("/form?age=").unwrap(), + uri: "/form?age=".try_into().unwrap(), ..request.clone() }; let wrong = bad_data.get_get_form_keys(&["name", "age"]).unwrap(); @@ -297,7 +299,7 @@ mod test { #[test] fn try_post_text() { let req = Request { - uri: UrlEncodeData::from_encoded("").unwrap(), + uri: "".try_into().unwrap(), headers: vec!["Content-Type: application/x-www-form-urlencoded".to_string()], method: Method::Post, cookies: None, @@ -317,7 +319,7 @@ mod test { map.get("message1").unwrap().as_ref().unwrap() ); let req = Request { - uri: UrlEncodeData::from_encoded("").unwrap(), + uri: "".try_into().unwrap(), headers: vec!["Content-Type: multipart/form-data; boundary=\"boundary\"".to_string()], method: Method::Post, cookies: None, diff --git a/core/http/src/handling/request/request_mime.rs b/core/http/src/handling/request/request_mime.rs index 75ad1e547677443479764d6b94013aacd57156ec..005be864655f10ddf851e1d239257f4a42fd16ac 100644 --- a/core/http/src/handling/request/request_mime.rs +++ b/core/http/src/handling/request/request_mime.rs @@ -69,15 +69,16 @@ impl Request { #[cfg(test)] mod test { + use crate::{ handling::{methods::Method, request::Request}, - utils::{mime::Mime, urlencoded::UrlEncodeData}, + utils::mime::Mime, }; #[test] pub fn test_mime_parse_from_header_vec() { let mut request = Request { - uri: UrlEncodeData::from_raw("thing"), + uri: "thing".try_into().unwrap(), headers: vec![ "GET / 23".to_string(), "SDF:LKJSD:F".to_string(), @@ -90,7 +91,7 @@ mod test { }; let mut wrong = Request { - uri: UrlEncodeData::from_raw("thing"), + uri: "thing".try_into().unwrap(), headers: vec![ "GET / 23".to_string(), "SDF:LKJSD:F".to_string(), diff --git a/core/http/src/handling/routes.rs b/core/http/src/handling/routes.rs index 02a81a3ac8bfab8712c48018e8589abbcef9b8e6..52ee733ac7d792f2800103e8d846b776b4c6a3ca 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, + utils::{mime::Mime, url_utils::RawUri}, }; /// A RouteBuilder struct @@ -39,8 +39,8 @@ pub struct RoutBuilder { } /// A struct to define Routes on the Server -#[derive(Clone, Copy)] -pub struct Route<'a> { +#[derive(Clone)] +pub struct Route { /// An optional name of the route pub name: Option<&'static str>, /// The [Method] via which the route is accesable @@ -55,7 +55,7 @@ pub struct Route<'a> { /// // All Information after this sequence is irrelvent /// // Matches: /a, /a/b/c ... /// ``` - pub uri: Uri<'a>, + pub uri: RawUri, /// The Handler function for this route, which gets called when the request need the route. /// Inputs to the function are an [Request] and the [Data] which represents the body of the /// [Request]. The Outcome is expected to be an [Outcome], which is a [Response], A [Status] if @@ -69,7 +69,7 @@ pub struct Route<'a> { pub format: Option<MediaType>, } -impl Route<'_> { +impl Route { /// generates a Route from a Routebuilder //TODO: ranking pub fn from(routeinfo: RoutBuilder) -> Self { @@ -77,39 +77,18 @@ impl Route<'_> { Route { name: routeinfo.name, method: routeinfo.method, - uri: routeinfo.path, + uri: routeinfo + .path + .try_into() + .unwrap_or_else(|_| panic!("Incorrect RawUri for path {}", routeinfo.path)), handler: routeinfo.handler, rank, format: routeinfo.format, } } - /// Matches a [Request] Uri with a [Route] Uri. Respecting special cases like `?` and `<a..>` - pub fn compare_uri(&self, uri: Uri) -> bool { - let mut iter_comp_str = uri.split('/'); - for true_str in self.uri.split('/') { - let comp_str = if let Some(str) = iter_comp_str.next() { - str - } else { - return false; - }; - if (true_str.starts_with('<') && true_str.ends_with("..>")) - || (comp_str.starts_with(true_str) && comp_str.contains('?')) - { - return true; - } - if true_str.starts_with('<') && true_str.ends_with('>') { - continue; - } - if true_str != comp_str { - return false; - } - } - true - } } /// Alias for using a &'a str for Uri -pub type Uri<'a> = &'a str; #[derive(Debug, Clone)] /// A basic Body type for respones diff --git a/core/http/src/setup.rs b/core/http/src/setup.rs index 9802f0edd3498c8a6ac71a53b5ba66ac29642afc..4c5b0dd3bed8798511d7a6f0de6d127efa606a1e 100644 --- a/core/http/src/setup.rs +++ b/core/http/src/setup.rs @@ -11,7 +11,7 @@ use tokio_native_tls::{native_tls::{Identity, self}, TlsAcceptor}; use crate::{ handlers::handler::handle_connection, - handling::routes::{Route, Uri}, + handling::routes::Route, utils::url_utils::Uri, }; #[cfg(feature = "secure")] use crate::handling::response::{Response, Status}; @@ -19,19 +19,19 @@ use crate::handling::response::{Response, Status}; #[derive(Clone)] /// Represnts a [MountPoint] that can be mounted in the config -pub struct MountPoint<'a> { +pub struct MountPoint { /// The prefix of the [MountPoint] - pub mountpoint: Uri<'a>, + pub mountpoint: Uri, /// All Routes mounted on the [MountPoint]. The Routes are all prefixed by the mountpoints /// mountpoint - pub routes: Vec<Route<'a>>, + pub routes: Vec<Route>, } /// A server configuration that is run pub struct Config { /// Contains an Optional [`Vec<MountPoint>`]. which contains all [MountPoint]s on the Server. /// Which contain all the [Route]s - mountpoints: Option<Vec<MountPoint<'static>>>, + mountpoints: Option<Vec<MountPoint>>, /// Contains a [tokio::net::TcpListener] that is bound for the server address: TcpListener, #[cfg(feature = "secure")] @@ -40,13 +40,14 @@ pub struct Config { tls_acceptor: TlsAcceptor, } + impl<'a> Config { /// Utility that checks if the given mointpoint is already taken. takes in the uri of the to be /// mounted mountpoint - fn check_mountpoint_taken(&self, to_insert: Uri) -> bool { + fn check_mountpoint_taken(&self, to_insert: &Uri) -> bool { if let Some(to_check) = &self.mountpoints { for i in to_check.iter() { - if i.mountpoint == to_insert { + if i.mountpoint == *to_insert { return true; // Found a duplicate &str } } @@ -55,13 +56,13 @@ impl<'a> Config { } /// mounts a [MountPoint] on the [Config] takes in a blank [MountPoint] and the [Route]s to be /// mounted, mounts them and inserts the new [MountPoint]. Also sorts by rank. - pub fn mount(mut self, mountpoint: Uri<'static>, mut routes: Vec<Route<'static>>) -> Self { - if self.check_mountpoint_taken(mountpoint) { - eprintln!("\x1b[31mTrying to reassign a mountpoint, mountpoint `{mountpoint}` already taken.\x1b[0m"); + pub fn mount(mut self, mountpoint: Uri, mut routes: Vec<Route>) -> Self { + if self.check_mountpoint_taken(&mountpoint) { + eprintln!("\x1b[31mTrying to reassign a mountpoint, mountpoint `{}` already taken.\x1b[0m", mountpoint); return self; } routes.sort_by(|a, b| a.rank.cmp(&b.rank)); - let mut mount_message = format!(" >> \x1b[35m{}\x1b[0m\n", mountpoint); + let mut mount_message = format!(" >> \x1b[35m{}\x1b[0m\n", mountpoint.to_pretty_print_string()); for (index, route) in routes.iter().enumerate() { let indent_sign = match index { i if i == routes.len() - 1 => "└─", @@ -69,11 +70,10 @@ impl<'a> Config { }; mount_message += &format!( - " \x1b[35m{indent_sign}\x1b[0m \x1b[36m(\x1b[0m{}\x1b[36m)\x1b[0m \x1b[32m{}\x1b[0m \x1b[34;4m{}\x1b[24m{}\x1b[0m\n", + " \x1b[35m{indent_sign}\x1b[0m \x1b[36m(\x1b[0m{}\x1b[36m)\x1b[0m \x1b[32m{}\x1b[0m {}\n", route.name.unwrap_or(""), route.method, - mountpoint, - route.uri + route.uri.to_pretty_print_string(&mountpoint) ) } diff --git a/core/http/src/utils/mod.rs b/core/http/src/utils/mod.rs index 6f54242fa58e4f066dad1846c4b4bc586b002a32..893f1e7201591035ccce0ef4c34ea69a7fd77784 100644 --- a/core/http/src/utils/mod.rs +++ b/core/http/src/utils/mod.rs @@ -1,3 +1,4 @@ pub mod mime; pub mod url_utils; pub mod urlencoded; +pub mod vec_utils; diff --git a/core/http/src/utils/url_utils/datatypes.rs b/core/http/src/utils/url_utils/datatypes.rs index 6e360807ec57cfb988d5e4f2664873f72791b807..a5f89dbd3a7a9809d548d3d13ddf704bd55e1e12 100644 --- a/core/http/src/utils/url_utils/datatypes.rs +++ b/core/http/src/utils/url_utils/datatypes.rs @@ -5,16 +5,17 @@ use crate::utils::urlencoded::UrlEncodeData; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct Uri { pub(super) parts: Vec<UrlEncodeData>, + pub raw: String, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub struct RawUri { pub(super) raw_string: String, pub(super) infinte_end: bool, pub(super) parts: Vec<RawUriElement>, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] pub enum RawUriElement { Variable, Name(UrlEncodeData), diff --git a/core/http/src/utils/url_utils/uri.rs b/core/http/src/utils/url_utils/uri.rs index 6b8146be14f1297f202e4fc59bcaa93928a5fbd5..e0a1cbf1a9d9dc3649aac8dfc1f0bae81108d210 100644 --- a/core/http/src/utils/url_utils/uri.rs +++ b/core/http/src/utils/url_utils/uri.rs @@ -1,15 +1,69 @@ use std::str::FromStr; -use crate::utils::{url_utils::datatypes::RawUriElement, urlencoded::UrlEncodeData}; +use crate::{ + setup::MountPoint, + utils::{ + url_utils::datatypes::RawUriElement, + urlencoded::{EnCodable, UrlEncodeData}, + vec_utils::remove_n, + }, +}; -use super::datatypes::{ParseUriError, RawUri, Uri, UriError}; +use super::datatypes::{ParseUriError, RawUri, Uri}; + +impl MountPoint { + pub fn compare_with_uri(&self, uri: &mut Uri) -> bool { + if !uri.raw.starts_with(&self.mountpoint.raw) { + return false; + } + let to_remove_after_finish = self.mountpoint.parts.len(); + remove_n(uri.mut_parts(), to_remove_after_finish); + true + } +} impl Uri { pub fn new(parts: Vec<&str>) -> Self { Self { + raw: "/".to_owned() + + &parts + .iter() + .map(|part| part.encode()) + .collect::<Vec<String>>() + .join("/"), parts: parts.into_iter().map(UrlEncodeData::from_raw).collect(), } } + pub fn parts(&self) -> &[UrlEncodeData] { + self.parts.as_slice() + } + pub fn mut_parts(&mut self) -> &mut Vec<UrlEncodeData> { + self.parts.as_mut() + } + pub fn compare(&self, uri: &Uri) -> bool { + let mut uri_iter = uri.parts.iter(); + for part in self.parts.iter() { + let Some(part_uri) = uri_iter.next() else { + return false; + }; + if part != part_uri { + return false; + } + } + true + } + pub(crate) fn to_pretty_print_string(&self) -> String { + if self.parts.is_empty() { + "/".to_string() + } else { + let url = self + .parts + .iter() + .map(|part| part.encoded()) + .collect::<Vec<_>>(); + "/".to_string() + &url.join("/") + } + } } impl RawUri { @@ -17,7 +71,7 @@ impl RawUri { let mut result = Self { infinte_end: false, parts: Vec::with_capacity(parts.len()), - raw_string: "/".to_owned() + &parts.join("/"), + raw_string: parts.join("/"), }; for part in parts { if part.starts_with('<') && part.ends_with("..>") { @@ -34,15 +88,15 @@ impl RawUri { } result } - pub fn compare_uri(self, uri: Uri) -> bool { + pub fn compare_uri(&self, uri: &Uri) -> bool { let mut iter_comp = uri.parts.iter(); - let mut counter = 0; + if uri.parts().len() != self.parts.len() && !self.infinte_end { + return false; + } for element in self.parts.iter() { - counter += 1; let Some(compare_element) = iter_comp.next() else { return false; }; - if *element == RawUriElement::Variable { continue; } @@ -54,11 +108,19 @@ impl RawUri { return false; } } - if counter > self.parts.len() && !self.infinte_end { - return false; + if uri.parts.len() > self.parts.len() && self.infinte_end { + return true; } true } + pub(crate) fn to_pretty_print_string(&self, is_after: &Uri) -> String { + let is_after = is_after.to_pretty_print_string(); + if is_after == "/" { + format!("\x1b[34;4m/\x1b[24m{}\x1b[0m", self) + } else { + format!("\x1b[34;4m{is_after}/\x1b[24m{self}\x1b[0m") + } + } } impl std::fmt::Display for RawUri { @@ -69,12 +131,16 @@ impl std::fmt::Display for RawUri { 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("/")) + if self.parts.is_empty() { + write!(f, "/") + } else { + let url = self + .parts + .iter() + .map(|part| part.encoded()) + .collect::<Vec<_>>(); + write!(f, "{}", url.join("/")) + } } } @@ -93,19 +159,21 @@ impl FromStr for Uri { UrlEncodeData::from_raw(sub) }); } - Ok(Self { parts: result }) + Ok(Self { + parts: result, + raw: s.to_string(), + }) } } impl FromStr for RawUri { - type Err = UriError; - + type Err = ParseUriError; 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("/"), + raw_string: s.to_string(), }; for part in parts { if part.is_empty() { @@ -127,6 +195,21 @@ impl FromStr for RawUri { } } +impl TryFrom<&str> for Uri { + type Error = ParseUriError; + + fn try_from(value: &str) -> Result<Self, Self::Error> { + Self::from_str(value) + } +} + +impl TryFrom<&str> for RawUri { + type Error = ParseUriError; + fn try_from(value: &str) -> Result<Self, Self::Error> { + Self::from_str(value) + } +} + #[cfg(test)] mod test { use crate::utils::{ @@ -139,7 +222,7 @@ mod test { #[test] fn uri_to_string() { - assert_eq!("/a/%20", Uri::new(vec!["a", " "]).to_string()); + assert_eq!("a/%20", Uri::new(vec!["a", " "]).to_string()); } #[test] diff --git a/core/http/src/utils/vec_utils.rs b/core/http/src/utils/vec_utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..d03ad1ccd7d25b3327680c0d2afda6fa551cde29 --- /dev/null +++ b/core/http/src/utils/vec_utils.rs @@ -0,0 +1,8 @@ +pub(crate) fn remove_n<T>(vec: &mut Vec<T>, n: usize) { + if n > vec.len() { + return; + } + for i in 0..n { + vec.remove(i); + } +} diff --git a/generatersenum.py b/generatersenum.py deleted file mode 100644 index 2c686bd3723dfe71e8fd961c918f3da077a628d3..0000000000000000000000000000000000000000 --- a/generatersenum.py +++ /dev/null @@ -1,73 +0,0 @@ -import csv - - -def generate_rust_enum(csv_file): - rust_enum = "use phf::phf_map;\n\nenum Mime {\n" - - with open(csv_file, "r") as file: - csv_data = csv.reader(file) - next(csv_data) # Skip the header row - - for row in csv_data: - if row[1] == "": - continue - if "DEPRECATED" in row[0]: - continue - name = format_enum_member(row[0:2]) - rust_enum += f"\t{name},\n" - - rust_enum += "}\n\n" - rust_enum += "impl std::fmt::Display for Mime {\n" - rust_enum += "\tfn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {\n" - rust_enum += "\t\tmatch self {\n" - - with open(csv_file, "r") as file: - csv_data = csv.reader(file) - next(csv_data) # Skip the header row - for row in csv_data: - if row[1] == "": - continue - if "DEPRECATED" in row[0]: - continue - name = format_enum_member(row[0:2]) - rust_enum += f'\t\t\tMime::{name} => write!(f, "{row[1]}"),\n' - - rust_enum += "\t\t}\n\t}\n}\n\n" - - rust_enum += "static MimeMap: phf::Map<&'static str, Mime> = phf_map! {\n" - with open(csv_file, "r") as file: - csv_data = csv.reader(file) - next(csv_data) - for row in csv_data: - if row[1] == "": - continue - if "DEPRECATED" in row[0]: - continue - key = row[1] - value = format_enum_member(row[0:2]) - rust_enum += f'\t"{key}" => Mime::{value},\n' - rust_enum += "};" - - return rust_enum - - -def format_enum_member(name): - prefix = "".join(name[1].split("/")[0:-1]) - name = name[0].split("-") - words = [] - parts = [] - for part in name: - parts += part.split("+") - for part in parts: - words += part.split(".") - - formatted_name = "".join(word.capitalize() for word in words) - if not formatted_name.startswith(prefix.capitalize()): - formatted_name = prefix.capitalize() + formatted_name - return formatted_name - - -# Usage example -csv_file = "mimes.csv" -rust_enum_code = generate_rust_enum(csv_file) -print(rust_enum_code) diff --git a/site/Cargo.lock b/site/Cargo.lock index 8373d437f28e393a378f4a04ae77f127649ecccc..f0357c6d747c2221b237557fac21eb960505c453 100644 --- a/site/Cargo.lock +++ b/site/Cargo.lock @@ -110,7 +110,7 @@ checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "http" -version = "0.1.0" +version = "1.0.0" dependencies = [ "phf", "tokio", @@ -457,7 +457,7 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "site" -version = "0.1.0" +version = "1.0.0" dependencies = [ "http", "tokio", diff --git a/site/Cargo.toml b/site/Cargo.toml index 1d8b4005c671ad045ca83a15315ba430f0a5f99f..999203e93d2810bfa3c9cb544e1d77ebe7ae222c 100644 --- a/site/Cargo.toml +++ b/site/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "site" -version = "0.1.0" +version = "1.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/site/src/main.rs b/site/src/main.rs index 3520b3bd3c4dd083cea7c153cd36180312dff64f..d494b898b008908cd82806dd8f9bc630d03413f4 100644 --- a/site/src/main.rs +++ b/site/src/main.rs @@ -1,7 +1,13 @@ -use http::handling::{methods::Method, routes::{Route, Data}, request::Request, response::{Response, Outcome, Status}, file_handlers::NamedFile}; +use http::handling::{ + file_handlers::NamedFile, + methods::Method, + request::Request, + response::{Outcome, Response, Status}, + routes::{Data, Route}, +}; -fn static_files_handler(request: Request<>, _data: Data) -> Outcome<Response, Status, Data> { - let response = static_files(request.uri.raw_string().unwrap()); +fn static_files_handler(request: Request, _data: Data) -> Outcome<Response, Status, Data> { + let response = static_files(&request.uri.to_string()); let response = match response { Ok(dat) => Response { headers: vec![], @@ -19,19 +25,24 @@ fn static_files(path: &str) -> Result<NamedFile, Status> { } fn index_handler(_request: Request, _data: Data) -> Outcome<Response, Status, Data> { - Outcome::Success(Response { headers: vec![], cookies: None, status: None, body: Box::new(index()) }) + Outcome::Success(Response { + headers: vec![], + cookies: None, + status: None, + body: Box::new(index()), + }) } fn index() -> NamedFile { - NamedFile::open("templates/index.html".into()).unwrap() + NamedFile::open("../templates/index.html".into()).unwrap() } fn favicon_handler(_request: Request, _data: Data) -> Outcome<Response, Status, Data> { let response = Response { headers: vec![], - cookies: None, + cookies: None, status: None, - body: Box::new(NamedFile::open("/assets/favicon.svg".into()).unwrap()) + body: Box::new(NamedFile::open("/assets/favicon.svg".into()).unwrap()), }; Outcome::Success(response) } @@ -42,34 +53,34 @@ async fn main() { format: None, handler: index_handler, name: Some("index"), - uri: "", + uri: "".try_into().unwrap(), method: Method::Get, rank: 0, }; - let static_route = Route { + let static_route = Route { format: None, handler: static_files_handler, name: Some("static files"), - uri: "", + uri: "<file..>".try_into().unwrap(), method: Method::Get, - rank: 0 + rank: 0, }; let favicon = Route { - format: None, + format: None, handler: favicon_handler, name: Some("favicon"), - uri: "favicon.ico", + uri: "favicon.ico".try_into().unwrap(), method: Method::Get, - rank: 0 + rank: 0, }; // http::build("127.0.0.1:8000") http::build("127.0.0.1:8443", "127.0.0.1:8080") .await - .mount("/", vec![index_route, favicon]) - .mount("/static", vec![static_route]) + .mount("/static".try_into().unwrap(), vec![static_route]) + .mount("/".try_into().unwrap(), vec![index_route, favicon]) .launch() .await; } diff --git a/site/templates/index.html b/site/templates/index.html index 7dc2842858c99981c04ebbb86641ad3a0f15d7e6..a14d4de32683279870adce76a78bd9aac1779180 100644 --- a/site/templates/index.html +++ b/site/templates/index.html @@ -8,7 +8,7 @@ <body> <header> <nav> - <div>LOGO</div> + <div><img src="/favicon.ico" alt="ICON" width="32" height="32" /></div> <div> <div>Dashboard</div> <div>Books</div> diff --git a/small.csv b/small.csv deleted file mode 100644 index aa3809cbacfbe48e7c7ad0d29099295f648890c0..0000000000000000000000000000000000000000 --- a/small.csv +++ /dev/null @@ -1,20 +0,0 @@ -Name, format, asdf -vnd.motorola.video,video/vnd.motorola.video,[Tom_McGinty] -vnd.motorola.videop,video/vnd.motorola.videop,[Tom_McGinty] -vnd.mpegurl,video/vnd.mpegurl,[Heiko_Recktenwald] -vnd.ms-playready.media.pyv,video/vnd.ms-playready.media.pyv,[Steve_DiAcetis] -vnd.nokia.interleaved-multimedia,video/vnd.nokia.interleaved-multimedia,[Petteri_Kangaslampi] -vnd.nokia.mp4vr,video/vnd.nokia.mp4vr,[Miska_M._Hannuksela] -vnd.nokia.videovoip,video/vnd.nokia.videovoip,[Nokia] -vnd.objectvideo,video/vnd.objectvideo,[John_Clark] -vnd.radgamettools.bink,video/vnd.radgamettools.bink,[Henrik_Andersson] -vnd.radgamettools.smacker,video/vnd.radgamettools.smacker,[Henrik_Andersson] -vnd.sealed.mpeg1,video/vnd.sealed.mpeg1,[David_Petersen] -vnd.sealed.mpeg4,video/vnd.sealed.mpeg4,[David_Petersen] -vnd.sealed.swf,video/vnd.sealed.swf,[David_Petersen] -vnd.sealedmedia.softseal.mov,video/vnd.sealedmedia.softseal.mov,[David_Petersen] -vnd.uvvu.mp4,video/vnd.uvvu.mp4,[Michael_A_Dolan] -vnd.youtube.yt,video/vnd.youtube.yt,[Google] -vnd.vivo,video/vnd.vivo,[John_Wolfe] -VP8,video/VP8,[RFC7741] -VP9,video/VP9,[RFC-ietf-payload-vp9-16] diff --git a/tree.txt b/tree.txt deleted file mode 100644 index 05d432b7e346d3f283399b681f39d6cb0463c3fd..0000000000000000000000000000000000000000 --- a/tree.txt +++ /dev/null @@ -1,44 +0,0 @@ -. -├── core -│  ├── codegen -│  │  ├── Cargo.lock -│  │  ├── Cargo.toml -│  │  ├── src -│  │  │  └── lib.rs -│  ├── html -│  │  ├── Cargo.lock -│  │  ├── Cargo.toml -│  │  └── src -│  │    └── lib.rs -│  └── http -│  ├── Cargo.lock -│  ├── Cargo.toml -│  └── src -│    ├── handlers -│    │  ├── file_handlers.rs -│    │  ├── handlers.rs -│    │  └── mod.rs -│    ├── lib.rs -│    ├── routing -│    │  ├── methods.rs -│    │  ├── mod.rs -│    │  └── routes.rs -│    ├── setup.rs -│    ├── threading.rs -│    └── utils -│    └── mod.rs -├── README.md -├── site -│  ├── 404.html -│  ├── Cargo.lock -│  ├── Cargo.toml -│  ├── hello.css -│  ├── img.jpg -│  ├── src -│  │  └── main.rs -│  ├── static -│  │  └── hello.html -│  └── target -│  └── CACHEDIR.TAG -└── tree.txt -