2021-11-30 14:46:13 +01:00
|
|
|
//! Types and traits for generating responses.
|
|
|
|
|
//!
|
|
|
|
|
//! See [`axum::response`] for more details.
|
|
|
|
|
//!
|
|
|
|
|
//! [`axum::response`]: https://docs.rs/axum/latest/axum/response/index.html
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
body::{boxed, BoxBody},
|
|
|
|
|
BoxError,
|
|
|
|
|
};
|
2022-02-17 13:30:42 +01:00
|
|
|
use bytes::{buf::Chain, Buf, Bytes, BytesMut};
|
2021-11-30 14:46:13 +01:00
|
|
|
use http::{
|
2022-01-23 17:46:41 +01:00
|
|
|
header::{self, HeaderMap, HeaderName, HeaderValue},
|
2021-12-05 18:16:46 +00:00
|
|
|
StatusCode,
|
2021-11-30 14:46:13 +01:00
|
|
|
};
|
|
|
|
|
use http_body::{
|
|
|
|
|
combinators::{MapData, MapErr},
|
2022-02-17 13:30:42 +01:00
|
|
|
Empty, Full, SizeHint,
|
|
|
|
|
};
|
|
|
|
|
use std::{
|
|
|
|
|
borrow::Cow,
|
|
|
|
|
convert::Infallible,
|
|
|
|
|
iter,
|
|
|
|
|
pin::Pin,
|
|
|
|
|
task::{Context, Poll},
|
2021-11-30 14:46:13 +01:00
|
|
|
};
|
|
|
|
|
|
2021-12-05 18:16:46 +00:00
|
|
|
/// Type alias for [`http::Response`] whose body type defaults to [`BoxBody`], the most common body
|
2021-12-06 10:30:09 +01:00
|
|
|
/// type used with axum.
|
2021-12-05 18:16:46 +00:00
|
|
|
pub type Response<T = BoxBody> = http::Response<T>;
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
/// 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.
|
|
|
|
|
///
|
|
|
|
|
/// However it might be necessary if you have a custom error type that you want
|
|
|
|
|
/// to return from handlers:
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// use axum::{
|
|
|
|
|
/// Router,
|
2021-12-05 18:16:46 +00:00
|
|
|
/// body::{self, Bytes},
|
2021-11-30 14:46:13 +01:00
|
|
|
/// routing::get,
|
2021-12-05 18:16:46 +00:00
|
|
|
/// http::StatusCode,
|
|
|
|
|
/// response::{IntoResponse, Response},
|
2021-11-30 14:46:13 +01:00
|
|
|
/// };
|
|
|
|
|
///
|
|
|
|
|
/// enum MyError {
|
|
|
|
|
/// SomethingWentWrong,
|
|
|
|
|
/// SomethingElseWentWrong,
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// impl IntoResponse for MyError {
|
2021-12-05 18:16:46 +00:00
|
|
|
/// fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
/// let body = match self {
|
|
|
|
|
/// MyError::SomethingWentWrong => {
|
|
|
|
|
/// body::boxed(body::Full::from("something went wrong"))
|
|
|
|
|
/// },
|
|
|
|
|
/// MyError::SomethingElseWentWrong => {
|
|
|
|
|
/// body::boxed(body::Full::from("something else went wrong"))
|
|
|
|
|
/// },
|
|
|
|
|
/// };
|
|
|
|
|
///
|
|
|
|
|
/// Response::builder()
|
|
|
|
|
/// .status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
|
|
|
/// .body(body)
|
|
|
|
|
/// .unwrap()
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// // `Result<impl IntoResponse, MyError>` can now be returned from handlers
|
|
|
|
|
/// let app = Router::new().route("/", get(handler));
|
|
|
|
|
///
|
|
|
|
|
/// async fn handler() -> Result<(), MyError> {
|
|
|
|
|
/// Err(MyError::SomethingWentWrong)
|
|
|
|
|
/// }
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// Or if you have a custom body type you'll also need to implement
|
|
|
|
|
/// `IntoResponse` for it:
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// use axum::{
|
2021-12-05 18:16:46 +00:00
|
|
|
/// body,
|
2021-11-30 14:46:13 +01:00
|
|
|
/// routing::get,
|
2021-12-05 18:16:46 +00:00
|
|
|
/// response::{IntoResponse, Response},
|
2021-11-30 14:46:13 +01:00
|
|
|
/// Router,
|
|
|
|
|
/// };
|
|
|
|
|
/// use http_body::Body;
|
2021-12-05 18:16:46 +00:00
|
|
|
/// use http::HeaderMap;
|
2021-11-30 14:46:13 +01:00
|
|
|
/// 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<Option<Result<Self::Data, Self::Error>>> {
|
|
|
|
|
/// # unimplemented!()
|
|
|
|
|
/// // ...
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// fn poll_trailers(
|
|
|
|
|
/// self: Pin<&mut Self>,
|
|
|
|
|
/// cx: &mut Context<'_>
|
|
|
|
|
/// ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
|
|
|
|
|
/// # unimplemented!()
|
|
|
|
|
/// // ...
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// // Now we can implement `IntoResponse` directly for `MyBody`
|
|
|
|
|
/// impl IntoResponse for MyBody {
|
2021-12-05 18:16:46 +00:00
|
|
|
/// fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
/// Response::new(body::boxed(self))
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// // We don't need to implement `IntoResponse for Response<MyBody>` as that is
|
|
|
|
|
/// // covered by a blanket implementation in axum.
|
|
|
|
|
///
|
|
|
|
|
/// // `MyBody` can now be returned from handlers.
|
|
|
|
|
/// let app = Router::new().route("/", get(|| async { MyBody }));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
pub trait IntoResponse {
|
|
|
|
|
/// Create a response.
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response;
|
2021-11-30 14:46:13 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:46:41 +01:00
|
|
|
/// Trait for generating response headers.
|
|
|
|
|
pub trait IntoResponseHeaders {
|
2022-01-23 18:23:37 +01:00
|
|
|
/// The return type of `into_headers`.
|
2022-01-23 17:46:41 +01:00
|
|
|
///
|
2022-01-23 18:23:37 +01:00
|
|
|
/// The iterator item is a [`Result`] to allow the implementation to return a server error
|
2022-01-23 17:46:41 +01:00
|
|
|
/// instead.
|
|
|
|
|
///
|
2022-01-23 18:23:37 +01:00
|
|
|
/// The header name is optional because [`HeaderMap`]s iterator doesn't yield it multiple times
|
2022-01-23 17:46:41 +01:00
|
|
|
/// for headers that have multiple values, to avoid unnecessary copies.
|
2022-01-23 20:20:28 +01:00
|
|
|
#[doc(hidden)]
|
2022-01-23 17:46:41 +01:00
|
|
|
type IntoIter: IntoIterator<Item = Result<(Option<HeaderName>, HeaderValue), Response>>;
|
|
|
|
|
|
|
|
|
|
/// Attempt to turn `self` into a list of headers.
|
2022-01-25 09:46:38 +01:00
|
|
|
///
|
|
|
|
|
/// In practice, only the implementation for `axum::response::Headers` ever returns `Err(_)`.
|
2022-01-23 20:20:28 +01:00
|
|
|
#[doc(hidden)]
|
2022-01-23 17:46:41 +01:00
|
|
|
fn into_headers(self) -> Self::IntoIter;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
impl IntoResponse for () {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(Empty::new()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for Infallible {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
match self {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T, E> IntoResponse for Result<T, E>
|
|
|
|
|
where
|
|
|
|
|
T: IntoResponse,
|
|
|
|
|
E: IntoResponse,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
match self {
|
|
|
|
|
Ok(value) => value.into_response(),
|
|
|
|
|
Err(err) => err.into_response(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<B> IntoResponse for Response<B>
|
|
|
|
|
where
|
|
|
|
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
|
|
|
|
B::Error: Into<BoxError>,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
self.map(boxed)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_into_response_for_body {
|
|
|
|
|
($body:ty) => {
|
|
|
|
|
impl IntoResponse for $body {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(self))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_into_response_for_body!(Full<Bytes>);
|
|
|
|
|
impl_into_response_for_body!(Empty<Bytes>);
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for http::response::Parts {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::from_parts(self, boxed(Empty::new()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<E> IntoResponse for http_body::combinators::BoxBody<Bytes, E>
|
|
|
|
|
where
|
|
|
|
|
E: Into<BoxError> + 'static,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(self))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<E> IntoResponse for http_body::combinators::UnsyncBoxBody<Bytes, E>
|
|
|
|
|
where
|
|
|
|
|
E: Into<BoxError> + 'static,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(self))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<B, F> IntoResponse for MapData<B, F>
|
|
|
|
|
where
|
|
|
|
|
B: http_body::Body + Send + 'static,
|
|
|
|
|
F: FnMut(B::Data) -> Bytes + Send + 'static,
|
|
|
|
|
B::Error: Into<BoxError>,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(self))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<B, F, E> IntoResponse for MapErr<B, F>
|
|
|
|
|
where
|
|
|
|
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
|
|
|
|
F: FnMut(B::Error) -> E + Send + 'static,
|
|
|
|
|
E: Into<BoxError>,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::new(boxed(self))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for &'static str {
|
|
|
|
|
#[inline]
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Cow::Borrowed(self).into_response()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for String {
|
|
|
|
|
#[inline]
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Cow::<'static, str>::Owned(self).into_response()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for Cow<'static, str> {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = Response::new(boxed(Full::from(self)));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for Bytes {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = Response::new(boxed(Full::from(self)));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 13:30:42 +01:00
|
|
|
impl IntoResponse for BytesMut {
|
|
|
|
|
fn into_response(self) -> Response {
|
|
|
|
|
self.freeze().into_response()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T, U> IntoResponse for Chain<T, U>
|
|
|
|
|
where
|
|
|
|
|
T: Buf + Unpin + Send + 'static,
|
|
|
|
|
U: Buf + Unpin + Send + 'static,
|
|
|
|
|
{
|
|
|
|
|
fn into_response(self) -> Response {
|
|
|
|
|
let (first, second) = self.into_inner();
|
|
|
|
|
let mut res = Response::new(boxed(BytesChainBody {
|
|
|
|
|
first: Some(first),
|
|
|
|
|
second: Some(second),
|
|
|
|
|
}));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct BytesChainBody<T, U> {
|
|
|
|
|
first: Option<T>,
|
|
|
|
|
second: Option<U>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T, U> http_body::Body for BytesChainBody<T, U>
|
|
|
|
|
where
|
|
|
|
|
T: Buf + Unpin,
|
|
|
|
|
U: Buf + Unpin,
|
|
|
|
|
{
|
|
|
|
|
type Data = Bytes;
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
|
|
|
|
|
fn poll_data(
|
|
|
|
|
mut self: Pin<&mut Self>,
|
|
|
|
|
_cx: &mut Context<'_>,
|
|
|
|
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
|
|
|
|
if let Some(mut buf) = self.first.take() {
|
|
|
|
|
let bytes = buf.copy_to_bytes(buf.remaining());
|
|
|
|
|
return Poll::Ready(Some(Ok(bytes)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(mut buf) = self.second.take() {
|
|
|
|
|
let bytes = buf.copy_to_bytes(buf.remaining());
|
|
|
|
|
return Poll::Ready(Some(Ok(bytes)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Poll::Ready(None)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn poll_trailers(
|
|
|
|
|
self: Pin<&mut Self>,
|
|
|
|
|
_cx: &mut Context<'_>,
|
|
|
|
|
) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_end_stream(&self) -> bool {
|
|
|
|
|
self.first.is_none() && self.second.is_none()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn size_hint(&self) -> SizeHint {
|
|
|
|
|
match (self.first.as_ref(), self.second.as_ref()) {
|
|
|
|
|
(Some(first), Some(second)) => {
|
|
|
|
|
let total_size = first.remaining() + second.remaining();
|
|
|
|
|
SizeHint::with_exact(total_size as u64)
|
|
|
|
|
}
|
|
|
|
|
(Some(buf), None) => SizeHint::with_exact(buf.remaining() as u64),
|
|
|
|
|
(None, Some(buf)) => SizeHint::with_exact(buf.remaining() as u64),
|
|
|
|
|
(None, None) => SizeHint::with_exact(0),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
impl IntoResponse for &'static [u8] {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = Response::new(boxed(Full::from(self)));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for Vec<u8> {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = Response::new(boxed(Full::from(self)));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for Cow<'static, [u8]> {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = Response::new(boxed(Full::from(self)));
|
|
|
|
|
res.headers_mut().insert(
|
|
|
|
|
header::CONTENT_TYPE,
|
|
|
|
|
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
|
|
|
|
|
);
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IntoResponse for StatusCode {
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
Response::builder()
|
|
|
|
|
.status(self)
|
|
|
|
|
.body(boxed(Empty::new()))
|
|
|
|
|
.unwrap()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 18:17:04 +01:00
|
|
|
impl IntoResponse for HeaderMap {
|
2022-01-23 17:46:41 +01:00
|
|
|
fn into_response(self) -> Response {
|
|
|
|
|
let mut res = Response::new(boxed(Empty::new()));
|
2022-01-23 18:17:04 +01:00
|
|
|
*res.headers_mut() = self;
|
2022-01-23 17:46:41 +01:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
impl<T> IntoResponse for (StatusCode, T)
|
|
|
|
|
where
|
|
|
|
|
T: IntoResponse,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = self.1.into_response();
|
|
|
|
|
*res.status_mut() = self.0;
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:46:41 +01:00
|
|
|
impl<H, T> IntoResponse for (H, T)
|
2021-11-30 14:46:13 +01:00
|
|
|
where
|
2022-01-23 17:46:41 +01:00
|
|
|
H: IntoResponseHeaders,
|
2021-11-30 14:46:13 +01:00
|
|
|
T: IntoResponse,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = self.1.into_response();
|
2022-01-23 17:46:41 +01:00
|
|
|
|
|
|
|
|
if let Err(e) = try_extend_headers(res.headers_mut(), self.0.into_headers()) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:46:41 +01:00
|
|
|
impl<H, T> IntoResponse for (StatusCode, H, T)
|
2021-11-30 14:46:13 +01:00
|
|
|
where
|
2022-01-23 17:46:41 +01:00
|
|
|
H: IntoResponseHeaders,
|
2021-11-30 14:46:13 +01:00
|
|
|
T: IntoResponse,
|
|
|
|
|
{
|
2021-12-05 18:16:46 +00:00
|
|
|
fn into_response(self) -> Response {
|
2021-11-30 14:46:13 +01:00
|
|
|
let mut res = self.2.into_response();
|
|
|
|
|
*res.status_mut() = self.0;
|
2022-01-23 17:46:41 +01:00
|
|
|
|
|
|
|
|
if let Err(e) = try_extend_headers(res.headers_mut(), self.1.into_headers()) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 14:46:13 +01:00
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:46:41 +01:00
|
|
|
impl IntoResponseHeaders for HeaderMap {
|
|
|
|
|
// FIXME: Use type_alias_impl_trait when available
|
|
|
|
|
type IntoIter = iter::Map<
|
|
|
|
|
http::header::IntoIter<HeaderValue>,
|
|
|
|
|
fn(
|
|
|
|
|
(Option<HeaderName>, HeaderValue),
|
|
|
|
|
) -> Result<(Option<HeaderName>, HeaderValue), Response>,
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
fn into_headers(self) -> Self::IntoIter {
|
|
|
|
|
self.into_iter().map(Ok)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Slightly adjusted version of `impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T>`.
|
|
|
|
|
// Accepts an iterator that returns Results and short-circuits on an `Err`.
|
|
|
|
|
fn try_extend_headers(
|
|
|
|
|
headers: &mut HeaderMap,
|
|
|
|
|
iter: impl IntoIterator<Item = Result<(Option<HeaderName>, HeaderValue), Response>>,
|
|
|
|
|
) -> Result<(), Response> {
|
|
|
|
|
use http::header::Entry;
|
|
|
|
|
|
|
|
|
|
let mut iter = iter.into_iter();
|
|
|
|
|
|
|
|
|
|
// The structure of this is a bit weird, but it is mostly to make the
|
|
|
|
|
// borrow checker happy.
|
|
|
|
|
let (mut key, mut val) = match iter.next().transpose()? {
|
|
|
|
|
Some((Some(key), val)) => (key, val),
|
|
|
|
|
Some((None, _)) => panic!("expected a header name, but got None"),
|
|
|
|
|
None => return Ok(()),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
'outer: loop {
|
|
|
|
|
let mut entry = match headers.entry(key) {
|
|
|
|
|
Entry::Occupied(mut e) => {
|
|
|
|
|
// Replace all previous values while maintaining a handle to
|
|
|
|
|
// the entry.
|
|
|
|
|
e.insert(val);
|
|
|
|
|
e
|
|
|
|
|
}
|
|
|
|
|
Entry::Vacant(e) => e.insert_entry(val),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// As long as `HeaderName` is none, keep inserting the value into
|
|
|
|
|
// the current entry
|
|
|
|
|
loop {
|
|
|
|
|
match iter.next().transpose()? {
|
|
|
|
|
Some((Some(k), v)) => {
|
|
|
|
|
key = k;
|
|
|
|
|
val = v;
|
|
|
|
|
continue 'outer;
|
|
|
|
|
}
|
|
|
|
|
Some((None, v)) => {
|
|
|
|
|
entry.append(v);
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-30 14:46:13 +01:00
|
|
|
}
|
|
|
|
|
}
|