use bytes::Bytes;
use cookie::CookieJar;
use http::request::Parts;
use http::{HeaderMap, Method, Uri, Version};
use http_body::Body;
use http_body_util::combinators::UnsyncBoxBody;
use hyper::body::Incoming;
use std::fmt::{self, Debug};
use std::sync::Arc;
use super::body::RequestBody;
use super::params::{Param, PathParams, QueryParam};
use crate::body::AnyBody;
use crate::Error;
pub struct Request<State = ()> {
pub(crate) parts: Box<Parts>,
body: RequestBody,
state: Arc<State>,
cookies: Option<Box<CookieJar>>,
pub(crate) params: PathParams,
}
impl<State> Request<State> {
pub fn into_body(self) -> RequestBody {
self.body
}
pub fn into_inner(self) -> http::Request<RequestBody> {
let (parts, body) = self.into_parts();
http::Request::from_parts(*parts, body)
}
pub fn into_parts(self) -> (Box<Parts>, RequestBody) {
(self.parts, self.body)
}
pub fn map<F, T>(self, map: F) -> Self
where
F: FnOnce(AnyBody<Incoming>) -> T,
T: Body<Data = Bytes, Error = Error> + Send + Sync + 'static,
{
let input = self.body.into_inner();
let output = map(input);
let box_body = AnyBody::Box(UnsyncBoxBody::new(output));
Self {
body: RequestBody::new(box_body),
..self
}
}
pub fn cookies(&self) -> Option<&CookieJar> {
self.cookies.as_deref()
}
pub fn headers(&self) -> &HeaderMap {
&self.parts.headers
}
pub fn method(&self) -> &Method {
&self.parts.method
}
pub fn param<'a>(&self, name: &'a str) -> Param<'_, 'a> {
let path = self.parts.uri.path();
let at = self.params.get(name);
Param::new(Some(at), name, path)
}
pub fn query<'a>(&self, name: &'a str) -> QueryParam<'_, 'a> {
let query = self.parts.uri.query().unwrap_or("");
QueryParam::new(name, query)
}
pub fn state(&self) -> &Arc<State> {
&self.state
}
pub fn uri(&self) -> &Uri {
&self.parts.uri
}
pub fn version(&self) -> Version {
self.parts.version
}
}
impl<State> Request<State> {
pub(crate) fn new(parts: Box<Parts>, body: RequestBody, state: Arc<State>) -> Self {
Self {
parts,
body,
state,
cookies: None,
params: PathParams::new(Vec::new()),
}
}
pub(crate) fn cookies_mut(&mut self) -> &mut CookieJar {
self.cookies.get_or_insert_with(Default::default)
}
}
impl<State> Debug for Request<State> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Request")
.field("method", self.method())
.field("uri", self.uri())
.field("params", &self.params)
.field("version", &self.version())
.field("headers", self.headers())
.field("cookies", &self.cookies)
.field("body", &self.body)
.finish()
}
}