From 0e76ded7666965b7789a9b6a3834bcae5d395f4d Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 11 Jul 2022 13:40:51 +0200 Subject: [PATCH] use `Body` rather than `BoxBody` --- Cargo.toml | 3 ++ axum-core/Cargo.toml | 2 +- axum-core/src/body.rs | 7 ++- axum-core/src/error.rs | 7 --- axum-core/src/extract/mod.rs | 22 ++++----- axum-core/src/extract/rejection.rs | 15 +++--- axum-core/src/extract/request_parts.rs | 8 ++-- axum-extra/src/json_lines.rs | 8 ++-- axum-extra/src/routing/mod.rs | 12 ++--- axum-extra/src/routing/resource.rs | 17 ++----- axum-extra/src/routing/spa.rs | 6 +-- .../debug_handler/fail/request_not_last.rs | 4 +- .../fail/request_not_last.stderr | 4 +- .../tests/debug_handler/pass/request_last.rs | 4 +- axum/src/error_handling/mod.rs | 17 +++---- axum/src/extract/mod.rs | 6 +-- axum/src/extract/path/mod.rs | 6 +-- axum/src/extract/request_parts.rs | 9 ++-- axum/src/form.rs | 13 ++--- axum/src/handler/future.rs | 12 ++--- axum/src/handler/into_service.rs | 13 ++--- axum/src/handler/mod.rs | 12 ++--- axum/src/middleware/from_extractor.rs | 16 +++---- axum/src/middleware/from_fn.rs | 40 +++++----------- axum/src/routing/method_routing.rs | 40 +++++++--------- axum/src/routing/mod.rs | 33 +++++-------- axum/src/routing/route.rs | 20 ++++---- axum/src/routing/tests/get_to_head.rs | 2 +- axum/src/routing/tests/merge.rs | 6 +-- axum/src/routing/tests/mod.rs | 47 ++++++++++--------- axum/src/routing/tests/nest.rs | 4 +- 31 files changed, 178 insertions(+), 237 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a221fbc5a9..41a3f49d67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,6 @@ members = [ # with `cargo +nightly update -Z minimal-versions` "internal-minimal-versions", ] + +[patch.crates-io] +hyper = { git = "https://github.com/hyperium/hyper", branch = "david/body-wrap-body" } diff --git a/axum-core/Cargo.toml b/axum-core/Cargo.toml index 4d6e74e71d..1b7f742cc2 100644 --- a/axum-core/Cargo.toml +++ b/axum-core/Cargo.toml @@ -16,10 +16,10 @@ bytes = "1.0" futures-util = { version = "0.3", default-features = false, features = ["alloc"] } http = "0.2.7" http-body = "0.4.5" +hyper = "0.14" mime = "0.3.16" [dev-dependencies] axum = { path = "../axum", version = "0.5" } futures-util = "0.3" -hyper = "0.14" tokio = { version = "1.0", features = ["macros"] } diff --git a/axum-core/src/body.rs b/axum-core/src/body.rs index 9f25408936..804ef0630b 100644 --- a/axum-core/src/body.rs +++ b/axum-core/src/body.rs @@ -3,7 +3,10 @@ use crate::{BoxError, Error}; use bytes::Bytes; use bytes::{Buf, BufMut}; -use http_body::Body; +use http_body::Body as _; + +#[doc(no_inline)] +pub use hyper::Body; /// A boxed [`Body`] trait object. /// @@ -55,7 +58,7 @@ where // THE SOFTWARE. pub(crate) async fn to_bytes(body: T) -> Result where - T: Body, + T: http_body::Body, { futures_util::pin_mut!(body); diff --git a/axum-core/src/error.rs b/axum-core/src/error.rs index 18e3441815..f578803479 100644 --- a/axum-core/src/error.rs +++ b/axum-core/src/error.rs @@ -14,13 +14,6 @@ impl Error { inner: error.into(), } } - - pub(crate) fn downcast_inner(self) -> Result, BoxError> - where - T: std::error::Error + 'static, - { - self.inner.downcast() - } } impl fmt::Display for Error { diff --git a/axum-core/src/extract/mod.rs b/axum-core/src/extract/mod.rs index 85dd884f74..2c31dc40f4 100644 --- a/axum-core/src/extract/mod.rs +++ b/axum-core/src/extract/mod.rs @@ -5,10 +5,10 @@ //! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html use self::rejection::*; -use crate::{body::BoxBody, response::IntoResponse, BoxError}; +use crate::{body::Body, response::IntoResponse, BoxError}; use async_trait::async_trait; use bytes::Bytes; -use http::{Extensions, HeaderMap, Method, Uri, Version}; +use http::{Extensions, HeaderMap, Method, Request, Uri, Version}; use std::convert::Infallible; pub mod rejection; @@ -16,10 +16,6 @@ pub mod rejection; mod request_parts; mod tuple; -/// Type alias for [`http::Request`] whose body type defaults to [`BoxBody`], the most common body -/// type used with axum. -pub type Request = http::Request; - /// Types that can be created from requests. /// /// See [`axum::extract`] for more details. @@ -84,7 +80,7 @@ pub struct RequestParts { version: Version, headers: HeaderMap, extensions: Extensions, - body: Option, + body: Option, } impl RequestParts { @@ -112,15 +108,13 @@ impl RequestParts { body, ) = req.into_parts(); - let body = crate::body::boxed(body); - RequestParts { method, uri, version, headers, extensions, - body: Some(body), + body: Some(Body::wrap_body(body)), } } @@ -165,7 +159,7 @@ impl RequestParts { /// been called. /// /// [`take_body`]: RequestParts::take_body - pub fn try_into_request(self) -> Result, BodyAlreadyExtracted> { + pub fn try_into_request(self) -> Result, BodyAlreadyExtracted> { let Self { method, uri, @@ -243,7 +237,7 @@ impl RequestParts { /// Gets a reference to the request body. /// /// Returns `None` if the body has been taken by another extractor. - pub fn body(&self) -> Option<&BoxBody> { + pub fn body(&self) -> Option<&Body> { self.body.as_ref() } @@ -251,12 +245,12 @@ impl RequestParts { /// /// Returns `None` if the body has been taken by another extractor. // this returns `&mut Option` rather than `Option<&mut B>` such that users can use it to set the body. - pub fn body_mut(&mut self) -> &mut Option { + pub fn body_mut(&mut self) -> &mut Option { &mut self.body } /// Takes the body out of the request, leaving a `None` in its place. - pub fn take_body(&mut self) -> Option { + pub fn take_body(&mut self) -> Option { self.body.take() } } diff --git a/axum-core/src/extract/rejection.rs b/axum-core/src/extract/rejection.rs index 68dd9b0344..1546b171fc 100644 --- a/axum-core/src/extract/rejection.rs +++ b/axum-core/src/extract/rejection.rs @@ -45,13 +45,14 @@ impl FailedToBufferBody { where E: Into, { - let err = match err.into().downcast::() { - Ok(err) => err, - Err(err) => return Self::UnknownBodyError(UnknownBodyError::from_err(err)), - }; - match err.downcast_inner::() { - Ok(err) => Self::LengthLimitError(LengthLimitError::from_err(err)), - Err(err) => Self::UnknownBodyError(UnknownBodyError::from_err(err)), + let err = err.into(); + if err + .source() + .map_or(false, |source| source.is::()) + { + Self::LengthLimitError(LengthLimitError::from_err(err)) + } else { + Self::UnknownBodyError(UnknownBodyError::from_err(err)) } } } diff --git a/axum-core/src/extract/request_parts.rs b/axum-core/src/extract/request_parts.rs index 6c59312478..c8cad44ba6 100644 --- a/axum-core/src/extract/request_parts.rs +++ b/axum-core/src/extract/request_parts.rs @@ -1,12 +1,12 @@ use super::{rejection::*, FromRequest, RequestParts}; -use crate::body::BoxBody; +use crate::body::Body; use async_trait::async_trait; use bytes::Bytes; use http::{Extensions, HeaderMap, Method, Request, Uri, Version}; use std::convert::Infallible; #[async_trait] -impl FromRequest for Request { +impl FromRequest for Request { type Rejection = BodyAlreadyExtracted; async fn from_request(req: &mut RequestParts) -> Result { @@ -68,7 +68,7 @@ impl FromRequest for HeaderMap { } #[async_trait] -impl FromRequest for BoxBody { +impl FromRequest for Body { type Rejection = BodyAlreadyExtracted; async fn from_request(req: &mut RequestParts) -> Result { @@ -140,6 +140,6 @@ fn unwrap_infallible(result: Result) -> T { } } -pub(crate) fn take_body(req: &mut RequestParts) -> Result { +pub(crate) fn take_body(req: &mut RequestParts) -> Result { req.take_body().ok_or(BodyAlreadyExtracted) } diff --git a/axum-extra/src/json_lines.rs b/axum-extra/src/json_lines.rs index 5006e51157..8ac9fb92de 100644 --- a/axum-extra/src/json_lines.rs +++ b/axum-extra/src/json_lines.rs @@ -2,7 +2,7 @@ use axum::{ async_trait, - body::{BoxBody, Bytes, HttpBody, StreamBody}, + body::{Body, Bytes, HttpBody, StreamBody}, extract::{rejection::BodyAlreadyExtracted, FromRequest, RequestParts}, response::{IntoResponse, Response}, BoxError, @@ -136,7 +136,7 @@ where pin_project! { struct BodyStream { #[pin] - body: BoxBody, + body: Body, } } @@ -144,7 +144,9 @@ impl Stream for BodyStream { type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.body).poll_data(cx) + Pin::new(&mut self.body) + .poll_data(cx) + .map_err(axum::Error::new) } } diff --git a/axum-extra/src/routing/mod.rs b/axum-extra/src/routing/mod.rs index 82c45b8fa5..3059ef4d30 100644 --- a/axum-extra/src/routing/mod.rs +++ b/axum-extra/src/routing/mod.rs @@ -1,7 +1,7 @@ //! Additional types for defining routes. use axum::{ - body::BoxBody, + body::Body, handler::Handler, http::Request, response::{Redirect, Response}, @@ -162,10 +162,7 @@ pub trait RouterExt: sealed::Sealed { /// ``` fn route_with_tsr(self, path: &str, service: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, Self: Sized; } @@ -253,10 +250,7 @@ impl RouterExt for Router { fn route_with_tsr(mut self, path: &str, service: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, Self: Sized, { diff --git a/axum-extra/src/routing/resource.rs b/axum-extra/src/routing/resource.rs index 18f0e73c37..a6796f42b2 100644 --- a/axum-extra/src/routing/resource.rs +++ b/axum-extra/src/routing/resource.rs @@ -1,5 +1,5 @@ use axum::{ - body::BoxBody, + body::Body, handler::Handler, http::Request, response::Response, @@ -138,10 +138,7 @@ impl Resource { /// The routes will be nested at `/{resource_name}/:{resource_name}_id`. pub fn nest(mut self, svc: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { let path = self.show_update_destroy_path(); @@ -154,10 +151,7 @@ impl Resource { /// The routes will be nested at `/{resource_name}`. pub fn nest_collection(mut self, svc: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { let path = self.index_create_path(); @@ -175,10 +169,7 @@ impl Resource { fn route(mut self, path: &str, svc: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { self.router = self.router.route(path, svc); diff --git a/axum-extra/src/routing/spa.rs b/axum-extra/src/routing/spa.rs index 532791c288..fc05e5a0fa 100644 --- a/axum-extra/src/routing/spa.rs +++ b/axum-extra/src/routing/spa.rs @@ -1,5 +1,5 @@ use axum::{ - body::BoxBody, + body::Body, error_handling::HandleError, response::Response, routing::{get_service, Route}, @@ -151,8 +151,8 @@ impl From> for Router where F: Clone + Send + 'static, HandleError, F, T>: - Service, Response = Response, Error = Infallible>, - , F, T> as Service>>::Future: Send, + Service, Response = Response, Error = Infallible>, + , F, T> as Service>>::Future: Send, T: 'static, { fn from(spa: SpaRouter) -> Self { diff --git a/axum-macros/tests/debug_handler/fail/request_not_last.rs b/axum-macros/tests/debug_handler/fail/request_not_last.rs index 9a324e4a7e..ff58b2a3f1 100644 --- a/axum-macros/tests/debug_handler/fail/request_not_last.rs +++ b/axum-macros/tests/debug_handler/fail/request_not_last.rs @@ -1,7 +1,7 @@ -use axum::extract::{Extension, Request}; +use axum::{extract::Extension, body::Body, http::Request}; use axum_macros::debug_handler; #[debug_handler] -async fn handler(_: Request, _: Extension) {} +async fn handler(_: Request, _: Extension) {} fn main() {} diff --git a/axum-macros/tests/debug_handler/fail/request_not_last.stderr b/axum-macros/tests/debug_handler/fail/request_not_last.stderr index 28e08398d8..a3482e6486 100644 --- a/axum-macros/tests/debug_handler/fail/request_not_last.stderr +++ b/axum-macros/tests/debug_handler/fail/request_not_last.stderr @@ -1,5 +1,5 @@ error: `Request` extractor should always be last --> tests/debug_handler/fail/request_not_last.rs:5:18 | -5 | async fn handler(_: Request, _: Extension) {} - | ^^^^^^^^^^ +5 | async fn handler(_: Request, _: Extension) {} + | ^^^^^^^^^^^^^^^^ diff --git a/axum-macros/tests/debug_handler/pass/request_last.rs b/axum-macros/tests/debug_handler/pass/request_last.rs index da1531f458..1572651e63 100644 --- a/axum-macros/tests/debug_handler/pass/request_last.rs +++ b/axum-macros/tests/debug_handler/pass/request_last.rs @@ -1,7 +1,7 @@ -use axum::extract::{Extension, Request}; +use axum::{extract::Extension, body::Body, http::Request}; use axum_macros::debug_handler; #[debug_handler] -async fn handler(_: Extension, _: Request) {} +async fn handler(_: Extension, _: Request) {} fn main() {} diff --git a/axum/src/error_handling/mod.rs b/axum/src/error_handling/mod.rs index 8309821c5b..0266e8b97a 100644 --- a/axum/src/error_handling/mod.rs +++ b/axum/src/error_handling/mod.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../docs/error_handling.md")] use crate::{ - body::{boxed, BoxBody, Bytes, HttpBody}, + body::{boxed, Body, Bytes, HttpBody}, extract::{FromRequest, RequestParts}, http::{Request, StatusCode}, response::{IntoResponse, Response}, @@ -114,15 +114,14 @@ where } } -impl Service> for HandleError +impl Service> for HandleError where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Error: Send, S::Future: Send, F: FnOnce(S::Error) -> Fut + Clone + Send + 'static, Fut: Future + Send, Res: IntoResponse, - ReqBody: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, { @@ -134,7 +133,7 @@ where Poll::Ready(Ok(())) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let f = self.f.clone(); let clone = self.inner.clone(); @@ -154,18 +153,16 @@ where #[allow(unused_macros)] macro_rules! impl_service { ( $($ty:ident),* $(,)? ) => { - impl Service> + impl Service> for HandleError where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Error: Send, S::Future: Send, F: FnOnce($($ty),*, S::Error) -> Fut + Clone + Send + 'static, Fut: Future + Send, Res: IntoResponse, $( $ty: FromRequest + Send,)* - ReqBody: HttpBody + Send + 'static, - ReqBody::Error: Into, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, { @@ -179,7 +176,7 @@ macro_rules! impl_service { } #[allow(non_snake_case)] - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let f = self.f.clone(); let clone = self.inner.clone(); diff --git a/axum/src/extract/mod.rs b/axum/src/extract/mod.rs index 98c891de34..ac920c9fcd 100644 --- a/axum/src/extract/mod.rs +++ b/axum/src/extract/mod.rs @@ -1,6 +1,6 @@ #![doc = include_str!("../docs/extract.md")] -use axum_core::body::BoxBody; +use axum_core::body::Body; use http::header; use rejection::*; @@ -17,7 +17,7 @@ mod raw_query; mod request_parts; #[doc(inline)] -pub use axum_core::extract::{FromRequest, Request, RequestParts}; +pub use axum_core::extract::{FromRequest, RequestParts}; #[doc(inline)] #[allow(deprecated)] @@ -70,7 +70,7 @@ pub use self::ws::WebSocketUpgrade; #[doc(no_inline)] pub use crate::TypedHeader; -pub(crate) fn take_body(req: &mut RequestParts) -> Result { +pub(crate) fn take_body(req: &mut RequestParts) -> Result { req.take_body().ok_or_else(BodyAlreadyExtracted::default) } diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index 83fe833517..317eee59a1 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -410,8 +410,8 @@ impl std::error::Error for FailedToDeserializePathParams {} #[cfg(test)] mod tests { use super::*; - use crate::{extract::Request, routing::get, test_helpers::*, Router}; - use http::StatusCode; + use crate::{body::Body, routing::get, test_helpers::*, Router}; + use http::{Request, StatusCode}; use std::collections::HashMap; #[tokio::test] @@ -518,7 +518,7 @@ mod tests { #[tokio::test] async fn when_extensions_are_missing() { - let app = Router::new().route("/:key", get(|_: Request, _: Path| async {})); + let app = Router::new().route("/:key", get(|_: Request, _: Path| async {})); let client = TestClient::new(app); diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs index a3821679e8..6c9e93f24e 100644 --- a/axum/src/extract/request_parts.rs +++ b/axum/src/extract/request_parts.rs @@ -141,7 +141,7 @@ impl FromRequest for BodyStream { type Rejection = BodyAlreadyExtracted; async fn from_request(req: &mut RequestParts) -> Result { - let body = take_body(req)?.map_data(Into::into); + let body = take_body(req)?.map_data(Into::into).map_err(Error::new); let stream = BodyStream(SyncWrapper::new(Box::pin(body))); Ok(stream) } @@ -162,16 +162,17 @@ fn body_stream_traits() { #[cfg(test)] mod tests { use crate::{ - extract::{Extension, Request}, + body::Body, + extract::Extension, routing::{get, post}, test_helpers::*, Router, }; - use http::{Method, StatusCode}; + use http::{Method, Request, StatusCode}; #[tokio::test] async fn multiple_request_extractors() { - async fn handler(_: Request, _: Request) {} + async fn handler(_: Request, _: Request) {} let app = Router::new().route("/", post(handler)); diff --git a/axum/src/form.rs b/axum/src/form.rs index 6a7988a887..83f11ff20a 100644 --- a/axum/src/form.rs +++ b/axum/src/form.rs @@ -108,7 +108,7 @@ impl Deref for Form { #[cfg(test)] mod tests { use super::*; - use crate::body::{Empty, Full}; + use crate::body::Body; use crate::extract::RequestParts; use http::Request; use serde::{Deserialize, Serialize}; @@ -124,7 +124,7 @@ mod tests { let mut req = RequestParts::new( Request::builder() .uri(uri.as_ref()) - .body(Empty::::new()) + .body(Body::empty()) .unwrap(), ); assert_eq!(Form::::from_request(&mut req).await.unwrap().0, value); @@ -139,9 +139,7 @@ mod tests { http::header::CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref(), ) - .body(Full::::new( - serde_urlencoded::to_string(&value).unwrap().into(), - )) + .body(Body::from(serde_urlencoded::to_string(&value).unwrap())) .unwrap(), ); assert_eq!(Form::::from_request(&mut req).await.unwrap().0, value); @@ -205,13 +203,12 @@ mod tests { .uri("http://example.com/test") .method(Method::POST) .header(http::header::CONTENT_TYPE, mime::APPLICATION_JSON.as_ref()) - .body(Full::::new( + .body(Body::from( serde_urlencoded::to_string(&Pagination { size: Some(10), page: None, }) - .unwrap() - .into(), + .unwrap(), )) .unwrap(), ); diff --git a/axum/src/handler/future.rs b/axum/src/handler/future.rs index db2b6fee08..cb02508dbf 100644 --- a/axum/src/handler/future.rs +++ b/axum/src/handler/future.rs @@ -1,6 +1,6 @@ //! Handler future types. -use crate::{body::BoxBody, response::Response}; +use crate::{body::Body, response::Response}; use futures_util::future::Map; use http::Request; use pin_project_lite::pin_project; @@ -21,19 +21,19 @@ pin_project! { /// The response future for [`Layered`](super::Layered). pub struct LayeredFuture where - S: Service>, + S: Service>, { #[pin] - inner: Map>, fn(Result) -> Response>, + inner: Map>, fn(Result) -> Response>, } } impl LayeredFuture where - S: Service>, + S: Service>, { pub(super) fn new( - inner: Map>, fn(Result) -> Response>, + inner: Map>, fn(Result) -> Response>, ) -> Self { Self { inner } } @@ -41,7 +41,7 @@ where impl Future for LayeredFuture where - S: Service>, + S: Service>, { type Output = Response; diff --git a/axum/src/handler/into_service.rs b/axum/src/handler/into_service.rs index 48c5de22c9..a0eb608283 100644 --- a/axum/src/handler/into_service.rs +++ b/axum/src/handler/into_service.rs @@ -1,9 +1,5 @@ use super::Handler; -use crate::{ - body::{self, Bytes, HttpBody}, - response::Response, - BoxError, -}; +use crate::{body::Body, response::Response}; use http::Request; use std::{ convert::Infallible, @@ -57,11 +53,9 @@ where } } -impl Service> for IntoService +impl Service> for IntoService where H: Handler + Clone + Send + 'static, - B: HttpBody + Send + 'static, - B::Error: Into, { type Response = Response; type Error = Infallible; @@ -75,10 +69,9 @@ where Poll::Ready(Ok(())) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { use futures_util::future::FutureExt; - let req = req.map(body::boxed); let handler = self.handler.clone(); let future = Handler::call(handler, req); let future = future.map(Ok as _); diff --git a/axum/src/handler/mod.rs b/axum/src/handler/mod.rs index b0a6146f32..1d016e42f0 100644 --- a/axum/src/handler/mod.rs +++ b/axum/src/handler/mod.rs @@ -36,7 +36,7 @@ #![doc = include_str!("../docs/debugging_handler_type_errors.md")] use crate::{ - body::{boxed, BoxBody, Bytes, HttpBody}, + body::{boxed, Body, Bytes, HttpBody}, extract::{connect_info::IntoMakeServiceWithConnectInfo, FromRequest, RequestParts}, response::{IntoResponse, Response}, routing::IntoMakeService, @@ -66,7 +66,7 @@ pub trait Handler: Clone + Send + Sized + 'static { type Future: Future + Send + 'static; /// Call the handler with the given request. - fn call(self, req: Request) -> Self::Future; + fn call(self, req: Request) -> Self::Future; /// Apply a [`tower::Layer`] to the handler. /// @@ -217,7 +217,7 @@ where { type Future = Pin + Send>>; - fn call(self, _req: Request) -> Self::Future { + fn call(self, _req: Request) -> Self::Future { Box::pin(async move { self().await.into_response() }) } } @@ -234,7 +234,7 @@ macro_rules! impl_handler { { type Future = Pin + Send>>; - fn call(self, req: Request) -> Self::Future { + fn call(self, req: Request) -> Self::Future { Box::pin(async move { let mut req = RequestParts::new(req); @@ -284,7 +284,7 @@ where impl Handler for Layered where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Error: IntoResponse, S::Future: Send, T: 'static, @@ -293,7 +293,7 @@ where { type Future = future::LayeredFuture; - fn call(self, req: Request) -> Self::Future { + fn call(self, req: Request) -> Self::Future { use futures_util::future::{FutureExt, Map}; let future: Map<_, fn(Result) -> _> = diff --git a/axum/src/middleware/from_extractor.rs b/axum/src/middleware/from_extractor.rs index 218730b41d..905e6c0800 100644 --- a/axum/src/middleware/from_extractor.rs +++ b/axum/src/middleware/from_extractor.rs @@ -4,7 +4,7 @@ use crate::{ response::{IntoResponse, Response}, BoxError, }; -use axum_core::body::BoxBody; +use axum_core::body::Body; use futures_util::{future::BoxFuture, ready}; use http::Request; use pin_project_lite::pin_project; @@ -167,12 +167,10 @@ where } } -impl Service> for FromExtractor +impl Service> for FromExtractor where E: FromRequest + 'static, - ReqBody: HttpBody + Default + Send + 'static, - ReqBody::Error: Into, - S: Service, Response = Response> + Clone, + S: Service, Response = Response> + Clone, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, { @@ -185,7 +183,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let extract_future = Box::pin(async move { let mut req = RequestParts::new(req); let extracted = E::from_request(&mut req).await; @@ -207,7 +205,7 @@ pin_project! { pub struct ResponseFuture where E: FromRequest, - S: Service>, + S: Service>, { #[pin] state: State, @@ -220,7 +218,7 @@ pin_project! { enum State where E: FromRequest, - S: Service>, + S: Service>, { Extracting { future: BoxFuture<'static, (RequestParts, Result)> }, Call { #[pin] future: S::Future }, @@ -230,7 +228,7 @@ pin_project! { impl Future for ResponseFuture where E: FromRequest, - S: Service, Response = Response>, + S: Service, Response = Response>, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, { diff --git a/axum/src/middleware/from_fn.rs b/axum/src/middleware/from_fn.rs index e24e2ec075..fadbf070ff 100644 --- a/axum/src/middleware/from_fn.rs +++ b/axum/src/middleware/from_fn.rs @@ -1,5 +1,5 @@ use crate::{ - body::{self, Bytes, HttpBody}, + body::{self, Body, Bytes, HttpBody}, response::{IntoResponse, Response}, BoxError, }; @@ -256,19 +256,17 @@ where macro_rules! impl_service { ( $($ty:ident),* $(,)? ) => { #[allow(non_snake_case)] - impl Service> for FromFn + impl Service> for FromFn where - F: FnMut($($ty),*, Next) -> Fut + Clone + Send + 'static, + F: FnMut($($ty),*, Next) -> Fut + Clone + Send + 'static, $( $ty: FromRequest + Send, )* Fut: Future + Send + 'static, Out: IntoResponse + 'static, - S: Service, Response = Response, Error = Infallible> + S: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, S::Future: Send + 'static, - ReqBody: HttpBody + Send + 'static, - ReqBody::Error: Into, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, { @@ -280,7 +278,7 @@ macro_rules! impl_service { self.inner.poll_ready(cx) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let not_ready_inner = self.inner.clone(); let ready_inner = std::mem::replace(&mut self.inner, not_ready_inner); @@ -327,13 +325,14 @@ where } /// The remainder of a middleware stack, including the handler. -pub struct Next { - inner: BoxCloneService, Response, Infallible>, +#[derive(Debug)] +pub struct Next { + inner: BoxCloneService, Response, Infallible>, } -impl Next { +impl Next { /// Execute the remaining middleware stack. - pub async fn run(mut self, req: Request) -> Response { + pub async fn run(mut self, req: Request) -> Response { match self.inner.call(req).await { Ok(res) => res, Err(err) => match err {}, @@ -341,14 +340,6 @@ impl Next { } } -impl fmt::Debug for Next { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FromFnLayer") - .field("inner", &self.inner) - .finish() - } -} - /// Response future for [`FromFn`]. pub struct ResponseFuture { inner: BoxFuture<'static, Response>, @@ -371,13 +362,13 @@ impl fmt::Debug for ResponseFuture { #[cfg(test)] mod tests { use super::*; - use crate::{body::Empty, routing::get, Router}; + use crate::{routing::get, Router}; use http::{HeaderMap, StatusCode}; use tower::ServiceExt; #[tokio::test] async fn basic() { - async fn insert_header(mut req: Request, next: Next) -> impl IntoResponse { + async fn insert_header(mut req: Request, next: Next) -> impl IntoResponse { req.headers_mut() .insert("x-axum-test", "ok".parse().unwrap()); @@ -393,12 +384,7 @@ mod tests { .layer(from_fn(insert_header)); let res = app - .oneshot( - Request::builder() - .uri("/") - .body(body::boxed(Empty::new())) - .unwrap(), - ) + .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()) .await .unwrap(); assert_eq!(res.status(), StatusCode::OK); diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index e0ae88c907..ade00671e9 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -1,6 +1,6 @@ use super::IntoMakeService; use crate::{ - body::{boxed, BoxBody, Bytes, Empty, HttpBody}, + body::{boxed, Body, Bytes, Empty, HttpBody}, error_handling::{HandleError, HandleErrorLayer}, extract::connect_info::IntoMakeServiceWithConnectInfo, handler::Handler, @@ -78,7 +78,7 @@ macro_rules! top_level_service_fn { $(#[$m])+ pub fn $name(svc: S) -> MethodRouter where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Future: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, @@ -209,7 +209,7 @@ macro_rules! chained_service_fn { $(#[$m])+ pub fn $name(self, svc: S) -> Self where - S: Service, Response = Response, Error = E> + S: Service, Response = Response, Error = E> + Clone + Send + 'static, @@ -317,7 +317,7 @@ top_level_service_fn!(trace_service, TRACE); /// ``` pub fn on_service(filter: MethodFilter, svc: S) -> MethodRouter where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Future: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, @@ -380,7 +380,7 @@ where /// ``` pub fn any_service(svc: S) -> MethodRouter where - S: Service, Response = Response> + Clone + Send + 'static, + S: Service, Response = Response> + Clone + Send + 'static, S::Future: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, @@ -517,7 +517,7 @@ impl MethodRouter { /// Create a default `MethodRouter` that will respond with `405 Method Not Allowed` to all /// requests. pub fn new() -> Self { - let fallback = Route::new(service_fn(|_: Request| async { + let fallback = Route::new(service_fn(|_: Request| async { let mut response = Response::new(boxed(Empty::new())); *response.status_mut() = StatusCode::METHOD_NOT_ALLOWED; Ok(response) @@ -677,10 +677,7 @@ impl MethodRouter { /// ``` pub fn on_service(self, filter: MethodFilter, svc: S) -> Self where - S: Service, Response = Response, Error = E> - + Clone - + Send - + 'static, + S: Service, Response = Response, Error = E> + Clone + Send + 'static, S::Future: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, @@ -700,10 +697,7 @@ impl MethodRouter { #[doc = include_str!("../docs/method_routing/fallback.md")] pub fn fallback(mut self, svc: S) -> Self where - S: Service, Response = Response, Error = E> - + Clone - + Send - + 'static, + S: Service, Response = Response, Error = E> + Clone + Send + 'static, S::Future: Send + 'static, ResBody: HttpBody + Send + 'static, ResBody::Error: Into, @@ -714,7 +708,7 @@ impl MethodRouter { fn fallback_boxed_response_body(mut self, svc: S) -> Self where - S: Service, Response = Response, Error = E> + Clone + Send + 'static, + S: Service, Response = Response, Error = E> + Clone + Send + 'static, S::Future: Send + 'static, { self.fallback = Fallback::Custom(Route::new(svc)); @@ -725,11 +719,11 @@ impl MethodRouter { pub fn layer(self, layer: L) -> MethodRouter where L: Layer>, - L::Service: Service, Response = Response, Error = NewError> + L::Service: Service, Response = Response, Error = NewError> + Clone + Send + 'static, - >>::Future: Send + 'static, + >>::Future: Send + 'static, NewResBody: HttpBody + Send + 'static, NewResBody::Error: Into, { @@ -759,11 +753,11 @@ impl MethodRouter { pub fn route_layer(self, layer: L) -> MethodRouter where L: Layer>, - L::Service: Service, Response = Response, Error = E> + L::Service: Service, Response = Response, Error = E> + Clone + Send + 'static, - >>::Future: Send + 'static, + >>::Future: Send + 'static, NewResBody: HttpBody + Send + 'static, NewResBody::Error: Into, { @@ -886,8 +880,8 @@ impl MethodRouter { where F: Clone + Send + 'static, HandleError, F, T>: - Service, Response = Response, Error = Infallible>, - , F, T> as Service>>::Future: Send, + Service, Response = Response, Error = Infallible>, + , F, T> as Service>>::Future: Send, T: 'static, E: 'static, { @@ -896,7 +890,7 @@ impl MethodRouter { fn on_service_boxed_response_body(self, filter: MethodFilter, svc: S) -> Self where - S: Service, Response = Response, Error = E> + Clone + Send + 'static, + S: Service, Response = Response, Error = E> + Clone + Send + 'static, S::Future: Send + 'static, { macro_rules! set_service { @@ -1051,7 +1045,7 @@ where }; } - let req = req.map(boxed); + let req = req.map(Body::wrap_body); let method = req.method().clone(); diff --git a/axum/src/routing/mod.rs b/axum/src/routing/mod.rs index 9e6f2c0778..d50ec4c3ca 100644 --- a/axum/src/routing/mod.rs +++ b/axum/src/routing/mod.rs @@ -2,7 +2,7 @@ use self::{future::RouteFuture, not_found::NotFound}; use crate::{ - body::{boxed, BoxBody, Bytes, HttpBody}, + body::{boxed, Body, Bytes, HttpBody}, extract::connect_info::IntoMakeServiceWithConnectInfo, response::Response, routing::strip_prefix::StripPrefix, @@ -96,10 +96,7 @@ impl Router { #[doc = include_str!("../docs/routing/route.md")] pub fn route(mut self, path: &str, service: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { if path.is_empty() { @@ -153,10 +150,7 @@ impl Router { #[doc = include_str!("../docs/routing/nest.md")] pub fn nest(mut self, mut path: &str, svc: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { if path.is_empty() { @@ -274,9 +268,9 @@ impl Router { where L: Layer, L::Service: - Service, Response = Response> + Clone + Send + 'static, - >>::Error: Into + 'static, - >>::Future: Send + 'static, + Service, Response = Response> + Clone + Send + 'static, + >>::Error: Into + 'static, + >>::Future: Send + 'static, NewResBody: HttpBody + Send + 'static, NewResBody::Error: Into, { @@ -315,9 +309,9 @@ impl Router { where L: Layer, L::Service: - Service, Response = Response> + Clone + Send + 'static, - >>::Error: Into + 'static, - >>::Future: Send + 'static, + Service, Response = Response> + Clone + Send + 'static, + >>::Error: Into + 'static, + >>::Future: Send + 'static, NewResBody: HttpBody + Send + 'static, NewResBody::Error: Into, { @@ -352,10 +346,7 @@ impl Router { #[doc = include_str!("../docs/routing/fallback.md")] pub fn fallback(mut self, svc: T) -> Self where - T: Service, Response = Response, Error = Infallible> - + Clone - + Send - + 'static, + T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, { self.fallback = Fallback::Custom(Route::new(svc)); @@ -398,7 +389,7 @@ impl Router { fn call_route( &self, match_: matchit::Match<&RouteId>, - mut req: Request, + mut req: Request, ) -> RouteFuture { let id = *match_.value; @@ -469,7 +460,7 @@ where #[inline] fn call(&mut self, req: Request) -> Self::Future { - let mut req = req.map(boxed); + let mut req = req.map(Body::wrap_body); #[cfg(feature = "original-uri")] { diff --git a/axum/src/routing/route.rs b/axum/src/routing/route.rs index 48edb180dd..50ec037288 100644 --- a/axum/src/routing/route.rs +++ b/axum/src/routing/route.rs @@ -1,8 +1,8 @@ use crate::{ - body::{boxed, Empty, HttpBody}, + body::{boxed, Body, Empty, HttpBody}, response::Response, }; -use axum_core::{body::BoxBody, BoxError}; +use axum_core::BoxError; use bytes::Bytes; use http::{ header::{self, CONTENT_LENGTH}, @@ -26,12 +26,12 @@ use tower_service::Service; /// /// You normally shouldn't need to care about this type. It's used in /// [`Router::layer`](super::Router::layer). -pub struct Route(BoxCloneService, Response, E>); +pub struct Route(BoxCloneService, Response, E>); impl Route { pub(super) fn new(svc: T) -> Self where - T: Service, Response = Response, Error = E> + Clone + Send + 'static, + T: Service, Response = Response, Error = E> + Clone + Send + 'static, T::Future: Send + 'static, { Self(BoxCloneService::new(svc)) @@ -39,8 +39,8 @@ impl Route { pub(crate) fn oneshot_inner( &mut self, - req: Request, - ) -> Oneshot, Response, E>, Request> { + req: Request, + ) -> Oneshot, Response, E>, Request> { self.0.clone().oneshot(req) } } @@ -73,7 +73,7 @@ where #[inline] fn call(&mut self, req: Request) -> Self::Future { - let req = req.map(crate::body::boxed); + let req = req.map(Body::wrap_body); RouteFuture::from_future(self.oneshot_inner(req)) } } @@ -94,8 +94,8 @@ pin_project! { Future { #[pin] future: Oneshot< - BoxCloneService, Response, E>, - Request, + BoxCloneService, Response, E>, + Request, >, }, Response { @@ -106,7 +106,7 @@ pin_project! { impl RouteFuture { pub(crate) fn from_future( - future: Oneshot, Response, E>, Request>, + future: Oneshot, Response, E>, Request>, ) -> Self { Self { kind: RouteFutureKind::Future { future }, diff --git a/axum/src/routing/tests/get_to_head.rs b/axum/src/routing/tests/get_to_head.rs index 53d9babd71..21888e6eb8 100644 --- a/axum/src/routing/tests/get_to_head.rs +++ b/axum/src/routing/tests/get_to_head.rs @@ -45,7 +45,7 @@ mod for_services { async fn get_handles_head() { let app = Router::new().route( "/", - get_service(service_fn(|_req: Request| async move { + get_service(service_fn(|_req: Request| async move { Ok::<_, Infallible>( ([("x-some-header", "foobar")], "you shouldn't see this").into_response(), ) diff --git a/axum/src/routing/tests/merge.rs b/axum/src/routing/tests/merge.rs index 538b5499ea..31a7bc9ae1 100644 --- a/axum/src/routing/tests/merge.rs +++ b/axum/src/routing/tests/merge.rs @@ -206,13 +206,13 @@ async fn services() { let app = Router::new() .route( "/foo", - get_service(service_fn(|_: Request| async { + get_service(service_fn(|_: Request| async { Ok::<_, Infallible>(Response::new(Body::empty())) })), ) .merge(Router::new().route( "/bar", - get_service(service_fn(|_: Request| async { + get_service(service_fn(|_: Request| async { Ok::<_, Infallible>(Response::new(Body::empty())) })), )); @@ -229,7 +229,7 @@ async fn services() { async fn all_the_uris( uri: Uri, OriginalUri(original_uri): OriginalUri, - req: Request, + req: Request, ) -> impl IntoResponse { Json(json!({ "uri": uri.to_string(), diff --git a/axum/src/routing/tests/mod.rs b/axum/src/routing/tests/mod.rs index 9da64886f3..fe27634a91 100644 --- a/axum/src/routing/tests/mod.rs +++ b/axum/src/routing/tests/mod.rs @@ -1,16 +1,14 @@ use crate::{ - body::{Bytes, Empty}, + body::{Body, Bytes, Empty}, error_handling::HandleErrorLayer, - extract::{self, Path, Request}, + extract::{self, Path}, handler::Handler, response::IntoResponse, routing::{delete, get, get_service, on, on_service, patch, patch_service, post, MethodFilter}, test_helpers::*, BoxError, Json, Router, }; -use axum_core::body::BoxBody; -use http::{header::CONTENT_LENGTH, HeaderMap, Method, Response, StatusCode, Uri}; -use hyper::Body; +use http::{header::CONTENT_LENGTH, HeaderMap, Method, Request, Response, StatusCode, Uri}; use serde::Deserialize; use serde_json::{json, Value}; use std::{ @@ -32,15 +30,15 @@ mod nest; #[tokio::test] async fn hello_world() { - async fn root(_: Request) -> &'static str { + async fn root(_: Request) -> &'static str { "Hello, World!" } - async fn foo(_: Request) -> &'static str { + async fn foo(_: Request) -> &'static str { "foo" } - async fn users_create(_: Request) -> &'static str { + async fn users_create(_: Request) -> &'static str { "users#create" } @@ -68,12 +66,13 @@ async fn routing() { let app = Router::new() .route( "/users", - get(|_: Request| async { "users#index" }).post(|_: Request| async { "users#create" }), + get(|_: Request| async { "users#index" }) + .post(|_: Request| async { "users#create" }), ) - .route("/users/:id", get(|_: Request| async { "users#show" })) + .route("/users/:id", get(|_: Request| async { "users#show" })) .route( "/users/:id/action", - get(|_: Request| async { "users#action" }), + get(|_: Request| async { "users#action" }), ); let client = TestClient::new(app); @@ -103,8 +102,12 @@ async fn router_type_doesnt_change() { let app: Router = Router::new() .route( "/", - on(MethodFilter::GET, |_: Request| async { "hi from GET" }) - .on(MethodFilter::POST, |_: Request| async { "hi from POST" }), + on(MethodFilter::GET, |_: Request| async { + "hi from GET" + }) + .on(MethodFilter::POST, |_: Request| async { + "hi from POST" + }), ) .layer(tower_http::compression::CompressionLayer::new()); @@ -124,22 +127,22 @@ async fn routing_between_services() { use std::convert::Infallible; use tower::service_fn; - async fn handle(_: Request) -> &'static str { + async fn handle(_: Request) -> &'static str { "handler" } let app = Router::new() .route( "/one", - get_service(service_fn(|_: Request| async { + get_service(service_fn(|_: Request| async { Ok::<_, Infallible>(Response::new(Body::from("one get"))) })) - .post_service(service_fn(|_: Request| async { + .post_service(service_fn(|_: Request| async { Ok::<_, Infallible>(Response::new(Body::from("one post"))) })) .on_service( MethodFilter::PUT, - service_fn(|_: Request| async { + service_fn(|_: Request| async { Ok::<_, Infallible>(Response::new(Body::from("one put"))) }), ), @@ -170,7 +173,7 @@ async fn middleware_on_single_route() { use tower::ServiceBuilder; use tower_http::{compression::CompressionLayer, trace::TraceLayer}; - async fn handle(_: Request) -> &'static str { + async fn handle(_: Request) -> &'static str { "Hello, World!" } @@ -194,7 +197,7 @@ async fn middleware_on_single_route() { #[tokio::test] async fn service_in_bottom() { - async fn handler(_req: Request) -> Result, Infallible> { + async fn handler(_req: Request) -> Result, Infallible> { Ok(Response::new(hyper::Body::empty())) } @@ -264,7 +267,7 @@ async fn wrong_method_service() { #[tokio::test] async fn multiple_methods_for_one_handler() { - async fn root(_: Request) -> &'static str { + async fn root(_: Request) -> &'static str { "Hello, World!" } @@ -720,10 +723,10 @@ async fn limited_body_with_streaming_body() { #[allow(dead_code)] fn adding_middleware_dont_change_request_body_type() -> Router { Router::new() - .route("/", get(|_: BoxBody| async {})) + .route("/", get(|_: Body| async {})) .route("/", get(|_: String| async {})) .route("/", get(|_: Bytes| async {})) .route("/", get(|_: Json| async {})) - .route("/", get(|_: Request| async {})) + .route("/", get(|_: Request| async {})) .layer(tower_http::limit::RequestBodyLimitLayer::new(1024)) } diff --git a/axum/src/routing/tests/nest.rs b/axum/src/routing/tests/nest.rs index 9a151d1a2e..42367be520 100644 --- a/axum/src/routing/tests/nest.rs +++ b/axum/src/routing/tests/nest.rs @@ -144,7 +144,7 @@ async fn nested_url_extractor() { .route("/baz", get(|uri: Uri| async move { uri.to_string() })) .route( "/qux", - get(|req: Request| async move { req.uri().to_string() }), + get(|req: Request| async move { req.uri().to_string() }), ), ), ); @@ -188,7 +188,7 @@ async fn nested_service_sees_stripped_uri() { "/bar", Router::new().route( "/baz", - service_fn(|req: Request| async move { + service_fn(|req: Request| async move { let body = boxed(Body::from(req.uri().to_string())); Ok::<_, Infallible>(Response::new(body)) }),