#[cfg(feature = "file")]
use crate::file::FilePart;
use crate::{
body::{Form, FromBytes, IncomingBody, Json, Query, QueryTrait},
error::Error,
};
use cookie::{Cookie, CookieJar};
use headers::{Header, HeaderMapExt};
use http_body_util::BodyExt;
use hyper::body::Bytes;
#[cfg(feature = "file")]
use multimap::MultiMap;
use serde::de::DeserializeOwned;
use std::{
collections::HashMap,
net::SocketAddr,
ops::{Deref, DerefMut},
};
pub struct Request {
#[doc(hidden)]
inner: hyper::Request<IncomingBody>,
#[doc(hidden)]
params: HashMap<String, String>,
#[doc(hidden)]
#[cfg(feature = "file")]
files: MultiMap<String, FilePart>,
#[doc(hidden)]
cookies: CookieJar,
#[doc(hidden)]
peer_addr: SocketAddr,
}
impl Request {
#[doc(hidden)]
#[inline]
pub fn new(inner: hyper::Request<IncomingBody>, remote_addr: SocketAddr) -> Self {
Request {
inner,
params: Default::default(),
#[cfg(feature = "file")]
files: MultiMap::new(),
cookies: Default::default(),
peer_addr: remote_addr,
}
}
#[inline]
pub fn inner_request(&mut self) -> &mut hyper::Request<IncomingBody> {
&mut self.inner
}
#[inline]
pub fn header<T: Header>(&self) -> Option<T> {
self.inner.headers().typed_get()
}
#[inline]
pub fn peer_addr(&self) -> &SocketAddr {
&self.peer_addr
}
#[inline]
pub fn peer_addr_mut(&mut self) -> &mut SocketAddr {
&mut self.peer_addr
}
#[inline]
pub fn cookies(&self) -> &CookieJar {
&self.cookies
}
#[inline]
pub fn cookies_mut(&mut self) -> &mut CookieJar {
&mut self.cookies
}
#[doc(hidden)]
#[inline]
pub fn take_cookies(&mut self) -> CookieJar {
std::mem::take(&mut self.cookies)
}
#[inline]
pub fn params(&self) -> &HashMap<String, String> {
&self.params
}
#[inline]
pub fn params_mut(&mut self) -> &mut HashMap<String, String> {
&mut self.params
}
#[inline]
pub fn param<T: std::str::FromStr>(&mut self, key: &str) -> Result<T, Error> {
let value = self
.params
.remove(key)
.ok_or_else(|| Error::MissingParameter(key.to_string(), false))?;
Ok(value
.parse::<T>()
.map_err(|_| Error::InvalidParameter(key.to_string(), false))?)
}
#[inline]
pub fn query<'de, B>(&'de self) -> Result<B, Error>
where
B: serde::Deserialize<'de>,
{
let query = self.uri().query().unwrap_or("");
serde_urlencoded::from_str::<B>(query).map_err(Error::SerdeUrlDe)
}
#[inline]
pub fn content_type(&self) -> Option<&str> {
let content_type = self.headers().get("content-type")?;
let content_type = content_type.to_str().ok()?;
Some(content_type)
}
pub fn take_body(&mut self) -> IncomingBody {
std::mem::replace(self.body_mut(), IncomingBody::Empty)
}
#[inline]
pub async fn body_bytes(&mut self) -> Result<Bytes, Error> {
let bytes = self.body_mut().collect().await?.to_bytes();
Ok(bytes)
}
#[inline]
pub async fn body_string(&mut self) -> Result<String, Error> {
let bytes = self.body_bytes().await?;
Ok(String::from_utf8(bytes.to_vec())?)
}
#[cfg(feature = "file")]
#[inline]
async fn form_data(&mut self) -> Result<(), Error> {
let c_type = self.content_type().expect("bad request");
let boundary = multer::parse_boundary(c_type)?;
let boundary = boundary.as_str();
let mut multipart = multer::Multipart::new(self.take_body(), boundary);
while let Some(mut field) = multipart.next_field().await? {
if let Some(name) = field.name().map(|s| s.to_owned()) {
if field.headers().get("content-type").is_some() {
self.files.insert(name, FilePart::new(&mut field).await?);
}
}
}
Ok(())
}
#[cfg(feature = "file")]
#[inline]
pub async fn file(&mut self, key: &str) -> Result<&FilePart, Error> {
self.form_data().await?;
let file_part = self.files.get(key).unwrap();
Ok(file_part)
}
#[cfg(feature = "file")]
#[inline]
pub async fn files(&mut self, key: &str) -> Result<&Vec<FilePart>, Error> {
self.form_data().await?;
let file_part = self.files.get_vec(key).unwrap();
Ok(file_part)
}
#[cfg(feature = "file")]
#[inline]
pub async fn upload(&mut self, key: &str, save_path: &str) -> Result<u64, Error> {
let file = self.file(key).await?;
std::fs::create_dir_all(save_path)?;
let dest = format!("{}/{}", save_path, file.name().unwrap());
Ok(std::fs::copy(file.path(), std::path::Path::new(&dest))?)
}
#[cfg(feature = "file")]
#[inline]
pub async fn uploads(&mut self, key: &str, save_path: &str) -> Result<String, Error> {
let files = self.files(key).await?;
std::fs::create_dir_all(save_path)?;
let mut msgs = Vec::with_capacity(files.len());
for file in files {
let dest = format!("{}/{}", save_path, file.name().unwrap());
if let Err(e) = std::fs::copy(file.path(), std::path::Path::new(&dest)) {
return Ok(format!("file not found in request: {e}"));
} else {
msgs.push(dest);
}
}
Ok(format!("Files uploaded:\n\n{}", msgs.join("\n")))
}
#[inline]
pub async fn parse<T>(&mut self) -> Result<T, Error>
where
T: DeserializeOwned,
{
let data = self.body_mut().collect().await?.to_bytes();
let essence = self.content_type();
match essence {
Some("application/json") => serde_json::from_slice(&data).map_err(Error::SerdeJson),
Some("application/x-www-form-urlencoded") => {
serde_urlencoded::from_bytes(&data).map_err(Error::SerdeUrlDe)
}
#[cfg(feature = "cbor")]
Some("application/cbor") => {
ciborium::de::from_reader(&data[..]).map_err(|e| Error::Other(e.to_string()))
}
#[cfg(feature = "msgpack")]
Some("application/msgpack") => {
rmp_serde::from_slice(&data).map_err(Error::MsgpackDeserialization)
}
_ => Err(Error::Other(String::from("Invalid Context-Type"))),
}
}
#[inline]
pub async fn parse_query<T: QueryTrait>(&mut self) -> Result<Query<T::Output>, Error> {
let query = self.uri().query().unwrap_or("");
let value = T::from_str(query)?;
Ok(Query(value))
}
#[inline]
pub async fn parse_body<T: FromBytes>(&mut self) -> Result<T::Output, Error> {
let bytes = self.body_mut().collect().await?.to_bytes();
let value = T::from_bytes(bytes)?;
Ok(value)
}
#[inline]
pub async fn parse_json<T: FromBytes>(&mut self) -> Result<Json<T::Output>, Error> {
let bytes = self.body_mut().collect().await?.to_bytes();
let value = T::from_bytes(bytes)?;
Ok(Json(value))
}
#[inline]
pub async fn parse_form<T: FromBytes>(&mut self) -> Result<Form<T::Output>, Error> {
let bytes = self.body_mut().collect().await?.to_bytes();
let value = T::from_bytes(bytes)?;
Ok(Form(value))
}
#[inline]
pub fn parse_cookies(&mut self) {
let jar = &mut self.cookies;
if let Some(cookie_iter) = self
.inner
.headers()
.get("Cookie")
.and_then(|cookies| cookies.to_str().ok())
.map(|cookies_str| cookies_str.split("; "))
.map(|cookie_iter| {
cookie_iter.filter_map(|cookie_s| Cookie::parse(cookie_s.to_string()).ok())
})
{
cookie_iter.for_each(|c| jar.add_original(c));
}
}
}
impl Deref for Request {
type Target = hyper::Request<IncomingBody>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for Request {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl From<Request> for hyper::Request<IncomingBody> {
#[inline]
fn from(request: Request) -> Self {
request.inner
}
}
#[inline]
#[doc(hidden)]
#[allow(dead_code)]
pub fn query_str_to_hashmap(
query_str: &str,
) -> Result<HashMap<String, String>, serde_urlencoded::de::Error> {
serde_urlencoded::from_str::<HashMap<String, String>>(query_str)
}
#[inline]
#[doc(hidden)]
#[allow(dead_code)]
pub fn query_str_to_type<T>(query_str: &str) -> Result<T, serde_urlencoded::de::Error>
where
T: for<'a> serde::Deserialize<'a>,
{
serde_urlencoded::from_str::<T>(query_str)
}