diff --git a/server/src/http_params.rs b/server/src/http_params.rs new file mode 100644 index 0000000..d47ff3d --- /dev/null +++ b/server/src/http_params.rs @@ -0,0 +1,84 @@ +use hyper::body::{to_bytes, Bytes, HttpBody}; +use hyper::Body; +use std::collections::HashMap; +use std::u8; + +fn bytes_to_string(bytes: &Bytes) -> String{ + let mut ret = String::new(); + for b in bytes.iter() { + ret.push(*b as char); + } + ret +} + +fn map_qs(query_string_raw: Option<&str>) -> HashMap<&str, &str> { + /* + * Parse a given query string and build a hashmap from it + */ + let mut map: HashMap<&str, &str> = HashMap::new(); + if let Some(qs) = query_string_raw { + let raw_pairs: Vec<&str> = qs.split('&').collect(); + for raw_pair in raw_pairs.iter() { + let sub_segment: Vec<&str> = raw_pair.split('=').collect(); + match sub_segment.len() { + 2 => map.insert(sub_segment[0], sub_segment[1]), + _ => continue + }; + } + } + map +} + +fn parse_body(map: &mut HashMap<&str, &str>, data: String) { + // Line delimited and 1 key value pair per line + // +} + +async fn map_body(map: &mut HashMap<&str, &str>, body_raw: &mut Body) { + /* + * Given an http body from Hyper we take the body data and parse out all the + * Parameters given to us up to the first non valid http character + */ + // First we grab a slice of the body data + // next we get a slice up to the first invalid char or the end of the body + // TODO: add some kind of .env limiter so we don't ingest too much data + const NEWLINE: u8 = 0x10; + const PRINTABLE_MIN: u8 = 0x20; + const PRINTABLE_MAX: u8 = 0x7e; + + match to_bytes(body_raw).await { + Ok(data) => { + if data.len() == 0 || data.len() > 4096 { + println!("EMPTY BODY"); + return; + } + // Assuming we havea reasonable sized body we check + println!("START BODY"); + let mut valid = true; + for byte in data.iter() { + match byte { + // only new lines and printable ascii chars are valid in our body + // delete characters are not valid however + &NEWLINE | PRINTABLE_MIN ..= PRINTABLE_MAX => {} + _ => { + valid = false; + break; + } + } + } + if valid { + parse_body(map, bytes_to_string(&data)); + } + println!("\nEND BODY") + }, + Err(_) => {} + } +} + + +// NOTE: we only need an async call because map body itself makes asynchronous calls +pub async fn parse_params<'q>(qs_raw: Option<&'q str>, body_raw: &mut Body) -> HashMap<&'q str, &'q str> { + let mut qs_map = map_qs(qs_raw); + map_body(&mut qs_map, body_raw).await; + qs_map +} \ No newline at end of file