// 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<_>>() ); } }