use core::ops::{Deref, DerefMut};
use core::str::FromStr;
use core::future::Future;
use core::mem;
use std::fs;
use crate::{extractor, header, upgrade};
pub mod errors;
pub(crate) type HyperResponse = hyper::Response<hyper::Body>;
#[derive(Debug)]
pub struct Response {
inner: HyperResponse,
}
impl Response {
#[inline]
pub fn new(hyper: HyperResponse) -> Self {
Self {
inner: hyper
}
}
#[inline]
pub fn status(&self) -> http::StatusCode {
self.inner.status()
}
#[inline]
pub fn is_info(&self) -> bool {
self.inner.status().is_informational()
}
#[inline]
pub fn is_success(&self) -> bool {
self.inner.status().is_success()
}
#[inline]
pub fn is_redirect(&self) -> bool {
self.inner.status().is_redirection()
}
#[inline]
pub fn is_error(&self) -> bool {
self.is_client_error() || self.is_internal_error()
}
#[inline]
pub fn is_client_error(&self) -> bool {
self.inner.status().is_client_error()
}
#[inline]
pub fn is_internal_error(&self) -> bool {
self.inner.status().is_client_error()
}
#[inline]
pub fn is_upgrade(&self) -> bool {
self.inner.status() == http::StatusCode::SWITCHING_PROTOCOLS
}
#[inline]
pub fn extensions(&self) -> &http::Extensions {
self.inner.extensions()
}
#[inline]
pub fn extensions_mut(&mut self) -> &mut http::Extensions {
self.inner.extensions_mut()
}
#[cfg(feature = "carry_extensions")]
#[inline]
pub(crate) fn replace_extensions(mut self, extensions: &mut http::Extensions) -> Self {
core::mem::swap(extensions, self.extensions_mut());
self
}
#[inline]
pub fn headers(&self) -> &http::HeaderMap {
self.inner.headers()
}
#[inline]
pub fn mime(&self) -> Result<Option<mime::Mime>, errors::ContentTypeError> {
let content_type = self.headers().get(header::CONTENT_TYPE)
.and_then(|content_type| content_type.to_str().ok());
if let Some(content_type) = content_type {
content_type.parse::<mime::Mime>().map(Some).map_err(errors::ContentTypeError::from)
} else {
Ok(None)
}
}
#[cfg(feature = "encoding")]
pub fn charset_encoding(&self) -> Result<&'static encoding_rs::Encoding, errors::ContentTypeError> {
let mime = self.mime()?;
let mime = mime.as_ref().and_then(|mime| mime.get_param(mime::CHARSET));
match mime {
Some(charset) => match encoding_rs::Encoding::for_label(charset.as_str().as_bytes()) {
Some(enc) => Ok(enc),
None => Err(errors::ContentTypeError::UnknownEncoding)
},
None => Ok(encoding_rs::UTF_8),
}
}
#[inline]
pub fn content_len(&self) -> Option<usize> {
self.inner.headers()
.get(header::CONTENT_LENGTH)
.and_then(|header| header.to_str().ok())
.and_then(|header| header.parse().ok())
}
#[inline]
pub fn content_encoding(&self) -> header::ContentEncoding {
self.inner.headers()
.get(header::CONTENT_ENCODING)
.and_then(|header| header.to_str().ok())
.map(|header| header.into())
.unwrap_or(header::ContentEncoding::Identity)
}
#[inline]
pub fn content_disposition(&self) -> Option<header::ContentDisposition> {
self.inner.headers()
.get(header::CONTENT_DISPOSITION)
.and_then(|header| header.to_str().ok())
.and_then(|header| header::ContentDisposition::from_str(header).ok())
}
#[inline]
pub fn cookies_iter(&self) -> extractor::CookieIter {
extractor::CookieIter::new(self.headers().get_all(header::SET_COOKIE).iter())
}
#[inline]
pub fn cookies_jar(&self) -> Result<cookie::CookieJar, cookie::ParseError> {
let mut jar = cookie::CookieJar::new();
for cook in self.cookies_iter() {
jar.add(cook?.into_owned());
}
Ok(jar)
}
#[inline]
pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>, cookie::ParseError> {
let mut cookies = Vec::new();
for cook in self.cookies_iter() {
cookies.push(cook?.into_owned());
}
Ok(cookies)
}
#[inline]
pub fn last_modified(&self) -> Option<httpdate::HttpDate> {
self.inner.headers().get(header::LAST_MODIFIED)
.and_then(|header| header.to_str().ok())
.and_then(|header| httpdate::HttpDate::from_str(header.trim()).ok())
}
#[inline]
pub fn etag(&self) -> Option<etag::EntityTag> {
self.inner.headers().get(header::ETAG)
.and_then(|header| header.to_str().ok())
.and_then(|header| header.trim().parse().ok())
}
#[inline]
pub fn extract_body(&mut self) -> (header::ContentEncoding, Option<usize>, hyper::Body) {
let encoding = self.content_encoding();
let buffer_size = self.content_len();
let mut body = hyper::Body::empty();
mem::swap(&mut body, self.inner.body_mut());
(encoding, buffer_size, body)
}
pub fn body(&mut self) -> impl Future<Output=Result<bytes::Bytes, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
extractor::raw_bytes(body, encoding, buffer_size)
}
pub fn text(&mut self) -> impl Future<Output=Result<String, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
#[cfg(feature = "encoding")]
{
let charset = self.charset_encoding().unwrap_or(encoding_rs::UTF_8);
extractor::text_charset(body, encoding, buffer_size, charset)
}
#[cfg(not(feature = "encoding"))]
{
extractor::text(body, encoding, buffer_size)
}
}
pub fn json<J: serde::de::DeserializeOwned>(&mut self) -> impl Future<Output=Result<J, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
#[cfg(feature = "encoding")]
{
let charset = self.charset_encoding().unwrap_or(encoding_rs::UTF_8);
extractor::json_charset(body, encoding, buffer_size, charset)
}
#[cfg(not(feature = "encoding"))]
{
extractor::json(body, encoding, buffer_size)
}
}
pub fn file(&mut self, file: fs::File) -> impl Future<Output=Result<fs::File, extractor::BodyReadError>> {
#[cfg(debug_assertions)]
{
let meta = file.metadata().expect("To be able to get metadata");
debug_assert!(!meta.permissions().readonly(), "File is read-only");
}
let (encoding, _, body) = self.extract_body();
extractor::file(file, body, encoding)
}
pub fn body_notify<N: extractor::Notifier>(&mut self, notify: N) -> impl Future<Output=Result<bytes::Bytes, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
extractor::raw_bytes_notify(body, encoding, buffer_size, notify)
}
pub fn text_notify<N: extractor::Notifier>(&mut self, notify: N) -> impl Future<Output=Result<String, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
#[cfg(feature = "encoding")]
{
let charset = self.charset_encoding().unwrap_or(encoding_rs::UTF_8);
extractor::text_charset_notify(body, encoding, buffer_size, charset, notify)
}
#[cfg(not(feature = "encoding"))]
{
extractor::text_notify(body, encoding, buffer_size, notify)
}
}
pub fn json_notify<N: extractor::Notifier, J: serde::de::DeserializeOwned>(&mut self, notify: N) -> impl Future<Output=Result<J, extractor::BodyReadError>> {
let (encoding, buffer_size, body) = self.extract_body();
#[cfg(feature = "encoding")]
{
let charset = self.charset_encoding().unwrap_or(encoding_rs::UTF_8);
extractor::json_charset_notify(body, encoding, buffer_size, charset, notify)
}
#[cfg(not(feature = "encoding"))]
{
extractor::json_notify(body, encoding, buffer_size, notify)
}
}
pub fn file_notify<N: extractor::Notifier>(&mut self, file: fs::File, notify: N) -> impl Future<Output=Result<fs::File, extractor::BodyReadError>> {
#[cfg(debug_assertions)]
{
let meta = file.metadata().expect("To be able to get metadata");
debug_assert!(!meta.permissions().readonly(), "File is read-only");
}
let (encoding, _, body) = self.extract_body();
extractor::file_notify(file, body, encoding, notify)
}
pub async fn upgrade<U: upgrade::Upgrade>(self, _: U) -> Result<Result<(Self, hyper::upgrade::Upgraded), hyper::Error>, U::VerifyError> {
if let Err(error) = U::verify_response(self.status(), self.inner.headers(), self.inner.extensions()) {
return Err(error);
}
let (head, body) = self.inner.into_parts();
Ok(match matsu!(upgrade::upgrade_response(head, body.on_upgrade())) {
Ok((hyper, body)) => Ok((Self::new(hyper), body)),
Err(err) => Err(err),
})
}
}
impl From<HyperResponse> for Response {
fn from(inner: HyperResponse) -> Self {
Self {
inner
}
}
}
impl Deref for Response {
type Target = HyperResponse;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for Response {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}