Remove the associated Body type on IntoResponse (#571)

This commit is contained in:
Kai Jewson
2021-11-28 18:52:18 +01:00
committed by GitHub
parent decdd4c948
commit 2b6dba49cb
25 changed files with 171 additions and 358 deletions
+2 -5
View File
@@ -1,5 +1,5 @@
use axum::{ use axum::{
body::{Bytes, Full}, body::BoxBody,
http::Response, http::Response,
response::IntoResponse, response::IntoResponse,
}; };
@@ -16,10 +16,7 @@ impl A {
} }
impl IntoResponse for A { impl IntoResponse for A {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
todo!() todo!()
} }
} }
+6 -9
View File
@@ -1,6 +1,6 @@
use axum::{ use axum::{
async_trait, async_trait,
body::{boxed, BoxBody}, body::BoxBody,
extract::{ extract::{
rejection::{ExtensionRejection, ExtensionsAlreadyExtracted}, rejection::{ExtensionRejection, ExtensionsAlreadyExtracted},
Extension, FromRequest, RequestParts, Extension, FromRequest, RequestParts,
@@ -30,7 +30,7 @@ use std::{
/// use axum::{ /// use axum::{
/// async_trait, /// async_trait,
/// extract::{FromRequest, RequestParts}, /// extract::{FromRequest, RequestParts},
/// body::{self, BoxBody}, /// body::BoxBody,
/// response::IntoResponse, /// response::IntoResponse,
/// http::{StatusCode, Response}, /// http::{StatusCode, Response},
/// }; /// };
@@ -67,7 +67,7 @@ use std::{
/// // once, in case other extractors for the same request also loads the session /// // once, in case other extractors for the same request also loads the session
/// let session: Session = Cached::<Session>::from_request(req) /// let session: Session = Cached::<Session>::from_request(req)
/// .await /// .await
/// .map_err(|err| err.into_response().map(body::boxed))? /// .map_err(|err| err.into_response())?
/// .0; /// .0;
/// ///
/// // load user from session... /// // load user from session...
@@ -157,13 +157,10 @@ impl<R> IntoResponse for CachedRejection<R>
where where
R: IntoResponse, R: IntoResponse,
{ {
type Body = BoxBody; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as axum::body::HttpBody>::Error;
fn into_response(self) -> Response<Self::Body> {
match self { match self {
Self::ExtensionsAlreadyExtracted(inner) => inner.into_response().map(boxed), Self::ExtensionsAlreadyExtracted(inner) => inner.into_response(),
Self::Inner(inner) => inner.into_response().map(boxed), Self::Inner(inner) => inner.into_response(),
} }
} }
} }
+4 -9
View File
@@ -1,7 +1,5 @@
use std::convert::Infallible;
use axum::{ use axum::{
body::{Bytes, Full}, body::{self, BoxBody, Full},
http::{header, HeaderValue, Response, StatusCode}, http::{header, HeaderValue, Response, StatusCode},
response::IntoResponse, response::IntoResponse,
}; };
@@ -41,22 +39,19 @@ impl ErasedJson {
} }
impl IntoResponse for ErasedJson { impl IntoResponse for ErasedJson {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
let bytes = match self.0 { let bytes = match self.0 {
Ok(res) => res, Ok(res) => res,
Err(err) => { Err(err) => {
return Response::builder() return Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR) .status(StatusCode::INTERNAL_SERVER_ERROR)
.header(header::CONTENT_TYPE, mime::TEXT_PLAIN_UTF_8.as_ref()) .header(header::CONTENT_TYPE, mime::TEXT_PLAIN_UTF_8.as_ref())
.body(Full::from(err.to_string())) .body(body::boxed(Full::from(err.to_string())))
.unwrap(); .unwrap();
} }
}; };
let mut res = Response::new(Full::from(bytes)); let mut res = Response::new(body::boxed(Full::from(bytes)));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
+4
View File
@@ -34,12 +34,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Previously it would be silently discarded ([#529]) Previously it would be silently discarded ([#529])
- Update WebSockets to use tokio-tungstenite 0.16 ([#525]) - Update WebSockets to use tokio-tungstenite 0.16 ([#525])
- **added:** Default to return `charset=utf-8` for text content type. ([#554]) - **added:** Default to return `charset=utf-8` for text content type. ([#554])
- **breaking:** The `Body` and `BodyError` associated types on the
`IntoResponse` trait have been removed - instead, `.into_response()` will now
always return `Response<BoxBody>` ([#571])
[#525]: https://github.com/tokio-rs/axum/pull/525 [#525]: https://github.com/tokio-rs/axum/pull/525
[#527]: https://github.com/tokio-rs/axum/pull/527 [#527]: https://github.com/tokio-rs/axum/pull/527
[#529]: https://github.com/tokio-rs/axum/pull/529 [#529]: https://github.com/tokio-rs/axum/pull/529
[#534]: https://github.com/tokio-rs/axum/pull/534 [#534]: https://github.com/tokio-rs/axum/pull/534
[#554]: https://github.com/tokio-rs/axum/pull/554 [#554]: https://github.com/tokio-rs/axum/pull/554
[#571]: https://github.com/tokio-rs/axum/pull/571
# 0.3.3 (13. November, 2021) # 0.3.3 (13. November, 2021)
+7 -6
View File
@@ -1,4 +1,8 @@
use crate::{response::IntoResponse, BoxError, Error}; use crate::{
body::{self, BoxBody},
response::IntoResponse,
BoxError, Error,
};
use bytes::Bytes; use bytes::Bytes;
use futures_util::{ use futures_util::{
ready, ready,
@@ -77,11 +81,8 @@ where
S::Ok: Into<Bytes>, S::Ok: Into<Bytes>,
S::Error: Into<BoxError>, S::Error: Into<BoxError>,
{ {
type Body = Self; fn into_response(self) -> Response<BoxBody> {
type BodyError = Error; Response::new(body::boxed(self))
fn into_response(self) -> Response<Self> {
Response::new(self)
} }
} }
+1 -1
View File
@@ -143,7 +143,7 @@ where
let future = Box::pin(async move { let future = Box::pin(async move {
match inner.oneshot(req).await { match inner.oneshot(req).await {
Ok(res) => Ok(res.map(boxed)), Ok(res) => Ok(res.map(boxed)),
Err(err) => Ok(f(err).await.into_response().map(boxed)), Err(err) => Ok(f(err).await.into_response()),
} }
}); });
+1 -1
View File
@@ -247,7 +247,7 @@ where
State::Call { future } State::Call { future }
} }
Err(err) => { Err(err) => {
let res = err.into_response().map(crate::body::boxed); let res = err.into_response();
return Poll::Ready(Ok(res)); return Poll::Ready(Ok(res));
} }
} }
+9 -20
View File
@@ -5,9 +5,7 @@ use crate::{
body::{boxed, BoxBody}, body::{boxed, BoxBody},
BoxError, Error, BoxError, Error,
}; };
use bytes::Bytes;
use http_body::Full; use http_body::Full;
use std::convert::Infallible;
define_rejection! { define_rejection! {
#[status = INTERNAL_SERVER_ERROR] #[status = INTERNAL_SERVER_ERROR]
@@ -115,11 +113,8 @@ impl InvalidPathParam {
} }
impl IntoResponse for InvalidPathParam { impl IntoResponse for InvalidPathParam {
type Body = Full<Bytes>; fn into_response(self) -> http::Response<BoxBody> {
type BodyError = Infallible; let mut res = http::Response::new(boxed(Full::from(self.to_string())));
fn into_response(self) -> http::Response<Self::Body> {
let mut res = http::Response::new(Full::from(self.to_string()));
*res.status_mut() = http::StatusCode::BAD_REQUEST; *res.status_mut() = http::StatusCode::BAD_REQUEST;
res res
} }
@@ -154,11 +149,8 @@ impl FailedToDeserializeQueryString {
} }
impl IntoResponse for FailedToDeserializeQueryString { impl IntoResponse for FailedToDeserializeQueryString {
type Body = Full<Bytes>; fn into_response(self) -> http::Response<BoxBody> {
type BodyError = Infallible; let mut res = http::Response::new(boxed(Full::from(self.to_string())));
fn into_response(self) -> http::Response<Self::Body> {
let mut res = http::Response::new(Full::from(self.to_string()));
*res.status_mut() = http::StatusCode::BAD_REQUEST; *res.status_mut() = http::StatusCode::BAD_REQUEST;
res res
} }
@@ -320,15 +312,12 @@ impl<T> IntoResponse for ContentLengthLimitRejection<T>
where where
T: IntoResponse, T: IntoResponse,
{ {
type Body = BoxBody; fn into_response(self) -> http::Response<BoxBody> {
type BodyError = Error;
fn into_response(self) -> http::Response<Self::Body> {
match self { match self {
Self::PayloadTooLarge(inner) => inner.into_response().map(boxed), Self::PayloadTooLarge(inner) => inner.into_response(),
Self::LengthRequired(inner) => inner.into_response().map(boxed), Self::LengthRequired(inner) => inner.into_response(),
Self::HeadersAlreadyExtracted(inner) => inner.into_response().map(boxed), Self::HeadersAlreadyExtracted(inner) => inner.into_response(),
Self::Inner(inner) => inner.into_response().map(boxed), Self::Inner(inner) => inner.into_response(),
} }
} }
} }
+2 -5
View File
@@ -1,8 +1,5 @@
use super::{FromRequest, RequestParts}; use super::{FromRequest, RequestParts};
use crate::{ use crate::{body::BoxBody, response::IntoResponse};
body::{boxed, BoxBody},
response::IntoResponse,
};
use async_trait::async_trait; use async_trait::async_trait;
use http::Response; use http::Response;
use std::convert::Infallible; use std::convert::Infallible;
@@ -33,7 +30,7 @@ macro_rules! impl_from_request {
type Rejection = Response<BoxBody>; type Rejection = Response<BoxBody>;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
$( let $ty = $ty::from_request(req).await.map_err(|err| err.into_response().map(boxed))?; )* $( let $ty = $ty::from_request(req).await.map_err(|err| err.into_response())?; )*
Ok(($($ty,)*)) Ok(($($ty,)*))
} }
} }
+3 -8
View File
@@ -1,10 +1,8 @@
use super::{FromRequest, RequestParts}; use super::{FromRequest, RequestParts};
use crate::response::IntoResponse; use crate::{body::BoxBody, response::IntoResponse};
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes;
use headers::HeaderMapExt; use headers::HeaderMapExt;
use http_body::Full; use std::ops::Deref;
use std::{convert::Infallible, ops::Deref};
/// Extractor that extracts a typed header value from [`headers`]. /// Extractor that extracts a typed header value from [`headers`].
/// ///
@@ -108,10 +106,7 @@ pub enum TypedHeaderRejectionReason {
} }
impl IntoResponse for TypedHeaderRejection { impl IntoResponse for TypedHeaderRejection {
type Body = Full<Bytes>; fn into_response(self) -> http::Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> http::Response<Self::Body> {
let mut res = self.to_string().into_response(); let mut res = self.to_string().into_response();
*res.status_mut() = http::StatusCode::BAD_REQUEST; *res.status_mut() = http::StatusCode::BAD_REQUEST;
res res
+7 -7
View File
@@ -65,7 +65,11 @@
use self::rejection::*; use self::rejection::*;
use super::{rejection::*, FromRequest, RequestParts}; use super::{rejection::*, FromRequest, RequestParts};
use crate::{response::IntoResponse, Error}; use crate::{
body::{self, BoxBody},
response::IntoResponse,
Error,
};
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
use futures_util::{ use futures_util::{
@@ -76,7 +80,6 @@ use http::{
header::{self, HeaderName, HeaderValue}, header::{self, HeaderName, HeaderValue},
Method, Response, StatusCode, Method, Response, StatusCode,
}; };
use http_body::Full;
use hyper::upgrade::{OnUpgrade, Upgraded}; use hyper::upgrade::{OnUpgrade, Upgraded};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
use std::{ use std::{
@@ -285,10 +288,7 @@ where
F: FnOnce(WebSocket) -> Fut + Send + 'static, F: FnOnce(WebSocket) -> Fut + Send + 'static,
Fut: Future + Send + 'static, Fut: Future + Send + 'static,
{ {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as http_body::Body>::Error;
fn into_response(self) -> Response<Self::Body> {
// check requested protocols // check requested protocols
let protocol = self let protocol = self
.extractor .extractor
@@ -347,7 +347,7 @@ where
builder = builder.header(header::SEC_WEBSOCKET_PROTOCOL, protocol); builder = builder.header(header::SEC_WEBSOCKET_PROTOCOL, protocol);
} }
builder.body(Full::default()).unwrap() builder.body(body::boxed(body::Empty::new())).unwrap()
} }
} }
+5 -10
View File
@@ -272,7 +272,7 @@ where
type Sealed = sealed::Hidden; type Sealed = sealed::Hidden;
async fn call(self, _req: Request<B>) -> Response<BoxBody> { async fn call(self, _req: Request<B>) -> Response<BoxBody> {
self().await.into_response().map(boxed) self().await.into_response()
} }
} }
@@ -296,13 +296,13 @@ macro_rules! impl_handler {
$( $(
let $ty = match $ty::from_request(&mut req).await { let $ty = match $ty::from_request(&mut req).await {
Ok(value) => value, Ok(value) => value,
Err(rejection) => return rejection.into_response().map(boxed), Err(rejection) => return rejection.into_response(),
}; };
)* )*
let res = self($($ty,)*).await; let res = self($($ty,)*).await;
res.into_response().map(boxed) res.into_response()
} }
} }
}; };
@@ -350,14 +350,9 @@ where
type Sealed = sealed::Hidden; type Sealed = sealed::Hidden;
async fn call(self, req: Request<ReqBody>) -> Response<BoxBody> { async fn call(self, req: Request<ReqBody>) -> Response<BoxBody> {
match self match self.svc.oneshot(req).await {
.svc
.oneshot(req)
.await
.map_err(IntoResponse::into_response)
{
Ok(res) => res.map(boxed), Ok(res) => res.map(boxed),
Err(res) => res.map(boxed), Err(res) => res.into_response(),
} }
} }
} }
+5 -11
View File
@@ -1,10 +1,10 @@
use crate::{ use crate::{
body::{self, BoxBody},
extract::{rejection::*, take_body, FromRequest, RequestParts}, extract::{rejection::*, take_body, FromRequest, RequestParts},
response::IntoResponse, response::IntoResponse,
BoxError, BoxError,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes;
use http::{ use http::{
header::{self, HeaderValue}, header::{self, HeaderValue},
StatusCode, StatusCode,
@@ -12,10 +12,7 @@ use http::{
use http_body::Full; use http_body::Full;
use hyper::Response; use hyper::Response;
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use std::{ use std::ops::{Deref, DerefMut};
convert::Infallible,
ops::{Deref, DerefMut},
};
/// JSON Extractor / Response. /// JSON Extractor / Response.
/// ///
@@ -172,10 +169,7 @@ impl<T> IntoResponse for Json<T>
where where
T: Serialize, T: Serialize,
{ {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
let bytes = match serde_json::to_vec(&self.0) { let bytes = match serde_json::to_vec(&self.0) {
Ok(res) => res, Ok(res) => res,
Err(err) => { Err(err) => {
@@ -185,12 +179,12 @@ where
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
) )
.body(Full::from(err.to_string())) .body(body::boxed(Full::from(err.to_string())))
.unwrap(); .unwrap();
} }
}; };
let mut res = Response::new(Full::from(bytes)); let mut res = Response::new(body::boxed(Full::from(bytes)));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
+5 -14
View File
@@ -59,11 +59,8 @@ macro_rules! define_rejection {
#[allow(deprecated)] #[allow(deprecated)]
impl $crate::response::IntoResponse for $name { impl $crate::response::IntoResponse for $name {
type Body = http_body::Full<bytes::Bytes>; fn into_response(self) -> http::Response<$crate::body::BoxBody> {
type BodyError = std::convert::Infallible; let mut res = http::Response::new($crate::body::boxed(http_body::Full::from($body)));
fn into_response(self) -> http::Response<Self::Body> {
let mut res = http::Response::new(http_body::Full::from($body));
*res.status_mut() = http::StatusCode::$status; *res.status_mut() = http::StatusCode::$status;
res res
} }
@@ -104,12 +101,9 @@ macro_rules! define_rejection {
} }
impl IntoResponse for $name { impl IntoResponse for $name {
type Body = http_body::Full<bytes::Bytes>; fn into_response(self) -> http::Response<$crate::body::BoxBody> {
type BodyError = std::convert::Infallible;
fn into_response(self) -> http::Response<Self::Body> {
let mut res = let mut res =
http::Response::new(http_body::Full::from(format!(concat!($body, ": {}"), self.0))); http::Response::new($crate::body::boxed(http_body::Full::from(format!(concat!($body, ": {}"), self.0))));
*res.status_mut() = http::StatusCode::$status; *res.status_mut() = http::StatusCode::$status;
res res
} }
@@ -148,10 +142,7 @@ macro_rules! composite_rejection {
} }
impl $crate::response::IntoResponse for $name { impl $crate::response::IntoResponse for $name {
type Body = http_body::Full<bytes::Bytes>; fn into_response(self) -> http::Response<$crate::body::BoxBody> {
type BodyError = std::convert::Infallible;
fn into_response(self) -> http::Response<Self::Body> {
match self { match self {
$( $(
Self::$variant(inner) => inner.into_response(), Self::$variant(inner) => inner.into_response(),
+12 -30
View File
@@ -1,14 +1,11 @@
use super::IntoResponse; use super::IntoResponse;
use crate::{ use crate::body::{boxed, BoxBody};
body::{boxed, BoxBody},
BoxError,
};
use bytes::Bytes; use bytes::Bytes;
use http::{ use http::{
header::{HeaderMap, HeaderName, HeaderValue}, header::{HeaderMap, HeaderName, HeaderValue},
Response, StatusCode, Response, StatusCode,
}; };
use http_body::{Body, Full}; use http_body::{Empty, Full};
use std::{convert::TryInto, fmt}; use std::{convert::TryInto, fmt};
use tower::util::Either; use tower::util::Either;
@@ -59,7 +56,7 @@ use tower::util::Either;
pub struct Headers<H>(pub H); pub struct Headers<H>(pub H);
impl<H> Headers<H> { impl<H> Headers<H> {
fn try_into_header_map<K, V>(self) -> Result<HeaderMap, Response<Full<Bytes>>> fn try_into_header_map<K, V>(self) -> Result<HeaderMap, Response<BoxBody>>
where where
H: IntoIterator<Item = (K, V)>, H: IntoIterator<Item = (K, V)>,
K: TryInto<HeaderName>, K: TryInto<HeaderName>,
@@ -81,7 +78,7 @@ impl<H> Headers<H> {
Either::B(err) => err.to_string(), Either::B(err) => err.to_string(),
}; };
let body = Full::new(Bytes::copy_from_slice(err.as_bytes())); let body = boxed(Full::new(Bytes::copy_from_slice(err.as_bytes())));
let mut res = Response::new(body); let mut res = Response::new(body);
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
res res
@@ -97,15 +94,12 @@ where
V: TryInto<HeaderValue>, V: TryInto<HeaderValue>,
V::Error: fmt::Display, V::Error: fmt::Display,
{ {
type Body = Full<Bytes>; fn into_response(self) -> http::Response<BoxBody> {
type BodyError = <Self::Body as Body>::Error;
fn into_response(self) -> http::Response<Self::Body> {
let headers = self.try_into_header_map(); let headers = self.try_into_header_map();
match headers { match headers {
Ok(headers) => { Ok(headers) => {
let mut res = Response::new(Full::new(Bytes::new())); let mut res = Response::new(boxed(Empty::new()));
*res.headers_mut() = headers; *res.headers_mut() = headers;
res res
} }
@@ -117,50 +111,38 @@ where
impl<H, T, K, V> IntoResponse for (Headers<H>, T) impl<H, T, K, V> IntoResponse for (Headers<H>, T)
where where
T: IntoResponse, T: IntoResponse,
T::Body: Body<Data = Bytes> + Send + 'static,
<T::Body as Body>::Error: Into<BoxError>,
H: IntoIterator<Item = (K, V)>, H: IntoIterator<Item = (K, V)>,
K: TryInto<HeaderName>, K: TryInto<HeaderName>,
K::Error: fmt::Display, K::Error: fmt::Display,
V: TryInto<HeaderValue>, V: TryInto<HeaderValue>,
V::Error: fmt::Display, V::Error: fmt::Display,
{ {
type Body = BoxBody; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as Body>::Error;
// this boxing could be improved with a EitherBody but thats
// an issue for another time
fn into_response(self) -> Response<Self::Body> {
let headers = match self.0.try_into_header_map() { let headers = match self.0.try_into_header_map() {
Ok(headers) => headers, Ok(headers) => headers,
Err(res) => return res.map(boxed), Err(res) => return res,
}; };
(headers, self.1).into_response().map(boxed) (headers, self.1).into_response()
} }
} }
impl<H, T, K, V> IntoResponse for (StatusCode, Headers<H>, T) impl<H, T, K, V> IntoResponse for (StatusCode, Headers<H>, T)
where where
T: IntoResponse, T: IntoResponse,
T::Body: Body<Data = Bytes> + Send + 'static,
<T::Body as Body>::Error: Into<BoxError>,
H: IntoIterator<Item = (K, V)>, H: IntoIterator<Item = (K, V)>,
K: TryInto<HeaderName>, K: TryInto<HeaderName>,
K::Error: fmt::Display, K::Error: fmt::Display,
V: TryInto<HeaderValue>, V: TryInto<HeaderValue>,
V::Error: fmt::Display, V::Error: fmt::Display,
{ {
type Body = BoxBody; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as Body>::Error;
fn into_response(self) -> Response<Self::Body> {
let headers = match self.1.try_into_header_map() { let headers = match self.1.try_into_header_map() {
Ok(headers) => headers, Ok(headers) => headers,
Err(res) => return res.map(boxed), Err(res) => return res,
}; };
(self.0, headers, self.2).into_response().map(boxed) (self.0, headers, self.2).into_response()
} }
} }
+57 -164
View File
@@ -2,7 +2,7 @@
use crate::{ use crate::{
body::{boxed, BoxBody}, body::{boxed, BoxBody},
BoxError, Error, BoxError,
}; };
use bytes::Bytes; use bytes::Bytes;
use http::{header, HeaderMap, HeaderValue, Response, StatusCode}; use http::{header, HeaderMap, HeaderValue, Response, StatusCode};
@@ -39,7 +39,7 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// ```rust /// ```rust
/// use axum::{ /// use axum::{
/// Router, /// Router,
/// body::Body, /// body::{self, BoxBody, Bytes},
/// routing::get, /// routing::get,
/// http::{Response, StatusCode}, /// http::{Response, StatusCode},
/// response::IntoResponse, /// response::IntoResponse,
@@ -51,16 +51,13 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// } /// }
/// ///
/// impl IntoResponse for MyError { /// impl IntoResponse for MyError {
/// type Body = Body; /// fn into_response(self) -> Response<BoxBody> {
/// type BodyError = <Self::Body as axum::body::HttpBody>::Error;
///
/// fn into_response(self) -> Response<Self::Body> {
/// let body = match self { /// let body = match self {
/// MyError::SomethingWentWrong => { /// MyError::SomethingWentWrong => {
/// Body::from("something went wrong") /// body::boxed(body::Full::from("something went wrong"))
/// }, /// },
/// MyError::SomethingElseWentWrong => { /// MyError::SomethingElseWentWrong => {
/// Body::from("something else went wrong") /// body::boxed(body::Full::from("something else went wrong"))
/// }, /// },
/// }; /// };
/// ///
@@ -87,6 +84,7 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// ///
/// ```rust /// ```rust
/// use axum::{ /// use axum::{
/// body::{self, BoxBody},
/// routing::get, /// routing::get,
/// response::IntoResponse, /// response::IntoResponse,
/// Router, /// Router,
@@ -127,11 +125,8 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// ///
/// // Now we can implement `IntoResponse` directly for `MyBody` /// // Now we can implement `IntoResponse` directly for `MyBody`
/// impl IntoResponse for MyBody { /// impl IntoResponse for MyBody {
/// type Body = Self; /// fn into_response(self) -> Response<BoxBody> {
/// type BodyError = <Self as Body>::Error; /// Response::new(body::boxed(self))
///
/// fn into_response(self) -> Response<Self::Body> {
/// Response::new(self)
/// } /// }
/// } /// }
/// ///
@@ -145,56 +140,18 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse};
/// # }; /// # };
/// ``` /// ```
pub trait IntoResponse { 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<Bytes>`]: When you know your response is always
/// empty.
/// - [`axum::body::Full<Bytes>`]: 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
/// [`boxed`].
///
/// [`axum::body::Body`]: crate::body::Body
/// [`axum::body::Empty<Bytes>`]: crate::body::Empty
/// [`axum::body::Full<Bytes>`]: crate::body::Full
/// [`axum::body::BoxBody`]: crate::body::BoxBody
type Body: http_body::Body<Data = Bytes, Error = Self::BodyError> + Send + 'static;
/// The error type `Self::Body` might generate.
///
/// Generally it should be possible to set this to:
///
/// ```rust,ignore
/// type BodyError = <Self::Body as axum::body::HttpBody>::Error;
/// ```
///
/// This associated type exists mainly to make returning `impl IntoResponse`
/// possible and to simplify trait bounds internally in axum.
type BodyError: Into<BoxError>;
/// Create a response. /// Create a response.
fn into_response(self) -> Response<Self::Body>; fn into_response(self) -> Response<BoxBody>;
} }
impl IntoResponse for () { impl IntoResponse for () {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; Response::new(boxed(Empty::new()))
fn into_response(self) -> Response<Self::Body> {
Response::new(Empty::new())
} }
} }
impl IntoResponse for Infallible { impl IntoResponse for Infallible {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
match self {} match self {}
} }
} }
@@ -204,13 +161,10 @@ where
T: IntoResponse, T: IntoResponse,
E: IntoResponse, E: IntoResponse,
{ {
type Body = BoxBody; fn into_response(self) -> Response<BoxBody> {
type BodyError = Error;
fn into_response(self) -> Response<Self::Body> {
match self { match self {
Ok(value) => value.into_response().map(boxed), Ok(value) => value.into_response(),
Err(err) => err.into_response().map(boxed), Err(err) => err.into_response(),
} }
} }
} }
@@ -220,22 +174,16 @@ where
B: http_body::Body<Data = Bytes> + Send + 'static, B: http_body::Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>, B::Error: Into<BoxError>,
{ {
type Body = B; fn into_response(self) -> Response<BoxBody> {
type BodyError = <B as http_body::Body>::Error; self.map(boxed)
fn into_response(self) -> Self {
self
} }
} }
macro_rules! impl_into_response_for_body { macro_rules! impl_into_response_for_body {
($body:ty) => { ($body:ty) => {
impl IntoResponse for $body { impl IntoResponse for $body {
type Body = $body; fn into_response(self) -> Response<BoxBody> {
type BodyError = <$body as http_body::Body>::Error; Response::new(boxed(self))
fn into_response(self) -> Response<Self> {
Response::new(self)
} }
} }
}; };
@@ -246,11 +194,8 @@ impl_into_response_for_body!(Full<Bytes>);
impl_into_response_for_body!(Empty<Bytes>); impl_into_response_for_body!(Empty<Bytes>);
impl IntoResponse for http::response::Parts { impl IntoResponse for http::response::Parts {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; Response::from_parts(self, boxed(Empty::new()))
fn into_response(self) -> Response<Self::Body> {
Response::from_parts(self, Empty::new())
} }
} }
@@ -258,11 +203,8 @@ impl<E> IntoResponse for http_body::combinators::BoxBody<Bytes, E>
where where
E: Into<BoxError> + 'static, E: Into<BoxError> + 'static,
{ {
type Body = Self; fn into_response(self) -> Response<BoxBody> {
type BodyError = E; Response::new(boxed(self))
fn into_response(self) -> Response<Self> {
Response::new(self)
} }
} }
@@ -270,11 +212,8 @@ impl<E> IntoResponse for http_body::combinators::UnsyncBoxBody<Bytes, E>
where where
E: Into<BoxError> + 'static, E: Into<BoxError> + 'static,
{ {
type Body = Self; fn into_response(self) -> Response<BoxBody> {
type BodyError = E; Response::new(boxed(self))
fn into_response(self) -> Response<Self> {
Response::new(self)
} }
} }
@@ -284,11 +223,8 @@ where
F: FnMut(B::Data) -> Bytes + Send + 'static, F: FnMut(B::Data) -> Bytes + Send + 'static,
B::Error: Into<BoxError>, B::Error: Into<BoxError>,
{ {
type Body = Self; fn into_response(self) -> Response<BoxBody> {
type BodyError = <B as http_body::Body>::Error; Response::new(boxed(self))
fn into_response(self) -> Response<Self::Body> {
Response::new(self)
} }
} }
@@ -298,40 +234,28 @@ where
F: FnMut(B::Error) -> E + Send + 'static, F: FnMut(B::Error) -> E + Send + 'static,
E: Into<BoxError>, E: Into<BoxError>,
{ {
type Body = Self; fn into_response(self) -> Response<BoxBody> {
type BodyError = E; Response::new(boxed(self))
fn into_response(self) -> Response<Self::Body> {
Response::new(self)
} }
} }
impl IntoResponse for &'static str { impl IntoResponse for &'static str {
type Body = Full<Bytes>;
type BodyError = Infallible;
#[inline] #[inline]
fn into_response(self) -> Response<Self::Body> { fn into_response(self) -> Response<BoxBody> {
Cow::Borrowed(self).into_response() Cow::Borrowed(self).into_response()
} }
} }
impl IntoResponse for String { impl IntoResponse for String {
type Body = Full<Bytes>;
type BodyError = Infallible;
#[inline] #[inline]
fn into_response(self) -> Response<Self::Body> { fn into_response(self) -> Response<BoxBody> {
Cow::<'static, str>::Owned(self).into_response() Cow::<'static, str>::Owned(self).into_response()
} }
} }
impl IntoResponse for std::borrow::Cow<'static, str> { impl IntoResponse for Cow<'static, str> {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Full::from(self)));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Full::from(self));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
@@ -341,11 +265,8 @@ impl IntoResponse for std::borrow::Cow<'static, str> {
} }
impl IntoResponse for Bytes { impl IntoResponse for Bytes {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Full::from(self)));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Full::from(self));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()), HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
@@ -355,11 +276,8 @@ impl IntoResponse for Bytes {
} }
impl IntoResponse for &'static [u8] { impl IntoResponse for &'static [u8] {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Full::from(self)));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Full::from(self));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()), HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
@@ -369,11 +287,8 @@ impl IntoResponse for &'static [u8] {
} }
impl IntoResponse for Vec<u8> { impl IntoResponse for Vec<u8> {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Full::from(self)));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Full::from(self));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()), HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
@@ -382,12 +297,9 @@ impl IntoResponse for Vec<u8> {
} }
} }
impl IntoResponse for std::borrow::Cow<'static, [u8]> { impl IntoResponse for Cow<'static, [u8]> {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Full::from(self)));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Full::from(self));
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()), HeaderValue::from_static(mime::APPLICATION_OCTET_STREAM.as_ref()),
@@ -397,11 +309,11 @@ impl IntoResponse for std::borrow::Cow<'static, [u8]> {
} }
impl IntoResponse for StatusCode { impl IntoResponse for StatusCode {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; Response::builder()
.status(self)
fn into_response(self) -> Response<Self::Body> { .body(boxed(Empty::new()))
Response::builder().status(self).body(Empty::new()).unwrap() .unwrap()
} }
} }
@@ -409,10 +321,7 @@ impl<T> IntoResponse for (StatusCode, T)
where where
T: IntoResponse, T: IntoResponse,
{ {
type Body = T::Body; fn into_response(self) -> Response<BoxBody> {
type BodyError = T::BodyError;
fn into_response(self) -> Response<T::Body> {
let mut res = self.1.into_response(); let mut res = self.1.into_response();
*res.status_mut() = self.0; *res.status_mut() = self.0;
res res
@@ -423,10 +332,7 @@ impl<T> IntoResponse for (HeaderMap, T)
where where
T: IntoResponse, T: IntoResponse,
{ {
type Body = T::Body; fn into_response(self) -> Response<BoxBody> {
type BodyError = T::BodyError;
fn into_response(self) -> Response<T::Body> {
let mut res = self.1.into_response(); let mut res = self.1.into_response();
res.headers_mut().extend(self.0); res.headers_mut().extend(self.0);
res res
@@ -437,10 +343,7 @@ impl<T> IntoResponse for (StatusCode, HeaderMap, T)
where where
T: IntoResponse, T: IntoResponse,
{ {
type Body = T::Body; fn into_response(self) -> Response<BoxBody> {
type BodyError = T::BodyError;
fn into_response(self) -> Response<T::Body> {
let mut res = self.2.into_response(); let mut res = self.2.into_response();
*res.status_mut() = self.0; *res.status_mut() = self.0;
res.headers_mut().extend(self.1); res.headers_mut().extend(self.1);
@@ -449,11 +352,8 @@ where
} }
impl IntoResponse for HeaderMap { impl IntoResponse for HeaderMap {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(Empty::new()));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Empty::new());
*res.headers_mut() = self; *res.headers_mut() = self;
res res
} }
@@ -469,11 +369,8 @@ impl<T> IntoResponse for Html<T>
where where
T: Into<Full<Bytes>>, T: Into<Full<Bytes>>,
{ {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible; let mut res = Response::new(boxed(self.0.into()));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(self.0.into());
res.headers_mut().insert( res.headers_mut().insert(
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()), HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()),
@@ -491,7 +388,6 @@ impl<T> From<T> for Html<T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::body::Body;
use http::header::{HeaderMap, HeaderName}; use http::header::{HeaderMap, HeaderName};
#[test] #[test]
@@ -499,11 +395,8 @@ mod tests {
struct MyResponse; struct MyResponse;
impl IntoResponse for MyResponse { impl IntoResponse for MyResponse {
type Body = Body; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as http_body::Body>::Error; let mut resp = Response::new(boxed(Empty::new()));
fn into_response(self) -> Response<Body> {
let mut resp = Response::new(String::new().into());
resp.headers_mut() resp.headers_mut()
.insert(HeaderName::from_static("a"), HeaderValue::from_static("1")); .insert(HeaderName::from_static("a"), HeaderValue::from_static("1"));
resp resp
+4 -7
View File
@@ -1,7 +1,7 @@
use super::IntoResponse; use super::IntoResponse;
use bytes::Bytes; use crate::body::{boxed, BoxBody};
use http::{header::LOCATION, HeaderValue, Response, StatusCode, Uri}; use http::{header::LOCATION, HeaderValue, Response, StatusCode, Uri};
use http_body::{Body, Empty}; use http_body::Empty;
use std::convert::TryFrom; use std::convert::TryFrom;
/// Response that redirects the request to another location. /// Response that redirects the request to another location.
@@ -105,11 +105,8 @@ impl Redirect {
} }
impl IntoResponse for Redirect { impl IntoResponse for Redirect {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as Body>::Error; let mut res = Response::new(boxed(Empty::new()));
fn into_response(self) -> Response<Self::Body> {
let mut res = Response::new(Empty::new());
*res.status_mut() = self.status_code; *res.status_mut() = self.status_code;
res.headers_mut().insert(LOCATION, self.location); res.headers_mut().insert(LOCATION, self.location);
res res
+9 -10
View File
@@ -27,7 +27,11 @@
//! # }; //! # };
//! ``` //! ```
use crate::{response::IntoResponse, BoxError}; use crate::{
body::{self, BoxBody},
response::IntoResponse,
BoxError,
};
use bytes::Bytes; use bytes::Bytes;
use futures_util::{ use futures_util::{
ready, ready,
@@ -94,14 +98,11 @@ where
S: Stream<Item = Result<Event, E>> + Send + 'static, S: Stream<Item = Result<Event, E>> + Send + 'static,
E: Into<BoxError>, E: Into<BoxError>,
{ {
type Body = Body<S>; fn into_response(self) -> Response<BoxBody> {
type BodyError = E; let body = body::boxed(Body {
fn into_response(self) -> Response<Self::Body> {
let body = Body {
event_stream: SyncWrapper::new(self.stream), event_stream: SyncWrapper::new(self.stream),
keep_alive: self.keep_alive.map(KeepAliveStream::new), keep_alive: self.keep_alive.map(KeepAliveStream::new),
}; });
Response::builder() Response::builder()
.header(http::header::CONTENT_TYPE, mime::TEXT_EVENT_STREAM.as_ref()) .header(http::header::CONTENT_TYPE, mime::TEXT_EVENT_STREAM.as_ref())
@@ -112,9 +113,7 @@ where
} }
pin_project! { pin_project! {
/// The body of an SSE response. struct Body<S> {
#[derive(Debug)]
pub struct Body<S> {
#[pin] #[pin]
event_stream: SyncWrapper<S>, event_stream: SyncWrapper<S>,
#[pin] #[pin]
@@ -9,7 +9,7 @@
use axum::{ use axum::{
async_trait, async_trait,
body::{Bytes, Full}, body::BoxBody,
extract::{Extension, Path}, extract::{Extension, Path},
http::{Response, StatusCode}, http::{Response, StatusCode},
response::IntoResponse, response::IntoResponse,
@@ -18,7 +18,7 @@ use axum::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use std::{convert::Infallible, net::SocketAddr, sync::Arc}; use std::{net::SocketAddr, sync::Arc};
use uuid::Uuid; use uuid::Uuid;
#[tokio::main] #[tokio::main]
@@ -92,10 +92,7 @@ impl From<UserRepoError> for AppError {
} }
impl IntoResponse for AppError { impl IntoResponse for AppError {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
let (status, error_message) = match self { let (status, error_message) = match self {
AppError::UserRepo(UserRepoError::NotFound) => { AppError::UserRepo(UserRepoError::NotFound) => {
(StatusCode::NOT_FOUND, "User not found") (StatusCode::NOT_FOUND, "User not found")
+10 -8
View File
@@ -13,8 +13,9 @@
//! Example is based on <https://github.com/hyperium/hyper/blob/master/examples/http_proxy.rs> //! Example is based on <https://github.com/hyperium/hyper/blob/master/examples/http_proxy.rs>
use axum::{ use axum::{
body::{boxed, Body}, body::{self, Body, BoxBody},
http::{Method, Request, Response, StatusCode}, http::{Method, Request, Response, StatusCode},
response::IntoResponse,
routing::get, routing::get,
Router, Router,
}; };
@@ -37,7 +38,7 @@ async fn main() {
let router = router.clone(); let router = router.clone();
async move { async move {
if req.method() == Method::CONNECT { if req.method() == Method::CONNECT {
proxy(req).await.map(|res| res.map(boxed)) proxy(req).await
} else { } else {
router.oneshot(req).await.map_err(|err| match err {}) router.oneshot(req).await.map_err(|err| match err {})
} }
@@ -54,7 +55,7 @@ async fn main() {
.unwrap(); .unwrap();
} }
async fn proxy(req: Request<Body>) -> Result<Response<Body>, hyper::Error> { async fn proxy(req: Request<Body>) -> Result<Response<BoxBody>, hyper::Error> {
tracing::trace!(?req); tracing::trace!(?req);
if let Some(host_addr) = req.uri().authority().map(|auth| auth.to_string()) { if let Some(host_addr) = req.uri().authority().map(|auth| auth.to_string()) {
@@ -69,13 +70,14 @@ async fn proxy(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
} }
}); });
Ok(Response::new(Body::empty())) Ok(Response::new(body::boxed(body::Empty::new())))
} else { } else {
tracing::warn!("CONNECT host is not socket addr: {:?}", req.uri()); tracing::warn!("CONNECT host is not socket addr: {:?}", req.uri());
let mut resp = Response::new(Body::from("CONNECT must be to a socket address")); Ok((
*resp.status_mut() = StatusCode::BAD_REQUEST; StatusCode::BAD_REQUEST,
"CONNECT must be to a socket address",
Ok(resp) )
.into_response())
} }
} }
+3 -6
View File
@@ -8,7 +8,7 @@
use axum::{ use axum::{
async_trait, async_trait,
body::{Bytes, Full}, body::BoxBody,
extract::{FromRequest, RequestParts, TypedHeader}, extract::{FromRequest, RequestParts, TypedHeader},
http::{Response, StatusCode}, http::{Response, StatusCode},
response::IntoResponse, response::IntoResponse,
@@ -20,7 +20,7 @@ use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use std::{convert::Infallible, fmt::Display, net::SocketAddr}; use std::{fmt::Display, net::SocketAddr};
// Quick instructions // Quick instructions
// //
@@ -141,10 +141,7 @@ where
} }
impl IntoResponse for AuthError { impl IntoResponse for AuthError {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
let (status, error_message) = match self { let (status, error_message) = match self {
AuthError::WrongCredentials => (StatusCode::UNAUTHORIZED, "Wrong credentials"), AuthError::WrongCredentials => (StatusCode::UNAUTHORIZED, "Wrong credentials"),
AuthError::MissingCredentials => (StatusCode::BAD_REQUEST, "Missing credentials"), AuthError::MissingCredentials => (StatusCode::BAD_REQUEST, "Missing credentials"),
+2 -5
View File
@@ -9,7 +9,7 @@
use async_session::{MemoryStore, Session, SessionStore}; use async_session::{MemoryStore, Session, SessionStore};
use axum::{ use axum::{
async_trait, async_trait,
body::{Bytes, Empty}, body::BoxBody,
extract::{Extension, FromRequest, Query, RequestParts, TypedHeader}, extract::{Extension, FromRequest, Query, RequestParts, TypedHeader},
http::{header::SET_COOKIE, HeaderMap, Response}, http::{header::SET_COOKIE, HeaderMap, Response},
response::{IntoResponse, Redirect}, response::{IntoResponse, Redirect},
@@ -199,10 +199,7 @@ async fn login_authorized(
struct AuthRedirect; struct AuthRedirect;
impl IntoResponse for AuthRedirect { impl IntoResponse for AuthRedirect {
type Body = Empty<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = <Self::Body as axum::body::HttpBody>::Error;
fn into_response(self) -> Response<Self::Body> {
Redirect::found("/auth/discord".parse().unwrap()).into_response() Redirect::found("/auth/discord".parse().unwrap()).into_response()
} }
} }
+5 -8
View File
@@ -6,14 +6,14 @@
use askama::Template; use askama::Template;
use axum::{ use axum::{
body::{Bytes, Full}, body::{self, BoxBody, Full},
extract, extract,
http::{Response, StatusCode}, http::{Response, StatusCode},
response::{Html, IntoResponse}, response::{Html, IntoResponse},
routing::get, routing::get,
Router, Router,
}; };
use std::{convert::Infallible, net::SocketAddr}; use std::net::SocketAddr;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@@ -52,18 +52,15 @@ impl<T> IntoResponse for HtmlTemplate<T>
where where
T: Template, T: Template,
{ {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
match self.0.render() { match self.0.render() {
Ok(html) => Html(html).into_response(), Ok(html) => Html(html).into_response(),
Err(err) => Response::builder() Err(err) => Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR) .status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Full::from(format!( .body(body::boxed(Full::from(format!(
"Failed to render template. Error: {}", "Failed to render template. Error: {}",
err err
))) ))))
.unwrap(), .unwrap(),
} }
} }
+3 -6
View File
@@ -12,7 +12,7 @@
use async_trait::async_trait; use async_trait::async_trait;
use axum::{ use axum::{
body::{Bytes, Full}, body::BoxBody,
extract::{Form, FromRequest, RequestParts}, extract::{Form, FromRequest, RequestParts},
http::{Response, StatusCode}, http::{Response, StatusCode},
response::{Html, IntoResponse}, response::{Html, IntoResponse},
@@ -20,7 +20,7 @@ use axum::{
BoxError, Router, BoxError, Router,
}; };
use serde::{de::DeserializeOwned, Deserialize}; use serde::{de::DeserializeOwned, Deserialize};
use std::{convert::Infallible, net::SocketAddr}; use std::net::SocketAddr;
use thiserror::Error; use thiserror::Error;
use validator::Validate; use validator::Validate;
@@ -84,10 +84,7 @@ pub enum ServerError {
} }
impl IntoResponse for ServerError { impl IntoResponse for ServerError {
type Body = Full<Bytes>; fn into_response(self) -> Response<BoxBody> {
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
match self { match self {
ServerError::ValidationError(_) => { ServerError::ValidationError(_) => {
let message = format!("Input validation error: [{}]", self).replace("\n", ", "); let message = format!("Input validation error: [{}]", self).replace("\n", ", ");
+2 -2
View File
@@ -6,7 +6,7 @@
use axum::{ use axum::{
async_trait, async_trait,
body::{Bytes, Full}, body::BoxBody,
extract::{FromRequest, Path, RequestParts}, extract::{FromRequest, Path, RequestParts},
http::{Response, StatusCode}, http::{Response, StatusCode},
response::IntoResponse, response::IntoResponse,
@@ -51,7 +51,7 @@ impl<B> FromRequest<B> for Version
where where
B: Send, B: Send,
{ {
type Rejection = Response<Full<Bytes>>; type Rejection = Response<BoxBody>;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> { async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let params = Path::<HashMap<String, String>>::from_request(req) let params = Path::<HashMap<String, String>>::from_request(req)