Skip to content
Snippets Groups Projects
Commit 35c2138d authored by codecraft's avatar codecraft :crocodile:
Browse files

FIX finish conversion to URLEncoded for URIs and UTF-8 support.

parent 929f96eb
No related branches found
No related tags found
1 merge request!1Initial feature merge
......@@ -123,10 +123,13 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin
let mut handled_response: Option<Outcome<Response, Status, Data>> = None;
for mountpoint in mountpoints {
if !request.uri.raw().starts_with(mountpoint.mountpoint) {
if request.uri.raw_string().is_none() {
return;
}
if !request.uri.raw_string().unwrap().starts_with(mountpoint.mountpoint) {
continue;
}
let mounted_request_uri = request.uri.strip_prefix(mountpoint.mountpoint).unwrap();
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))
......@@ -138,7 +141,7 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin
}
handled_response = Some((route.handler)(
Request {
uri: mounted_request_uri,
uri: UrlEncodeData::from_raw(mounted_request_uri),
..request.clone()
},
data.clone(),
......@@ -165,7 +168,7 @@ pub async fn handle_connection(mut stream: TcpStream, mountpoints: Vec<MountPoin
}
}
fn failure_handler<'a>(status: Status) -> Response<'a> {
fn failure_handler<'a>(status: Status) -> Response {
let page_404 = NamedFile::open(PathBuf::from("404.html")).unwrap();
Response {
cookies: None,
......
......@@ -68,7 +68,10 @@ impl Request {
&'a self,
keys: &'a [&str],
) -> Result<HashMap<&str, Result<&str, ParseFormError>>, ParseFormError> {
let data = if let Some(val) = self.uri.split_once('?') {
let Some(uri) = self.uri.raw_string() else {
return Err(ParseFormError { error: ParseErrors::BadData });
};
let data = if let Some(val) = uri.split_once('?') {
val
} else {
return Err(ParseFormError {
......@@ -133,6 +136,9 @@ impl Request {
let Ok(key) = kvp.0.decode() else {
return Err(ParseFormError { error: ParseErrors::BadData });
};
let Ok(key) = String::from_utf8(key) else {
return Err(ParseFormError { error: ParseErrors::BadData });
};
let Ok(value) = kvp.1.trim_end_matches('\0').decode() else {
return Err(ParseFormError { error: ParseErrors::BadData });
};
......@@ -245,14 +251,17 @@ mod test {
request::{datatypes::ParseErrors, ParseFormError},
routes::Data,
},
utils::mime::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData},
utils::{
mime::Mime::{ApplicationXWwwFormUrlencoded, MultipartFormData},
urlencoded::UrlEncodeData,
},
};
use super::Request;
#[test]
fn try_get_test() {
let request = Request {
uri: "/form?name=Name&age=Age",
uri: UrlEncodeData::from_encoded("/form?name=Name&age=Age").unwrap(),
headers: vec![],
method: Method::Get,
cookies: None,
......@@ -263,7 +272,7 @@ mod test {
assert_eq!(&"Age", right.get("age").unwrap().as_ref().unwrap());
let wrong_request = Request {
uri: "/form",
uri: UrlEncodeData::from_encoded("/form").unwrap(),
..request.clone()
};
assert_eq!(
......@@ -274,7 +283,7 @@ mod test {
);
let bad_data = Request {
uri: "/form?age=",
uri: UrlEncodeData::from_encoded("/form?age=").unwrap(),
..request.clone()
};
let wrong = bad_data.get_get_form_keys(&["name", "age"]).unwrap();
......@@ -290,7 +299,7 @@ mod test {
#[test]
fn try_post_text() {
let req = Request {
uri: "",
uri: UrlEncodeData::from_encoded("").unwrap(),
headers: vec!["Content-Type: application/x-www-form-urlencoded".to_string()],
method: Method::Post,
cookies: None,
......@@ -310,7 +319,7 @@ mod test {
map.get("message1").unwrap().as_ref().unwrap()
);
let req = Request {
uri: "",
uri: UrlEncodeData::from_encoded("").unwrap(),
headers: vec!["Content-Type: multipart/form-data; boundary=\"boundary\"".to_string()],
method: Method::Post,
cookies: None,
......
use std::time::Duration;
pub struct Cookie<'a> {
pub struct Cookie {
/// Storage for the cookie string. Only used if this structure was derived
/// from a string that was subsequently parsed.
pub(crate) cookie_string: Option<&'a str>,
pub(crate) name: &'a str,
pub(crate) value: &'a str,
pub(crate) cookie_string: Option<String>,
pub(crate) name: String,
pub(crate) value: String,
// expires: Option<Tm>,
pub(crate) max_age: Option<Duration>,
/// The cookie's domain, if any.
pub(crate) domain: Option<&'a str>,
pub(crate) domain: Option<String>,
/// The cookie's path domain, if any.
pub(crate) path: Option<&'a str>,
pub(crate) path: Option<String>,
/// Whether this cookie was marked Secure.
pub(crate) secure: Option<bool>,
/// Whether this cookie was marked HttpOnly.
pub(crate) http_only: Option<bool>,
/// The draft `SameSite` attribute.
pub(crate) same_site: Option<SameSite>,
pub(crate) expires: Option<&'a str>,
pub(crate) expires: Option<String>,
pub(crate) partitioned: Option<bool>,
}
......@@ -39,7 +39,7 @@ impl std::fmt::Display for SameSite {
}
}
impl std::fmt::Display for Cookie<'_> {
impl std::fmt::Display for Cookie {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
......
......@@ -2,17 +2,17 @@ use std::time::Duration;
use super::{Cookie, SameSite};
pub struct CookieBuilder<'a> {
inner: Cookie<'a>,
pub struct CookieBuilder {
inner: Cookie,
}
impl<'a> CookieBuilder<'a> {
pub fn build(name: &'a str, value: &'a str) -> Self {
impl CookieBuilder {
pub fn build(name: &str, value: &str) -> Self {
CookieBuilder {
inner: Cookie {
cookie_string: None,
name,
value,
name: name.to_owned(),
value: value.to_owned(),
max_age: None,
domain: None,
path: None,
......@@ -24,19 +24,19 @@ impl<'a> CookieBuilder<'a> {
},
}
}
pub fn finish(self) -> Cookie<'a> {
pub fn finish(self) -> Cookie {
self.inner
}
pub fn max_age(mut self, duration: Duration) -> Self {
self.inner.max_age = Some(duration);
self
}
pub fn domain(mut self, domain: &'a str) -> Self {
self.inner.domain = Some(domain);
pub fn domain(mut self, domain: &str) -> Self {
self.inner.domain = Some(domain.to_owned());
self
}
pub fn path(mut self, path: &'a str) -> Self {
self.inner.path = Some(path);
pub fn path(mut self, path: &str) -> Self {
self.inner.path = Some(path.to_owned());
self
}
pub fn secure(mut self, secure: bool) -> Self {
......@@ -51,20 +51,20 @@ impl<'a> CookieBuilder<'a> {
self.inner.same_site = Some(same_site);
self
}
pub fn expires(mut self, expire: &'a str) -> Self {
self.inner.expires = Some(expire);
pub fn expires(mut self, expire: &str) -> Self {
self.inner.expires = Some(expire.to_owned());
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;
pub fn name(mut self, name: &str) -> Self {
self.inner.name = name.to_owned();
self
}
pub fn value(mut self, value: &'a str) -> Self {
self.inner.value = value;
pub fn value(mut self, value: &str) -> Self {
self.inner.value = value.to_owned();
self
}
}
......@@ -9,9 +9,9 @@ pub enum Outcome<S, E, F> {
Forward(F),
}
pub struct Response<'a> {
pub struct Response {
pub headers: HeaderMap,
pub cookies: Option<Cookie<'a>>,
pub cookies: Option<Cookie>,
pub status: Option<Status>,
pub body: Box<dyn ResponseBody>,
}
......@@ -6,7 +6,7 @@ use crate::handling::{methods::Method, request::Request, response::Status};
use super::Response;
impl Response<'_> {
impl Response<> {
pub fn build(self, request: Option<Request>) -> Vec<u8> {
let compiled_headers = format!(
"HTTP/1.1 {}\r\nContent-Length: {}\r\nContent-Type: {}\r\n",
......
use std::{borrow::Cow, string::FromUtf8Error};
use crate::utils::urlencoded::endecode::EnCodable;
use super::endecode::DeCodable;
......@@ -12,12 +10,12 @@ pub struct UrlEncodeData {
}
impl UrlEncodeData {
pub fn from_raw<T: AsRef<[u8]>>(raw: T) -> Result<Self, FromUtf8Error> {
Ok(Self {
pub fn from_raw<T: AsRef<[u8]>>(raw: T) -> Self {
Self {
raw: raw.as_ref().to_owned(),
encoded: raw.as_ref().encode(),
raw_string: String::from_utf8(raw.as_ref().into()).ok(),
})
}
}
pub fn from_encoded(encoded: &str) -> Result<Self, ()> {
Ok(Self {
......
......@@ -40,7 +40,7 @@ impl DeCodable for &str {
result.extend_from_slice(i.as_bytes());
continue;
}
let Ok(char) = u8::from_str_radix(i[0..2].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
let Ok(char) = u8::from_str_radix(i[0..=1].as_ref(), BASE16_HEXA_DECIMAL.into()) else {
return Err(());
};
result.push(char);
......@@ -84,5 +84,9 @@ mod test {
Err(()),
"Darius%2iis%20the%20biggest%20genius%2FGenie%2FHuman%20extraordin%C3%A4ire".decode()
);
assert_eq!(
"hi?asdf=sadf%%&jkl=s",
String::from_utf8("hi?asdf=sadf%25%25&jkl=s".decode().unwrap()).unwrap()
)
}
}
......@@ -20,7 +20,7 @@ fn hashmap_to_string(map: &HashMap<&str, Result<&str, ParseFormError>>) -> Strin
result
}
fn handle_static_hi(request: Request<'_>, data: Data) -> Outcome<Response, Status, Data> {
fn handle_static_hi(request: Request<>, data: Data) -> Outcome<Response, Status, Data> {
let keys = if let Ok(keys) = request.get_get_form_keys(&["asdf", "jkl"]) {
keys
} else {
......@@ -36,8 +36,8 @@ fn handle_static_hi(request: Request<'_>, data: Data) -> Outcome<Response, Statu
// Outcome::Forward(data)
}
fn handler(request: Request<'_>, _data: Data) -> Outcome<Response, Status, Data> {
let response = fileserver(request.uri.strip_prefix("static/").unwrap());
fn handler(request: Request<>, _data: Data) -> Outcome<Response, Status, Data> {
let response = fileserver(request.uri.raw_string().unwrap().strip_prefix("static/").unwrap());
let response = match response {
Ok(dat) => Response {
headers: vec![],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment