use bytes::Bytes;
use cookie::CookieJar;
use futures_core::Stream;
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SET_COOKIE, TRANSFER_ENCODING};
use http::response::Parts;
use http::{HeaderMap, HeaderName, HeaderValue, StatusCode, Version};
use http_body::{Body, Frame};
use serde::Serialize;
use std::fmt::{self, Debug, Formatter};
use super::{ResponseBody, ResponseBuilder, StreamAdapter};
use super::{APPLICATION_JSON, CHUNKED_ENCODING, TEXT_HTML, TEXT_PLAIN};
use crate::body::{AnyBody, ByteBuffer};
use crate::{Error, Result};
pub struct Response {
cookies: Option<Box<CookieJar>>,
response: http::Response<ResponseBody>,
}
impl Response {
pub fn new(body: ResponseBody) -> Self {
Self {
cookies: None,
response: http::Response::new(body),
}
}
pub fn new_with_status(body: ResponseBody, status: StatusCode) -> Self {
let mut response = Self::new(body);
response.set_status(status);
response
}
pub fn html(body: String) -> Self {
let len = body.len();
let mut response = Self::new(ResponseBody::from_string(body));
let headers = response.headers_mut();
headers.insert(CONTENT_TYPE, TEXT_HTML);
headers.insert(CONTENT_LENGTH, len.into());
response
}
pub fn text(body: String) -> Self {
let len = body.len();
let mut response = Self::new(ResponseBody::from_string(body));
let headers = response.headers_mut();
headers.insert(CONTENT_TYPE, TEXT_PLAIN);
headers.insert(CONTENT_LENGTH, len.into());
response
}
pub fn json<T: Serialize>(body: &T) -> Result<Response, Error> {
let buf = serde_json::to_vec(body)?;
let len = buf.len();
let mut response = Self::new(ResponseBody::from_vec(buf));
let headers = response.headers_mut();
headers.insert(CONTENT_TYPE, APPLICATION_JSON);
headers.insert(CONTENT_LENGTH, len.into());
Ok(response)
}
pub fn stream<T, E>(stream: T) -> Self
where
T: Stream<Item = Result<Frame<Bytes>, E>> + Send + Unpin + 'static,
Error: From<E>,
{
let stream_body = StreamAdapter::new(stream);
let mut response = Self::new(ResponseBody::from_dyn(stream_body));
response.set_header(TRANSFER_ENCODING, CHUNKED_ENCODING);
response
}
pub fn not_found() -> Self {
let mut response = Response::text("Not Found".to_string());
response.set_status(StatusCode::NOT_FOUND);
response
}
pub fn build() -> ResponseBuilder {
ResponseBuilder::new()
}
pub fn from_parts(parts: Parts, body: ResponseBody) -> Self {
Self {
cookies: None,
response: http::Response::from_parts(parts, body),
}
}
pub fn into_parts(self) -> (Parts, ResponseBody) {
self.response.into_parts()
}
pub fn map<F, T>(self, map: F) -> Self
where
F: FnOnce(AnyBody<ByteBuffer>) -> T,
T: Body<Data = Bytes, Error = Error> + Send + Sync + 'static,
{
let (parts, body) = self.response.into_parts();
let output = map(body.into_inner());
let body = ResponseBody::from_dyn(output);
Self::from_parts(parts, body)
}
pub fn body(&self) -> &ResponseBody {
self.response.body()
}
pub fn body_mut(&mut self) -> &mut ResponseBody {
self.response.body_mut()
}
pub fn cookies(&self) -> Option<&CookieJar> {
self.cookies.as_deref()
}
pub fn cookies_mut(&mut self) -> &mut CookieJar {
self.cookies.get_or_insert_with(Default::default)
}
pub fn headers(&self) -> &HeaderMap {
self.response.headers()
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
self.response.headers_mut()
}
pub fn set_header(&mut self, name: HeaderName, value: HeaderValue) {
self.headers_mut().insert(name, value);
}
pub fn status(&self) -> StatusCode {
self.response.status()
}
pub fn status_mut(&mut self) -> &mut StatusCode {
self.response.status_mut()
}
pub fn set_status(&mut self, status: StatusCode) {
*self.response.status_mut() = status;
}
pub fn version(&self) -> Version {
self.response.version()
}
}
impl Response {
pub(crate) fn into_outgoing_response(self) -> http::Response<AnyBody<ByteBuffer>> {
let (mut parts, body) = self.response.into_parts();
let set_cookie_headers = self.cookies.as_ref().map(|cookies| {
cookies.delta().filter_map(|cookie| {
match cookie.encoded().to_string().parse() {
Ok(header) => Some((SET_COOKIE, header)),
Err(error) => {
let _ = error;
None
}
}
})
});
if let Some(headers) = set_cookie_headers {
parts.headers.extend(headers);
}
http::Response::from_parts(parts, body.into_inner())
}
pub(crate) fn set_cookies(&mut self, cookies: Box<CookieJar>) {
self.cookies = Some(cookies);
}
}
impl Default for Response {
fn default() -> Self {
Self::new(Default::default())
}
}
impl Debug for Response {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.response, f)
}
}
impl From<http::Response<ResponseBody>> for Response {
fn from(response: http::Response<ResponseBody>) -> Self {
Self {
response,
cookies: None,
}
}
}
impl From<Response> for http::Response<AnyBody<ByteBuffer>> {
fn from(from: Response) -> Self {
let (parts, body) = from.into_parts();
let body = body.into_inner();
Self::from_parts(parts, body)
}
}