Forked from
codecraft / WebServer
49 commits behind the upstream repository.
request.rs 11.48 KiB
// use std::net::SocketAddr;
use std::{collections::HashMap, error::Error, fmt::Display};
use crate::utils::mime::mime_enum::Mime;
use super::{
methods::Method,
routes::{Data, Uri},
};
type HeaderMap = Vec<String>;
#[derive(Clone)]
pub struct Request<'a> {
pub uri: Uri<'a>,
pub headers: HeaderMap,
pub method: Method,
// pub connection: ConnectionMeta,
}
// struct ConnectionMeta {
// remote: Option<SocketAddr>,
// // certificates
// }
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum MediaType {
Json,
Plain,
Html,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ParseErrors {
NoData,
BadData,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ParseFormError {
pub error: ParseErrors,
}
impl Display for ParseFormError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.error)
}
}
impl Display for ParseErrors {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseErrors::NoData => write!(f, "No Data at key"),
ParseErrors::BadData => write!(f, "Bad Data at key"),
}
}
}
impl Error for ParseFormError {}
impl Request<'_> {
pub fn can_have_body(&self) -> bool {
match self.method {
Method::Post | Method::Put | Method::Patch | Method::Delete => true,
_ => false,
}
}
pub fn mandatory_body(&self) -> bool {
match self.method {
Method::Post | Method::Put | Method::Patch => true,
_ => false,
}
}
pub fn get_get_form_keys<'a>(
&'a self,
keys: &'a [&str],
) -> Result<HashMap<&str, Result<&str, ParseFormError>>, ParseFormError> {
let data = if let Some(val) = self.uri.split_once("?") {
val
} else {
return Err(ParseFormError {
error: ParseErrors::NoData,
});
};
let data = data
.1
.split("&")
.map(|kvp| kvp.split_once("="))
.collect::<Vec<Option<(&str, &str)>>>();
let mut values: HashMap<&str, &str> = HashMap::new();
for kvp in data {
let kvp = if let Some(kvp) = kvp {
kvp
} else {
continue;
};
values.insert(kvp.0, kvp.1);
}
let mut response = HashMap::new();
for key in keys {
let entry = if let Some(val) = values.get(key) {
Ok(*val)
} else {
Err(ParseFormError {
error: ParseErrors::NoData,
})
};
response.insert((*key).into(), entry);
}
Ok(response)
}
pub fn get_post_data<'a>(
&'a self,
keys: &[&'a str],
data: &Data,
) -> Result<HashMap<&str, Result<Vec<u8>, ParseFormError>>, ParseFormError> {
let post_type = if let Some(val) = self
.headers
.iter()
.find(|header| header.contains("Content-Type: "))
{
if let Ok(mime_type) = val.strip_prefix("Content-Type: ").unwrap().trim().parse() {
mime_type
} else {
return Err(ParseFormError {
error: ParseErrors::NoData,
});
}
} else {
return Err(ParseFormError {
error: ParseErrors::NoData,
});
};
let data = data.buffer.as_slice();
let mut keymap: HashMap<&str, Result<Vec<u8>, ParseFormError>> =
HashMap::with_capacity(keys.len());
for key in keys {
keymap.entry(key).or_insert(Err(ParseFormError {
error: ParseErrors::NoData,
}));
}
match post_type {
Mime::ApplicationXWwwFormUrlencoded => {
for kvp in data.split(|byte| *byte == b'&') {
let kvp = kvp.split(|byte| *byte == b'=').collect::<Vec<&[u8]>>();
let key = if let Some(kv) = kvp.get(0) {
kv
} else {
return Err(ParseFormError {
error: ParseErrors::BadData,
});
};
let key = if let Ok(kv) = String::from_utf8(key.to_vec()) {
kv
} else {
return Err(ParseFormError {
error: ParseErrors::BadData,
});
};
let value = kvp.get(1).ok_or(ParseFormError {
error: ParseErrors::NoData,
});
let thing = if let Some(val) = keymap.get_mut(key.as_str()) {
val
} else {
continue;
};
*thing = match value {
Ok(val) => Ok(val.to_vec()),
Err(err) => Err(err),
}
}
}
_ => {
return Err(ParseFormError {
error: ParseErrors::BadData,
})
}
};
Ok(keymap)
}
// pub fn get_post_text_form_key(
// &self,
// keys: &[&str],
// data: &Data,
// ) -> Result<HashMap<&str, Result<&str, ParseFormError>>, ParseFormError> {
// let mut post_type = self
// .headers
// .iter()
// .find(|header| header.contains("Content-Type: "))
// .unwrap()
// .to_string();
//
// post_type = post_type
// .strip_prefix("Content-Type: ")
// .unwrap()
// .to_string();
//
// let post_type: Vec<&str> = post_type.trim().split(';').collect();
// let mime_type = post_type[0].parse().unwrap();
//
// // let data = String::from_utf8(vec)
//
// let mut result = HashMap::new();
// match mime_type {
// Mime::ApplicationXWwwFormUrlencoded => {
// let data = String::from_utf8(data.buffer.clone()).unwrap();
// let kvps = data
// .split("&")
// .map(|kvp| kvp.split_once("=").unwrap())
// .collect::<HashMap<&str, &str>>();
//
// for key in keys {
// let entry = if let Some(val) = kvps.get(key) {
// Ok(*val)
// } else {
// Err(ParseFormError {
// error: ParseErrors::NoData,
// })
// };
// result.insert(*key, entry);
// }
// Ok(result)
// }
// Mime::MultipartFormData => {
// let from_req = post_type[1..]
// .iter()
// .find(|val| val.contains("boundary="))
// .unwrap()
// .strip_prefix("boundary=")
// .unwrap();
// let mut boundary = b"--".to_vec();
// boundary.extend_from_slice(from_req.trim_matches('"').as_bytes());
// let mut end_boundary = boundary.clone();
// end_boundary.extend_from_slice(b"--");
// boundary.extend_from_slice(&[b'\r']);
// let parts = data
// .buffer
// .split(|byte| byte == &b'\n')
// .collect::<Vec<&[u8]>>();
//
// let mut boundary_found = false;
// let mut current_key: Option<&str> = None;
// let mut result: HashMap<&str, Vec<u8>> = HashMap::new();
// for part in parts {
// if part == [] {
// continue;
// }
// if part == end_boundary {
// break;
// }
// if !boundary_found && part == boundary {
// current_key = None;
// boundary_found = true;
// continue;
// }
// if part.starts_with(b"Content-Disposition: form-data; name=") {
// let headers = part
// .split(|byte| byte == &b';')
// .filter(|header| !header.is_empty())
// .collect::<Vec<_>>();
// if headers.len() < 2 {
// continue;
// }
// let name = headers[1].split(|byte| byte == &b'=').collect::<Vec<_>>();
// if name.len() != 2 {
// continue;
// }
// let mkey = String::from_utf8_lossy(name[1])
// .as_ref()
// .trim_end()
// .trim_matches('"')
// .to_owned();
// for i in keys {
// if *i == mkey {
// current_key = Some(&mkey);
// }
// }
// boundary_found = false;
// } else if let Some(key) = current_key {
// if None == result.get(key) {
// result.insert(key, part.to_vec());
// continue;
// }
// result.get_mut(key).unwrap().extend_from_slice(part);
// }
// }
// if result.len() == 0 {
// return Err(ParseFormError {
// error: ParseErrors::NoData,
// });
// }
// let return_result: HashMap<&str, Result<&str, ParseErrors>> =
// HashMap::with_capacity(keys.len());
//
// for key in keys {
// let val = result.get(key).ok_or(ParseFormError {
// error: ParseErrors::NoData,
// }).map(|value| String::from_utf8(value))
// let val = if let Ok(str) = String::from_utf8(val) {
// Ok(str)
// } else {
// Err(ParseFormError {
// error: ParseErrors::BadData,
// })
// };
// }
// }
// _ => Err(ParseFormError {
// error: ParseErrors::BadData,
// }),
// }
// }
}
#[cfg(test)]
mod test {
use crate::handling::routes::Data;
use super::Request;
#[test]
fn try_post_text() {
let req = Request {
uri: "",
headers: vec!["Content-Type: application/x-www-form-urlencoded".to_string()],
method: crate::handling::methods::Method::Post,
};
let data = Data {
buffer: b"message=23&message1=24".to_vec(),
is_complete: true,
};
assert_eq!(
vec![&Ok(b"23".to_vec()), &Ok(b"24".to_vec())],
req.get_post_data(&["message", "message1"], &data)
.unwrap()
.values()
.collect::<Vec<_>>()
);
}
}