diff --git a/core/http/src/handlers/handler.rs b/core/http/src/handlers/handler.rs index 8b021882f78c3341eb4144303f9a14bf20f8d7ff..7ffa9e9376c07fd5d20ac484889f217ff426ef7a 100644 --- a/core/http/src/handlers/handler.rs +++ b/core/http/src/handlers/handler.rs @@ -14,8 +14,20 @@ use crate::{handling::{ }, utils::urlencoded::UrlEncodeData}; use crate::setup::MountPoint; +/// The Maximal size of the Body of an HTTP-Message in bytes static MAX_HTTP_MESSAGE_SIZE: u16 = 4196; +/// Function which handles a TCP Connection according to http-Standards by taking in a +/// [tokio::net::TcpStream] and a [`Vec<MountPoint<'_>>`]. +/// +/// Firstly validates the headers and body, Aborts with error messages if it finds faults. +/// +/// Secondly matches the request with a route in the mountpoint Vector and executes its handler +/// function. If it fails, checks for another, if nothing is found writes back a +/// [Status::NotFound]. If the handler function could respond it uses the [Response] of the handler +/// +/// # Panics +/// No Panics pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoint<'_>>) { let mut buf_reader = BufReader::new(&mut stream); let mut http_request: Vec<String> = Vec::with_capacity(10); @@ -168,7 +180,8 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin } } -fn failure_handler<'a>(status: Status) -> Response { +/// Dumb function that renders a 404 page from any status given. but still writes that status code. +fn failure_handler(status: Status) -> Response { let page_404 = NamedFile::open(PathBuf::from("404.html")).unwrap(); Response { cookies: None, @@ -178,6 +191,7 @@ fn failure_handler<'a>(status: Status) -> Response { } } +/// Handler for len_not_defined errors. writes back directly async fn len_not_defined(stream: TcpStream, status: Status) -> io::Result<()> { let page_411 = NamedFile::open(PathBuf::from("411.html")).unwrap(); Response { @@ -191,6 +205,7 @@ async fn len_not_defined(stream: TcpStream, status: Status) -> io::Result<()> { Ok(()) } +/// takes in an io error and writes it back in the server console to the user if writing failed fn error_occured_when_writing(e: io::Error) { eprintln!("\x1b[31mError {e} occured when trying to write answer to TCP-Stream for Client, aborting\x1b[0m"); } diff --git a/core/http/src/handling/file_handlers.rs b/core/http/src/handling/file_handlers.rs index 7a0b0805690449759cfa206f3ce9ec7fd13bf6b3..2d4d39bbcb0e9085e0ec33f1a487c1e3ebdd5d72 100644 --- a/core/http/src/handling/file_handlers.rs +++ b/core/http/src/handling/file_handlers.rs @@ -6,9 +6,14 @@ use crate::{ }; #[derive(Debug)] +/// Struct to handle files on the server side. +/// Validates paths ignores actions like `..` pub struct NamedFile { + /// The length of the file in bytes, format: [usize] pub content_len: usize, + /// The Mime Type of the file as a [Mime] pub content_type: Mime, + /// The content of the file as a [`Vec<u8>`] pub content: Vec<u8>, } @@ -27,6 +32,17 @@ impl ResponseBody for NamedFile { } impl NamedFile { + /// Reads in a file as a [NamedFile]. Ignores seqences like `..` + /// + /// # Panics + /// + /// Panics if a [PathBuf] can't be convertet to a [str] + /// + /// # Errors + /// + /// Can give a [Status::NotFound] if it can't find the file + /// + /// This function will return an error if . pub fn open(path: PathBuf) -> Result<NamedFile, Status> { let path = proove_path(path); let data = fs::read(&path); @@ -44,6 +60,11 @@ impl NamedFile { } } +/// Validates a path so that seqences like `//` and `..` are omitted +/// +/// # Panics +/// +/// Panics if it can't convert a [PathBuf] to a [str] fn proove_path(path: PathBuf) -> PathBuf { PathBuf::from( path.to_str() diff --git a/core/http/src/handling/methods.rs b/core/http/src/handling/methods.rs index 5ca6211081ea5dd26aa3bf0fbb6f74166af50b25..a13e498af505b385f6fc122f9af042f44a531d66 100644 --- a/core/http/src/handling/methods.rs +++ b/core/http/src/handling/methods.rs @@ -1,6 +1,7 @@ use std::{fmt::Display, str::FromStr}; #[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord)] +/// All HTTP Methods pub enum Method { Get, Head, diff --git a/core/http/src/handling/request/datatypes.rs b/core/http/src/handling/request/datatypes.rs index e8b03030d171a5a089f1dcd02f4106b6bbc1e72e..44f1cf3e1fe0083f84da94b337f167a14fece4bf 100644 --- a/core/http/src/handling/request/datatypes.rs +++ b/core/http/src/handling/request/datatypes.rs @@ -5,25 +5,6 @@ use crate::{ utils::{mime::Mime, urlencoded::UrlEncodeData}, }; -pub trait FromRequest: Send { - fn get_data(&self) -> &Self; - fn set_data(&mut self, data: &Self); - fn append(&mut self, data: &Self); -} - -impl FromRequest for Vec<u8> { - fn get_data(&self) -> &Self { - self - } - - fn set_data(&mut self, data: &Self) { - *self = data.to_vec(); - } - fn append(&mut self, data: &Self) { - self.extend_from_slice(data); - } -} - type HeaderMap = Vec<String>; /// A struct to handle Requests @@ -49,9 +30,13 @@ pub struct Request { // } #[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)] +/// Media Types in which a Route can be requested to ansewr, optional for routes pub enum MediaType { + /// Json Data Json, + /// Plain Text Plain, + /// HTML Text Html, } @@ -62,6 +47,7 @@ pub enum ParseErrors { } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +/// Errors that Occur when a Form can't be parsed pub struct ParseFormError { pub error: ParseErrors, } diff --git a/core/http/src/handling/request/request_impl.rs b/core/http/src/handling/request/request_impl.rs index 2eb6fd0a63dd9ade031cf27b2754810ed64527c5..01d6e4498bf964b9f244db91a318882d228f8328 100644 --- a/core/http/src/handling/request/request_impl.rs +++ b/core/http/src/handling/request/request_impl.rs @@ -3,12 +3,14 @@ use crate::handling::methods::Method; use super::Request; impl Request { + /// Checks if the request can have a body pub fn can_have_body(&self) -> bool { matches!( self.method, Method::Post | Method::Put | Method::Patch | Method::Delete ) } + /// Checks if a body is mandatory for the Request pub fn mandatory_body(&self) -> bool { matches!(self.method, Method::Post | Method::Put | Method::Patch) } diff --git a/core/http/src/handling/response/cookie_management/cookie.rs b/core/http/src/handling/response/cookie_management/cookie.rs index e96f825961745f3333034d9d8dda795fe0ce1994..58d2a0d648b47de5fd191f62119a8c9519054ea3 100644 --- a/core/http/src/handling/response/cookie_management/cookie.rs +++ b/core/http/src/handling/response/cookie_management/cookie.rs @@ -1,5 +1,13 @@ use std::time::Duration; +/// Structure representing a Cookie +/// # Creating a Cookie: +/// ``` +/// use http::handling::response::Cookie; +/// use http::handling::response::CookieBuilder; +/// +/// let cookie = CookieBuilder::build("name", "value").finish(); +/// ``` pub struct Cookie { /// Storage for the cookie string. Only used if this structure was derived /// from a string that was subsequently parsed. @@ -23,7 +31,9 @@ pub struct Cookie { } #[derive(Debug)] +/// SameSite Paremeters pub enum SameSite { + /// Requires Secure None, Lax, Strict, 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 e71eb449258ead8826554bee88eae9dc1c6ca8a7..a38f92cdae59d9ac46c679b9742d8304725bfe41 100644 --- a/core/http/src/handling/response/cookie_management/cookie_builder.rs +++ b/core/http/src/handling/response/cookie_management/cookie_builder.rs @@ -2,11 +2,22 @@ use std::time::Duration; use super::{Cookie, SameSite}; +/// Builder wrapper for a Cookie +/// +/// # Example +/// ``` +/// use http::handling::response::Cookie; +/// use http::handling::response::CookieBuilder; +/// +/// let cookie = CookieBuilder::build("name", "value").path("/").finish(); +/// ``` pub struct CookieBuilder { + /// Cookie under the hood inner: Cookie, } impl CookieBuilder { + /// Builds a basic CookieBuilder from a name and a value pub fn build(name: &str, value: &str) -> Self { CookieBuilder { inner: Cookie { diff --git a/core/http/src/handling/response/cookie_management/mod.rs b/core/http/src/handling/response/cookie_management/mod.rs index 06d6b85578319879491961ad465272996469b194..50f34ea4c9ed80fdaf39a474f764b8de1f0790b6 100644 --- a/core/http/src/handling/response/cookie_management/mod.rs +++ b/core/http/src/handling/response/cookie_management/mod.rs @@ -3,3 +3,4 @@ mod cookie_builder; pub use cookie::Cookie; pub use cookie::SameSite; +pub use cookie_builder::CookieBuilder; diff --git a/core/http/src/handling/response/datatypes.rs b/core/http/src/handling/response/datatypes.rs index 7800deb53bb5749475e2093d89fd4c9b2855fcba..9225ced968351185e4ce286e48eb9b08e9f0b7aa 100644 --- a/core/http/src/handling/response/datatypes.rs +++ b/core/http/src/handling/response/datatypes.rs @@ -3,15 +3,37 @@ use super::{Cookie, ResponseBody, Status}; type HeaderMap = Vec<String>; #[derive(Debug)] +/// Enum for the result of a Handling Function, where... +/// +/// [Outcome::Success] represents that the route +/// was successful and the Answer is contained in \[S\]. +/// [Outcome::Failure] represents that it was unsuccessful and nobody else is going to be +/// successful. \[E\] represnts the Error Code. +/// [Outcome::Forward] represents that some requirements weren't met for a route to be working with +/// the request so the next one that matches should cover that \[F\] represents the maybe processed +/// data of the request. +/// +/// # Example +/// ``` +/// use http::handling::{response::{Outcome, Response, Status}, routes::Data, request::Request}; +/// fn handler(request: Request, _data: Data) -> Outcome<Response, Status, Data> { +/// todo!() +/// } +/// ``` pub enum Outcome<S, E, F> { Success(S), Failure(E), Forward(F), } +/// Response is a wrapper for http responses. pub struct Response { + /// the [`Vec<String>`] of headers unrelated to `Content-Type` and `Content-Length` pub headers: HeaderMap, + /// Optional Cookie in the response pub cookies: Option<Cookie>, + /// Status code of the response pub status: Option<Status>, + /// Response body and `Content-Type` and `Content-Length` headers. pub body: Box<dyn ResponseBody>, } diff --git a/core/http/src/handling/response/mod.rs b/core/http/src/handling/response/mod.rs index ede6a42639847eca70d1376891eb61aa22d391c8..535eaa812a2192d9b897d3c506f1e0f48dacfd88 100644 --- a/core/http/src/handling/response/mod.rs +++ b/core/http/src/handling/response/mod.rs @@ -5,6 +5,7 @@ mod status; mod traits; pub use cookie_management::Cookie; +pub use cookie_management::CookieBuilder; pub use cookie_management::SameSite; pub use datatypes::Outcome; pub use datatypes::Response; diff --git a/core/http/src/handling/response/response.rs b/core/http/src/handling/response/response.rs index 23d2b09c68c2a2fb35e3caff84475de24124d9ef..62de6e97759b6888e02665e8e9e52a787921b8b8 100644 --- a/core/http/src/handling/response/response.rs +++ b/core/http/src/handling/response/response.rs @@ -6,7 +6,9 @@ use crate::handling::{methods::Method, request::Request, response::Status}; use super::Response; -impl Response<> { +impl Response { + /// Builds a [`Vec<u8>`] valid http response from a [Response] and consumes it. Optionally + /// takes in a request for things like [Method::Head] pub fn build(self, request: Option<Request>) -> Vec<u8> { let compiled_headers = format!( "HTTP/1.1 {}\r\nContent-Length: {}\r\nContent-Type: {}\r\n", @@ -29,6 +31,7 @@ impl Response<> { compiled_out.extend_from_slice(&compiled_body); compiled_out } + /// Builds and writes The http-Response, consumes the [tokio::net::TcpStream] [Request] and [Response] pub async fn write(self, mut stream: TcpStream, request: Option<Request>) -> Result<()> { let resp = self.build(request); stream.write_all(&resp).await?; diff --git a/core/http/src/handling/response/status.rs b/core/http/src/handling/response/status.rs index 9f825af3207baa7ffef63a8599f81d3fa0bdff87..dfc56a555b706b1d2aa8559fc54f73341dbeeccd 100644 --- a/core/http/src/handling/response/status.rs +++ b/core/http/src/handling/response/status.rs @@ -1,11 +1,14 @@ use std::fmt::Display; #[derive(Debug)] +/// Enum With every http status for complete documentation [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) pub enum Status { Continue, SwitchingProtocols, - WebDavProcessing, - ExperimentalEarlyHints, + /// WebDAV + Processing, + /// Experimental + EarlyHints, Ok, Created, Accepted, @@ -13,21 +16,26 @@ pub enum Status { NoContent, ResetContent, PartialContent, - WebDavMultiStatus, - WebDavAlreadyReported, + /// WebDAV + MultiStatus, + /// WebDAV + AlreadyReported, HttpDataEncodingImUsed, MultipleChoices, MovedPermanently, Found, SeeOther, NotModfiied, - DeprecatedUseProxy, - UnusedUnused, + /// Deprecated + UseProxy, + /// Deprecated + Unused, TemporaryRedirect, PermanentRedirect, BadRequest, Unauthorized, - ExperimentalPaymentRequired, + /// Experimental + PaymentRequired, Forbidden, NotFound, MethodNotAllowed, @@ -45,10 +53,14 @@ pub enum Status { ExpectationFailed, ImATeapot, MisdirectedRequest, - WebDavUnprocessableContent, - WebDavLocked, - WebDavFailedDependency, - ExperimenalTooEarly, + /// WebDAV + UnprocessableContent, + /// WebDAV + Locked, + /// WebDAV + FailedDependency, + /// Experimental + TooEarly, UpgradeRequred, PreconditionRequired, TooManyRequests, @@ -61,8 +73,10 @@ pub enum Status { GetawayTimeout, HttpVersionNotSupported, VariantAlsoNegotiates, - WebDavInsufficientStorage, - WebDavLoopDetected, + /// WebDAV + InsufficientStorage, + /// WebDAV + LoopDetected, NotExtended, NetworkAuthenticationRequired, } @@ -72,8 +86,8 @@ impl Display for Status { match self { Status::Continue => write!(f, "100 Continue"), Status::SwitchingProtocols => write!(f, "101 Switching Protocols"), - Status::WebDavProcessing => write!(f, "102 Processing"), - Status::ExperimentalEarlyHints => write!(f, "103 Early Hints"), + Status::Processing => write!(f, "102 Processing"), + Status::EarlyHints => write!(f, "103 Early Hints"), Status::Ok => write!(f, "200 OK"), Status::Created => write!(f, "201 Created"), Status::Accepted => write!(f, "202 Accepted"), @@ -81,8 +95,8 @@ impl Display for Status { Status::NoContent => write!(f, "204 No Content"), Status::ResetContent => write!(f, "205 Reset Content"), Status::PartialContent => write!(f, "206 Partial Content"), - Status::WebDavMultiStatus => write!(f, "207 Mutli-Status"), - Status::WebDavAlreadyReported => write!(f, "208 Already Reported"), + Status::MultiStatus => write!(f, "207 Mutli-Status"), + Status::AlreadyReported => write!(f, "208 Already Reported"), Status::HttpDataEncodingImUsed => write!(f, "226 IM Used"), Status::MultipleChoices => write!(f, "300 Multiple Choices"), Status::MovedPermanently => write!(f, "301 Moved Permanently"), @@ -91,11 +105,11 @@ impl Display for Status { Status::NotModfiied => write!(f, "304 Not Modified"), Status::TemporaryRedirect => write!(f, "307 Temporary Redirect"), Status::PermanentRedirect => write!(f, "308 Permanent Redirect"), - Status::DeprecatedUseProxy => write!(f, "305 Use Proxy"), - Status::UnusedUnused => write!(f, "306 unused"), + Status::UseProxy => write!(f, "305 Use Proxy"), + Status::Unused => write!(f, "306 unused"), Status::BadRequest => write!(f, "400 Bad Request"), Status::Unauthorized => write!(f, "401 Unauthorized"), - Status::ExperimentalPaymentRequired => write!(f, "402 Payment Required"), + Status::PaymentRequired => write!(f, "402 Payment Required"), Status::Forbidden => write!(f, "403 Forbidden"), Status::NotFound => write!(f, "404 Not Found"), Status::MethodNotAllowed => write!(f, "405 Method Not Allowed"), @@ -115,10 +129,10 @@ impl Display for Status { Status::ExpectationFailed => write!(f, "417 Expectation Failed"), Status::ImATeapot => write!(f, "418 I'm a Teapot"), Status::MisdirectedRequest => write!(f, "421 Misdirected Request"), - Status::WebDavUnprocessableContent => write!(f, "422 Unprocessable Content"), - Status::WebDavLocked => write!(f, "423 Locked"), - Status::WebDavFailedDependency => write!(f, "424 Failed Dependency"), - Status::ExperimenalTooEarly => write!(f, "425 Too Early"), + Status::UnprocessableContent => write!(f, "422 Unprocessable Content"), + Status::Locked => write!(f, "423 Locked"), + Status::FailedDependency => write!(f, "424 Failed Dependency"), + Status::TooEarly => write!(f, "425 Too Early"), Status::UpgradeRequred => write!(f, "426 Upgrade Required"), Status::PreconditionRequired => write!(f, "428 Precondition Required"), Status::TooManyRequests => write!(f, "429 Too Many Requests"), @@ -135,8 +149,8 @@ impl Display for Status { Status::GetawayTimeout => write!(f, "504 Getaway Timeout"), Status::HttpVersionNotSupported => write!(f, "505 HTTP Version Not Supported"), Status::VariantAlsoNegotiates => write!(f, "506 Variant Also Negotiates"), - Status::WebDavInsufficientStorage => write!(f, "507 Insufficient Storage"), - Status::WebDavLoopDetected => write!(f, "508 Loop Detected"), + Status::InsufficientStorage => write!(f, "507 Insufficient Storage"), + Status::LoopDetected => write!(f, "508 Loop Detected"), Status::NotExtended => write!(f, "510 Not Extendend"), Status::NetworkAuthenticationRequired => { write!(f, "511 Network Authentication Required") diff --git a/core/http/src/handling/response/traits.rs b/core/http/src/handling/response/traits.rs index bc0aed55e9beba1ebbc2e74081d577588b71135b..6e96ddf50dca13976e8a3ffc4929dd7e25c47744 100644 --- a/core/http/src/handling/response/traits.rs +++ b/core/http/src/handling/response/traits.rs @@ -1,5 +1,6 @@ use crate::{handling::routes::Body, utils::mime::Mime}; +/// Trait for using datatypes as response bodies pub trait ResponseBody: Send { /// Get a cloned version of the data as a [`Vec<u8>`] /// # Ecamples diff --git a/core/http/src/handling/routes.rs b/core/http/src/handling/routes.rs index a31dc80b5162a3f607b874e0bbabf4b314659d80..02a81a3ac8bfab8712c48018e8589abbcef9b8e6 100644 --- a/core/http/src/handling/routes.rs +++ b/core/http/src/handling/routes.rs @@ -7,12 +7,34 @@ use crate::{ utils::mime::Mime, }; -pub struct RoutInfo { +/// A RouteBuilder struct +pub struct RoutBuilder { + /// An optional name of the route name: Option<&'static str>, + /// The [Method] via which the route is accesable method: Method, + /// The path of the route, allows special cases: + /// # Examples + /// ``` + /// "/home"; // Only /home + /// "/<home>/something"; + /// // Variable content the users provides this acts for /<anything>/something + /// "/<home..>"; + /// // All Information after this sequence is irrelvent + /// // Matches: /a, /a/b/c ... + /// ``` path: &'static str, + /// 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 + /// something went wrong and a [Status] page is need or a [Outcome::Forward] of the requests + /// [Data] for the next [Route] to take care of. handler: fn(Request, Data) -> Outcome<Response, Status, Data>, + /// The Specific answer format of the [Route] as a [MediaType]. Optional format: Option<MediaType>, + /// The Optional Rank of the Route, dependent on its specificness. so the rank of a uri `"/home"` would be + /// ranked high, whereas a uri of `"/<anything..>"` would be ranked the lowest + /// If not given generated based on parematers. rank: Option<isize>, } @@ -48,7 +70,9 @@ pub struct Route<'a> { } impl Route<'_> { - pub fn from(routeinfo: RoutInfo) -> Self { + /// generates a Route from a Routebuilder + //TODO: ranking + pub fn from(routeinfo: RoutBuilder) -> Self { let rank = routeinfo.rank.unwrap_or(0); Route { name: routeinfo.name, @@ -84,6 +108,7 @@ impl Route<'_> { } } +/// Alias for using a &'a str for Uri pub type Uri<'a> = &'a str; #[derive(Debug, Clone)] @@ -96,18 +121,23 @@ pub struct Body { } impl Body { + /// New body of a Response pub fn new(body: Vec<u8>, mime_type: Mime) -> Self { Self { body, mime_type } } + /// Sets the `mime_type` of the Body pub fn set_mime_type(&mut self, mime_type: Mime) { self.mime_type = mime_type; } + /// Reassigns the body pub fn set_body(&mut self, body: Vec<u8>) { self.body = body; } + /// mime_type of the body pub fn mime_type(&self) -> Mime { self.mime_type } + /// cloned body as [`Vec<u8>`] pub fn body(&self) -> Vec<u8> { self.body.clone() } @@ -123,6 +153,7 @@ pub struct Data { } impl Data { + /// Checks if the buffer.oen() is -0 pub fn is_empty(&self) -> bool { self.buffer.len() == 0 } diff --git a/core/http/src/setup.rs b/core/http/src/setup.rs index 1f061c6e3c58d053aa528c486643cf4048cc95cb..31669bb9bf2b773bdd019fbecc15df8896a077b5 100644 --- a/core/http/src/setup.rs +++ b/core/http/src/setup.rs @@ -12,17 +12,27 @@ use crate::{ }; #[derive(Clone)] +/// Represnts a [MountPoint] that can be mounted in the config pub struct MountPoint<'a> { + /// The prefix of the [MountPoint] pub mountpoint: Uri<'a>, + /// All Routes mounted on the [MountPoint]. The Routes are all prefixed by the mountpoints + /// mountpoint pub routes: Vec<Route<'a>>, } +/// 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>>>, + /// Contains a [tokio::net::TcpListener] that is bound for the server address: TcpListener, } 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 { if let Some(to_check) = &self.mountpoints { for i in to_check.iter() { @@ -33,6 +43,8 @@ impl<'a> Config { }; false } + /// 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"); diff --git a/core/http/src/utils/mime/map.rs b/core/http/src/utils/mime/map.rs index 711731417020bd490ffed23182be04cbe9a82a2e..7cb4db211a5df5f5c02bb13c1118e79397996b04 100644 --- a/core/http/src/utils/mime/map.rs +++ b/core/http/src/utils/mime/map.rs @@ -1,5 +1,6 @@ use super::mime_enum::Mime; +/// Map with the string version of the Mime types and the values being corresponding [Mime]s pub static MIME_MAP: phf::Map<&'static str, Mime> = phf::phf_map! { "application/1d-interleaved-parityfec" => Mime::Application1dInterleavedParityfec, "application/3gpdash-qoe-report+xml" => Mime::Application3gpdashQoeReportXml, diff --git a/core/http/src/utils/mime/mime_enum.rs b/core/http/src/utils/mime/mime_enum.rs index 0a6a0686f8923b0b7e613724250b4b17738333a1..12c63d60e55c593c0ecc4544dae8c4ccc4f3dbfa 100644 --- a/core/http/src/utils/mime/mime_enum.rs +++ b/core/http/src/utils/mime/mime_enum.rs @@ -1,6 +1,7 @@ use super::map::MIME_MAP; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +/// An Enum of all Mime types pub enum Mime { Application1dInterleavedParityfec, Application3gpdashQoeReportXml, @@ -4074,6 +4075,7 @@ impl std::str::FromStr for Mime { } impl Mime { + /// Gets the mime type from filename, defaults to [Mime::TextPlain] pub fn from_filename(filename: &str) -> Self { match filename.split('.').last() { Some(v) => match v { diff --git a/core/http/src/utils/urlencoded/datatypes.rs b/core/http/src/utils/urlencoded/datatypes.rs index 6829e6b97a512b3fce0b066f69847cf53b4740a3..cbb24c2d865732fab9db0a6da812b28948efa7c6 100644 --- a/core/http/src/utils/urlencoded/datatypes.rs +++ b/core/http/src/utils/urlencoded/datatypes.rs @@ -3,13 +3,18 @@ use crate::utils::urlencoded::endecode::EnCodable; use super::endecode::DeCodable; #[derive(Clone)] +/// A way to store UrlEncoded data pub struct UrlEncodeData { + /// Encoded string encoded: String, + /// raw data, unencoded raw: Vec<u8>, + /// raw string if it exists raw_string: Option<String>, } impl UrlEncodeData { + /// Generates a [UrlEncodeData] from any raw data that can be a slice of [u8] pub fn from_raw<T: AsRef<[u8]>>(raw: T) -> Self { Self { raw: raw.as_ref().to_owned(), @@ -17,6 +22,11 @@ impl UrlEncodeData { raw_string: String::from_utf8(raw.as_ref().into()).ok(), } } + /// Generates a [UrlEncodeData] from a correctly encoded string + /// + /// # Errors + /// + /// errors if the encoded data is wrongly encoded -> %<invalid_character> pub fn from_encoded(encoded: &str) -> Result<Self, ()> { Ok(Self { encoded: encoded.to_owned(), @@ -25,12 +35,15 @@ impl UrlEncodeData { }) } + /// Gets a reference to the encoded data pub fn encoded(&self) -> &str { self.encoded.as_ref() } + /// Get a reference to the raw [u8] slice pub fn raw(&self) -> &[u8] { self.raw.as_ref() } + /// Gets an Optional string slice to the raw data pub fn raw_string(&self) -> Option<&str> { self.raw_string.as_ref().map(|x| x.as_str()) } diff --git a/core/http/src/utils/urlencoded/endecode.rs b/core/http/src/utils/urlencoded/endecode.rs index 389eb28902e51d2d64d9de55a67105ab6ee6f6e0..9fba4cb4763bdafea6115959a35316218c7101cc 100644 --- a/core/http/src/utils/urlencoded/endecode.rs +++ b/core/http/src/utils/urlencoded/endecode.rs @@ -1,12 +1,20 @@ -static BASE16_HEXA_DECIMAL: u8 = 16; -static BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT: u8 = 15; +/// Base of the HexaDecimal Number system +static BASE16_HEXA_DECIMAL: u8 = 0x10; +/// Highest possible Value per digit +static BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT: u8 = 0xF; +/// Bits of a hexa decimal number static BASE16_HEXA_DECIMAL_DIGIT_BITS: u8 = 4; pub trait EnCodable { + /// Encodes the give data into a Percent Encoded [String] fn encode(&self) -> String; } pub trait DeCodable { + /// Decodes the given data into a [`Vec<u8>`] + /// + /// # Errors + /// Errors if the encoding isn't right fn decode(&self) -> Result<Vec<u8>, ()>; } @@ -50,6 +58,8 @@ impl DeCodable for &str { } } +/// converts a [u8] digit into the ascii code of its counterpart. The digit shouldn't be bigger +/// than [BASE16_HEXA_DECIMAL_POSSIBLE_VALUE_PER_DIGIT] fn hex_to_digit(digit: u8) -> u8 { match digit { 0..=9 => b'0' + digit,