//! Types and traits for generating responses. use crate::{ body::{box_body, BoxBody}, Error, }; use bytes::Bytes; use http::{header, HeaderMap, HeaderValue, Response, StatusCode}; use http_body::{ combinators::{MapData, MapErr}, Empty, Full, }; use std::{borrow::Cow, convert::Infallible}; use tower::{util::Either, BoxError}; #[doc(no_inline)] pub use crate::Json; mod redirect; pub use self::redirect::Redirect; pub mod sse; pub use sse::{sse, Sse}; /// Trait for generating responses. /// /// Types that implement `IntoResponse` can be returned from handlers. /// /// # Implementing `IntoResponse` /// /// You generally shouldn't have to implement `IntoResponse` manually, as axum /// provides implementations for many common types. /// /// A manual implementation should only be necessary if you have a custom /// response body type: /// /// ```rust /// use axum::{prelude::*, response::IntoResponse}; /// use http_body::Body; /// use http::{Response, HeaderMap}; /// use bytes::Bytes; /// use std::{ /// convert::Infallible, /// task::{Poll, Context}, /// pin::Pin, /// }; /// /// struct MyBody; /// /// // First implement `Body` for `MyBody`. This could for example use /// // some custom streaming protocol. /// impl Body for MyBody { /// type Data = Bytes; /// type Error = Infallible; /// /// fn poll_data( /// self: Pin<&mut Self>, /// cx: &mut Context<'_> /// ) -> Poll>> { /// # unimplemented!() /// // ... /// } /// /// fn poll_trailers( /// self: Pin<&mut Self>, /// cx: &mut Context<'_> /// ) -> Poll, Self::Error>> { /// # unimplemented!() /// // ... /// } /// } /// /// // Now we can implement `IntoResponse` directly for `MyBody` /// impl IntoResponse for MyBody { /// type Body = Self; /// type BodyError = ::Error; /// /// fn into_response(self) -> Response { /// Response::new(self) /// } /// } /// /// // We don't need to implement `IntoResponse for Response` as that is /// // covered by a blanket implementation in axum. /// /// // `MyBody` can now be returned from handlers. /// let app = route("/", get(|| async { MyBody })); /// # async { /// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; /// ``` pub trait IntoResponse { /// The body type of the response. /// /// Unless you're implementing this trait for a custom body type, these are /// some common types you can use: /// /// - [`axum::body::Body`]: A good default that supports most use cases. /// - [`axum::body::Empty`]: When you know your response is always /// empty. /// - [`axum::body::Full`]: When you know your response always /// contains exactly one chunk. /// - [`axum::body::BoxBody`]: If you need to unify multiple body types into /// one, or return a body type that cannot be named. Can be created with /// [`box_body`]. /// /// [`axum::body::Body`]: crate::body::Body /// [`axum::body::Empty`]: crate::body::Empty /// [`axum::body::Full`]: crate::body::Full /// [`axum::body::BoxBody`]: crate::body::BoxBody type Body: http_body::Body + Send + Sync + 'static; /// The error type `Self::Body` might generate. /// /// Generally it should be possible to set this to: /// /// ```rust,ignore /// type BodyError = ::Error; /// ``` /// /// This associated type exists mainly to make returning `impl IntoResponse` /// possible and to simplify trait bounds internally in axum. type BodyError: Into; /// Create a response. fn into_response(self) -> Response; } impl IntoResponse for () { type Body = Empty; type BodyError = Infallible; fn into_response(self) -> Response { Response::new(Empty::new()) } } impl IntoResponse for Infallible { type Body = Empty; type BodyError = Infallible; fn into_response(self) -> Response { match self {} } } impl IntoResponse for Either where T: IntoResponse, K: IntoResponse, { type Body = BoxBody; type BodyError = Error; fn into_response(self) -> Response { match self { Either::A(inner) => inner.into_response().map(box_body), Either::B(inner) => inner.into_response().map(box_body), } } } impl IntoResponse for Result where T: IntoResponse, E: IntoResponse, { type Body = BoxBody; type BodyError = Error; fn into_response(self) -> Response { match self { Ok(value) => value.into_response().map(box_body), Err(err) => err.into_response().map(box_body), } } } impl IntoResponse for Response where B: http_body::Body + Send + Sync + 'static, B::Error: Into, { type Body = B; type BodyError = ::Error; fn into_response(self) -> Self { self } } macro_rules! impl_into_response_for_body { ($body:ty) => { impl IntoResponse for $body { type Body = $body; type BodyError = <$body as http_body::Body>::Error; fn into_response(self) -> Response { Response::new(self) } } }; } impl_into_response_for_body!(hyper::Body); impl_into_response_for_body!(Full); impl_into_response_for_body!(Empty); impl IntoResponse for http_body::combinators::BoxBody where E: Into + 'static, { type Body = Self; type BodyError = E; fn into_response(self) -> Response { Response::new(self) } } impl IntoResponse for MapData where B: http_body::Body + Send + Sync + 'static, F: FnMut(B::Data) -> Bytes + Send + Sync + 'static, B::Error: Into, { type Body = Self; type BodyError = ::Error; fn into_response(self) -> Response { Response::new(self) } } impl IntoResponse for MapErr where B: http_body::Body + Send + Sync + 'static, F: FnMut(B::Error) -> E + Send + Sync + 'static, E: Into, { type Body = Self; type BodyError = E; fn into_response(self) -> Response { Response::new(self) } } impl IntoResponse for &'static str { type Body = Full; type BodyError = Infallible; #[inline] fn into_response(self) -> Response { Cow::Borrowed(self).into_response() } } impl IntoResponse for String { type Body = Full; type BodyError = Infallible; #[inline] fn into_response(self) -> Response { Cow::<'static, str>::Owned(self).into_response() } } impl IntoResponse for std::borrow::Cow<'static, str> { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Full::from(self)); res.headers_mut() .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain")); res } } impl IntoResponse for Bytes { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Full::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for &'static [u8] { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Full::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for Vec { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Full::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for std::borrow::Cow<'static, [u8]> { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Full::from(self)); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"), ); res } } impl IntoResponse for StatusCode { type Body = Empty; type BodyError = Infallible; fn into_response(self) -> Response { Response::builder().status(self).body(Empty::new()).unwrap() } } impl IntoResponse for (StatusCode, T) where T: IntoResponse, { type Body = T::Body; type BodyError = T::BodyError; fn into_response(self) -> Response { let mut res = self.1.into_response(); *res.status_mut() = self.0; res } } impl IntoResponse for (HeaderMap, T) where T: IntoResponse, { type Body = T::Body; type BodyError = T::BodyError; fn into_response(self) -> Response { let mut res = self.1.into_response(); res.headers_mut().extend(self.0); res } } impl IntoResponse for (StatusCode, HeaderMap, T) where T: IntoResponse, { type Body = T::Body; type BodyError = T::BodyError; fn into_response(self) -> Response { let mut res = self.2.into_response(); *res.status_mut() = self.0; res.headers_mut().extend(self.1); res } } impl IntoResponse for HeaderMap { type Body = Empty; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(Empty::new()); *res.headers_mut() = self; res } } /// An HTML response. /// /// Will automatically get `Content-Type: text/html`. #[derive(Clone, Copy, Debug)] pub struct Html(pub T); impl IntoResponse for Html where T: Into>, { type Body = Full; type BodyError = Infallible; fn into_response(self) -> Response { let mut res = Response::new(self.0.into()); res.headers_mut() .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html")); res } } impl From for Html { fn from(inner: T) -> Self { Self(inner) } } #[cfg(test)] mod tests { use super::*; use crate::body::Body; use http::header::{HeaderMap, HeaderName}; #[test] fn test_merge_headers() { struct MyResponse; impl IntoResponse for MyResponse { type Body = Body; type BodyError = ::Error; fn into_response(self) -> Response { let mut resp = Response::new(String::new().into()); resp.headers_mut() .insert(HeaderName::from_static("a"), HeaderValue::from_static("1")); resp } } fn check(resp: impl IntoResponse) { let resp = resp.into_response(); assert_eq!( resp.headers().get(HeaderName::from_static("a")).unwrap(), &HeaderValue::from_static("1") ); assert_eq!( resp.headers().get(HeaderName::from_static("b")).unwrap(), &HeaderValue::from_static("2") ); } let headers: HeaderMap = std::iter::once((HeaderName::from_static("b"), HeaderValue::from_static("2"))) .collect(); check((headers.clone(), MyResponse)); check((StatusCode::OK, headers, MyResponse)); } }