Skip to content

Commit

Permalink
Remove Sync requirement from response bodies (#440)
Browse files Browse the repository at this point in the history
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]: hyperium/tonic#117
  • Loading branch information
davidpdrsn authored Nov 1, 2021
1 parent 9465128 commit 3d07d40
Show file tree
Hide file tree
Showing 13 changed files with 47 additions and 30 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
thus wasn't necessary
- **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public
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:
- Big internal refactoring of routing leading to several improvements ([#363])
- **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported.
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ bitflags = "1.0"
bytes = "1.0"
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
http = "0.2"
http-body = "0.4.3"
hyper = { version = "0.14", features = ["server", "tcp", "stream"] }
http-body = "0.4.4"
hyper = { version = "0.14.14", features = ["server", "tcp", "stream"] }
matchit = "0.4.4"
percent-encoding = "2.1"
pin-project-lite = "0.2.7"
Expand Down
6 changes: 3 additions & 3 deletions src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ pub use bytes::Bytes;
///
/// This is used in axum as the response body type for applications. Its
/// 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`].
pub fn box_body<B>(body: B) -> BoxBody
where
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
B: http_body::Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>,
{
body.map_err(Error::new).boxed()
body.map_err(Error::new).boxed_unsync()
}

pub(crate) fn empty() -> BoxBody {
Expand Down
8 changes: 4 additions & 4 deletions src/error_handling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ where
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
F: FnOnce(S::Error) -> Res + Clone,
Res: IntoResponse,
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
ResBody::Error: Into<BoxError>,
{
type Response = Response<BoxBody>;
type Error = Infallible;
Expand Down Expand Up @@ -181,8 +181,8 @@ pub mod future {
Fut: Future<Output = Result<Response<B>, E>>,
F: FnOnce(E) -> Res,
Res: IntoResponse,
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
B::Error: Into<BoxError> + Send + Sync + 'static,
B: http_body::Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>,
{
type Output = Result<Response<BoxBody>, Infallible>;

Expand Down
4 changes: 2 additions & 2 deletions src/extract/extractor_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ where
E: FromRequest<ReqBody> + 'static,
ReqBody: Default + Send + 'static,
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>,
{
type Response = Response<BoxBody>;
Expand Down Expand Up @@ -213,7 +213,7 @@ where
E: FromRequest<ReqBody>,
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
ReqBody: Default,
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
ResBody::Error: Into<BoxError>,
{
type Output = Result<Response<BoxBody>, S::Error>;
Expand Down
2 changes: 1 addition & 1 deletion src/extract/multipart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub struct Multipart {
impl<B> FromRequest<B> for Multipart
where
B: http_body::Body<Data = Bytes> + Default + Unpin + Send + 'static,
B::Error: Into<BoxError> + 'static,
B::Error: Into<BoxError>,
{
type Rejection = MultipartRejection;

Expand Down
4 changes: 2 additions & 2 deletions src/handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ where
S::Future: Send,
T: 'static,
ReqBody: Send + 'static,
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
ResBody: http_body::Body<Data = Bytes> + Send + 'static,
ResBody::Error: Into<BoxError>,
{
type Sealed = sealed::Hidden;

Expand Down
4 changes: 2 additions & 2 deletions src/response/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ where
impl<H, T, K, V> IntoResponse for (Headers<H>, T)
where
T: IntoResponse,
T::Body: Body<Data = Bytes> + Send + Sync + 'static,
T::Body: Body<Data = Bytes> + Send + 'static,
<T::Body as Body>::Error: Into<BoxError>,
H: IntoIterator<Item = (K, V)>,
K: TryInto<HeaderName>,
Expand All @@ -141,7 +141,7 @@ where
impl<H, T, K, V> IntoResponse for (StatusCode, Headers<H>, T)
where
T: IntoResponse,
T::Body: Body<Data = Bytes> + Send + Sync + 'static,
T::Body: Body<Data = Bytes> + Send + 'static,
<T::Body as Body>::Error: Into<BoxError>,
H: IntoIterator<Item = (K, V)>,
K: TryInto<HeaderName>,
Expand Down
24 changes: 18 additions & 6 deletions src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub trait IntoResponse {
/// [`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 + Sync + 'static;
type Body: http_body::Body<Data = Bytes, Error = Self::BodyError> + Send + 'static;

/// The error type `Self::Body` might generate.
///
Expand Down Expand Up @@ -217,7 +217,7 @@ where

impl<B> IntoResponse for Response<B>
where
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
B: http_body::Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>,
{
type Body = B;
Expand Down Expand Up @@ -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>
where
B: http_body::Body + Send + Sync + 'static,
F: FnMut(B::Data) -> Bytes + Send + Sync + 'static,
B: http_body::Body + Send + 'static,
F: FnMut(B::Data) -> Bytes + Send + 'static,
B::Error: Into<BoxError>,
{
type Body = Self;
Expand All @@ -273,8 +285,8 @@ where

impl<B, F, E> IntoResponse for MapErr<B, F>
where
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
F: FnMut(B::Error) -> E + Send + Sync + 'static,
B: http_body::Body<Data = Bytes> + Send + 'static,
F: FnMut(B::Error) -> E + Send + 'static,
E: Into<BoxError>,
{
type Body = Self;
Expand Down
2 changes: 1 addition & 1 deletion src/routing/method_not_allowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl<E> fmt::Debug for MethodNotAllowed<E> {

impl<B, E> Service<Request<B>> for MethodNotAllowed<E>
where
B: Send + Sync + 'static,
B: Send + 'static,
{
type Response = Response<BoxBody>;
type Error = E;
Expand Down
8 changes: 4 additions & 4 deletions src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<B> Clone for Router<B> {

impl<B> Default for Router<B>
where
B: Send + Sync + 'static,
B: Send + 'static,
{
fn default() -> Self {
Self::new()
Expand All @@ -99,7 +99,7 @@ const NEST_TAIL_PARAM_CAPTURE: &str = "/*axum_nest";

impl<B> Router<B>
where
B: Send + Sync + 'static,
B: Send + 'static,
{
/// Create a new `Router`.
///
Expand Down Expand Up @@ -240,7 +240,7 @@ where
+ 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>,
{
let layer = ServiceBuilder::new()
Expand Down Expand Up @@ -361,7 +361,7 @@ where

impl<B> Service<Request<B>> for Router<B>
where
B: Send + Sync + 'static,
B: Send + 'static,
{
type Response = Response<BoxBody>;
type Error = Infallible;
Expand Down
2 changes: 1 addition & 1 deletion src/routing/not_found.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) struct NotFound;

impl<B> Service<Request<B>> for NotFound
where
B: Send + Sync + 'static,
B: Send + 'static,
{
type Response = Response<BoxBody>;
type Error = Infallible;
Expand Down
4 changes: 2 additions & 2 deletions src/routing/service_method_routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
where
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>,
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error> + Clone,
{
Expand Down Expand Up @@ -514,7 +514,7 @@ pin_project! {
impl<S, F, B, ResBody> Future for MethodRouterFuture<S, F, B>
where
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>,
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error>,
{
Expand Down

0 comments on commit 3d07d40

Please sign in to comment.