use serde_json::{self, Value}; use hyper::http::HeaderValue; use hyper::Response; use hyper::Body; use std::collections::HashMap; const APP_JSON_HEADER: &'static str = "application/json"; const CONTENT_TYPE: &'static str = "Content-Type"; pub fn set_json_body(response: &mut Response, values: Value) { response.headers_mut().insert( CONTENT_TYPE, HeaderValue::from_static(APP_JSON_HEADER)); *response.body_mut() = Body::from(values.to_string()); } fn percent_decode(url: &str) -> String { // completely ripped from: https://docs.rs/urldecode/0.1.1/src/urldecode/lib.rs.html#1-21 let url = String::from(url); let mut decoded = String::from(""); let mut skip = 0; for i in 0..url.len() { if skip != 0 { skip -= 1; continue; } let c: char = url.chars().nth(i).unwrap(); if c == '%' { let left = url.chars().nth(i + 1).unwrap(); let right = url.chars().nth(i + 2).unwrap(); let byte = u8::from_str_radix(&format!("{}{}", left, right), 16).unwrap(); decoded += &(byte as char).to_string(); skip = 2; } else { decoded += &c.to_string(); } } decoded } pub fn parse_query_string<'qs>(string: &str) -> HashMap { let mut map: HashMap = HashMap::new(); // get pairs of [key1=value1, key2=value2, ...] for pair in string.split('&') { let kv: Vec<&str> = pair.split('=').collect(); match (kv.get(0), kv.get(1)) { // only if the format is some_key=some_value do we actually care about it (Some(key), Some(value)) => { map.insert(percent_decode(&key), percent_decode(&value)); }, // ignore all non-pairs _ => continue }; } return map; } // Pulls out Option from a HashMap<&str, &str> // NOTE: If you need &str just use the hashmap directly #[macro_export] macro_rules! qs_param { ($obj:expr, $id:literal, $type:ty) => { match $obj.get($id) { Some(val) => { if let Ok(pval) = val.to_string().parse::<$type>() { Some(pval) } else{ None } }, None => None } } } #[cfg(test)] mod tests { use std::collections::HashMap; #[test] fn validate_qs_param() { let mut map: HashMap<&str, &str> = HashMap::new(); map.insert("key", "value"); map.insert("asdf", "123"); // It should be noted if you want &str values then just // use the hashmap directly, since the macro is a bit clumsy with strings // Thust the cast to a String not &str is required assert_eq!(qs_param!(map, "key", String).is_some(), true); assert_eq!(qs_param!(map, "not-there", String).is_some(), false); assert_eq!(qs_param!(map, "asdf", u64).is_some(), true); assert_eq!(qs_param!(map, "asdf", bool).is_some(), false); } }