use std::collections::HashMap;
use crate::method::Method;
pub struct Request {
pub(crate) body: Vec<u8>,
pub(crate) headers: Vec<(String, String)>,
pub(crate) method: Method,
pub(crate) params: HashMap<String, String>,
pub(crate) path: String,
pub(crate) query: HashMap<String, String>,
pub(crate) raw_query: String,
}
impl Request {
pub(crate) fn new(
body: Vec<u8>,
headers: Vec<(String, String)>,
method: Method,
params: HashMap<String, String>,
path: String,
raw_query: String,
) -> Self {
let query = parse_query(&raw_query);
Self { body, headers, method, params, path, query, raw_query }
}
pub fn method(&self) -> Method { self.method }
pub fn path(&self) -> &str { &self.path }
pub fn query(&self, key: &str) -> Option<&str> {
self.query.get(key).map(String::as_str)
}
pub fn raw_query(&self) -> &str { &self.raw_query }
pub fn headers(&self) -> &[(String, String)] { &self.headers }
pub fn body(&self) -> &[u8] { &self.body }
pub fn header(&self, name: &str) -> Option<&str> {
self.headers.iter()
.find(|(k, _)| k.eq_ignore_ascii_case(name))
.map(|(_, v)| v.as_str())
}
pub fn param(&self, key: &str) -> Option<&str> {
self.params.get(key).map(String::as_str)
}
}
fn parse_query(raw: &str) -> HashMap<String, String> {
if raw.is_empty() {
return HashMap::new();
}
raw.split('&')
.filter_map(|pair| {
let (k, v) = pair.split_once('=').unwrap_or((pair, ""));
if k.is_empty() { return None; }
Some((k.to_owned(), v.to_owned()))
})
.collect()
}