mirror of
https://github.com/tokio-rs/axum.git
synced 2024-12-27 23:10:20 +01:00
Remove Sync
requirement from response bodies (#440)
As we learned [in Tonic] bodies don't need to be `Sync` because they can only be polled from one thread at a time. This changes axum's bodies to no longer require `Sync` and makes `BoxBody` an alias for `UnsyncBoxBody<Bytes, axum::Error>`. [in Tonic]: https://github.com/hyperium/tonic/issues/117
This commit is contained in:
parent
9465128f3e
commit
3d07d40e02
13 changed files with 47 additions and 30 deletions
|
@ -34,6 +34,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
thus wasn't necessary
|
thus wasn't necessary
|
||||||
- **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public
|
- **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public
|
||||||
dependencies
|
dependencies
|
||||||
|
- **breaking:** `body::BoxBody` is now a type alias for
|
||||||
|
`http_body::combinators::UnsyncBoxBody` and thus is no longer `Sync`. This
|
||||||
|
is because bodies are streams and requiring streams to be `Sync` is
|
||||||
|
unnecessary.
|
||||||
|
- **added:** Implement `IntoResponse` for `http_body::combinators::UnsyncBoxBody`.
|
||||||
- Routing:
|
- Routing:
|
||||||
- Big internal refactoring of routing leading to several improvements ([#363])
|
- Big internal refactoring of routing leading to several improvements ([#363])
|
||||||
- **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
|
- **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
|
||||||
|
|
|
@ -29,8 +29,8 @@ bitflags = "1.0"
|
||||||
bytes = "1.0"
|
bytes = "1.0"
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
http-body = "0.4.3"
|
http-body = "0.4.4"
|
||||||
hyper = { version = "0.14", features = ["server", "tcp", "stream"] }
|
hyper = { version = "0.14.14", features = ["server", "tcp", "stream"] }
|
||||||
matchit = "0.4.4"
|
matchit = "0.4.4"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pin-project-lite = "0.2.7"
|
pin-project-lite = "0.2.7"
|
||||||
|
|
|
@ -20,15 +20,15 @@ pub use bytes::Bytes;
|
||||||
///
|
///
|
||||||
/// This is used in axum as the response body type for applications. Its
|
/// This is used in axum as the response body type for applications. Its
|
||||||
/// necessary to unify multiple response bodies types into one.
|
/// necessary to unify multiple response bodies types into one.
|
||||||
pub type BoxBody = http_body::combinators::BoxBody<Bytes, Error>;
|
pub type BoxBody = http_body::combinators::UnsyncBoxBody<Bytes, Error>;
|
||||||
|
|
||||||
/// Convert a [`http_body::Body`] into a [`BoxBody`].
|
/// Convert a [`http_body::Body`] into a [`BoxBody`].
|
||||||
pub fn box_body<B>(body: B) -> BoxBody
|
pub fn box_body<B>(body: B) -> BoxBody
|
||||||
where
|
where
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
B::Error: Into<BoxError>,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
body.map_err(Error::new).boxed()
|
body.map_err(Error::new).boxed_unsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn empty() -> BoxBody {
|
pub(crate) fn empty() -> BoxBody {
|
||||||
|
|
|
@ -114,8 +114,8 @@ where
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||||
F: FnOnce(S::Error) -> Res + Clone,
|
F: FnOnce(S::Error) -> Res + Clone,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
@ -181,8 +181,8 @@ pub mod future {
|
||||||
Fut: Future<Output = Result<Response<B>, E>>,
|
Fut: Future<Output = Result<Response<B>, E>>,
|
||||||
F: FnOnce(E) -> Res,
|
F: FnOnce(E) -> Res,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Output = Result<Response<BoxBody>, Infallible>;
|
type Output = Result<Response<BoxBody>, Infallible>;
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ where
|
||||||
E: FromRequest<ReqBody> + 'static,
|
E: FromRequest<ReqBody> + 'static,
|
||||||
ReqBody: Default + Send + 'static,
|
ReqBody: Default + Send + 'static,
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError>,
|
ResBody::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
|
@ -213,7 +213,7 @@ where
|
||||||
E: FromRequest<ReqBody>,
|
E: FromRequest<ReqBody>,
|
||||||
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
||||||
ReqBody: Default,
|
ReqBody: Default,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError>,
|
ResBody::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Output = Result<Response<BoxBody>, S::Error>;
|
type Output = Result<Response<BoxBody>, S::Error>;
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub struct Multipart {
|
||||||
impl<B> FromRequest<B> for Multipart
|
impl<B> FromRequest<B> for Multipart
|
||||||
where
|
where
|
||||||
B: http_body::Body<Data = Bytes> + Default + Unpin + Send + 'static,
|
B: http_body::Body<Data = Bytes> + Default + Unpin + Send + 'static,
|
||||||
B::Error: Into<BoxError> + 'static,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Rejection = MultipartRejection;
|
type Rejection = MultipartRejection;
|
||||||
|
|
||||||
|
|
|
@ -281,8 +281,8 @@ where
|
||||||
S::Future: Send,
|
S::Future: Send,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
ReqBody: Send + 'static,
|
ReqBody: Send + 'static,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Sealed = sealed::Hidden;
|
type Sealed = sealed::Hidden;
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ 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 + Sync + 'static,
|
T::Body: Body<Data = Bytes> + Send + 'static,
|
||||||
<T::Body as Body>::Error: Into<BoxError>,
|
<T::Body as Body>::Error: Into<BoxError>,
|
||||||
H: IntoIterator<Item = (K, V)>,
|
H: IntoIterator<Item = (K, V)>,
|
||||||
K: TryInto<HeaderName>,
|
K: TryInto<HeaderName>,
|
||||||
|
@ -141,7 +141,7 @@ where
|
||||||
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 + Sync + 'static,
|
T::Body: Body<Data = Bytes> + Send + 'static,
|
||||||
<T::Body as Body>::Error: Into<BoxError>,
|
<T::Body as Body>::Error: Into<BoxError>,
|
||||||
H: IntoIterator<Item = (K, V)>,
|
H: IntoIterator<Item = (K, V)>,
|
||||||
K: TryInto<HeaderName>,
|
K: TryInto<HeaderName>,
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub trait IntoResponse {
|
||||||
/// [`axum::body::Empty<Bytes>`]: crate::body::Empty
|
/// [`axum::body::Empty<Bytes>`]: crate::body::Empty
|
||||||
/// [`axum::body::Full<Bytes>`]: crate::body::Full
|
/// [`axum::body::Full<Bytes>`]: crate::body::Full
|
||||||
/// [`axum::body::BoxBody`]: crate::body::BoxBody
|
/// [`axum::body::BoxBody`]: crate::body::BoxBody
|
||||||
type Body: http_body::Body<Data = Bytes, Error = Self::BodyError> + Send + Sync + 'static;
|
type Body: http_body::Body<Data = Bytes, Error = Self::BodyError> + Send + 'static;
|
||||||
|
|
||||||
/// The error type `Self::Body` might generate.
|
/// The error type `Self::Body` might generate.
|
||||||
///
|
///
|
||||||
|
@ -217,7 +217,7 @@ where
|
||||||
|
|
||||||
impl<B> IntoResponse for Response<B>
|
impl<B> IntoResponse for Response<B>
|
||||||
where
|
where
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
B::Error: Into<BoxError>,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Body = B;
|
type Body = B;
|
||||||
|
@ -257,10 +257,22 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E> IntoResponse for http_body::combinators::UnsyncBoxBody<Bytes, E>
|
||||||
|
where
|
||||||
|
E: Into<BoxError> + 'static,
|
||||||
|
{
|
||||||
|
type Body = Self;
|
||||||
|
type BodyError = E;
|
||||||
|
|
||||||
|
fn into_response(self) -> Response<Self> {
|
||||||
|
Response::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B, F> IntoResponse for MapData<B, F>
|
impl<B, F> IntoResponse for MapData<B, F>
|
||||||
where
|
where
|
||||||
B: http_body::Body + Send + Sync + 'static,
|
B: http_body::Body + Send + 'static,
|
||||||
F: FnMut(B::Data) -> Bytes + Send + Sync + 'static,
|
F: FnMut(B::Data) -> Bytes + Send + 'static,
|
||||||
B::Error: Into<BoxError>,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Body = Self;
|
type Body = Self;
|
||||||
|
@ -273,8 +285,8 @@ where
|
||||||
|
|
||||||
impl<B, F, E> IntoResponse for MapErr<B, F>
|
impl<B, F, E> IntoResponse for MapErr<B, F>
|
||||||
where
|
where
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
B: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
F: FnMut(B::Error) -> E + Send + Sync + 'static,
|
F: FnMut(B::Error) -> E + Send + 'static,
|
||||||
E: Into<BoxError>,
|
E: Into<BoxError>,
|
||||||
{
|
{
|
||||||
type Body = Self;
|
type Body = Self;
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl<E> fmt::Debug for MethodNotAllowed<E> {
|
||||||
|
|
||||||
impl<B, E> Service<Request<B>> for MethodNotAllowed<E>
|
impl<B, E> Service<Request<B>> for MethodNotAllowed<E>
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = E;
|
type Error = E;
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl<B> Clone for Router<B> {
|
||||||
|
|
||||||
impl<B> Default for Router<B>
|
impl<B> Default for Router<B>
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
|
@ -99,7 +99,7 @@ const NEST_TAIL_PARAM_CAPTURE: &str = "/*axum_nest";
|
||||||
|
|
||||||
impl<B> Router<B>
|
impl<B> Router<B>
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
/// Create a new `Router`.
|
/// Create a new `Router`.
|
||||||
///
|
///
|
||||||
|
@ -240,7 +240,7 @@ where
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
<L::Service as Service<Request<LayeredReqBody>>>::Future: Send + 'static,
|
<L::Service as Service<Request<LayeredReqBody>>>::Future: Send + 'static,
|
||||||
LayeredResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
LayeredResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
LayeredResBody::Error: Into<BoxError>,
|
LayeredResBody::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
let layer = ServiceBuilder::new()
|
let layer = ServiceBuilder::new()
|
||||||
|
@ -361,7 +361,7 @@ where
|
||||||
|
|
||||||
impl<B> Service<Request<B>> for Router<B>
|
impl<B> Service<Request<B>> for Router<B>
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub(crate) struct NotFound;
|
||||||
|
|
||||||
impl<B> Service<Request<B>> for NotFound
|
impl<B> Service<Request<B>> for NotFound
|
||||||
where
|
where
|
||||||
B: Send + Sync + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
|
@ -464,7 +464,7 @@ impl<S, F, B> MethodRouter<S, F, B> {
|
||||||
impl<S, F, B, ResBody> Service<Request<B>> for MethodRouter<S, F, B>
|
impl<S, F, B, ResBody> Service<Request<B>> for MethodRouter<S, F, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError>,
|
ResBody::Error: Into<BoxError>,
|
||||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error> + Clone,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error> + Clone,
|
||||||
{
|
{
|
||||||
|
@ -514,7 +514,7 @@ pin_project! {
|
||||||
impl<S, F, B, ResBody> Future for MethodRouterFuture<S, F, B>
|
impl<S, F, B, ResBody> Future for MethodRouterFuture<S, F, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
||||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
|
||||||
ResBody::Error: Into<BoxError>,
|
ResBody::Error: Into<BoxError>,
|
||||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error>,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error>,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue