diff --git a/axum-debug/tests/pass/returns_self.rs b/axum-debug/tests/pass/returns_self.rs index 70e7c2a0..449e8a15 100644 --- a/axum-debug/tests/pass/returns_self.rs +++ b/axum-debug/tests/pass/returns_self.rs @@ -1,5 +1,5 @@ use axum::{ - body::{Bytes, Full}, + body::BoxBody, http::Response, response::IntoResponse, }; @@ -16,10 +16,7 @@ impl A { } impl IntoResponse for A { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { todo!() } } diff --git a/axum-extra/src/extract/cached.rs b/axum-extra/src/extract/cached.rs index 613a79d3..a45ed397 100644 --- a/axum-extra/src/extract/cached.rs +++ b/axum-extra/src/extract/cached.rs @@ -1,6 +1,6 @@ use axum::{ async_trait, - body::{boxed, BoxBody}, + body::BoxBody, extract::{ rejection::{ExtensionRejection, ExtensionsAlreadyExtracted}, Extension, FromRequest, RequestParts, @@ -30,7 +30,7 @@ use std::{ /// use axum::{ /// async_trait, /// extract::{FromRequest, RequestParts}, -/// body::{self, BoxBody}, +/// body::BoxBody, /// response::IntoResponse, /// http::{StatusCode, Response}, /// }; @@ -67,7 +67,7 @@ use std::{ /// // once, in case other extractors for the same request also loads the session /// let session: Session = Cached::::from_request(req) /// .await -/// .map_err(|err| err.into_response().map(body::boxed))? +/// .map_err(|err| err.into_response())? /// .0; /// /// // load user from session... @@ -157,13 +157,10 @@ impl IntoResponse for CachedRejection where R: IntoResponse, { - type Body = BoxBody; - type BodyError = ::Error; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self { - Self::ExtensionsAlreadyExtracted(inner) => inner.into_response().map(boxed), - Self::Inner(inner) => inner.into_response().map(boxed), + Self::ExtensionsAlreadyExtracted(inner) => inner.into_response(), + Self::Inner(inner) => inner.into_response(), } } } diff --git a/axum-extra/src/response/erased_json.rs b/axum-extra/src/response/erased_json.rs index 411f4f3a..d8f860ac 100644 --- a/axum-extra/src/response/erased_json.rs +++ b/axum-extra/src/response/erased_json.rs @@ -1,7 +1,5 @@ -use std::convert::Infallible; - use axum::{ - body::{Bytes, Full}, + body::{self, BoxBody, Full}, http::{header, HeaderValue, Response, StatusCode}, response::IntoResponse, }; @@ -41,22 +39,19 @@ impl ErasedJson { } impl IntoResponse for ErasedJson { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let bytes = match self.0 { Ok(res) => res, Err(err) => { return Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) .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(); } }; - let mut res = Response::new(Full::from(bytes)); + let mut res = Response::new(body::boxed(Full::from(bytes))); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 5dce5631..d274db51 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -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]) - Update WebSockets to use tokio-tungstenite 0.16 ([#525]) - **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` ([#571]) [#525]: https://github.com/tokio-rs/axum/pull/525 [#527]: https://github.com/tokio-rs/axum/pull/527 [#529]: https://github.com/tokio-rs/axum/pull/529 [#534]: https://github.com/tokio-rs/axum/pull/534 [#554]: https://github.com/tokio-rs/axum/pull/554 +[#571]: https://github.com/tokio-rs/axum/pull/571 # 0.3.3 (13. November, 2021) diff --git a/axum/src/body/stream_body.rs b/axum/src/body/stream_body.rs index 616cc7e9..d2d2f510 100644 --- a/axum/src/body/stream_body.rs +++ b/axum/src/body/stream_body.rs @@ -1,4 +1,8 @@ -use crate::{response::IntoResponse, BoxError, Error}; +use crate::{ + body::{self, BoxBody}, + response::IntoResponse, + BoxError, Error, +}; use bytes::Bytes; use futures_util::{ ready, @@ -77,11 +81,8 @@ where S::Ok: Into, S::Error: Into, { - type Body = Self; - type BodyError = Error; - - fn into_response(self) -> Response { - Response::new(self) + fn into_response(self) -> Response { + Response::new(body::boxed(self)) } } diff --git a/axum/src/error_handling/mod.rs b/axum/src/error_handling/mod.rs index a3ca9d61..716a06ff 100644 --- a/axum/src/error_handling/mod.rs +++ b/axum/src/error_handling/mod.rs @@ -143,7 +143,7 @@ where let future = Box::pin(async move { match inner.oneshot(req).await { Ok(res) => Ok(res.map(boxed)), - Err(err) => Ok(f(err).await.into_response().map(boxed)), + Err(err) => Ok(f(err).await.into_response()), } }); diff --git a/axum/src/extract/extractor_middleware.rs b/axum/src/extract/extractor_middleware.rs index 4319beb2..5e6a6671 100644 --- a/axum/src/extract/extractor_middleware.rs +++ b/axum/src/extract/extractor_middleware.rs @@ -247,7 +247,7 @@ where State::Call { future } } Err(err) => { - let res = err.into_response().map(crate::body::boxed); + let res = err.into_response(); return Poll::Ready(Ok(res)); } } diff --git a/axum/src/extract/rejection.rs b/axum/src/extract/rejection.rs index c30d223e..40c0d467 100644 --- a/axum/src/extract/rejection.rs +++ b/axum/src/extract/rejection.rs @@ -5,9 +5,7 @@ use crate::{ body::{boxed, BoxBody}, BoxError, Error, }; -use bytes::Bytes; use http_body::Full; -use std::convert::Infallible; define_rejection! { #[status = INTERNAL_SERVER_ERROR] @@ -115,11 +113,8 @@ impl InvalidPathParam { } impl IntoResponse for InvalidPathParam { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> http::Response { - let mut res = http::Response::new(Full::from(self.to_string())); + fn into_response(self) -> http::Response { + let mut res = http::Response::new(boxed(Full::from(self.to_string()))); *res.status_mut() = http::StatusCode::BAD_REQUEST; res } @@ -154,11 +149,8 @@ impl FailedToDeserializeQueryString { } impl IntoResponse for FailedToDeserializeQueryString { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> http::Response { - let mut res = http::Response::new(Full::from(self.to_string())); + fn into_response(self) -> http::Response { + let mut res = http::Response::new(boxed(Full::from(self.to_string()))); *res.status_mut() = http::StatusCode::BAD_REQUEST; res } @@ -320,15 +312,12 @@ impl IntoResponse for ContentLengthLimitRejection where T: IntoResponse, { - type Body = BoxBody; - type BodyError = Error; - - fn into_response(self) -> http::Response { + fn into_response(self) -> http::Response { match self { - Self::PayloadTooLarge(inner) => inner.into_response().map(boxed), - Self::LengthRequired(inner) => inner.into_response().map(boxed), - Self::HeadersAlreadyExtracted(inner) => inner.into_response().map(boxed), - Self::Inner(inner) => inner.into_response().map(boxed), + Self::PayloadTooLarge(inner) => inner.into_response(), + Self::LengthRequired(inner) => inner.into_response(), + Self::HeadersAlreadyExtracted(inner) => inner.into_response(), + Self::Inner(inner) => inner.into_response(), } } } diff --git a/axum/src/extract/tuple.rs b/axum/src/extract/tuple.rs index 5c483e3e..1c28412d 100644 --- a/axum/src/extract/tuple.rs +++ b/axum/src/extract/tuple.rs @@ -1,8 +1,5 @@ use super::{FromRequest, RequestParts}; -use crate::{ - body::{boxed, BoxBody}, - response::IntoResponse, -}; +use crate::{body::BoxBody, response::IntoResponse}; use async_trait::async_trait; use http::Response; use std::convert::Infallible; @@ -33,7 +30,7 @@ macro_rules! impl_from_request { type Rejection = Response; async fn from_request(req: &mut RequestParts) -> Result { - $( 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,)*)) } } diff --git a/axum/src/extract/typed_header.rs b/axum/src/extract/typed_header.rs index 2f78cc18..76b757bc 100644 --- a/axum/src/extract/typed_header.rs +++ b/axum/src/extract/typed_header.rs @@ -1,10 +1,8 @@ use super::{FromRequest, RequestParts}; -use crate::response::IntoResponse; +use crate::{body::BoxBody, response::IntoResponse}; use async_trait::async_trait; -use bytes::Bytes; use headers::HeaderMapExt; -use http_body::Full; -use std::{convert::Infallible, ops::Deref}; +use std::ops::Deref; /// Extractor that extracts a typed header value from [`headers`]. /// @@ -108,10 +106,7 @@ pub enum TypedHeaderRejectionReason { } impl IntoResponse for TypedHeaderRejection { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> http::Response { + fn into_response(self) -> http::Response { let mut res = self.to_string().into_response(); *res.status_mut() = http::StatusCode::BAD_REQUEST; res diff --git a/axum/src/extract/ws.rs b/axum/src/extract/ws.rs index 6203e7d3..b98f8c4d 100644 --- a/axum/src/extract/ws.rs +++ b/axum/src/extract/ws.rs @@ -65,7 +65,11 @@ use self::rejection::*; use super::{rejection::*, FromRequest, RequestParts}; -use crate::{response::IntoResponse, Error}; +use crate::{ + body::{self, BoxBody}, + response::IntoResponse, + Error, +}; use async_trait::async_trait; use bytes::Bytes; use futures_util::{ @@ -76,7 +80,6 @@ use http::{ header::{self, HeaderName, HeaderValue}, Method, Response, StatusCode, }; -use http_body::Full; use hyper::upgrade::{OnUpgrade, Upgraded}; use sha1::{Digest, Sha1}; use std::{ @@ -285,10 +288,7 @@ where F: FnOnce(WebSocket) -> Fut + Send + 'static, Fut: Future + Send + 'static, { - type Body = Full; - type BodyError = ::Error; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { // check requested protocols let protocol = self .extractor @@ -347,7 +347,7 @@ where builder = builder.header(header::SEC_WEBSOCKET_PROTOCOL, protocol); } - builder.body(Full::default()).unwrap() + builder.body(body::boxed(body::Empty::new())).unwrap() } } diff --git a/axum/src/handler/mod.rs b/axum/src/handler/mod.rs index 37240b0d..4ecd4c44 100644 --- a/axum/src/handler/mod.rs +++ b/axum/src/handler/mod.rs @@ -272,7 +272,7 @@ where type Sealed = sealed::Hidden; async fn call(self, _req: Request) -> Response { - 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 { Ok(value) => value, - Err(rejection) => return rejection.into_response().map(boxed), + Err(rejection) => return rejection.into_response(), }; )* let res = self($($ty,)*).await; - res.into_response().map(boxed) + res.into_response() } } }; @@ -350,14 +350,9 @@ where type Sealed = sealed::Hidden; async fn call(self, req: Request) -> Response { - match self - .svc - .oneshot(req) - .await - .map_err(IntoResponse::into_response) - { + match self.svc.oneshot(req).await { Ok(res) => res.map(boxed), - Err(res) => res.map(boxed), + Err(res) => res.into_response(), } } } diff --git a/axum/src/json.rs b/axum/src/json.rs index 8c29c57e..c161c5a3 100644 --- a/axum/src/json.rs +++ b/axum/src/json.rs @@ -1,10 +1,10 @@ use crate::{ + body::{self, BoxBody}, extract::{rejection::*, take_body, FromRequest, RequestParts}, response::IntoResponse, BoxError, }; use async_trait::async_trait; -use bytes::Bytes; use http::{ header::{self, HeaderValue}, StatusCode, @@ -12,10 +12,7 @@ use http::{ use http_body::Full; use hyper::Response; use serde::{de::DeserializeOwned, Serialize}; -use std::{ - convert::Infallible, - ops::{Deref, DerefMut}, -}; +use std::ops::{Deref, DerefMut}; /// JSON Extractor / Response. /// @@ -172,10 +169,7 @@ impl IntoResponse for Json where T: Serialize, { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let bytes = match serde_json::to_vec(&self.0) { Ok(res) => res, Err(err) => { @@ -185,12 +179,12 @@ where header::CONTENT_TYPE, 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(); } }; - let mut res = Response::new(Full::from(bytes)); + let mut res = Response::new(body::boxed(Full::from(bytes))); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), diff --git a/axum/src/macros.rs b/axum/src/macros.rs index 2a9e9554..7b8ce5a7 100644 --- a/axum/src/macros.rs +++ b/axum/src/macros.rs @@ -59,11 +59,8 @@ macro_rules! define_rejection { #[allow(deprecated)] impl $crate::response::IntoResponse for $name { - type Body = http_body::Full; - type BodyError = std::convert::Infallible; - - fn into_response(self) -> http::Response { - let mut res = http::Response::new(http_body::Full::from($body)); + fn into_response(self) -> http::Response<$crate::body::BoxBody> { + let mut res = http::Response::new($crate::body::boxed(http_body::Full::from($body))); *res.status_mut() = http::StatusCode::$status; res } @@ -104,12 +101,9 @@ macro_rules! define_rejection { } impl IntoResponse for $name { - type Body = http_body::Full; - type BodyError = std::convert::Infallible; - - fn into_response(self) -> http::Response { + fn into_response(self) -> http::Response<$crate::body::BoxBody> { 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 } @@ -148,10 +142,7 @@ macro_rules! composite_rejection { } impl $crate::response::IntoResponse for $name { - type Body = http_body::Full; - type BodyError = std::convert::Infallible; - - fn into_response(self) -> http::Response { + fn into_response(self) -> http::Response<$crate::body::BoxBody> { match self { $( Self::$variant(inner) => inner.into_response(), diff --git a/axum/src/response/headers.rs b/axum/src/response/headers.rs index ffc0b8de..7415998f 100644 --- a/axum/src/response/headers.rs +++ b/axum/src/response/headers.rs @@ -1,14 +1,11 @@ use super::IntoResponse; -use crate::{ - body::{boxed, BoxBody}, - BoxError, -}; +use crate::body::{boxed, BoxBody}; use bytes::Bytes; use http::{ header::{HeaderMap, HeaderName, HeaderValue}, Response, StatusCode, }; -use http_body::{Body, Full}; +use http_body::{Empty, Full}; use std::{convert::TryInto, fmt}; use tower::util::Either; @@ -59,7 +56,7 @@ use tower::util::Either; pub struct Headers(pub H); impl Headers { - fn try_into_header_map(self) -> Result>> + fn try_into_header_map(self) -> Result> where H: IntoIterator, K: TryInto, @@ -81,7 +78,7 @@ impl Headers { 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); *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; res @@ -97,15 +94,12 @@ where V: TryInto, V::Error: fmt::Display, { - type Body = Full; - type BodyError = ::Error; - - fn into_response(self) -> http::Response { + fn into_response(self) -> http::Response { let headers = self.try_into_header_map(); match 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 } @@ -117,50 +111,38 @@ where impl IntoResponse for (Headers, T) where T: IntoResponse, - T::Body: Body + Send + 'static, - ::Error: Into, H: IntoIterator, K: TryInto, K::Error: fmt::Display, V: TryInto, V::Error: fmt::Display, { - type Body = BoxBody; - type BodyError = ::Error; - - // this boxing could be improved with a EitherBody but thats - // an issue for another time - fn into_response(self) -> Response { + fn into_response(self) -> Response { let headers = match self.0.try_into_header_map() { 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 IntoResponse for (StatusCode, Headers, T) where T: IntoResponse, - T::Body: Body + Send + 'static, - ::Error: Into, H: IntoIterator, K: TryInto, K::Error: fmt::Display, V: TryInto, V::Error: fmt::Display, { - type Body = BoxBody; - type BodyError = ::Error; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let headers = match self.1.try_into_header_map() { 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() } } diff --git a/axum/src/response/mod.rs b/axum/src/response/mod.rs index c206cf84..f551a826 100644 --- a/axum/src/response/mod.rs +++ b/axum/src/response/mod.rs @@ -2,7 +2,7 @@ use crate::{ body::{boxed, BoxBody}, - BoxError, Error, + BoxError, }; use bytes::Bytes; use http::{header, HeaderMap, HeaderValue, Response, StatusCode}; @@ -39,7 +39,7 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse}; /// ```rust /// use axum::{ /// Router, -/// body::Body, +/// body::{self, BoxBody, Bytes}, /// routing::get, /// http::{Response, StatusCode}, /// response::IntoResponse, @@ -51,16 +51,13 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse}; /// } /// /// impl IntoResponse for MyError { -/// type Body = Body; -/// type BodyError = ::Error; -/// -/// fn into_response(self) -> Response { +/// fn into_response(self) -> Response { /// let body = match self { /// MyError::SomethingWentWrong => { -/// Body::from("something went wrong") +/// body::boxed(body::Full::from("something went wrong")) /// }, /// 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 /// use axum::{ +/// body::{self, BoxBody}, /// routing::get, /// response::IntoResponse, /// Router, @@ -127,11 +125,8 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse}; /// /// // 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) +/// fn into_response(self) -> Response { +/// Response::new(body::boxed(self)) /// } /// } /// @@ -145,56 +140,18 @@ pub use self::{headers::Headers, redirect::Redirect, sse::Sse}; /// # }; /// ``` 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 - /// [`boxed`]. - /// - /// [`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 + '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; + fn into_response(self) -> Response; } impl IntoResponse for () { - type Body = Empty; - type BodyError = Infallible; - - fn into_response(self) -> Response { - Response::new(Empty::new()) + fn into_response(self) -> Response { + Response::new(boxed(Empty::new())) } } impl IntoResponse for Infallible { - type Body = Empty; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self {} } } @@ -204,13 +161,10 @@ where T: IntoResponse, E: IntoResponse, { - type Body = BoxBody; - type BodyError = Error; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self { - Ok(value) => value.into_response().map(boxed), - Err(err) => err.into_response().map(boxed), + Ok(value) => value.into_response(), + Err(err) => err.into_response(), } } } @@ -220,22 +174,16 @@ where B: http_body::Body + Send + 'static, B::Error: Into, { - type Body = B; - type BodyError = ::Error; - - fn into_response(self) -> Self { - self + fn into_response(self) -> Response { + self.map(boxed) } } 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) + fn into_response(self) -> Response { + Response::new(boxed(self)) } } }; @@ -246,11 +194,8 @@ impl_into_response_for_body!(Full); impl_into_response_for_body!(Empty); impl IntoResponse for http::response::Parts { - type Body = Empty; - type BodyError = Infallible; - - fn into_response(self) -> Response { - Response::from_parts(self, Empty::new()) + fn into_response(self) -> Response { + Response::from_parts(self, boxed(Empty::new())) } } @@ -258,11 +203,8 @@ 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) + fn into_response(self) -> Response { + Response::new(boxed(self)) } } @@ -270,11 +212,8 @@ impl IntoResponse for http_body::combinators::UnsyncBoxBody where E: Into + 'static, { - type Body = Self; - type BodyError = E; - - fn into_response(self) -> Response { - Response::new(self) + fn into_response(self) -> Response { + Response::new(boxed(self)) } } @@ -284,11 +223,8 @@ where F: FnMut(B::Data) -> Bytes + Send + 'static, B::Error: Into, { - type Body = Self; - type BodyError = ::Error; - - fn into_response(self) -> Response { - Response::new(self) + fn into_response(self) -> Response { + Response::new(boxed(self)) } } @@ -298,40 +234,28 @@ where F: FnMut(B::Error) -> E + Send + 'static, E: Into, { - type Body = Self; - type BodyError = E; - - fn into_response(self) -> Response { - Response::new(self) + fn into_response(self) -> Response { + Response::new(boxed(self)) } } impl IntoResponse for &'static str { - type Body = Full; - type BodyError = Infallible; - #[inline] - fn into_response(self) -> Response { + 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 { + 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)); +impl IntoResponse for Cow<'static, str> { + fn into_response(self) -> Response { + 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()), @@ -341,11 +265,8 @@ impl IntoResponse for std::borrow::Cow<'static, str> { } impl IntoResponse for Bytes { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { - let mut res = Response::new(Full::from(self)); + fn into_response(self) -> Response { + 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()), @@ -355,11 +276,8 @@ impl IntoResponse for Bytes { } impl IntoResponse for &'static [u8] { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { - let mut res = Response::new(Full::from(self)); + fn into_response(self) -> Response { + 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()), @@ -369,11 +287,8 @@ impl IntoResponse for &'static [u8] { } impl IntoResponse for Vec { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { - let mut res = Response::new(Full::from(self)); + fn into_response(self) -> Response { + 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()), @@ -382,12 +297,9 @@ impl IntoResponse for Vec { } } -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)); +impl IntoResponse for Cow<'static, [u8]> { + fn into_response(self) -> Response { + 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()), @@ -397,11 +309,11 @@ impl IntoResponse for std::borrow::Cow<'static, [u8]> { } impl IntoResponse for StatusCode { - type Body = Empty; - type BodyError = Infallible; - - fn into_response(self) -> Response { - Response::builder().status(self).body(Empty::new()).unwrap() + fn into_response(self) -> Response { + Response::builder() + .status(self) + .body(boxed(Empty::new())) + .unwrap() } } @@ -409,10 +321,7 @@ impl IntoResponse for (StatusCode, T) where T: IntoResponse, { - type Body = T::Body; - type BodyError = T::BodyError; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let mut res = self.1.into_response(); *res.status_mut() = self.0; res @@ -423,10 +332,7 @@ impl IntoResponse for (HeaderMap, T) where T: IntoResponse, { - type Body = T::Body; - type BodyError = T::BodyError; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let mut res = self.1.into_response(); res.headers_mut().extend(self.0); res @@ -437,10 +343,7 @@ impl IntoResponse for (StatusCode, HeaderMap, T) where T: IntoResponse, { - type Body = T::Body; - type BodyError = T::BodyError; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let mut res = self.2.into_response(); *res.status_mut() = self.0; res.headers_mut().extend(self.1); @@ -449,11 +352,8 @@ where } impl IntoResponse for HeaderMap { - type Body = Empty; - type BodyError = Infallible; - - fn into_response(self) -> Response { - let mut res = Response::new(Empty::new()); + fn into_response(self) -> Response { + let mut res = Response::new(boxed(Empty::new())); *res.headers_mut() = self; res } @@ -469,11 +369,8 @@ 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()); + fn into_response(self) -> Response { + let mut res = Response::new(boxed(self.0.into())); res.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()), @@ -491,7 +388,6 @@ impl From for Html { #[cfg(test)] mod tests { use super::*; - use crate::body::Body; use http::header::{HeaderMap, HeaderName}; #[test] @@ -499,11 +395,8 @@ mod tests { 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()); + fn into_response(self) -> Response { + let mut resp = Response::new(boxed(Empty::new())); resp.headers_mut() .insert(HeaderName::from_static("a"), HeaderValue::from_static("1")); resp diff --git a/axum/src/response/redirect.rs b/axum/src/response/redirect.rs index 91df811c..b99d91f1 100644 --- a/axum/src/response/redirect.rs +++ b/axum/src/response/redirect.rs @@ -1,7 +1,7 @@ use super::IntoResponse; -use bytes::Bytes; +use crate::body::{boxed, BoxBody}; use http::{header::LOCATION, HeaderValue, Response, StatusCode, Uri}; -use http_body::{Body, Empty}; +use http_body::Empty; use std::convert::TryFrom; /// Response that redirects the request to another location. @@ -105,11 +105,8 @@ impl Redirect { } impl IntoResponse for Redirect { - type Body = Empty; - type BodyError = ::Error; - - fn into_response(self) -> Response { - let mut res = Response::new(Empty::new()); + fn into_response(self) -> Response { + let mut res = Response::new(boxed(Empty::new())); *res.status_mut() = self.status_code; res.headers_mut().insert(LOCATION, self.location); res diff --git a/axum/src/response/sse.rs b/axum/src/response/sse.rs index 18d9a469..be374d5d 100644 --- a/axum/src/response/sse.rs +++ b/axum/src/response/sse.rs @@ -27,7 +27,11 @@ //! # }; //! ``` -use crate::{response::IntoResponse, BoxError}; +use crate::{ + body::{self, BoxBody}, + response::IntoResponse, + BoxError, +}; use bytes::Bytes; use futures_util::{ ready, @@ -94,14 +98,11 @@ where S: Stream> + Send + 'static, E: Into, { - type Body = Body; - type BodyError = E; - - fn into_response(self) -> Response { - let body = Body { + fn into_response(self) -> Response { + let body = body::boxed(Body { event_stream: SyncWrapper::new(self.stream), keep_alive: self.keep_alive.map(KeepAliveStream::new), - }; + }); Response::builder() .header(http::header::CONTENT_TYPE, mime::TEXT_EVENT_STREAM.as_ref()) @@ -112,9 +113,7 @@ where } pin_project! { - /// The body of an SSE response. - #[derive(Debug)] - pub struct Body { + struct Body { #[pin] event_stream: SyncWrapper, #[pin] diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs index c55e385d..0da8c566 100644 --- a/examples/error-handling-and-dependency-injection/src/main.rs +++ b/examples/error-handling-and-dependency-injection/src/main.rs @@ -9,7 +9,7 @@ use axum::{ async_trait, - body::{Bytes, Full}, + body::BoxBody, extract::{Extension, Path}, http::{Response, StatusCode}, response::IntoResponse, @@ -18,7 +18,7 @@ use axum::{ }; use serde::{Deserialize, Serialize}; use serde_json::json; -use std::{convert::Infallible, net::SocketAddr, sync::Arc}; +use std::{net::SocketAddr, sync::Arc}; use uuid::Uuid; #[tokio::main] @@ -92,10 +92,7 @@ impl From for AppError { } impl IntoResponse for AppError { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let (status, error_message) = match self { AppError::UserRepo(UserRepoError::NotFound) => { (StatusCode::NOT_FOUND, "User not found") diff --git a/examples/http-proxy/src/main.rs b/examples/http-proxy/src/main.rs index dd215d2e..3d3b9b26 100644 --- a/examples/http-proxy/src/main.rs +++ b/examples/http-proxy/src/main.rs @@ -13,8 +13,9 @@ //! Example is based on use axum::{ - body::{boxed, Body}, + body::{self, Body, BoxBody}, http::{Method, Request, Response, StatusCode}, + response::IntoResponse, routing::get, Router, }; @@ -37,7 +38,7 @@ async fn main() { let router = router.clone(); async move { if req.method() == Method::CONNECT { - proxy(req).await.map(|res| res.map(boxed)) + proxy(req).await } else { router.oneshot(req).await.map_err(|err| match err {}) } @@ -54,7 +55,7 @@ async fn main() { .unwrap(); } -async fn proxy(req: Request) -> Result, hyper::Error> { +async fn proxy(req: Request) -> Result, hyper::Error> { tracing::trace!(?req); if let Some(host_addr) = req.uri().authority().map(|auth| auth.to_string()) { @@ -69,13 +70,14 @@ async fn proxy(req: Request) -> Result, hyper::Error> { } }); - Ok(Response::new(Body::empty())) + Ok(Response::new(body::boxed(body::Empty::new()))) } else { tracing::warn!("CONNECT host is not socket addr: {:?}", req.uri()); - let mut resp = Response::new(Body::from("CONNECT must be to a socket address")); - *resp.status_mut() = StatusCode::BAD_REQUEST; - - Ok(resp) + Ok(( + StatusCode::BAD_REQUEST, + "CONNECT must be to a socket address", + ) + .into_response()) } } diff --git a/examples/jwt/src/main.rs b/examples/jwt/src/main.rs index 1a6e7681..609a8d34 100644 --- a/examples/jwt/src/main.rs +++ b/examples/jwt/src/main.rs @@ -8,7 +8,7 @@ use axum::{ async_trait, - body::{Bytes, Full}, + body::BoxBody, extract::{FromRequest, RequestParts, TypedHeader}, http::{Response, StatusCode}, response::IntoResponse, @@ -20,7 +20,7 @@ use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation} use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use serde_json::json; -use std::{convert::Infallible, fmt::Display, net::SocketAddr}; +use std::{fmt::Display, net::SocketAddr}; // Quick instructions // @@ -141,10 +141,7 @@ where } impl IntoResponse for AuthError { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { let (status, error_message) = match self { AuthError::WrongCredentials => (StatusCode::UNAUTHORIZED, "Wrong credentials"), AuthError::MissingCredentials => (StatusCode::BAD_REQUEST, "Missing credentials"), diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs index 37c81fcd..250e9836 100644 --- a/examples/oauth/src/main.rs +++ b/examples/oauth/src/main.rs @@ -9,7 +9,7 @@ use async_session::{MemoryStore, Session, SessionStore}; use axum::{ async_trait, - body::{Bytes, Empty}, + body::BoxBody, extract::{Extension, FromRequest, Query, RequestParts, TypedHeader}, http::{header::SET_COOKIE, HeaderMap, Response}, response::{IntoResponse, Redirect}, @@ -199,10 +199,7 @@ async fn login_authorized( struct AuthRedirect; impl IntoResponse for AuthRedirect { - type Body = Empty; - type BodyError = ::Error; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { Redirect::found("/auth/discord".parse().unwrap()).into_response() } } diff --git a/examples/templates/src/main.rs b/examples/templates/src/main.rs index a014722f..3bf1ce21 100644 --- a/examples/templates/src/main.rs +++ b/examples/templates/src/main.rs @@ -6,14 +6,14 @@ use askama::Template; use axum::{ - body::{Bytes, Full}, + body::{self, BoxBody, Full}, extract, http::{Response, StatusCode}, response::{Html, IntoResponse}, routing::get, Router, }; -use std::{convert::Infallible, net::SocketAddr}; +use std::net::SocketAddr; #[tokio::main] async fn main() { @@ -52,18 +52,15 @@ impl IntoResponse for HtmlTemplate where T: Template, { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self.0.render() { Ok(html) => Html(html).into_response(), Err(err) => Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Full::from(format!( + .body(body::boxed(Full::from(format!( "Failed to render template. Error: {}", err - ))) + )))) .unwrap(), } } diff --git a/examples/validator/src/main.rs b/examples/validator/src/main.rs index a1ddebca..bb1523b5 100644 --- a/examples/validator/src/main.rs +++ b/examples/validator/src/main.rs @@ -12,7 +12,7 @@ use async_trait::async_trait; use axum::{ - body::{Bytes, Full}, + body::BoxBody, extract::{Form, FromRequest, RequestParts}, http::{Response, StatusCode}, response::{Html, IntoResponse}, @@ -20,7 +20,7 @@ use axum::{ BoxError, Router, }; use serde::{de::DeserializeOwned, Deserialize}; -use std::{convert::Infallible, net::SocketAddr}; +use std::net::SocketAddr; use thiserror::Error; use validator::Validate; @@ -84,10 +84,7 @@ pub enum ServerError { } impl IntoResponse for ServerError { - type Body = Full; - type BodyError = Infallible; - - fn into_response(self) -> Response { + fn into_response(self) -> Response { match self { ServerError::ValidationError(_) => { let message = format!("Input validation error: [{}]", self).replace("\n", ", "); diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs index 03f6133a..aec6f385 100644 --- a/examples/versioning/src/main.rs +++ b/examples/versioning/src/main.rs @@ -6,7 +6,7 @@ use axum::{ async_trait, - body::{Bytes, Full}, + body::BoxBody, extract::{FromRequest, Path, RequestParts}, http::{Response, StatusCode}, response::IntoResponse, @@ -51,7 +51,7 @@ impl FromRequest for Version where B: Send, { - type Rejection = Response>; + type Rejection = Response; async fn from_request(req: &mut RequestParts) -> Result { let params = Path::>::from_request(req)