use bytes::Bytes;
use http::{HeaderMap, Method, Uri};
use http_body_util::BodyExt;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
pub type Extensions = http::Extensions;
pub struct Request {
method: Method,
uri: Uri,
headers: HeaderMap,
body: Bytes,
params: HashMap<String, String>,
query: HashMap<String, String>,
extensions: Extensions,
}
impl Request {
pub fn new(
method: Method,
uri: Uri,
headers: HeaderMap,
body: Bytes,
) -> Self {
let query = Self::parse_query_params(&uri);
Self {
method,
uri,
headers,
body,
params: HashMap::new(),
query,
extensions: Extensions::new(),
}
}
pub fn method(&self) -> &Method {
&self.method
}
pub fn uri(&self) -> &Uri {
&self.uri
}
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn param(&self, name: &str) -> Option<&str> {
self.params.get(name).map(|s| s.as_str())
}
pub fn query(&self, name: &str) -> Option<&str> {
self.query.get(name).map(|s| s.as_str())
}
pub fn params(&self) -> &HashMap<String, String> {
&self.params
}
pub fn query_params(&self) -> &HashMap<String, String> {
&self.query
}
pub fn set_param(&mut self, name: String, value: String) {
self.params.insert(name, value);
}
pub async fn json<T: DeserializeOwned>(&mut self) -> crate::Result<T> {
let body_bytes = &self.body;
serde_json::from_slice(body_bytes)
.map_err(|e| crate::Error::JsonParseError(e))
}
pub fn body(&self) -> &Bytes {
&self.body
}
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.extensions
}
pub fn extensions(&self) -> &Extensions {
&self.extensions
}
fn parse_query_params(uri: &Uri) -> HashMap<String, String> {
let mut params = HashMap::new();
if let Some(query) = uri.query() {
for pair in query.split('&') {
if let Some((key, value)) = pair.split_once('=') {
if let (Ok(decoded_key), Ok(decoded_value)) = (
urlencoding::decode(key),
urlencoding::decode(value),
) {
params.insert(decoded_key.into_owned(), decoded_value.into_owned());
}
} else {
if let Ok(decoded_key) = urlencoding::decode(pair) {
params.insert(decoded_key.into_owned(), String::new());
}
}
}
}
params
}
}
impl<B> TryFrom<hyper::Request<B>> for Request
where
B: hyper::body::Body + Send + 'static,
B::Data: Send,
B::Error: std::error::Error + Send + Sync + 'static,
{
type Error = crate::Error;
fn try_from(req: hyper::Request<B>) -> Result<Self, Self::Error> {
let (_parts, _body) = req.into_parts();
Err(crate::Error::InternalServerError(
"Use from_hyper_async instead".to_string()
))
}
}
impl Request {
pub async fn from_hyper<B>(req: hyper::Request<B>) -> crate::Result<Self>
where
B: hyper::body::Body + Send + 'static,
B::Data: Send,
B::Error: std::error::Error + Send + Sync + 'static,
{
let (parts, body) = req.into_parts();
let body_bytes = body
.collect()
.await
.map_err(|e| crate::Error::InternalServerError(e.to_string()))?
.to_bytes();
Ok(Request::new(
parts.method,
parts.uri,
parts.headers,
body_bytes,
))
}
}