mirror of
https://github.com/tokio-rs/axum.git
synced 2024-10-23 17:36:39 +02:00
Remove B
type param (#1751)
Co-authored-by: Jonas Platte <jplatte+git@posteo.de> Co-authored-by: Michael Scofield <mscofield0@tutanota.com>
This commit is contained in:
parent
9be0ea934c
commit
4e4c29175f
100 changed files with 966 additions and 1160 deletions
|
@ -1,15 +1,16 @@
|
|||
use crate::body::Body;
|
||||
use crate::extract::{DefaultBodyLimitKind, FromRequest, FromRequestParts};
|
||||
use futures_util::future::BoxFuture;
|
||||
use http::Request;
|
||||
use http_body::Limited;
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed<B> {}
|
||||
impl<B> Sealed<B> for http::Request<B> {}
|
||||
pub trait Sealed {}
|
||||
impl Sealed for http::Request<crate::body::Body> {}
|
||||
}
|
||||
|
||||
/// Extension trait that adds additional methods to [`Request`].
|
||||
pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
||||
pub trait RequestExt: sealed::Sealed + Sized {
|
||||
/// Apply an extractor to this `Request`.
|
||||
///
|
||||
/// This is just a convenience for `E::from_request(req, &())`.
|
||||
|
@ -23,6 +24,7 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// extract::FromRequest,
|
||||
/// body::Body,
|
||||
/// http::{header::CONTENT_TYPE, Request, StatusCode},
|
||||
/// response::{IntoResponse, Response},
|
||||
/// Form, Json, RequestExt,
|
||||
|
@ -31,17 +33,16 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// struct FormOrJson<T>(T);
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B, T> FromRequest<S, B> for FormOrJson<T>
|
||||
/// impl<S, T> FromRequest<S> for FormOrJson<T>
|
||||
/// where
|
||||
/// Json<T>: FromRequest<(), B>,
|
||||
/// Form<T>: FromRequest<(), B>,
|
||||
/// Json<T>: FromRequest<()>,
|
||||
/// Form<T>: FromRequest<()>,
|
||||
/// T: 'static,
|
||||
/// B: Send + 'static,
|
||||
/// S: Send + Sync,
|
||||
/// {
|
||||
/// type Rejection = Response;
|
||||
///
|
||||
/// async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// let content_type = req
|
||||
/// .headers()
|
||||
/// .get(CONTENT_TYPE)
|
||||
|
@ -70,7 +71,7 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// ```
|
||||
fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
|
||||
where
|
||||
E: FromRequest<(), B, M> + 'static,
|
||||
E: FromRequest<(), M> + 'static,
|
||||
M: 'static;
|
||||
|
||||
/// Apply an extractor that requires some state to this `Request`.
|
||||
|
@ -85,6 +86,7 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// ```
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// body::Body,
|
||||
/// extract::{FromRef, FromRequest},
|
||||
/// http::Request,
|
||||
/// RequestExt,
|
||||
|
@ -95,15 +97,14 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B> FromRequest<S, B> for MyExtractor
|
||||
/// impl<S> FromRequest<S> for MyExtractor
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
/// S: Send + Sync,
|
||||
/// B: Send + 'static,
|
||||
/// {
|
||||
/// type Rejection = std::convert::Infallible;
|
||||
///
|
||||
/// async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// let requires_state = req.extract_with_state::<RequiresState, _, _>(state).await?;
|
||||
///
|
||||
/// Ok(Self { requires_state })
|
||||
|
@ -114,22 +115,21 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// struct RequiresState { /* ... */ }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B> FromRequest<S, B> for RequiresState
|
||||
/// impl<S> FromRequest<S> for RequiresState
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
/// S: Send + Sync,
|
||||
/// B: Send + 'static,
|
||||
/// {
|
||||
/// // ...
|
||||
/// # type Rejection = std::convert::Infallible;
|
||||
/// # async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// # async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// # todo!()
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
where
|
||||
E: FromRequest<S, B, M> + 'static,
|
||||
E: FromRequest<S, M> + 'static,
|
||||
S: Send + Sync;
|
||||
|
||||
/// Apply a parts extractor to this `Request`.
|
||||
|
@ -145,6 +145,7 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// headers::{authorization::Bearer, Authorization},
|
||||
/// http::Request,
|
||||
/// response::{IntoResponse, Response},
|
||||
/// body::Body,
|
||||
/// Json, RequestExt, TypedHeader,
|
||||
/// };
|
||||
///
|
||||
|
@ -154,16 +155,15 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B, T> FromRequest<S, B> for MyExtractor<T>
|
||||
/// impl<S, T> FromRequest<S> for MyExtractor<T>
|
||||
/// where
|
||||
/// B: Send + 'static,
|
||||
/// S: Send + Sync,
|
||||
/// Json<T>: FromRequest<(), B>,
|
||||
/// Json<T>: FromRequest<()>,
|
||||
/// T: 'static,
|
||||
/// {
|
||||
/// type Rejection = Response;
|
||||
///
|
||||
/// async fn from_request(mut req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// async fn from_request(mut req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// let TypedHeader(auth_header) = req
|
||||
/// .extract_parts::<TypedHeader<Authorization<Bearer>>>()
|
||||
/// .await
|
||||
|
@ -197,6 +197,7 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// extract::{FromRef, FromRequest, FromRequestParts},
|
||||
/// http::{request::Parts, Request},
|
||||
/// response::{IntoResponse, Response},
|
||||
/// body::Body,
|
||||
/// Json, RequestExt,
|
||||
/// };
|
||||
///
|
||||
|
@ -206,17 +207,16 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// }
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B, T> FromRequest<S, B> for MyExtractor<T>
|
||||
/// impl<S, T> FromRequest<S> for MyExtractor<T>
|
||||
/// where
|
||||
/// String: FromRef<S>,
|
||||
/// Json<T>: FromRequest<(), B>,
|
||||
/// Json<T>: FromRequest<()>,
|
||||
/// T: 'static,
|
||||
/// S: Send + Sync,
|
||||
/// B: Send + 'static,
|
||||
/// {
|
||||
/// type Rejection = Response;
|
||||
///
|
||||
/// async fn from_request(mut req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// async fn from_request(mut req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// let requires_state = req
|
||||
/// .extract_parts_with_state::<RequiresState, _>(state)
|
||||
/// .await
|
||||
|
@ -260,21 +260,18 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized {
|
|||
/// Apply the [default body limit](crate::extract::DefaultBodyLimit).
|
||||
///
|
||||
/// If it is disabled, return the request as-is in `Err`.
|
||||
fn with_limited_body(self) -> Result<Request<Limited<B>>, Request<B>>;
|
||||
fn with_limited_body(self) -> Result<Request<Limited<Body>>, Request<Body>>;
|
||||
|
||||
/// Consumes the request, returning the body wrapped in [`Limited`] if a
|
||||
/// [default limit](crate::extract::DefaultBodyLimit) is in place, or not wrapped if the
|
||||
/// default limit is disabled.
|
||||
fn into_limited_body(self) -> Result<Limited<B>, B>;
|
||||
fn into_limited_body(self) -> Result<Limited<Body>, Body>;
|
||||
}
|
||||
|
||||
impl<B> RequestExt<B> for Request<B>
|
||||
where
|
||||
B: Send + 'static,
|
||||
{
|
||||
impl RequestExt for Request<Body> {
|
||||
fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>>
|
||||
where
|
||||
E: FromRequest<(), B, M> + 'static,
|
||||
E: FromRequest<(), M> + 'static,
|
||||
M: 'static,
|
||||
{
|
||||
self.extract_with_state(&())
|
||||
|
@ -282,7 +279,7 @@ where
|
|||
|
||||
fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>>
|
||||
where
|
||||
E: FromRequest<S, B, M> + 'static,
|
||||
E: FromRequest<S, M> + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
E::from_request(self, state)
|
||||
|
@ -324,7 +321,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn with_limited_body(self) -> Result<Request<Limited<B>>, Request<B>> {
|
||||
fn with_limited_body(self) -> Result<Request<Limited<Body>>, Request<Body>> {
|
||||
// update docs in `axum-core/src/extract/default_body_limit.rs` and
|
||||
// `axum/src/docs/extract.md` if this changes
|
||||
const DEFAULT_LIMIT: usize = 2_097_152; // 2 mb
|
||||
|
@ -338,7 +335,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn into_limited_body(self) -> Result<Limited<B>, B> {
|
||||
fn into_limited_body(self) -> Result<Limited<Body>, Body> {
|
||||
self.with_limited_body()
|
||||
.map(Request::into_body)
|
||||
.map_err(Request::into_body)
|
||||
|
@ -354,11 +351,10 @@ mod tests {
|
|||
};
|
||||
use async_trait::async_trait;
|
||||
use http::Method;
|
||||
use hyper::Body;
|
||||
|
||||
#[tokio::test]
|
||||
async fn extract_without_state() {
|
||||
let req = Request::new(());
|
||||
let req = Request::new(Body::empty());
|
||||
|
||||
let method: Method = req.extract().await.unwrap();
|
||||
|
||||
|
@ -376,7 +372,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn extract_with_state() {
|
||||
let req = Request::new(());
|
||||
let req = Request::new(Body::empty());
|
||||
|
||||
let state = "state".to_owned();
|
||||
|
||||
|
@ -387,7 +383,10 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn extract_parts_without_state() {
|
||||
let mut req = Request::builder().header("x-foo", "foo").body(()).unwrap();
|
||||
let mut req = Request::builder()
|
||||
.header("x-foo", "foo")
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
|
||||
let method: Method = req.extract_parts().await.unwrap();
|
||||
|
||||
|
@ -397,7 +396,10 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn extract_parts_with_state() {
|
||||
let mut req = Request::builder().header("x-foo", "foo").body(()).unwrap();
|
||||
let mut req = Request::builder()
|
||||
.header("x-foo", "foo")
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
|
||||
let state = "state".to_owned();
|
||||
|
||||
|
@ -417,15 +419,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for WorksForCustomExtractor
|
||||
impl<S> FromRequest<S> for WorksForCustomExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
B: Send + 'static,
|
||||
String: FromRef<S> + FromRequest<(), B>,
|
||||
String: FromRef<S> + FromRequest<()>,
|
||||
{
|
||||
type Rejection = <String as FromRequest<(), B>>::Rejection;
|
||||
type Rejection = <String as FromRequest<()>>::Rejection;
|
||||
|
||||
async fn from_request(mut req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(mut req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let RequiresState(from_state) = req.extract_parts_with_state(state).await.unwrap();
|
||||
let method = req.extract_parts().await.unwrap();
|
||||
let body = req.extract().await?;
|
||||
|
|
|
@ -41,7 +41,7 @@ use tower_layer::Layer;
|
|||
/// post(|request: Request<Body>| async {}),
|
||||
/// )
|
||||
/// .layer(DefaultBodyLimit::max(1024));
|
||||
/// # let _: Router<(), _> = app;
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
|
@ -54,10 +54,10 @@ use tower_layer::Layer;
|
|||
/// "/",
|
||||
/// // `RequestBodyLimitLayer` changes the request body type to `Limited<Body>`
|
||||
/// // extracting a different body type wont work
|
||||
/// post(|request: Request<Limited<Body>>| async {}),
|
||||
/// post(|request: Request<Body>| async {}),
|
||||
/// )
|
||||
/// .layer(RequestBodyLimitLayer::new(1024));
|
||||
/// # let _: Router<(), _> = app;
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
///
|
||||
/// In general using `DefaultBodyLimit` is recommended but if you need to use third party
|
||||
|
@ -105,7 +105,7 @@ impl DefaultBodyLimit {
|
|||
/// use tower_http::limit::RequestBodyLimitLayer;
|
||||
/// use http_body::Limited;
|
||||
///
|
||||
/// let app: Router<(), Limited<Body>> = Router::new()
|
||||
/// let app: Router<()> = Router::new()
|
||||
/// .route("/", get(|body: Bytes| async {}))
|
||||
/// // Disable the default limit
|
||||
/// .layer(DefaultBodyLimit::disable())
|
||||
|
@ -140,7 +140,7 @@ impl DefaultBodyLimit {
|
|||
/// use tower_http::limit::RequestBodyLimitLayer;
|
||||
/// use http_body::Limited;
|
||||
///
|
||||
/// let app: Router<(), Limited<Body>> = Router::new()
|
||||
/// let app: Router<()> = Router::new()
|
||||
/// .route("/", get(|body: Bytes| async {}))
|
||||
/// // Replace the default of 2MB with 1024 bytes.
|
||||
/// .layer(DefaultBodyLimit::max(1024));
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//!
|
||||
//! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html
|
||||
|
||||
use crate::response::IntoResponse;
|
||||
use crate::{body::Body, response::IntoResponse};
|
||||
use async_trait::async_trait;
|
||||
use http::{request::Parts, Request};
|
||||
use std::convert::Infallible;
|
||||
|
@ -64,48 +64,6 @@ pub trait FromRequestParts<S>: Sized {
|
|||
///
|
||||
/// See [`axum::extract`] for more general docs about extractors.
|
||||
///
|
||||
/// # What is the `B` type parameter?
|
||||
///
|
||||
/// `FromRequest` is generic over the request body (the `B` in
|
||||
/// [`http::Request<B>`]). This is to allow `FromRequest` to be usable with any
|
||||
/// type of request body. This is necessary because some middleware change the
|
||||
/// request body, for example to add timeouts.
|
||||
///
|
||||
/// If you're writing your own `FromRequest` that wont be used outside your
|
||||
/// application, and not using any middleware that changes the request body, you
|
||||
/// can most likely use `axum::body::Body`.
|
||||
///
|
||||
/// If you're writing a library that's intended for others to use, it's recommended
|
||||
/// to keep the generic type parameter:
|
||||
///
|
||||
/// ```rust
|
||||
/// use axum::{
|
||||
/// async_trait,
|
||||
/// extract::FromRequest,
|
||||
/// http::{self, Request},
|
||||
/// };
|
||||
///
|
||||
/// struct MyExtractor;
|
||||
///
|
||||
/// #[async_trait]
|
||||
/// impl<S, B> FromRequest<S, B> for MyExtractor
|
||||
/// where
|
||||
/// // these bounds are required by `async_trait`
|
||||
/// B: Send + 'static,
|
||||
/// S: Send + Sync,
|
||||
/// {
|
||||
/// type Rejection = http::StatusCode;
|
||||
///
|
||||
/// async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
/// // ...
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This ensures your extractor is as flexible as possible.
|
||||
///
|
||||
/// [`http::Request<B>`]: http::Request
|
||||
/// [`axum::extract`]: https://docs.rs/axum/0.6.0/axum/extract/index.html
|
||||
#[async_trait]
|
||||
#[cfg_attr(
|
||||
|
@ -114,25 +72,24 @@ pub trait FromRequestParts<S>: Sized {
|
|||
note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details",
|
||||
)
|
||||
)]
|
||||
pub trait FromRequest<S, B, M = private::ViaRequest>: Sized {
|
||||
pub trait FromRequest<S, M = private::ViaRequest>: Sized {
|
||||
/// If the extractor fails it'll use this "rejection" type. A rejection is
|
||||
/// a kind of error that can be converted into a response.
|
||||
type Rejection: IntoResponse;
|
||||
|
||||
/// Perform the extraction.
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>;
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B, private::ViaParts> for T
|
||||
impl<S, T> FromRequest<S, private::ViaParts> for T
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
T: FromRequestParts<S>,
|
||||
{
|
||||
type Rejection = <Self as FromRequestParts<S>>::Rejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let (mut parts, _) = req.into_parts();
|
||||
Self::from_request_parts(&mut parts, state).await
|
||||
}
|
||||
|
@ -155,15 +112,14 @@ where
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T, B> FromRequest<S, B> for Option<T>
|
||||
impl<S, T> FromRequest<S> for Option<T>
|
||||
where
|
||||
T: FromRequest<S, B>,
|
||||
B: Send + 'static,
|
||||
T: FromRequest<S>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Option<T>, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Option<T>, Self::Rejection> {
|
||||
Ok(T::from_request(req, state).await.ok())
|
||||
}
|
||||
}
|
||||
|
@ -182,15 +138,14 @@ where
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, T, B> FromRequest<S, B> for Result<T, T::Rejection>
|
||||
impl<S, T> FromRequest<S> for Result<T, T::Rejection>
|
||||
where
|
||||
T: FromRequest<S, B>,
|
||||
B: Send + 'static,
|
||||
T: FromRequest<S>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
Ok(T::from_request(req, state).await)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use crate::__composite_rejection as composite_rejection;
|
||||
use crate::__define_rejection as define_rejection;
|
||||
|
||||
use crate::BoxError;
|
||||
use crate::{BoxError, Error};
|
||||
|
||||
composite_rejection! {
|
||||
/// Rejection type for extractors that buffer the request body. Used if the
|
||||
|
@ -19,7 +19,11 @@ impl FailedToBufferBody {
|
|||
where
|
||||
E: Into<BoxError>,
|
||||
{
|
||||
match err.into().downcast::<http_body::LengthLimitError>() {
|
||||
let box_error = match err.into().downcast::<Error>() {
|
||||
Ok(err) => err.into_inner(),
|
||||
Err(err) => err,
|
||||
};
|
||||
match box_error.downcast::<http_body::LengthLimitError>() {
|
||||
Ok(err) => Self::LengthLimitError(LengthLimitError::from_err(err)),
|
||||
Err(err) => Self::UnknownBodyError(UnknownBodyError::from_err(err)),
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
use super::{rejection::*, FromRequest, FromRequestParts};
|
||||
use crate::{BoxError, RequestExt};
|
||||
use crate::{body::Body, RequestExt};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use http::{request::Parts, HeaderMap, Method, Request, Uri, Version};
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Request<B>
|
||||
impl<S> FromRequest<S> for Request<Body>
|
||||
where
|
||||
B: Send,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
Ok(req)
|
||||
}
|
||||
}
|
||||
|
@ -72,16 +71,13 @@ where
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Bytes
|
||||
impl<S> FromRequest<S> for Bytes
|
||||
where
|
||||
B: http_body::Body + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = BytesRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
let bytes = match req.into_limited_body() {
|
||||
Ok(limited_body) => crate::body::to_bytes(limited_body)
|
||||
.await
|
||||
|
@ -96,16 +92,13 @@ where
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for String
|
||||
impl<S> FromRequest<S> for String
|
||||
where
|
||||
B: http_body::Body + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = StringRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let bytes = Bytes::from_request(req, state)
|
||||
.await
|
||||
.map_err(|err| match err {
|
||||
|
@ -123,14 +116,13 @@ where
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Parts
|
||||
impl<S> FromRequest<S> for Parts
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _: &S) -> Result<Self, Self::Rejection> {
|
||||
Ok(req.into_parts().0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::{FromRequest, FromRequestParts};
|
||||
use crate::body::Body;
|
||||
use crate::response::{IntoResponse, Response};
|
||||
use async_trait::async_trait;
|
||||
use http::request::{Parts, Request};
|
||||
|
@ -45,19 +46,18 @@ macro_rules! impl_from_request {
|
|||
}
|
||||
|
||||
// This impl must not be generic over M, otherwise it would conflict with the blanket
|
||||
// implementation of `FromRequest<S, B, Mut>` for `T: FromRequestParts<S>`.
|
||||
// implementation of `FromRequest<S, Mut>` for `T: FromRequestParts<S>`.
|
||||
#[async_trait]
|
||||
#[allow(non_snake_case, unused_mut, unused_variables)]
|
||||
impl<S, B, $($ty,)* $last> FromRequest<S, B> for ($($ty,)* $last,)
|
||||
impl<S, $($ty,)* $last> FromRequest<S> for ($($ty,)* $last,)
|
||||
where
|
||||
$( $ty: FromRequestParts<S> + Send, )*
|
||||
$last: FromRequest<S, B> + Send,
|
||||
B: Send + 'static,
|
||||
$last: FromRequest<S> + Send,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let (mut parts, body) = req.into_parts();
|
||||
|
||||
$(
|
||||
|
@ -85,7 +85,7 @@ mod tests {
|
|||
|
||||
fn assert_from_request<M, T>()
|
||||
where
|
||||
T: FromRequest<(), http_body::Full<Bytes>, M>,
|
||||
T: FromRequest<(), M>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -119,9 +119,7 @@ use std::{
|
|||
///
|
||||
/// // `MyBody` can now be returned from handlers.
|
||||
/// let app = Router::new().route("/", get(|| async { MyBody }));
|
||||
/// # async {
|
||||
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
pub trait IntoResponse {
|
||||
/// Create a response.
|
||||
|
|
|
@ -255,7 +255,7 @@ mod tests {
|
|||
custom_key: CustomKey(Key::generate()),
|
||||
};
|
||||
|
||||
let app = Router::<_, Body>::new()
|
||||
let app = Router::new()
|
||||
.route("/set", get(set_cookie))
|
||||
.route("/get", get(get_cookie))
|
||||
.route("/remove", get(remove_cookie))
|
||||
|
@ -352,7 +352,7 @@ mod tests {
|
|||
custom_key: CustomKey(Key::generate()),
|
||||
};
|
||||
|
||||
let app = Router::<_, Body>::new()
|
||||
let app = Router::new()
|
||||
.route("/get", get(get_cookie))
|
||||
.with_state(state);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use axum::{
|
||||
async_trait,
|
||||
body::HttpBody,
|
||||
body::Body,
|
||||
extract::{rejection::RawFormRejection, FromRequest, RawForm},
|
||||
response::{IntoResponse, Response},
|
||||
BoxError, Error, RequestExt,
|
||||
Error, RequestExt,
|
||||
};
|
||||
use http::{Request, StatusCode};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
@ -46,17 +46,14 @@ pub struct Form<T>(pub T);
|
|||
axum_core::__impl_deref!(Form);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for Form<T>
|
||||
impl<T, S> FromRequest<S> for Form<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = FormRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let RawForm(bytes) = req
|
||||
.extract()
|
||||
.await
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{Bytes, HttpBody},
|
||||
extract::{BodyStream, FromRequest},
|
||||
body::{Body, Bytes},
|
||||
extract::FromRequest,
|
||||
response::{IntoResponse, Response},
|
||||
BoxError, RequestExt,
|
||||
};
|
||||
|
@ -91,22 +91,18 @@ pub struct Multipart {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Multipart
|
||||
impl<S> FromRequest<S> for Multipart
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Into<Bytes>,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = MultipartRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let boundary = parse_boundary(req.headers()).ok_or(InvalidBoundary)?;
|
||||
let stream_result = match req.with_limited_body() {
|
||||
Ok(limited) => BodyStream::from_request(limited, state).await,
|
||||
Err(unlimited) => BodyStream::from_request(unlimited, state).await,
|
||||
let stream = match req.with_limited_body() {
|
||||
Ok(limited) => Body::new(limited),
|
||||
Err(unlimited) => unlimited.into_body(),
|
||||
};
|
||||
let stream = stream_result.unwrap_or_else(|err| match err {});
|
||||
let multipart = multer::Multipart::new(stream, boundary);
|
||||
Ok(Self { inner: multipart })
|
||||
}
|
||||
|
@ -452,7 +448,7 @@ mod tests {
|
|||
// No need for this to be a #[test], we just want to make sure it compiles
|
||||
fn _multipart_from_request_limited() {
|
||||
async fn handler(_: Multipart) {}
|
||||
let _app: Router<(), http_body::Limited<Body>> = Router::new().route("/", post(handler));
|
||||
let _app: Router<()> = Router::new().route("/", post(handler));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use axum::async_trait;
|
||||
use axum::body::Body;
|
||||
use axum::extract::{FromRequest, FromRequestParts};
|
||||
use axum::response::IntoResponse;
|
||||
use http::request::Parts;
|
||||
|
@ -109,16 +110,15 @@ impl<E, R> DerefMut for WithRejection<E, R> {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B, E, R, S> FromRequest<S, B> for WithRejection<E, R>
|
||||
impl<E, R, S> FromRequest<S> for WithRejection<E, R>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
E: FromRequest<S, B>,
|
||||
E: FromRequest<S>,
|
||||
R: From<E::Rejection> + IntoResponse,
|
||||
{
|
||||
type Rejection = R;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let extractor = E::from_request(req, state).await?;
|
||||
Ok(WithRejection(extractor, PhantomData))
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let req = Request::new(());
|
||||
let req = Request::new(Body::empty());
|
||||
let result = WithRejection::<TestExtractor, TestRejection>::from_request(req, &()).await;
|
||||
assert!(matches!(result, Err(TestRejection)));
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Additional handler utilities.
|
||||
|
||||
use axum::body::Body;
|
||||
use axum::{
|
||||
extract::FromRequest,
|
||||
handler::Handler,
|
||||
|
@ -19,15 +20,15 @@ pub use self::or::Or;
|
|||
///
|
||||
/// The drawbacks of this trait is that you cannot apply middleware to individual handlers like you
|
||||
/// can with [`Handler::layer`].
|
||||
pub trait HandlerCallWithExtractors<T, S, B>: Sized {
|
||||
pub trait HandlerCallWithExtractors<T, S>: Sized {
|
||||
/// The type of future calling this handler returns.
|
||||
type Future: Future<Output = Response> + Send + 'static;
|
||||
|
||||
/// Call the handler with the extracted inputs.
|
||||
fn call(self, extractors: T, state: S) -> <Self as HandlerCallWithExtractors<T, S, B>>::Future;
|
||||
fn call(self, extractors: T, state: S) -> <Self as HandlerCallWithExtractors<T, S>>::Future;
|
||||
|
||||
/// Conver this `HandlerCallWithExtractors` into [`Handler`].
|
||||
fn into_handler(self) -> IntoHandler<Self, T, S, B> {
|
||||
fn into_handler(self) -> IntoHandler<Self, T, S> {
|
||||
IntoHandler {
|
||||
handler: self,
|
||||
_marker: PhantomData,
|
||||
|
@ -102,9 +103,9 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized {
|
|||
/// );
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
fn or<R, Rt>(self, rhs: R) -> Or<Self, R, T, Rt, S, B>
|
||||
fn or<R, Rt>(self, rhs: R) -> Or<Self, R, T, Rt, S>
|
||||
where
|
||||
R: HandlerCallWithExtractors<Rt, S, B>,
|
||||
R: HandlerCallWithExtractors<Rt, S>,
|
||||
{
|
||||
Or {
|
||||
lhs: self,
|
||||
|
@ -117,7 +118,7 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized {
|
|||
macro_rules! impl_handler_call_with {
|
||||
( $($ty:ident),* $(,)? ) => {
|
||||
#[allow(non_snake_case)]
|
||||
impl<F, Fut, S, B, $($ty,)*> HandlerCallWithExtractors<($($ty,)*), S, B> for F
|
||||
impl<F, Fut, S, $($ty,)*> HandlerCallWithExtractors<($($ty,)*), S> for F
|
||||
where
|
||||
F: FnOnce($($ty,)*) -> Fut,
|
||||
Fut: Future + Send + 'static,
|
||||
|
@ -130,7 +131,7 @@ macro_rules! impl_handler_call_with {
|
|||
self,
|
||||
($($ty,)*): ($($ty,)*),
|
||||
_state: S,
|
||||
) -> <Self as HandlerCallWithExtractors<($($ty,)*), S, B>>::Future {
|
||||
) -> <Self as HandlerCallWithExtractors<($($ty,)*), S>>::Future {
|
||||
self($($ty,)*).map(IntoResponse::into_response)
|
||||
}
|
||||
}
|
||||
|
@ -159,22 +160,22 @@ impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
|
|||
///
|
||||
/// Created with [`HandlerCallWithExtractors::into_handler`].
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct IntoHandler<H, T, S, B> {
|
||||
pub struct IntoHandler<H, T, S> {
|
||||
handler: H,
|
||||
_marker: PhantomData<fn() -> (T, S, B)>,
|
||||
_marker: PhantomData<fn() -> (T, S)>,
|
||||
}
|
||||
|
||||
impl<H, T, S, B> Handler<T, S, B> for IntoHandler<H, T, S, B>
|
||||
impl<H, T, S> Handler<T, S> for IntoHandler<H, T, S>
|
||||
where
|
||||
H: HandlerCallWithExtractors<T, S, B> + Clone + Send + 'static,
|
||||
T: FromRequest<S, B> + Send + 'static,
|
||||
H: HandlerCallWithExtractors<T, S> + Clone + Send + 'static,
|
||||
T: FromRequest<S> + Send + 'static,
|
||||
T::Rejection: Send,
|
||||
B: Send + 'static,
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
type Future = BoxFuture<'static, Response>;
|
||||
|
||||
fn call(self, req: http::Request<B>, state: S) -> Self::Future {
|
||||
fn call(self, req: http::Request<Body>, state: S) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
Box::pin(async move {
|
||||
match T::from_request(req, &state).await {
|
||||
Ok(t) => self.handler.call(t, state).await,
|
||||
|
@ -184,9 +185,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, T, S, B> Copy for IntoHandler<H, T, S, B> where H: Copy {}
|
||||
impl<H, T, S> Copy for IntoHandler<H, T, S> where H: Copy {}
|
||||
|
||||
impl<H, T, S, B> Clone for IntoHandler<H, T, S, B>
|
||||
impl<H, T, S> Clone for IntoHandler<H, T, S>
|
||||
where
|
||||
H: Clone,
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::HandlerCallWithExtractors;
|
||||
use crate::either::Either;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::{FromRequest, FromRequestParts},
|
||||
handler::Handler,
|
||||
http::Request,
|
||||
|
@ -14,19 +15,18 @@ use std::{future::Future, marker::PhantomData};
|
|||
///
|
||||
/// Created with [`HandlerCallWithExtractors::or`](super::HandlerCallWithExtractors::or).
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Or<L, R, Lt, Rt, S, B> {
|
||||
pub struct Or<L, R, Lt, Rt, S> {
|
||||
pub(super) lhs: L,
|
||||
pub(super) rhs: R,
|
||||
pub(super) _marker: PhantomData<fn() -> (Lt, Rt, S, B)>,
|
||||
pub(super) _marker: PhantomData<fn() -> (Lt, Rt, S)>,
|
||||
}
|
||||
|
||||
impl<S, B, L, R, Lt, Rt> HandlerCallWithExtractors<Either<Lt, Rt>, S, B> for Or<L, R, Lt, Rt, S, B>
|
||||
impl<S, L, R, Lt, Rt> HandlerCallWithExtractors<Either<Lt, Rt>, S> for Or<L, R, Lt, Rt, S>
|
||||
where
|
||||
L: HandlerCallWithExtractors<Lt, S, B> + Send + 'static,
|
||||
R: HandlerCallWithExtractors<Rt, S, B> + Send + 'static,
|
||||
L: HandlerCallWithExtractors<Lt, S> + Send + 'static,
|
||||
R: HandlerCallWithExtractors<Rt, S> + Send + 'static,
|
||||
Rt: Send + 'static,
|
||||
Lt: Send + 'static,
|
||||
B: Send + 'static,
|
||||
{
|
||||
// this puts `futures_util` in our public API but thats fine in axum-extra
|
||||
type Future = EitherFuture<
|
||||
|
@ -38,7 +38,7 @@ where
|
|||
self,
|
||||
extractors: Either<Lt, Rt>,
|
||||
state: S,
|
||||
) -> <Self as HandlerCallWithExtractors<Either<Lt, Rt>, S, B>>::Future {
|
||||
) -> <Self as HandlerCallWithExtractors<Either<Lt, Rt>, S>>::Future {
|
||||
match extractors {
|
||||
Either::E1(lt) => self
|
||||
.lhs
|
||||
|
@ -54,21 +54,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, L, R, Lt, Rt, M> Handler<(M, Lt, Rt), S, B> for Or<L, R, Lt, Rt, S, B>
|
||||
impl<S, L, R, Lt, Rt, M> Handler<(M, Lt, Rt), S> for Or<L, R, Lt, Rt, S>
|
||||
where
|
||||
L: HandlerCallWithExtractors<Lt, S, B> + Clone + Send + 'static,
|
||||
R: HandlerCallWithExtractors<Rt, S, B> + Clone + Send + 'static,
|
||||
L: HandlerCallWithExtractors<Lt, S> + Clone + Send + 'static,
|
||||
R: HandlerCallWithExtractors<Rt, S> + Clone + Send + 'static,
|
||||
Lt: FromRequestParts<S> + Send + 'static,
|
||||
Rt: FromRequest<S, B, M> + Send + 'static,
|
||||
Rt: FromRequest<S, M> + Send + 'static,
|
||||
Lt::Rejection: Send,
|
||||
Rt::Rejection: Send,
|
||||
B: Send + 'static,
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
// this puts `futures_util` in our public API but thats fine in axum-extra
|
||||
type Future = BoxFuture<'static, Response>;
|
||||
|
||||
fn call(self, req: Request<B>, state: S) -> Self::Future {
|
||||
fn call(self, req: Request<Body>, state: S) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
let (mut parts, body) = req.into_parts();
|
||||
|
||||
|
@ -86,14 +85,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<L, R, Lt, Rt, S, B> Copy for Or<L, R, Lt, Rt, S, B>
|
||||
impl<L, R, Lt, Rt, S> Copy for Or<L, R, Lt, Rt, S>
|
||||
where
|
||||
L: Copy,
|
||||
R: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
impl<L, R, Lt, Rt, S, B> Clone for Or<L, R, Lt, Rt, S, B>
|
||||
impl<L, R, Lt, Rt, S> Clone for Or<L, R, Lt, Rt, S>
|
||||
where
|
||||
L: Clone,
|
||||
R: Clone,
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{HttpBody, StreamBody},
|
||||
body::{Body, StreamBody},
|
||||
extract::FromRequest,
|
||||
response::{IntoResponse, Response},
|
||||
BoxError,
|
||||
};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures_util::stream::{BoxStream, Stream, TryStream, TryStreamExt};
|
||||
use http::Request;
|
||||
use pin_project_lite::pin_project;
|
||||
|
@ -101,26 +101,19 @@ impl<S> JsonLines<S, AsResponse> {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for JsonLines<T, AsExtractor>
|
||||
impl<S, T> FromRequest<S> for JsonLines<T, AsExtractor>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Into<Bytes>,
|
||||
B::Error: Into<BoxError>,
|
||||
T: DeserializeOwned,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
// `Stream::lines` isn't a thing so we have to convert it into an `AsyncRead`
|
||||
// so we can call `AsyncRead::lines` and then convert it back to a `Stream`
|
||||
let body = BodyStream {
|
||||
body: req.into_body(),
|
||||
};
|
||||
let body = req.into_body();
|
||||
|
||||
let stream = body
|
||||
.map_ok(Into::into)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err));
|
||||
let stream = TryStreamExt::map_err(body, |err| io::Error::new(io::ErrorKind::Other, err));
|
||||
let read = StreamReader::new(stream);
|
||||
let lines_stream = LinesStream::new(read.lines());
|
||||
|
||||
|
@ -140,26 +133,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// like `axum::extract::BodyStream` except it doesn't box the inner body
|
||||
// we don't need that since we box the final stream in `Inner::Extractor`
|
||||
pin_project! {
|
||||
struct BodyStream<B> {
|
||||
#[pin]
|
||||
body: B,
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Stream for BodyStream<B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
type Item = Result<B::Data, B::Error>;
|
||||
|
||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.project().body.poll_data(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for JsonLines<T, AsExtractor> {
|
||||
type Item = Result<T, axum::Error>;
|
||||
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{Bytes, HttpBody},
|
||||
body::Body,
|
||||
extract::{rejection::BytesRejection, FromRequest},
|
||||
response::{IntoResponse, Response},
|
||||
BoxError,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use http::{Request, StatusCode};
|
||||
use prost::Message;
|
||||
|
||||
|
@ -97,17 +96,14 @@ use prost::Message;
|
|||
pub struct Protobuf<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for Protobuf<T>
|
||||
impl<T, S> FromRequest<S> for Protobuf<T>
|
||||
where
|
||||
T: Message + Default,
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ProtobufRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let mut bytes = Bytes::from_request(req, state).await?;
|
||||
|
||||
match T::decode(&mut bytes) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Additional types for defining routes.
|
||||
|
||||
use axum::{
|
||||
body::Body,
|
||||
http::Request,
|
||||
response::{IntoResponse, Redirect, Response},
|
||||
routing::{any, MethodRouter},
|
||||
|
@ -26,7 +27,7 @@ pub use axum_macros::TypedPath;
|
|||
pub use self::typed::{SecondElementIs, TypedPath};
|
||||
|
||||
/// Extension trait that adds additional methods to [`Router`].
|
||||
pub trait RouterExt<S, B>: sealed::Sealed {
|
||||
pub trait RouterExt<S>: sealed::Sealed {
|
||||
/// Add a typed `GET` route to the router.
|
||||
///
|
||||
/// The path will be inferred from the first argument to the handler function which must
|
||||
|
@ -36,7 +37,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_get<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -49,7 +50,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_delete<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -62,7 +63,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_head<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -75,7 +76,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_options<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -88,7 +89,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_patch<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -101,7 +102,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_post<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -114,7 +115,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_put<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -127,7 +128,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_trace<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath;
|
||||
|
||||
|
@ -156,7 +157,7 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
/// .route_with_tsr("/bar/", get(|| async {}));
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
fn route_with_tsr(self, path: &str, method_router: MethodRouter<S, B>) -> Self
|
||||
fn route_with_tsr(self, path: &str, method_router: MethodRouter<S>) -> Self
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
|
@ -165,21 +166,20 @@ pub trait RouterExt<S, B>: sealed::Sealed {
|
|||
/// This works like [`RouterExt::route_with_tsr`] but accepts any [`Service`].
|
||||
fn route_service_with_tsr<T>(self, path: &str, service: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<S, B> RouterExt<S, B> for Router<S, B>
|
||||
impl<S> RouterExt<S> for Router<S>
|
||||
where
|
||||
B: axum::body::HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_get<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -189,7 +189,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_delete<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -199,7 +199,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_head<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_options<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -219,7 +219,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_patch<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -229,7 +229,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_post<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -239,7 +239,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_put<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -249,7 +249,7 @@ where
|
|||
#[cfg(feature = "typed-routing")]
|
||||
fn typed_trace<H, T, P>(self, handler: H) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, S, B>,
|
||||
H: axum::handler::Handler<T, S>,
|
||||
T: SecondElementIs<P> + 'static,
|
||||
P: TypedPath,
|
||||
{
|
||||
|
@ -257,7 +257,7 @@ where
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
fn route_with_tsr(mut self, path: &str, method_router: MethodRouter<S, B>) -> Self
|
||||
fn route_with_tsr(mut self, path: &str, method_router: MethodRouter<S>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ where
|
|||
#[track_caller]
|
||||
fn route_service_with_tsr<T>(mut self, path: &str, service: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
Self: Sized,
|
||||
|
@ -287,9 +287,8 @@ fn validate_tsr_path(path: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_tsr_redirect_route<S, B>(router: Router<S, B>, path: &str) -> Router<S, B>
|
||||
fn add_tsr_redirect_route<S>(router: Router<S>, path: &str) -> Router<S>
|
||||
where
|
||||
B: axum::body::HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
async fn redirect_handler(uri: Uri) -> Response {
|
||||
|
@ -337,7 +336,7 @@ where
|
|||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
impl<S, B> Sealed for axum::Router<S, B> {}
|
||||
impl<S> Sealed for axum::Router<S> {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use axum::{
|
||||
body::Body,
|
||||
handler::Handler,
|
||||
routing::{delete, get, on, post, MethodFilter, MethodRouter},
|
||||
Router,
|
||||
|
@ -34,14 +33,13 @@ use axum::{
|
|||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[must_use]
|
||||
pub struct Resource<S = (), B = Body> {
|
||||
pub struct Resource<S = ()> {
|
||||
pub(crate) name: String,
|
||||
pub(crate) router: Router<S, B>,
|
||||
pub(crate) router: Router<S>,
|
||||
}
|
||||
|
||||
impl<S, B> Resource<S, B>
|
||||
impl<S> Resource<S>
|
||||
where
|
||||
B: axum::body::HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
/// Create a `Resource` with the given name.
|
||||
|
@ -57,7 +55,7 @@ where
|
|||
/// Add a handler at `GET /{resource_name}`.
|
||||
pub fn index<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = self.index_create_path();
|
||||
|
@ -67,7 +65,7 @@ where
|
|||
/// Add a handler at `POST /{resource_name}`.
|
||||
pub fn create<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = self.index_create_path();
|
||||
|
@ -77,7 +75,7 @@ where
|
|||
/// Add a handler at `GET /{resource_name}/new`.
|
||||
pub fn new<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = format!("/{}/new", self.name);
|
||||
|
@ -87,7 +85,7 @@ where
|
|||
/// Add a handler at `GET /{resource_name}/:{resource_name}_id`.
|
||||
pub fn show<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = self.show_update_destroy_path();
|
||||
|
@ -97,7 +95,7 @@ where
|
|||
/// Add a handler at `GET /{resource_name}/:{resource_name}_id/edit`.
|
||||
pub fn edit<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = format!("/{0}/:{0}_id/edit", self.name);
|
||||
|
@ -107,7 +105,7 @@ where
|
|||
/// Add a handler at `PUT or PATCH /resource_name/:{resource_name}_id`.
|
||||
pub fn update<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = self.show_update_destroy_path();
|
||||
|
@ -117,7 +115,7 @@ where
|
|||
/// Add a handler at `DELETE /{resource_name}/:{resource_name}_id`.
|
||||
pub fn destroy<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let path = self.show_update_destroy_path();
|
||||
|
@ -132,14 +130,14 @@ where
|
|||
format!("/{0}/:{0}_id", self.name)
|
||||
}
|
||||
|
||||
fn route(mut self, path: &str, method_router: MethodRouter<S, B>) -> Self {
|
||||
fn route(mut self, path: &str, method_router: MethodRouter<S>) -> Self {
|
||||
self.router = self.router.route(path, method_router);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> From<Resource<S, B>> for Router<S, B> {
|
||||
fn from(resource: Resource<S, B>) -> Self {
|
||||
impl<S> From<Resource<S>> for Router<S> {
|
||||
fn from(resource: Resource<S>) -> Self {
|
||||
resource.router
|
||||
}
|
||||
}
|
||||
|
@ -148,9 +146,9 @@ impl<S, B> From<Resource<S, B>> for Router<S, B> {
|
|||
mod tests {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
use axum::{extract::Path, http::Method, Router};
|
||||
use axum::{body::Body, extract::Path, http::Method, Router};
|
||||
use http::Request;
|
||||
use tower::{Service, ServiceExt};
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[tokio::test]
|
||||
async fn works() {
|
||||
|
@ -208,10 +206,8 @@ mod tests {
|
|||
|
||||
async fn call_route(app: &mut Router, method: Method, uri: &str) -> String {
|
||||
let res = app
|
||||
.ready()
|
||||
.await
|
||||
.unwrap()
|
||||
.call(
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(method)
|
||||
.uri(uri)
|
||||
|
|
|
@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
# Unreleased
|
||||
|
||||
- None.
|
||||
- **breaking:** `#[debug_handler]` no longer accepts a `body = _` argument. The
|
||||
body type is always `axum::body::Body` ([#1751])
|
||||
|
||||
[#1751]: https://github.com/tokio-rs/axum/pull/1751
|
||||
|
||||
# 0.3.7 (22. March, 2023)
|
||||
|
||||
|
|
|
@ -6,14 +6,10 @@ use crate::{
|
|||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use syn::{parse::Parse, parse_quote, spanned::Spanned, FnArg, ItemFn, Token, Type};
|
||||
use syn::{parse::Parse, spanned::Spanned, FnArg, ItemFn, Token, Type};
|
||||
|
||||
pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream {
|
||||
let Attrs { body_ty, state_ty } = attr;
|
||||
|
||||
let body_ty = body_ty
|
||||
.map(second)
|
||||
.unwrap_or_else(|| parse_quote!(axum::body::Body));
|
||||
let Attrs { state_ty } = attr;
|
||||
|
||||
let mut state_ty = state_ty.map(second);
|
||||
|
||||
|
@ -57,7 +53,7 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> TokenStream {
|
|||
}
|
||||
} else {
|
||||
let check_inputs_impls_from_request =
|
||||
check_inputs_impls_from_request(&item_fn, &body_ty, state_ty);
|
||||
check_inputs_impls_from_request(&item_fn, state_ty);
|
||||
|
||||
quote! {
|
||||
#check_inputs_impls_from_request
|
||||
|
@ -88,20 +84,16 @@ mod kw {
|
|||
}
|
||||
|
||||
pub(crate) struct Attrs {
|
||||
body_ty: Option<(kw::body, Type)>,
|
||||
state_ty: Option<(kw::state, Type)>,
|
||||
}
|
||||
|
||||
impl Parse for Attrs {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut body_ty = None;
|
||||
let mut state_ty = None;
|
||||
|
||||
while !input.is_empty() {
|
||||
let lh = input.lookahead1();
|
||||
if lh.peek(kw::body) {
|
||||
parse_assignment_attribute(input, &mut body_ty)?;
|
||||
} else if lh.peek(kw::state) {
|
||||
if lh.peek(kw::state) {
|
||||
parse_assignment_attribute(input, &mut state_ty)?;
|
||||
} else {
|
||||
return Err(lh.error());
|
||||
|
@ -110,7 +102,7 @@ impl Parse for Attrs {
|
|||
let _ = input.parse::<Token![,]>();
|
||||
}
|
||||
|
||||
Ok(Self { body_ty, state_ty })
|
||||
Ok(Self { state_ty })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,11 +175,7 @@ fn is_self_pat_type(typed: &syn::PatType) -> bool {
|
|||
ident == "self"
|
||||
}
|
||||
|
||||
fn check_inputs_impls_from_request(
|
||||
item_fn: &ItemFn,
|
||||
body_ty: &Type,
|
||||
state_ty: Type,
|
||||
) -> TokenStream {
|
||||
fn check_inputs_impls_from_request(item_fn: &ItemFn, state_ty: Type) -> TokenStream {
|
||||
let takes_self = item_fn.sig.inputs.first().map_or(false, |arg| match arg {
|
||||
FnArg::Receiver(_) => true,
|
||||
FnArg::Typed(typed) => is_self_pat_type(typed),
|
||||
|
@ -266,11 +254,11 @@ fn check_inputs_impls_from_request(
|
|||
}
|
||||
} else if consumes_request {
|
||||
quote_spanned! {span=>
|
||||
#ty: ::axum::extract::FromRequest<#state_ty, #body_ty> + Send
|
||||
#ty: ::axum::extract::FromRequest<#state_ty> + Send
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
#ty: ::axum::extract::FromRequest<#state_ty, #body_ty, M> + Send
|
||||
#ty: ::axum::extract::FromRequest<#state_ty, M> + Send
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -379,7 +367,6 @@ fn request_consuming_type_name(ty: &Type) -> Option<&'static str> {
|
|||
|
||||
let type_name = match &*ident.to_string() {
|
||||
"Json" => "Json<_>",
|
||||
"BodyStream" => "BodyStream",
|
||||
"RawBody" => "RawBody<_>",
|
||||
"RawForm" => "RawForm",
|
||||
"Multipart" => "Multipart",
|
||||
|
|
|
@ -19,13 +19,6 @@ pub(crate) enum Trait {
|
|||
}
|
||||
|
||||
impl Trait {
|
||||
fn body_type(&self) -> impl Iterator<Item = Type> {
|
||||
match self {
|
||||
Trait::FromRequest => Some(parse_quote!(B)).into_iter(),
|
||||
Trait::FromRequestParts => None.into_iter(),
|
||||
}
|
||||
}
|
||||
|
||||
fn via_marker_type(&self) -> Option<Type> {
|
||||
match self {
|
||||
Trait::FromRequest => Some(parse_quote!(M)),
|
||||
|
@ -370,14 +363,12 @@ fn impl_struct_by_extracting_each_field(
|
|||
quote!(::axum::response::Response)
|
||||
};
|
||||
|
||||
let impl_generics = tr
|
||||
.body_type()
|
||||
.chain(state.impl_generics())
|
||||
let impl_generics = state
|
||||
.impl_generics()
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
let trait_generics = state
|
||||
.trait_generics()
|
||||
.chain(tr.body_type())
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
let state_bounds = state.bounds();
|
||||
|
@ -388,15 +379,12 @@ fn impl_struct_by_extracting_each_field(
|
|||
#[automatically_derived]
|
||||
impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident
|
||||
where
|
||||
B: ::axum::body::HttpBody + ::std::marker::Send + 'static,
|
||||
B::Data: ::std::marker::Send,
|
||||
B::Error: ::std::convert::Into<::axum::BoxError>,
|
||||
#state_bounds
|
||||
{
|
||||
type Rejection = #rejection_ident;
|
||||
|
||||
async fn from_request(
|
||||
mut req: ::axum::http::Request<B>,
|
||||
mut req: ::axum::http::Request<::axum::body::Body>,
|
||||
state: &#state,
|
||||
) -> ::std::result::Result<Self, Self::Rejection> {
|
||||
#trait_fn_body
|
||||
|
@ -749,7 +737,7 @@ fn impl_struct_by_extracting_all_at_once(
|
|||
// struct AppState {}
|
||||
// ```
|
||||
//
|
||||
// we need to implement `impl<B, M> FromRequest<AppState, B, M>` but only for
|
||||
// we need to implement `impl<M> FromRequest<AppState, M>` but only for
|
||||
// - `#[derive(FromRequest)]`, not `#[derive(FromRequestParts)]`
|
||||
// - `State`, not other extractors
|
||||
//
|
||||
|
@ -760,16 +748,15 @@ fn impl_struct_by_extracting_all_at_once(
|
|||
None
|
||||
};
|
||||
|
||||
let impl_generics = tr
|
||||
.body_type()
|
||||
.chain(via_marker_type.clone())
|
||||
let impl_generics = via_marker_type
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(state.impl_generics())
|
||||
.chain(generic_ident.is_some().then(|| parse_quote!(T)))
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
let trait_generics = state
|
||||
.trait_generics()
|
||||
.chain(tr.body_type())
|
||||
.chain(via_marker_type)
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
|
@ -828,13 +815,12 @@ fn impl_struct_by_extracting_all_at_once(
|
|||
where
|
||||
#via_path<#via_type_generics>: ::axum::extract::FromRequest<#trait_generics>,
|
||||
#rejection_bound
|
||||
B: ::std::marker::Send + 'static,
|
||||
#state_bounds
|
||||
{
|
||||
type Rejection = #associated_rejection_type;
|
||||
|
||||
async fn from_request(
|
||||
req: ::axum::http::Request<B>,
|
||||
req: ::axum::http::Request<::axum::body::Body>,
|
||||
state: &#state,
|
||||
) -> ::std::result::Result<Self, Self::Rejection> {
|
||||
::axum::extract::FromRequest::from_request(req, state)
|
||||
|
@ -923,14 +909,12 @@ fn impl_enum_by_extracting_all_at_once(
|
|||
|
||||
let path_span = path.span();
|
||||
|
||||
let impl_generics = tr
|
||||
.body_type()
|
||||
.chain(state.impl_generics())
|
||||
let impl_generics = state
|
||||
.impl_generics()
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
let trait_generics = state
|
||||
.trait_generics()
|
||||
.chain(tr.body_type())
|
||||
.collect::<Punctuated<Type, Token![,]>>();
|
||||
|
||||
let state_bounds = state.bounds();
|
||||
|
@ -942,15 +926,12 @@ fn impl_enum_by_extracting_all_at_once(
|
|||
#[automatically_derived]
|
||||
impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident
|
||||
where
|
||||
B: ::axum::body::HttpBody + ::std::marker::Send + 'static,
|
||||
B::Data: ::std::marker::Send,
|
||||
B::Error: ::std::convert::Into<::axum::BoxError>,
|
||||
#state_bounds
|
||||
{
|
||||
type Rejection = #associated_rejection_type;
|
||||
|
||||
async fn from_request(
|
||||
req: ::axum::http::Request<B>,
|
||||
req: ::axum::http::Request<::axum::body::Body>,
|
||||
state: &#state,
|
||||
) -> ::std::result::Result<Self, Self::Rejection> {
|
||||
::axum::extract::FromRequest::from_request(req, state)
|
||||
|
|
|
@ -148,7 +148,7 @@ use from_request::Trait::{FromRequest, FromRequestParts};
|
|||
/// ```
|
||||
/// pub struct ViaExtractor<T>(pub T);
|
||||
///
|
||||
/// // impl<T, S, B> FromRequest<S, B> for ViaExtractor<T> { ... }
|
||||
/// // impl<T, S> FromRequest<S> for ViaExtractor<T> { ... }
|
||||
/// ```
|
||||
///
|
||||
/// More complex via extractors are not supported and require writing a manual implementation.
|
||||
|
@ -481,21 +481,6 @@ pub fn derive_from_request_parts(item: TokenStream) -> TokenStream {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Changing request body type
|
||||
///
|
||||
/// By default `#[debug_handler]` assumes your request body type is `axum::body::Body`. This will
|
||||
/// work for most extractors but, for example, it wont work for `Request<axum::body::BoxBody>`,
|
||||
/// which only implements `FromRequest<BoxBody>` and _not_ `FromRequest<Body>`.
|
||||
///
|
||||
/// To work around that the request body type can be customized like so:
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{body::BoxBody, http::Request, debug_handler};
|
||||
///
|
||||
/// #[debug_handler(body = BoxBody)]
|
||||
/// async fn handler(request: Request<BoxBody>) {}
|
||||
/// ```
|
||||
///
|
||||
/// # Changing state type
|
||||
///
|
||||
/// By default `#[debug_handler]` assumes your state type is `()` unless your handler has a
|
||||
|
|
|
@ -16,7 +16,7 @@ error[E0277]: the trait bound `bool: FromRequestParts<()>` is not satisfied
|
|||
<(T1, T2, T3, T4, T5, T6, T7) as FromRequestParts<S>>
|
||||
<(T1, T2, T3, T4, T5, T6, T7, T8) as FromRequestParts<S>>
|
||||
and 26 others
|
||||
= note: required for `bool` to implement `FromRequest<(), Body, axum_core::extract::private::ViaParts>`
|
||||
= note: required for `bool` to implement `FromRequest<(), axum_core::extract::private::ViaParts>`
|
||||
note: required by a bound in `__axum_macros_check_handler_0_from_request_check`
|
||||
--> tests/debug_handler/fail/argument_not_extractor.rs:4:23
|
||||
|
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use axum_macros::debug_handler;
|
||||
|
||||
#[debug_handler(body = BoxBody, body = BoxBody)]
|
||||
#[debug_handler(state = (), state = ())]
|
||||
async fn handler() {}
|
||||
|
||||
#[debug_handler(state = (), state = ())]
|
||||
async fn handler_2() {}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
error: `body` specified more than once
|
||||
--> tests/debug_handler/fail/duplicate_args.rs:3:33
|
||||
|
|
||||
3 | #[debug_handler(body = BoxBody, body = BoxBody)]
|
||||
| ^^^^
|
||||
|
||||
error: `state` specified more than once
|
||||
--> tests/debug_handler/fail/duplicate_args.rs:6:29
|
||||
--> tests/debug_handler/fail/duplicate_args.rs:3:29
|
||||
|
|
||||
6 | #[debug_handler(state = (), state = ())]
|
||||
3 | #[debug_handler(state = (), state = ())]
|
||||
| ^^^^^
|
||||
|
|
|
@ -8,14 +8,13 @@ use axum_macros::debug_handler;
|
|||
struct A;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for A
|
||||
impl<S> FromRequest<S> for A
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ();
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: Handlers must only take owned values
|
||||
--> tests/debug_handler/fail/extract_self_mut.rs:25:22
|
||||
--> tests/debug_handler/fail/extract_self_mut.rs:24:22
|
||||
|
|
||||
25 | async fn handler(&mut self) {}
|
||||
24 | async fn handler(&mut self) {}
|
||||
| ^^^^^^^^^
|
||||
|
|
|
@ -8,14 +8,13 @@ use axum_macros::debug_handler;
|
|||
struct A;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for A
|
||||
impl<S> FromRequest<S> for A
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ();
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: Handlers must only take owned values
|
||||
--> tests/debug_handler/fail/extract_self_ref.rs:25:22
|
||||
--> tests/debug_handler/fail/extract_self_ref.rs:24:22
|
||||
|
|
||||
25 | async fn handler(&self) {}
|
||||
24 | async fn handler(&self) {}
|
||||
| ^^^^^
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: expected `body` or `state`
|
||||
error: expected `state`
|
||||
--> tests/debug_handler/fail/invalid_attrs.rs:3:17
|
||||
|
|
||||
3 | #[debug_handler(foo)]
|
||||
|
|
|
@ -15,6 +15,6 @@ error[E0277]: the trait bound `for<'de> Struct: serde::de::Deserialize<'de>` is
|
|||
(T0, T1, T2, T3)
|
||||
and $N others
|
||||
= note: required for `Struct` to implement `serde::de::DeserializeOwned`
|
||||
= note: required for `Json<Struct>` to implement `FromRequest<(), Body>`
|
||||
= note: required for `Json<Struct>` to implement `FromRequest<()>`
|
||||
= help: see issue #48214
|
||||
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
use axum::{body::BoxBody, http::Request};
|
||||
use axum_macros::debug_handler;
|
||||
|
||||
#[debug_handler(body = BoxBody)]
|
||||
async fn handler(_: Request<BoxBody>) {}
|
||||
|
||||
#[debug_handler(body = axum::body::BoxBody,)]
|
||||
async fn handler_with_trailing_comma_and_type_path(_: Request<axum::body::BoxBody>) {}
|
||||
|
||||
fn main() {}
|
|
@ -8,27 +8,25 @@ use axum_macros::debug_handler;
|
|||
struct A;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for A
|
||||
impl<S> FromRequest<S> for A
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ();
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Box<A>
|
||||
impl<S> FromRequest<S> for Box<A>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ();
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,14 @@ struct AppState;
|
|||
struct A;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for A
|
||||
impl<S> FromRequest<S> for A
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
AppState: FromRef<S>,
|
||||
{
|
||||
type Rejection = ();
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<axum::body::Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use axum_macros::debug_handler;
|
||||
use axum::{body::BoxBody, extract::State, http::Request};
|
||||
use axum::{extract::State, http::Request};
|
||||
|
||||
#[debug_handler(state = AppState, body = BoxBody)]
|
||||
async fn handler(_: State<AppState>, _: Request<BoxBody>) {}
|
||||
#[debug_handler(state = AppState)]
|
||||
async fn handler(_: State<AppState>, _: Request<axum::body::Body>) {}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use axum::{body::Body, routing::get, Router};
|
||||
use axum::{routing::get, Router};
|
||||
use axum_macros::FromRequest;
|
||||
|
||||
#[derive(FromRequest, Clone)]
|
||||
|
@ -7,5 +7,5 @@ struct Extractor<T>(T);
|
|||
async fn foo(_: Extractor<()>) {}
|
||||
|
||||
fn main() {
|
||||
Router::<(), Body>::new().route("/", get(foo));
|
||||
_ = Router::<()>::new().route("/", get(foo));
|
||||
}
|
||||
|
|
|
@ -4,21 +4,21 @@ error: #[derive(FromRequest)] only supports generics when used with #[from_reque
|
|||
5 | struct Extractor<T>(T);
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {foo}: Handler<_, _, _>` is not satisfied
|
||||
--> tests/from_request/fail/generic_without_via.rs:10:46
|
||||
|
|
||||
10 | Router::<(), Body>::new().route("/", get(foo));
|
||||
| --- ^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Extractor<()>) -> impl Future<Output = ()> {foo}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S, B>`:
|
||||
<Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
|
||||
<MethodRouter<S, B> as Handler<(), S, B>>
|
||||
error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {foo}: Handler<_, _>` is not satisfied
|
||||
--> tests/from_request/fail/generic_without_via.rs:10:44
|
||||
|
|
||||
10 | _ = Router::<()>::new().route("/", get(foo));
|
||||
| --- ^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Extractor<()>) -> impl Future<Output = ()> {foo}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S>`:
|
||||
<Layered<L, H, T, S> as Handler<T, S>>
|
||||
<MethodRouter<S> as Handler<(), S>>
|
||||
note: required by a bound in `axum::routing::get`
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
| top_level_handler_fn!(get, GET);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
|
||||
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
| top_level_handler_fn!(get, GET);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
|
||||
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use axum::{body::Body, routing::get, Router};
|
||||
use axum::{routing::get, Router};
|
||||
use axum_macros::FromRequest;
|
||||
|
||||
#[derive(FromRequest, Clone)]
|
||||
|
@ -8,5 +8,5 @@ struct Extractor<T>(T);
|
|||
async fn foo(_: Extractor<()>) {}
|
||||
|
||||
fn main() {
|
||||
Router::<(), Body>::new().route("/", get(foo));
|
||||
_ = Router::<()>::new().route("/", get(foo));
|
||||
}
|
||||
|
|
|
@ -4,21 +4,21 @@ error: #[derive(FromRequest)] only supports generics when used with #[from_reque
|
|||
6 | struct Extractor<T>(T);
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {foo}: Handler<_, _, _>` is not satisfied
|
||||
--> tests/from_request/fail/generic_without_via_rejection.rs:11:46
|
||||
|
|
||||
11 | Router::<(), Body>::new().route("/", get(foo));
|
||||
| --- ^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Extractor<()>) -> impl Future<Output = ()> {foo}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S, B>`:
|
||||
<Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
|
||||
<MethodRouter<S, B> as Handler<(), S, B>>
|
||||
error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {foo}: Handler<_, _>` is not satisfied
|
||||
--> tests/from_request/fail/generic_without_via_rejection.rs:11:44
|
||||
|
|
||||
11 | _ = Router::<()>::new().route("/", get(foo));
|
||||
| --- ^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Extractor<()>) -> impl Future<Output = ()> {foo}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S>`:
|
||||
<Layered<L, H, T, S> as Handler<T, S>>
|
||||
<MethodRouter<S> as Handler<(), S>>
|
||||
note: required by a bound in `axum::routing::get`
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
| top_level_handler_fn!(get, GET);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
|
||||
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
| top_level_handler_fn!(get, GET);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
|
||||
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -4,18 +4,18 @@ error: cannot use `rejection` without `via`
|
|||
18 | #[from_request(rejection(MyRejection))]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `fn(MyExtractor) -> impl Future<Output = ()> {handler}: Handler<_, _, _>` is not satisfied
|
||||
error[E0277]: the trait bound `fn(MyExtractor) -> impl Future<Output = ()> {handler}: Handler<_, _>` is not satisfied
|
||||
--> tests/from_request/fail/override_rejection_on_enum_without_via.rs:10:50
|
||||
|
|
||||
10 | let _: Router = Router::new().route("/", get(handler).post(handler_result));
|
||||
| --- ^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(MyExtractor) -> impl Future<Output = ()> {handler}`
|
||||
| --- ^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(MyExtractor) -> impl Future<Output = ()> {handler}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S, B>`:
|
||||
<Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
|
||||
<MethodRouter<S, B> as Handler<(), S, B>>
|
||||
= help: the following other types implement trait `Handler<T, S>`:
|
||||
<Layered<L, H, T, S> as Handler<T, S>>
|
||||
<MethodRouter<S> as Handler<(), S>>
|
||||
note: required by a bound in `axum::routing::get`
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
|
@ -23,21 +23,21 @@ note: required by a bound in `axum::routing::get`
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
|
||||
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}: Handler<_, _, _>` is not satisfied
|
||||
error[E0277]: the trait bound `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}: Handler<_, _>` is not satisfied
|
||||
--> tests/from_request/fail/override_rejection_on_enum_without_via.rs:10:64
|
||||
|
|
||||
10 | let _: Router = Router::new().route("/", get(handler).post(handler_result));
|
||||
| ---- ^^^^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}`
|
||||
| ---- ^^^^^^^^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: Consider using `#[axum::debug_handler]` to improve the error message
|
||||
= help: the following other types implement trait `Handler<T, S, B>`:
|
||||
<Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
|
||||
<MethodRouter<S, B> as Handler<(), S, B>>
|
||||
note: required by a bound in `MethodRouter::<S, B>::post`
|
||||
= help: the following other types implement trait `Handler<T, S>`:
|
||||
<Layered<L, H, T, S> as Handler<T, S>>
|
||||
<MethodRouter<S> as Handler<(), S>>
|
||||
note: required by a bound in `MethodRouter::<S>::post`
|
||||
--> $WORKSPACE/axum/src/routing/method_routing.rs
|
||||
|
|
||||
| chained_handler_fn!(post, POST);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MethodRouter::<S, B>::post`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MethodRouter::<S>::post`
|
||||
= note: this error originates in the macro `chained_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -15,7 +15,7 @@ struct OtherState {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<AppState, axum::body::Body, Rejection = axum::response::Response>,
|
||||
Extractor: axum::extract::FromRequest<AppState, Rejection = axum::response::Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use axum::{
|
||||
body::Body,
|
||||
extract::{FromRequest, Json},
|
||||
response::Response,
|
||||
};
|
||||
|
@ -15,7 +14,7 @@ struct Extractor {
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: FromRequest<(), Body, Rejection = Response>,
|
||||
Extractor: FromRequest<(), Rejection = Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Extractor {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body, Rejection = std::convert::Infallible>,
|
||||
Extractor: axum::extract::FromRequest<(), Rejection = std::convert::Infallible>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Extractor();
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body, Rejection = std::convert::Infallible>,
|
||||
Extractor: axum::extract::FromRequest<(), Rejection = std::convert::Infallible>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use axum::{body::Body, routing::get, Extension, Router};
|
||||
use axum::{routing::get, Extension, Router};
|
||||
use axum_macros::FromRequest;
|
||||
|
||||
#[derive(FromRequest, Clone)]
|
||||
|
@ -8,5 +8,5 @@ enum Extractor {}
|
|||
async fn foo(_: Extractor) {}
|
||||
|
||||
fn main() {
|
||||
Router::<(), Body>::new().route("/", get(foo));
|
||||
_ = Router::<()>::new().route("/", get(foo));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use axum::{body::Body, routing::get, Extension, Router};
|
||||
use axum::{routing::get, Extension, Router};
|
||||
use axum_macros::FromRequestParts;
|
||||
|
||||
#[derive(FromRequestParts, Clone)]
|
||||
|
@ -8,5 +8,5 @@ enum Extractor {}
|
|||
async fn foo(_: Extractor) {}
|
||||
|
||||
fn main() {
|
||||
Router::<(), Body>::new().route("/", get(foo));
|
||||
_ = Router::<()>::new().route("/", get(foo));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use axum::{
|
||||
body::Body,
|
||||
extract::{FromRequest, TypedHeader, rejection::TypedHeaderRejection},
|
||||
response::Response,
|
||||
headers::{self, UserAgent},
|
||||
|
@ -17,7 +16,7 @@ struct Extractor {
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: FromRequest<(), Body, Rejection = Response>,
|
||||
Extractor: FromRequest<(), Rejection = Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use axum::{
|
||||
body::Body,
|
||||
response::Response,
|
||||
extract::{
|
||||
rejection::TypedHeaderRejection,
|
||||
|
@ -24,7 +23,7 @@ struct Extractor {
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: FromRequest<(), Body, Rejection = Response>,
|
||||
Extractor: FromRequest<(), Rejection = Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use axum::{
|
|||
http::{StatusCode, Request},
|
||||
response::{IntoResponse, Response},
|
||||
routing::get,
|
||||
body::Body,
|
||||
Extension, Router,
|
||||
};
|
||||
|
||||
|
@ -27,15 +28,14 @@ struct MyExtractor {
|
|||
struct OtherExtractor;
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for OtherExtractor
|
||||
impl<S> FromRequest<S> for OtherExtractor
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
{
|
||||
// this rejection doesn't implement `Display` and `Error`
|
||||
type Rejection = (StatusCode, String);
|
||||
|
||||
async fn from_request(_req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(_req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ impl FromRef<AppState> for Key {
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<AppState, axum::body::Body, Rejection = axum::response::Response>,
|
||||
Extractor: axum::extract::FromRequest<AppState, Rejection = axum::response::Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ struct AppState {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<AppState, axum::body::Body, Rejection = axum::response::Response>,
|
||||
Extractor: axum::extract::FromRequest<AppState, Rejection = axum::response::Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ struct AppState {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<AppState, axum::body::Body, Rejection = axum::response::Response>,
|
||||
Extractor: axum::extract::FromRequest<AppState, Rejection = axum::response::Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Extractor(axum::http::HeaderMap, String);
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body>,
|
||||
Extractor: axum::extract::FromRequest<()>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ struct Payload {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body>,
|
||||
Extractor: axum::extract::FromRequest<()>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ struct Payload {}
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body, Rejection = Response>,
|
||||
Extractor: axum::extract::FromRequest<(), Rejection = Response>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ struct State;
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body>,
|
||||
Extractor: axum::extract::FromRequest<()>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Extractor;
|
|||
|
||||
fn assert_from_request()
|
||||
where
|
||||
Extractor: axum::extract::FromRequest<(), axum::body::Body, Rejection = std::convert::Infallible>,
|
||||
Extractor: axum::extract::FromRequest<(), Rejection = std::convert::Infallible>,
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ impl Default for MyRejection {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new()
|
||||
_ = axum::Router::<()>::new()
|
||||
.typed_get(|_: Result<MyPathNamed, MyRejection>| async {})
|
||||
.typed_post(|_: Result<MyPathUnnamed, MyRejection>| async {})
|
||||
.typed_put(|_: Result<MyPathUnit, MyRejection>| async {});
|
||||
|
|
|
@ -9,7 +9,7 @@ struct MyPath {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new().route("/", axum::routing::get(|_: MyPath| async {}));
|
||||
_ = axum::Router::<()>::new().route("/", axum::routing::get(|_: MyPath| async {}));
|
||||
|
||||
assert_eq!(MyPath::PATH, "/users/:user_id/teams/:team_id");
|
||||
assert_eq!(
|
||||
|
|
|
@ -19,7 +19,7 @@ struct UsersIndex;
|
|||
async fn result_handler_unit_struct(_: Result<UsersIndex, StatusCode>) {}
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new()
|
||||
_ = axum::Router::<()>::new()
|
||||
.typed_get(option_handler)
|
||||
.typed_post(result_handler)
|
||||
.typed_post(result_handler_unit_struct);
|
||||
|
|
|
@ -8,7 +8,7 @@ pub type Result<T> = std::result::Result<T, ()>;
|
|||
struct MyPath(u32, u32);
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new().route("/", axum::routing::get(|_: MyPath| async {}));
|
||||
_ = axum::Router::<()>::new().route("/", axum::routing::get(|_: MyPath| async {}));
|
||||
|
||||
assert_eq!(MyPath::PATH, "/users/:user_id/teams/:team_id");
|
||||
assert_eq!(format!("{}", MyPath(1, 2)), "/users/1/teams/2");
|
||||
|
|
|
@ -5,7 +5,7 @@ use axum_extra::routing::TypedPath;
|
|||
struct MyPath;
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new()
|
||||
_ = axum::Router::<()>::new()
|
||||
.route("/", axum::routing::get(|_: MyPath| async {}));
|
||||
|
||||
assert_eq!(MyPath::PATH, "/users");
|
||||
|
|
|
@ -8,5 +8,5 @@ struct MyPath {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
axum::Router::<(), axum::body::Body>::new().typed_get(|_: MyPath| async {});
|
||||
_ = axum::Router::<()>::new().typed_get(|_: MyPath| async {});
|
||||
}
|
||||
|
|
|
@ -7,12 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
# Unreleased
|
||||
|
||||
- **breaking:** The following types/traits are no longer generic over the request body
|
||||
(i.e. the `B` type param has been removed) ([#1751]):
|
||||
- `FromRequest`
|
||||
- `FromRequestParts`
|
||||
- `Handler`
|
||||
- `HandlerService`
|
||||
- `HandlerWithoutStateExt`
|
||||
- `Layered`
|
||||
- `LayeredFuture`
|
||||
- `MethodRouter`
|
||||
- `RequestExt`
|
||||
- `Route`
|
||||
- `RouteFuture`
|
||||
- `Router`
|
||||
- **breaking:** axum no longer re-exports `hyper::Body` as that type is removed
|
||||
in hyper 1.0. Instead axum has its own body type at `axum::body::Body` ([#1751])
|
||||
- **breaking:** `extract::BodyStream` has been removed as `body::Body`
|
||||
implements `Stream` and `FromRequest` directly ([#1751])
|
||||
- **breaking:** Change `sse::Event::json_data` to use `axum_core::Error` as its error type ([#1762])
|
||||
- **breaking:** Rename `DefaultOnFailedUpdgrade` to `DefaultOnFailedUpgrade` ([#1664])
|
||||
- **breaking:** Rename `OnFailedUpdgrade` to `OnFailedUpgrade` ([#1664])
|
||||
- **added:** Add `Router::as_service` and `Router::into_service` to workaround
|
||||
type inference issues when calling `ServiceExt` methods on a `Router` ([#1835])
|
||||
|
||||
[#1762]: https://github.com/tokio-rs/axum/pull/1762
|
||||
[#1664]: https://github.com/tokio-rs/axum/pull/1664
|
||||
[#1751]: https://github.com/tokio-rs/axum/pull/1751
|
||||
[#1762]: https://github.com/tokio-rs/axum/pull/1762
|
||||
[#1835]: https://github.com/tokio-rs/axum/pull/1835
|
||||
|
||||
# 0.6.16 (18. April, 2023)
|
||||
|
||||
|
|
|
@ -7,11 +7,8 @@ pub use self::stream_body::StreamBody;
|
|||
#[doc(no_inline)]
|
||||
pub use http_body::{Body as HttpBody, Empty, Full};
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use hyper::body::Body;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use bytes::Bytes;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use axum_core::body::{boxed, BoxBody};
|
||||
pub use axum_core::body::{boxed, Body, BoxBody};
|
||||
|
|
|
@ -21,7 +21,7 @@ pin_project! {
|
|||
///
|
||||
/// The purpose of this type is to be used in responses. If you want to
|
||||
/// extract the request body as a stream consider using
|
||||
/// [`BodyStream`](crate::extract::BodyStream).
|
||||
/// [`Body`](crate::body::Body).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
use std::{convert::Infallible, fmt};
|
||||
|
||||
use axum_core::body::Body;
|
||||
use http::Request;
|
||||
use tower::Service;
|
||||
|
||||
use crate::{
|
||||
body::HttpBody,
|
||||
handler::Handler,
|
||||
routing::{future::RouteFuture, Route},
|
||||
Router,
|
||||
};
|
||||
|
||||
pub(crate) struct BoxedIntoRoute<S, B, E>(Box<dyn ErasedIntoRoute<S, B, E>>);
|
||||
pub(crate) struct BoxedIntoRoute<S, E>(Box<dyn ErasedIntoRoute<S, E>>);
|
||||
|
||||
impl<S, B> BoxedIntoRoute<S, B, Infallible>
|
||||
impl<S> BoxedIntoRoute<S, Infallible>
|
||||
where
|
||||
S: Clone + Send + Sync + 'static,
|
||||
B: Send + 'static,
|
||||
{
|
||||
pub(crate) fn from_handler<H, T>(handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
B: HttpBody,
|
||||
{
|
||||
Self(Box::new(MakeErasedHandler {
|
||||
handler,
|
||||
|
@ -30,14 +28,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> BoxedIntoRoute<S, B, E> {
|
||||
pub(crate) fn map<F, B2, E2>(self, f: F) -> BoxedIntoRoute<S, B2, E2>
|
||||
impl<S, E> BoxedIntoRoute<S, E> {
|
||||
pub(crate) fn map<F, E2>(self, f: F) -> BoxedIntoRoute<S, E2>
|
||||
where
|
||||
S: 'static,
|
||||
B: 'static,
|
||||
E: 'static,
|
||||
F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + Send + 'static,
|
||||
B2: HttpBody + 'static,
|
||||
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
|
||||
E2: 'static,
|
||||
{
|
||||
BoxedIntoRoute(Box::new(Map {
|
||||
|
@ -46,60 +42,59 @@ impl<S, B, E> BoxedIntoRoute<S, B, E> {
|
|||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn into_route(self, state: S) -> Route<B, E> {
|
||||
pub(crate) fn into_route(self, state: S) -> Route<E> {
|
||||
self.0.into_route(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> Clone for BoxedIntoRoute<S, B, E> {
|
||||
impl<S, E> Clone for BoxedIntoRoute<S, E> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone_box())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> fmt::Debug for BoxedIntoRoute<S, B, E> {
|
||||
impl<S, E> fmt::Debug for BoxedIntoRoute<S, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("BoxedIntoRoute").finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ErasedIntoRoute<S, B, E>: Send {
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, E>>;
|
||||
pub(crate) trait ErasedIntoRoute<S, E>: Send {
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, E>>;
|
||||
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<B, E>;
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<E>;
|
||||
|
||||
fn call_with_state(self: Box<Self>, request: Request<B>, state: S) -> RouteFuture<B, E>;
|
||||
fn call_with_state(self: Box<Self>, request: Request<Body>, state: S) -> RouteFuture<E>;
|
||||
}
|
||||
|
||||
pub(crate) struct MakeErasedHandler<H, S, B> {
|
||||
pub(crate) struct MakeErasedHandler<H, S> {
|
||||
pub(crate) handler: H,
|
||||
pub(crate) into_route: fn(H, S) -> Route<B>,
|
||||
pub(crate) into_route: fn(H, S) -> Route,
|
||||
}
|
||||
|
||||
impl<H, S, B> ErasedIntoRoute<S, B, Infallible> for MakeErasedHandler<H, S, B>
|
||||
impl<H, S> ErasedIntoRoute<S, Infallible> for MakeErasedHandler<H, S>
|
||||
where
|
||||
H: Clone + Send + 'static,
|
||||
S: 'static,
|
||||
B: HttpBody + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, Infallible>> {
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, Infallible>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<B> {
|
||||
fn into_route(self: Box<Self>, state: S) -> Route {
|
||||
(self.into_route)(self.handler, state)
|
||||
}
|
||||
|
||||
fn call_with_state(
|
||||
self: Box<Self>,
|
||||
request: Request<B>,
|
||||
request: Request<Body>,
|
||||
state: S,
|
||||
) -> RouteFuture<B, Infallible> {
|
||||
) -> RouteFuture<Infallible> {
|
||||
self.into_route(state).call(request)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, S, B> Clone for MakeErasedHandler<H, S, B>
|
||||
impl<H, S> Clone for MakeErasedHandler<H, S>
|
||||
where
|
||||
H: Clone,
|
||||
{
|
||||
|
@ -111,34 +106,33 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MakeErasedRouter<S, B> {
|
||||
pub(crate) router: Router<S, B>,
|
||||
pub(crate) into_route: fn(Router<S, B>, S) -> Route<B>,
|
||||
pub(crate) struct MakeErasedRouter<S> {
|
||||
pub(crate) router: Router<S>,
|
||||
pub(crate) into_route: fn(Router<S>, S) -> Route,
|
||||
}
|
||||
|
||||
impl<S, B> ErasedIntoRoute<S, B, Infallible> for MakeErasedRouter<S, B>
|
||||
impl<S> ErasedIntoRoute<S, Infallible> for MakeErasedRouter<S>
|
||||
where
|
||||
S: Clone + Send + Sync + 'static,
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, Infallible>> {
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, Infallible>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<B> {
|
||||
fn into_route(self: Box<Self>, state: S) -> Route {
|
||||
(self.into_route)(self.router, state)
|
||||
}
|
||||
|
||||
fn call_with_state(
|
||||
mut self: Box<Self>,
|
||||
request: Request<B>,
|
||||
request: Request<Body>,
|
||||
state: S,
|
||||
) -> RouteFuture<B, Infallible> {
|
||||
) -> RouteFuture<Infallible> {
|
||||
self.router.call_with_state(request, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> Clone for MakeErasedRouter<S, B>
|
||||
impl<S> Clone for MakeErasedRouter<S>
|
||||
where
|
||||
S: Clone,
|
||||
{
|
||||
|
@ -150,44 +144,42 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Map<S, B, E, B2, E2> {
|
||||
pub(crate) inner: Box<dyn ErasedIntoRoute<S, B, E>>,
|
||||
pub(crate) layer: Box<dyn LayerFn<B, E, B2, E2>>,
|
||||
pub(crate) struct Map<S, E, E2> {
|
||||
pub(crate) inner: Box<dyn ErasedIntoRoute<S, E>>,
|
||||
pub(crate) layer: Box<dyn LayerFn<E, E2>>,
|
||||
}
|
||||
|
||||
impl<S, B, E, B2, E2> ErasedIntoRoute<S, B2, E2> for Map<S, B, E, B2, E2>
|
||||
impl<S, E, E2> ErasedIntoRoute<S, E2> for Map<S, E, E2>
|
||||
where
|
||||
S: 'static,
|
||||
B: 'static,
|
||||
E: 'static,
|
||||
B2: HttpBody + 'static,
|
||||
E2: 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B2, E2>> {
|
||||
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, E2>> {
|
||||
Box::new(Self {
|
||||
inner: self.inner.clone_box(),
|
||||
layer: self.layer.clone_box(),
|
||||
})
|
||||
}
|
||||
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<B2, E2> {
|
||||
fn into_route(self: Box<Self>, state: S) -> Route<E2> {
|
||||
(self.layer)(self.inner.into_route(state))
|
||||
}
|
||||
|
||||
fn call_with_state(self: Box<Self>, request: Request<B2>, state: S) -> RouteFuture<B2, E2> {
|
||||
fn call_with_state(self: Box<Self>, request: Request<Body>, state: S) -> RouteFuture<E2> {
|
||||
(self.layer)(self.inner.into_route(state)).call(request)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait LayerFn<B, E, B2, E2>: FnOnce(Route<B, E>) -> Route<B2, E2> + Send {
|
||||
fn clone_box(&self) -> Box<dyn LayerFn<B, E, B2, E2>>;
|
||||
pub(crate) trait LayerFn<E, E2>: FnOnce(Route<E>) -> Route<E2> + Send {
|
||||
fn clone_box(&self) -> Box<dyn LayerFn<E, E2>>;
|
||||
}
|
||||
|
||||
impl<F, B, E, B2, E2> LayerFn<B, E, B2, E2> for F
|
||||
impl<F, E, E2> LayerFn<E, E2> for F
|
||||
where
|
||||
F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + Send + 'static,
|
||||
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
|
||||
{
|
||||
fn clone_box(&self) -> Box<dyn LayerFn<B, E, B2, E2>> {
|
||||
fn clone_box(&self) -> Box<dyn LayerFn<E, E2>> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ async fn handler(
|
|||
// ...
|
||||
}
|
||||
#
|
||||
# let _: axum::routing::MethodRouter<AppState, String> = axum::routing::get(handler);
|
||||
# let _: axum::routing::MethodRouter<AppState> = axum::routing::get(handler);
|
||||
```
|
||||
|
||||
We get a compile error if `String` isn't the last extractor:
|
||||
|
@ -466,7 +466,7 @@ use axum::{
|
|||
async_trait,
|
||||
extract::FromRequest,
|
||||
response::{Response, IntoResponse},
|
||||
body::Bytes,
|
||||
body::{Bytes, Body},
|
||||
routing::get,
|
||||
Router,
|
||||
http::{
|
||||
|
@ -479,15 +479,14 @@ use axum::{
|
|||
struct ValidatedBody(Bytes);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for ValidatedBody
|
||||
impl<S> FromRequest<S> for ValidatedBody
|
||||
where
|
||||
Bytes: FromRequest<S, B>,
|
||||
B: Send + 'static,
|
||||
Bytes: FromRequest<S>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let body = Bytes::from_request(req, state)
|
||||
.await
|
||||
.map_err(IntoResponse::into_response)?;
|
||||
|
@ -520,6 +519,7 @@ use axum::{
|
|||
routing::get,
|
||||
extract::{FromRequest, FromRequestParts},
|
||||
http::{Request, request::Parts},
|
||||
body::Body,
|
||||
async_trait,
|
||||
};
|
||||
use std::convert::Infallible;
|
||||
|
@ -529,14 +529,13 @@ struct MyExtractor;
|
|||
|
||||
// `MyExtractor` implements both `FromRequest`
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for MyExtractor
|
||||
impl<S> FromRequest<S> for MyExtractor
|
||||
where
|
||||
S: Send + Sync,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
// ...
|
||||
# todo!()
|
||||
}
|
||||
|
@ -639,81 +638,6 @@ For security reasons, [`Bytes`] will, by default, not accept bodies larger than
|
|||
|
||||
For more details, including how to disable this limit, see [`DefaultBodyLimit`].
|
||||
|
||||
# Request body extractors
|
||||
|
||||
Most of the time your request body type will be [`body::Body`] (a re-export
|
||||
of [`hyper::Body`]), which is directly supported by all extractors.
|
||||
|
||||
However if you're applying a tower middleware that changes the request body type
|
||||
you might have to apply a different body type to some extractors:
|
||||
|
||||
```rust
|
||||
use std::{
|
||||
task::{Context, Poll},
|
||||
pin::Pin,
|
||||
};
|
||||
use tower_http::map_request_body::MapRequestBodyLayer;
|
||||
use axum::{
|
||||
extract::{self, BodyStream},
|
||||
body::{Body, HttpBody},
|
||||
routing::get,
|
||||
http::{header::HeaderMap, Request},
|
||||
Router,
|
||||
};
|
||||
|
||||
struct MyBody<B>(B);
|
||||
|
||||
impl<B> HttpBody for MyBody<B>
|
||||
where
|
||||
B: HttpBody + Unpin,
|
||||
{
|
||||
type Data = B::Data;
|
||||
type Error = B::Error;
|
||||
|
||||
fn poll_data(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||
Pin::new(&mut self.0).poll_data(cx)
|
||||
}
|
||||
|
||||
fn poll_trailers(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
|
||||
Pin::new(&mut self.0).poll_trailers(cx)
|
||||
}
|
||||
}
|
||||
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/string",
|
||||
// `String` works directly with any body type
|
||||
get(|_: String| async {})
|
||||
)
|
||||
.route(
|
||||
"/body",
|
||||
// `extract::Body` defaults to `axum::body::Body`
|
||||
// but can be customized
|
||||
get(|_: extract::RawBody<MyBody<Body>>| async {})
|
||||
)
|
||||
.route(
|
||||
"/body-stream",
|
||||
// same for `extract::BodyStream`
|
||||
get(|_: extract::BodyStream| async {}),
|
||||
)
|
||||
.route(
|
||||
// and `Request<_>`
|
||||
"/request",
|
||||
get(|_: Request<MyBody<Body>>| async {})
|
||||
)
|
||||
// middleware that changes the request body type
|
||||
.layer(MapRequestBodyLayer::new(MyBody));
|
||||
# async {
|
||||
# axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
# };
|
||||
```
|
||||
|
||||
# Running extractors from middleware
|
||||
|
||||
Extractors can also be run from middleware:
|
||||
|
@ -759,7 +683,7 @@ fn token_is_valid(token: &str) -> bool {
|
|||
}
|
||||
|
||||
let app = Router::new().layer(middleware::from_fn(auth_middleware));
|
||||
# let _: Router<()> = app;
|
||||
# let _: Router = app;
|
||||
```
|
||||
|
||||
# Wrapping extractors
|
||||
|
@ -771,6 +695,7 @@ may or may not consume the request body) you should implement both
|
|||
```rust
|
||||
use axum::{
|
||||
Router,
|
||||
body::Body,
|
||||
routing::get,
|
||||
extract::{FromRequest, FromRequestParts},
|
||||
http::{Request, HeaderMap, request::Parts},
|
||||
|
@ -806,15 +731,14 @@ where
|
|||
|
||||
// and `FromRequest`
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for Timing<T>
|
||||
impl<S, T> FromRequest<S> for Timing<T>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
T: FromRequest<S, B>,
|
||||
T: FromRequest<S>,
|
||||
{
|
||||
type Rejection = T::Rejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let start = Instant::now();
|
||||
let extractor = T::from_request(req, state).await?;
|
||||
let duration = start.elapsed();
|
||||
|
|
|
@ -97,7 +97,7 @@ let app = Router::new()
|
|||
.layer(layer_one)
|
||||
.layer(layer_two)
|
||||
.layer(layer_three);
|
||||
# let _: Router<(), axum::body::Body> = app;
|
||||
# let _: Router = app;
|
||||
```
|
||||
|
||||
Think of the middleware as being layered like an onion where each new layer
|
||||
|
@ -156,7 +156,7 @@ let app = Router::new()
|
|||
.layer(layer_two)
|
||||
.layer(layer_three),
|
||||
);
|
||||
# let _: Router<(), axum::body::Body> = app;
|
||||
# let _: Router = app;
|
||||
```
|
||||
|
||||
`ServiceBuilder` works by composing all layers into one such that they run top
|
||||
|
@ -523,7 +523,7 @@ async fn handler(
|
|||
let app = Router::new()
|
||||
.route("/", get(handler))
|
||||
.route_layer(middleware::from_fn(auth));
|
||||
# let _: Router<()> = app;
|
||||
# let _: Router = app;
|
||||
```
|
||||
|
||||
[Response extensions] can also be used but note that request extensions are not
|
||||
|
@ -549,13 +549,13 @@ use axum::{
|
|||
http::Request,
|
||||
};
|
||||
|
||||
async fn rewrite_request_uri<B>(req: Request<B>, next: Next<B>) -> Response {
|
||||
fn rewrite_request_uri<B>(req: Request<B>) -> Request<B> {
|
||||
// ...
|
||||
# next.run(req).await
|
||||
# req
|
||||
}
|
||||
|
||||
// this can be any `tower::Layer`
|
||||
let middleware = axum::middleware::from_fn(rewrite_request_uri);
|
||||
let middleware = tower::util::MapRequestLayer::new(rewrite_request_uri);
|
||||
|
||||
let app = Router::new();
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ pub use self::{
|
|||
path::{Path, RawPathParams},
|
||||
raw_form::RawForm,
|
||||
raw_query::RawQuery,
|
||||
request_parts::{BodyStream, RawBody},
|
||||
request_parts::RawBody,
|
||||
state::State,
|
||||
};
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
//!
|
||||
//! See [`Multipart`] for more details.
|
||||
|
||||
use super::{BodyStream, FromRequest};
|
||||
use crate::body::{Bytes, HttpBody};
|
||||
use crate::BoxError;
|
||||
use super::FromRequest;
|
||||
use crate::body::Bytes;
|
||||
use async_trait::async_trait;
|
||||
use axum_core::__composite_rejection as composite_rejection;
|
||||
use axum_core::__define_rejection as define_rejection;
|
||||
use axum_core::response::{IntoResponse, Response};
|
||||
use axum_core::body::Body;
|
||||
use axum_core::RequestExt;
|
||||
use futures_util::stream::Stream;
|
||||
use http::header::{HeaderMap, CONTENT_TYPE};
|
||||
|
@ -59,22 +59,18 @@ pub struct Multipart {
|
|||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for Multipart
|
||||
impl<S> FromRequest<S> for Multipart
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Into<Bytes>,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = MultipartRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let boundary = parse_boundary(req.headers()).ok_or(InvalidBoundary)?;
|
||||
let stream_result = match req.with_limited_body() {
|
||||
Ok(limited) => BodyStream::from_request(limited, state).await,
|
||||
Err(unlimited) => BodyStream::from_request(unlimited, state).await,
|
||||
let stream = match req.with_limited_body() {
|
||||
Ok(limited) => Body::new(limited),
|
||||
Err(unlimited) => unlimited.into_body(),
|
||||
};
|
||||
let stream = stream_result.unwrap_or_else(|err| match err {});
|
||||
let multipart = multer::Multipart::new(stream, boundary);
|
||||
Ok(Self { inner: multipart })
|
||||
}
|
||||
|
@ -310,7 +306,7 @@ mod tests {
|
|||
use axum_core::extract::DefaultBodyLimit;
|
||||
|
||||
use super::*;
|
||||
use crate::{body::Body, response::IntoResponse, routing::post, test_helpers::*, Router};
|
||||
use crate::{response::IntoResponse, routing::post, test_helpers::*, Router};
|
||||
|
||||
#[crate::test]
|
||||
async fn content_type_with_encoding() {
|
||||
|
@ -346,7 +342,9 @@ mod tests {
|
|||
// No need for this to be a #[test], we just want to make sure it compiles
|
||||
fn _multipart_from_request_limited() {
|
||||
async fn handler(_: Multipart) {}
|
||||
let _app: Router<(), http_body::Limited<Body>> = Router::new().route("/", post(handler));
|
||||
let _app: Router = Router::new()
|
||||
.route("/", post(handler))
|
||||
.layer(tower_http::limit::RequestBodyLimitLayer::new(1024));
|
||||
}
|
||||
|
||||
#[crate::test]
|
||||
|
|
|
@ -71,7 +71,7 @@ mod tests {
|
|||
use crate::{routing::get, test_helpers::TestClient, Router};
|
||||
|
||||
use super::*;
|
||||
use axum_core::extract::FromRequest;
|
||||
use axum_core::{body::Body, extract::FromRequest};
|
||||
use http::{Request, StatusCode};
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Debug;
|
||||
|
@ -80,7 +80,10 @@ mod tests {
|
|||
where
|
||||
T: DeserializeOwned + PartialEq + Debug,
|
||||
{
|
||||
let req = Request::builder().uri(uri.as_ref()).body(()).unwrap();
|
||||
let req = Request::builder()
|
||||
.uri(uri.as_ref())
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
assert_eq!(Query::<T>::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use async_trait::async_trait;
|
||||
use axum_core::extract::FromRequest;
|
||||
use axum_core::{body::Body, extract::FromRequest};
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use http::{Method, Request};
|
||||
|
||||
|
@ -8,8 +8,6 @@ use super::{
|
|||
rejection::{InvalidFormContentType, RawFormRejection},
|
||||
};
|
||||
|
||||
use crate::{body::HttpBody, BoxError};
|
||||
|
||||
/// Extractor that extracts raw form requests.
|
||||
///
|
||||
/// For `GET` requests it will extract the raw query. For other methods it extracts the raw
|
||||
|
@ -35,16 +33,13 @@ use crate::{body::HttpBody, BoxError};
|
|||
pub struct RawForm(pub Bytes);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for RawForm
|
||||
impl<S> FromRequest<S> for RawForm
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = RawFormRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
if req.method() == Method::GET {
|
||||
let mut bytes = BytesMut::new();
|
||||
|
||||
|
@ -65,20 +60,15 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use axum_core::body::Body;
|
||||
use http::{header::CONTENT_TYPE, Request};
|
||||
|
||||
use super::{InvalidFormContentType, RawForm, RawFormRejection};
|
||||
|
||||
use crate::{
|
||||
body::{Bytes, Empty, Full},
|
||||
extract::FromRequest,
|
||||
};
|
||||
use crate::extract::FromRequest;
|
||||
|
||||
async fn check_query(uri: &str, value: &[u8]) {
|
||||
let req = Request::builder()
|
||||
.uri(uri)
|
||||
.body(Empty::<Bytes>::new())
|
||||
.unwrap();
|
||||
let req = Request::builder().uri(uri).body(Body::empty()).unwrap();
|
||||
|
||||
assert_eq!(RawForm::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
@ -86,7 +76,7 @@ mod tests {
|
|||
async fn check_body(body: &'static [u8]) {
|
||||
let req = Request::post("http://example.com/test")
|
||||
.header(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())
|
||||
.body(Full::new(Bytes::from(body)))
|
||||
.body(Body::from(body))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(RawForm::from_request(req, &()).await.unwrap().0, body);
|
||||
|
@ -109,7 +99,7 @@ mod tests {
|
|||
#[crate::test]
|
||||
async fn test_incorrect_content_type() {
|
||||
let req = Request::post("http://example.com/test")
|
||||
.body(Full::<Bytes>::from(Bytes::from("page=0&size=10")))
|
||||
.body(Body::from("page=0&size=10"))
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
|
|
|
@ -1,18 +1,8 @@
|
|||
use super::{Extension, FromRequest, FromRequestParts};
|
||||
use crate::{
|
||||
body::{Body, Bytes, HttpBody},
|
||||
BoxError, Error,
|
||||
};
|
||||
use crate::body::Body;
|
||||
use async_trait::async_trait;
|
||||
use futures_util::stream::Stream;
|
||||
use http::{request::Parts, Request, Uri};
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
fmt,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use sync_wrapper::SyncWrapper;
|
||||
use std::convert::Infallible;
|
||||
|
||||
/// Extractor that gets the original request URI regardless of nesting.
|
||||
///
|
||||
|
@ -104,82 +94,6 @@ where
|
|||
#[cfg(feature = "original-uri")]
|
||||
axum_core::__impl_deref!(OriginalUri: Uri);
|
||||
|
||||
/// Extractor that extracts the request body as a [`Stream`].
|
||||
///
|
||||
/// Since extracting the request body requires consuming it, the `BodyStream` extractor must be
|
||||
/// *last* if there are multiple extractors in a handler.
|
||||
/// See ["the order of extractors"][order-of-extractors]
|
||||
///
|
||||
/// [order-of-extractors]: crate::extract#the-order-of-extractors
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use axum::{
|
||||
/// extract::BodyStream,
|
||||
/// routing::get,
|
||||
/// Router,
|
||||
/// };
|
||||
/// use futures_util::StreamExt;
|
||||
///
|
||||
/// async fn handler(mut stream: BodyStream) {
|
||||
/// while let Some(chunk) = stream.next().await {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let app = Router::new().route("/users", get(handler));
|
||||
/// # async {
|
||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// [`Stream`]: https://docs.rs/futures/latest/futures/stream/trait.Stream.html
|
||||
/// [`body::Body`]: crate::body::Body
|
||||
pub struct BodyStream(
|
||||
SyncWrapper<Pin<Box<dyn HttpBody<Data = Bytes, Error = Error> + Send + 'static>>>,
|
||||
);
|
||||
|
||||
impl Stream for BodyStream {
|
||||
type Item = Result<Bytes, Error>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Pin::new(self.0.get_mut()).poll_data(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for BodyStream
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Into<Bytes>,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let body = req
|
||||
.into_body()
|
||||
.map_data(Into::into)
|
||||
.map_err(|err| Error::new(err.into()));
|
||||
let stream = BodyStream(SyncWrapper::new(Box::pin(body)));
|
||||
Ok(stream)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BodyStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("BodyStream").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn body_stream_traits() {
|
||||
crate::test_helpers::assert_send::<BodyStream>();
|
||||
crate::test_helpers::assert_sync::<BodyStream>();
|
||||
}
|
||||
|
||||
/// Extractor that extracts the raw request body.
|
||||
///
|
||||
/// Since extracting the raw request body requires consuming it, the `RawBody` extractor must be
|
||||
|
@ -208,24 +122,21 @@ fn body_stream_traits() {
|
|||
/// ```
|
||||
///
|
||||
/// [`body::Body`]: crate::body::Body
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RawBody<B = Body>(pub B);
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RawBody(pub Body);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for RawBody<B>
|
||||
impl<S> FromRequest<S> for RawBody
|
||||
where
|
||||
B: Send,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
Ok(Self(req.into_body()))
|
||||
}
|
||||
}
|
||||
|
||||
axum_core::__impl_deref!(RawBody);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{extract::Extension, routing::get, test_helpers::*, Router};
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::body::HttpBody;
|
||||
use crate::extract::{rejection::*, FromRequest, RawForm};
|
||||
use crate::BoxError;
|
||||
use async_trait::async_trait;
|
||||
use axum_core::body::Body;
|
||||
use axum_core::response::{IntoResponse, Response};
|
||||
use axum_core::RequestExt;
|
||||
use http::header::CONTENT_TYPE;
|
||||
|
@ -64,17 +63,14 @@ use serde::Serialize;
|
|||
pub struct Form<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for Form<T>
|
||||
impl<T, S> FromRequest<S> for Form<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = FormRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let is_get_or_head =
|
||||
req.method() == http::Method::GET || req.method() == http::Method::HEAD;
|
||||
|
||||
|
@ -120,12 +116,11 @@ axum_core::__impl_deref!(Form);
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
body::{Empty, Full},
|
||||
body::Body,
|
||||
routing::{on, MethodFilter},
|
||||
test_helpers::TestClient,
|
||||
Router,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use http::{header::CONTENT_TYPE, Method, Request};
|
||||
use mime::APPLICATION_WWW_FORM_URLENCODED;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -140,7 +135,7 @@ mod tests {
|
|||
async fn check_query<T: DeserializeOwned + PartialEq + Debug>(uri: impl AsRef<str>, value: T) {
|
||||
let req = Request::builder()
|
||||
.uri(uri.as_ref())
|
||||
.body(Empty::<Bytes>::new())
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
assert_eq!(Form::<T>::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
@ -150,9 +145,7 @@ mod tests {
|
|||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(CONTENT_TYPE, APPLICATION_WWW_FORM_URLENCODED.as_ref())
|
||||
.body(Full::<Bytes>::new(
|
||||
serde_urlencoded::to_string(&value).unwrap().into(),
|
||||
))
|
||||
.body(Body::from(serde_urlencoded::to_string(&value).unwrap()))
|
||||
.unwrap();
|
||||
assert_eq!(Form::<T>::from_request(req, &()).await.unwrap().0, value);
|
||||
}
|
||||
|
@ -214,13 +207,12 @@ mod tests {
|
|||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
|
||||
.body(Full::<Bytes>::new(
|
||||
.body(Body::from(
|
||||
serde_urlencoded::to_string(&Pagination {
|
||||
size: Some(10),
|
||||
page: None,
|
||||
})
|
||||
.unwrap()
|
||||
.into(),
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Handler future types.
|
||||
|
||||
use crate::body::Body;
|
||||
use crate::response::Response;
|
||||
use futures_util::future::Map;
|
||||
use http::Request;
|
||||
|
@ -19,29 +20,29 @@ opaque_future! {
|
|||
|
||||
pin_project! {
|
||||
/// The response future for [`Layered`](super::Layered).
|
||||
pub struct LayeredFuture<B, S>
|
||||
pub struct LayeredFuture<S>
|
||||
where
|
||||
S: Service<Request<B>>,
|
||||
S: Service<Request<Body>>,
|
||||
{
|
||||
#[pin]
|
||||
inner: Map<Oneshot<S, Request<B>>, fn(Result<S::Response, S::Error>) -> Response>,
|
||||
inner: Map<Oneshot<S, Request<Body>>, fn(Result<S::Response, S::Error>) -> Response>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, S> LayeredFuture<B, S>
|
||||
impl<S> LayeredFuture<S>
|
||||
where
|
||||
S: Service<Request<B>>,
|
||||
S: Service<Request<Body>>,
|
||||
{
|
||||
pub(super) fn new(
|
||||
inner: Map<Oneshot<S, Request<B>>, fn(Result<S::Response, S::Error>) -> Response>,
|
||||
inner: Map<Oneshot<S, Request<Body>>, fn(Result<S::Response, S::Error>) -> Response>,
|
||||
) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, S> Future for LayeredFuture<B, S>
|
||||
impl<S> Future for LayeredFuture<S>
|
||||
where
|
||||
S: Service<Request<B>>,
|
||||
S: Service<Request<Body>>,
|
||||
{
|
||||
type Output = Response;
|
||||
|
||||
|
|
|
@ -37,11 +37,11 @@
|
|||
#[cfg(feature = "tokio")]
|
||||
use crate::extract::connect_info::IntoMakeServiceWithConnectInfo;
|
||||
use crate::{
|
||||
body::Body,
|
||||
extract::{FromRequest, FromRequestParts},
|
||||
response::{IntoResponse, Response},
|
||||
routing::IntoMakeService,
|
||||
};
|
||||
use axum_core::body::Body;
|
||||
use http::Request;
|
||||
use std::{convert::Infallible, fmt, future::Future, marker::PhantomData, pin::Pin};
|
||||
use tower::ServiceExt;
|
||||
|
@ -99,12 +99,12 @@ pub use self::service::HandlerService;
|
|||
note = "Consider using `#[axum::debug_handler]` to improve the error message"
|
||||
)
|
||||
)]
|
||||
pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
|
||||
pub trait Handler<T, S>: Clone + Send + Sized + 'static {
|
||||
/// The type of future calling this handler returns.
|
||||
type Future: Future<Output = Response> + Send + 'static;
|
||||
|
||||
/// Call the handler with the given request.
|
||||
fn call(self, req: Request<B>, state: S) -> Self::Future;
|
||||
fn call(self, req: Request<Body>, state: S) -> Self::Future;
|
||||
|
||||
/// Apply a [`tower::Layer`] to the handler.
|
||||
///
|
||||
|
@ -142,10 +142,10 @@ pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
fn layer<L, NewReqBody>(self, layer: L) -> Layered<L, Self, T, S, B, NewReqBody>
|
||||
fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>
|
||||
where
|
||||
L: Layer<HandlerService<Self, T, S, B>> + Clone,
|
||||
L::Service: Service<Request<NewReqBody>>,
|
||||
L: Layer<HandlerService<Self, T, S>> + Clone,
|
||||
L::Service: Service<Request<Body>>,
|
||||
{
|
||||
Layered {
|
||||
layer,
|
||||
|
@ -155,21 +155,20 @@ pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
|
|||
}
|
||||
|
||||
/// Convert the handler into a [`Service`] by providing the state
|
||||
fn with_state(self, state: S) -> HandlerService<Self, T, S, B> {
|
||||
fn with_state(self, state: S) -> HandlerService<Self, T, S> {
|
||||
HandlerService::new(self, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Fut, Res, S, B> Handler<((),), S, B> for F
|
||||
impl<F, Fut, Res, S> Handler<((),), S> for F
|
||||
where
|
||||
F: FnOnce() -> Fut + Clone + Send + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
Res: IntoResponse,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
|
||||
|
||||
fn call(self, _req: Request<B>, _state: S) -> Self::Future {
|
||||
fn call(self, _req: Request<Body>, _state: S) -> Self::Future {
|
||||
Box::pin(async move { self().await.into_response() })
|
||||
}
|
||||
}
|
||||
|
@ -179,19 +178,18 @@ macro_rules! impl_handler {
|
|||
[$($ty:ident),*], $last:ident
|
||||
) => {
|
||||
#[allow(non_snake_case, unused_mut)]
|
||||
impl<F, Fut, S, B, Res, M, $($ty,)* $last> Handler<(M, $($ty,)* $last,), S, B> for F
|
||||
impl<F, Fut, S, Res, M, $($ty,)* $last> Handler<(M, $($ty,)* $last,), S> for F
|
||||
where
|
||||
F: FnOnce($($ty,)* $last,) -> Fut + Clone + Send + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
B: Send + 'static,
|
||||
S: Send + Sync + 'static,
|
||||
Res: IntoResponse,
|
||||
$( $ty: FromRequestParts<S> + Send, )*
|
||||
$last: FromRequest<S, B, M> + Send,
|
||||
$last: FromRequest<S, M> + Send,
|
||||
{
|
||||
type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
|
||||
|
||||
fn call(self, req: Request<B>, state: S) -> Self::Future {
|
||||
fn call(self, req: Request<Body>, state: S) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
let (mut parts, body) = req.into_parts();
|
||||
let state = &state;
|
||||
|
@ -224,13 +222,13 @@ all_the_tuples!(impl_handler);
|
|||
/// A [`Service`] created from a [`Handler`] by applying a Tower middleware.
|
||||
///
|
||||
/// Created with [`Handler::layer`]. See that method for more details.
|
||||
pub struct Layered<L, H, T, S, B, B2> {
|
||||
pub struct Layered<L, H, T, S> {
|
||||
layer: L,
|
||||
handler: H,
|
||||
_marker: PhantomData<fn() -> (T, S, B, B2)>,
|
||||
_marker: PhantomData<fn() -> (T, S)>,
|
||||
}
|
||||
|
||||
impl<L, H, T, S, B, B2> fmt::Debug for Layered<L, H, T, S, B, B2>
|
||||
impl<L, H, T, S> fmt::Debug for Layered<L, H, T, S>
|
||||
where
|
||||
L: fmt::Debug,
|
||||
{
|
||||
|
@ -241,7 +239,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<L, H, T, S, B, B2> Clone for Layered<L, H, T, S, B, B2>
|
||||
impl<L, H, T, S> Clone for Layered<L, H, T, S>
|
||||
where
|
||||
L: Clone,
|
||||
H: Clone,
|
||||
|
@ -255,21 +253,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, S, T, L, B, B2> Handler<T, S, B2> for Layered<L, H, T, S, B, B2>
|
||||
impl<H, S, T, L> Handler<T, S> for Layered<L, H, T, S>
|
||||
where
|
||||
L: Layer<HandlerService<H, T, S, B>> + Clone + Send + 'static,
|
||||
H: Handler<T, S, B>,
|
||||
L::Service: Service<Request<B2>, Error = Infallible> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<B2>>>::Response: IntoResponse,
|
||||
<L::Service as Service<Request<B2>>>::Future: Send,
|
||||
L: Layer<HandlerService<H, T, S>> + Clone + Send + 'static,
|
||||
H: Handler<T, S>,
|
||||
L::Service: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send,
|
||||
T: 'static,
|
||||
S: 'static,
|
||||
B: Send + 'static,
|
||||
B2: Send + 'static,
|
||||
{
|
||||
type Future = future::LayeredFuture<B2, L::Service>;
|
||||
type Future = future::LayeredFuture<L::Service>;
|
||||
|
||||
fn call(self, req: Request<B2>, state: S) -> Self::Future {
|
||||
fn call(self, req: Request<Body>, state: S) -> Self::Future {
|
||||
use futures_util::future::{FutureExt, Map};
|
||||
|
||||
let svc = self.handler.with_state(state);
|
||||
|
@ -279,8 +275,8 @@ where
|
|||
_,
|
||||
fn(
|
||||
Result<
|
||||
<L::Service as Service<Request<B2>>>::Response,
|
||||
<L::Service as Service<Request<B2>>>::Error,
|
||||
<L::Service as Service<Request<Body>>>::Response,
|
||||
<L::Service as Service<Request<Body>>>::Error,
|
||||
>,
|
||||
) -> _,
|
||||
> = svc.oneshot(req).map(|result| match result {
|
||||
|
@ -297,16 +293,16 @@ where
|
|||
/// This provides convenience methods to convert the [`Handler`] into a [`Service`] or [`MakeService`].
|
||||
///
|
||||
/// [`MakeService`]: tower::make::MakeService
|
||||
pub trait HandlerWithoutStateExt<T, B>: Handler<T, (), B> {
|
||||
pub trait HandlerWithoutStateExt<T>: Handler<T, ()> {
|
||||
/// Convert the handler into a [`Service`] and no state.
|
||||
fn into_service(self) -> HandlerService<Self, T, (), B>;
|
||||
fn into_service(self) -> HandlerService<Self, T, ()>;
|
||||
|
||||
/// Convert the handler into a [`MakeService`] and no state.
|
||||
///
|
||||
/// See [`HandlerService::into_make_service`] for more details.
|
||||
///
|
||||
/// [`MakeService`]: tower::make::MakeService
|
||||
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>>;
|
||||
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, ()>>;
|
||||
|
||||
/// Convert the handler into a [`MakeService`] which stores information
|
||||
/// about the incoming connection and has no state.
|
||||
|
@ -317,25 +313,25 @@ pub trait HandlerWithoutStateExt<T, B>: Handler<T, (), B> {
|
|||
#[cfg(feature = "tokio")]
|
||||
fn into_make_service_with_connect_info<C>(
|
||||
self,
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C>;
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, ()>, C>;
|
||||
}
|
||||
|
||||
impl<H, T, B> HandlerWithoutStateExt<T, B> for H
|
||||
impl<H, T> HandlerWithoutStateExt<T> for H
|
||||
where
|
||||
H: Handler<T, (), B>,
|
||||
H: Handler<T, ()>,
|
||||
{
|
||||
fn into_service(self) -> HandlerService<Self, T, (), B> {
|
||||
fn into_service(self) -> HandlerService<Self, T, ()> {
|
||||
self.with_state(())
|
||||
}
|
||||
|
||||
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>> {
|
||||
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, ()>> {
|
||||
self.into_service().into_make_service()
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
fn into_make_service_with_connect_info<C>(
|
||||
self,
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C> {
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, ()>, C> {
|
||||
self.into_service().into_make_service_with_connect_info()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use super::Handler;
|
||||
use crate::body::{Body, Bytes, HttpBody};
|
||||
#[cfg(feature = "tokio")]
|
||||
use crate::extract::connect_info::IntoMakeServiceWithConnectInfo;
|
||||
use crate::response::Response;
|
||||
use crate::routing::IntoMakeService;
|
||||
use crate::BoxError;
|
||||
use http::Request;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
|
@ -17,13 +19,13 @@ use tower_service::Service;
|
|||
/// Created with [`Handler::with_state`] or [`HandlerWithoutStateExt::into_service`].
|
||||
///
|
||||
/// [`HandlerWithoutStateExt::into_service`]: super::HandlerWithoutStateExt::into_service
|
||||
pub struct HandlerService<H, T, S, B> {
|
||||
pub struct HandlerService<H, T, S> {
|
||||
handler: H,
|
||||
state: S,
|
||||
_marker: PhantomData<fn() -> (T, B)>,
|
||||
_marker: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<H, T, S, B> HandlerService<H, T, S, B> {
|
||||
impl<H, T, S> HandlerService<H, T, S> {
|
||||
/// Get a reference to the state.
|
||||
pub fn state(&self) -> &S {
|
||||
&self.state
|
||||
|
@ -61,7 +63,7 @@ impl<H, T, S, B> HandlerService<H, T, S, B> {
|
|||
/// ```
|
||||
///
|
||||
/// [`MakeService`]: tower::make::MakeService
|
||||
pub fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, S, B>> {
|
||||
pub fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, S>> {
|
||||
IntoMakeService::new(self)
|
||||
}
|
||||
|
||||
|
@ -104,7 +106,7 @@ impl<H, T, S, B> HandlerService<H, T, S, B> {
|
|||
#[cfg(feature = "tokio")]
|
||||
pub fn into_make_service_with_connect_info<C>(
|
||||
self,
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<H, T, S, B>, C> {
|
||||
) -> IntoMakeServiceWithConnectInfo<HandlerService<H, T, S>, C> {
|
||||
IntoMakeServiceWithConnectInfo::new(self)
|
||||
}
|
||||
}
|
||||
|
@ -112,11 +114,11 @@ impl<H, T, S, B> HandlerService<H, T, S, B> {
|
|||
#[test]
|
||||
fn traits() {
|
||||
use crate::test_helpers::*;
|
||||
assert_send::<HandlerService<(), NotSendSync, (), NotSendSync>>();
|
||||
assert_sync::<HandlerService<(), NotSendSync, (), NotSendSync>>();
|
||||
assert_send::<HandlerService<(), NotSendSync, ()>>();
|
||||
assert_sync::<HandlerService<(), NotSendSync, ()>>();
|
||||
}
|
||||
|
||||
impl<H, T, S, B> HandlerService<H, T, S, B> {
|
||||
impl<H, T, S> HandlerService<H, T, S> {
|
||||
pub(super) fn new(handler: H, state: S) -> Self {
|
||||
Self {
|
||||
handler,
|
||||
|
@ -126,13 +128,13 @@ impl<H, T, S, B> HandlerService<H, T, S, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, T, S, B> fmt::Debug for HandlerService<H, T, S, B> {
|
||||
impl<H, T, S> fmt::Debug for HandlerService<H, T, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("IntoService").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, T, S, B> Clone for HandlerService<H, T, S, B>
|
||||
impl<H, T, S> Clone for HandlerService<H, T, S>
|
||||
where
|
||||
H: Clone,
|
||||
S: Clone,
|
||||
|
@ -146,10 +148,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, T, S, B> Service<Request<B>> for HandlerService<H, T, S, B>
|
||||
impl<H, T, S, B> Service<Request<B>> for HandlerService<H, T, S>
|
||||
where
|
||||
H: Handler<T, S, B> + Clone + Send + 'static,
|
||||
B: Send + 'static,
|
||||
H: Handler<T, S> + Clone + Send + 'static,
|
||||
B: HttpBody<Data = Bytes> + Send + 'static,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Clone + Send + Sync,
|
||||
{
|
||||
type Response = Response;
|
||||
|
@ -167,6 +170,8 @@ where
|
|||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
use futures_util::future::FutureExt;
|
||||
|
||||
let req = req.map(Body::new);
|
||||
|
||||
let handler = self.handler.clone();
|
||||
let future = Handler::call(handler, req, self.state.clone());
|
||||
let future = future.map(Ok as _);
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use crate::{
|
||||
body::{Bytes, HttpBody},
|
||||
extract::{rejection::*, FromRequest},
|
||||
BoxError,
|
||||
};
|
||||
use crate::extract::{rejection::*, FromRequest};
|
||||
use async_trait::async_trait;
|
||||
use axum_core::response::{IntoResponse, Response};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use axum_core::{
|
||||
body::Body,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use http::{
|
||||
header::{self, HeaderMap, HeaderValue},
|
||||
Request, StatusCode,
|
||||
|
@ -100,17 +99,14 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
pub struct Json<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for Json<T>
|
||||
impl<T, S> FromRequest<S> for Json<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = JsonRejection;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
if json_content_type(req.headers()) {
|
||||
let bytes = Bytes::from_request(req, state).await?;
|
||||
let deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::body::{Body, Bytes, HttpBody};
|
||||
use crate::response::{IntoResponse, Response};
|
||||
use crate::BoxError;
|
||||
use axum_core::extract::{FromRequest, FromRequestParts};
|
||||
use futures_util::future::BoxFuture;
|
||||
use http::Request;
|
||||
|
@ -247,7 +249,7 @@ macro_rules! impl_service {
|
|||
where
|
||||
F: FnMut($($ty,)* $last, Next<B>) -> Fut + Clone + Send + 'static,
|
||||
$( $ty: FromRequestParts<S> + Send, )*
|
||||
$last: FromRequest<S, B> + Send,
|
||||
$last: FromRequest<S> + Send,
|
||||
Fut: Future<Output = Out> + Send + 'static,
|
||||
Out: IntoResponse + 'static,
|
||||
I: Service<Request<B>, Error = Infallible>
|
||||
|
@ -256,7 +258,8 @@ macro_rules! impl_service {
|
|||
+ 'static,
|
||||
I::Response: IntoResponse,
|
||||
I::Future: Send + 'static,
|
||||
B: Send + 'static,
|
||||
B: HttpBody<Data = Bytes> + Send + 'static,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Response = Response;
|
||||
|
@ -268,6 +271,8 @@ macro_rules! impl_service {
|
|||
}
|
||||
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
|
||||
let not_ready_inner = self.inner.clone();
|
||||
let ready_inner = std::mem::replace(&mut self.inner, not_ready_inner);
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::body::{Body, Bytes, HttpBody};
|
||||
use crate::response::{IntoResponse, Response};
|
||||
use crate::BoxError;
|
||||
use axum_core::extract::{FromRequest, FromRequestParts};
|
||||
use futures_util::future::BoxFuture;
|
||||
use http::Request;
|
||||
|
@ -251,7 +253,7 @@ macro_rules! impl_service {
|
|||
where
|
||||
F: FnMut($($ty,)* $last) -> Fut + Clone + Send + 'static,
|
||||
$( $ty: FromRequestParts<S> + Send, )*
|
||||
$last: FromRequest<S, B> + Send,
|
||||
$last: FromRequest<S> + Send,
|
||||
Fut: Future + Send + 'static,
|
||||
Fut::Output: IntoMapRequestResult<B> + Send + 'static,
|
||||
I: Service<Request<B>, Error = Infallible>
|
||||
|
@ -260,7 +262,8 @@ macro_rules! impl_service {
|
|||
+ 'static,
|
||||
I::Response: IntoResponse,
|
||||
I::Future: Send + 'static,
|
||||
B: Send + 'static,
|
||||
B: HttpBody<Data = Bytes> + Send + 'static,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Response = Response;
|
||||
|
@ -272,6 +275,8 @@ macro_rules! impl_service {
|
|||
}
|
||||
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
|
||||
let not_ready_inner = self.inner.clone();
|
||||
let mut ready_inner = std::mem::replace(&mut self.inner, not_ready_inner);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ impl<T> From<T> for Html<T> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::extract::Extension;
|
||||
use crate::{body::Body, routing::get, Router};
|
||||
use crate::{routing::get, Router};
|
||||
use axum_core::response::IntoResponse;
|
||||
use http::HeaderMap;
|
||||
use http::{StatusCode, Uri};
|
||||
|
@ -99,7 +99,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
_ = Router::<(), Body>::new()
|
||||
_ = Router::<()>::new()
|
||||
.route("/", get(impl_trait_ok))
|
||||
.route("/", get(impl_trait_err))
|
||||
.route("/", get(impl_trait_both))
|
||||
|
@ -209,7 +209,7 @@ mod tests {
|
|||
)
|
||||
}
|
||||
|
||||
_ = Router::<(), Body>::new()
|
||||
_ = Router::<()>::new()
|
||||
.route("/", get(status))
|
||||
.route("/", get(status_headermap))
|
||||
.route("/", get(status_header_array))
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
response::Response,
|
||||
routing::{future::RouteFuture, Fallback, MethodFilter, Route},
|
||||
};
|
||||
use axum_core::response::IntoResponse;
|
||||
use axum_core::{response::IntoResponse, BoxError};
|
||||
use bytes::BytesMut;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
|
@ -37,10 +37,10 @@ macro_rules! top_level_service_fn {
|
|||
/// http::Request,
|
||||
/// Router,
|
||||
/// routing::get_service,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -78,12 +78,11 @@ macro_rules! top_level_service_fn {
|
|||
$name:ident, $method:ident
|
||||
) => {
|
||||
$(#[$m])+
|
||||
pub fn $name<T, S, B>(svc: T) -> MethodRouter<S, B, T::Error>
|
||||
pub fn $name<T, S>(svc: T) -> MethodRouter<S, T::Error>
|
||||
where
|
||||
T: Service<Request<B>> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
on_service(MethodFilter::$method, svc)
|
||||
|
@ -140,10 +139,9 @@ macro_rules! top_level_handler_fn {
|
|||
$name:ident, $method:ident
|
||||
) => {
|
||||
$(#[$m])+
|
||||
pub fn $name<H, T, S, B>(handler: H) -> MethodRouter<S, B, Infallible>
|
||||
pub fn $name<H, T, S>(handler: H) -> MethodRouter<S, Infallible>
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
B: HttpBody + Send + 'static,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
|
@ -166,10 +164,10 @@ macro_rules! chained_service_fn {
|
|||
/// http::Request,
|
||||
/// Router,
|
||||
/// routing::post_service,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -215,7 +213,7 @@ macro_rules! chained_service_fn {
|
|||
#[track_caller]
|
||||
pub fn $name<T>(self, svc: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = E>
|
||||
T: Service<Request<Body>, Error = E>
|
||||
+ Clone
|
||||
+ Send
|
||||
+ 'static,
|
||||
|
@ -279,7 +277,7 @@ macro_rules! chained_handler_fn {
|
|||
#[track_caller]
|
||||
pub fn $name<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
|
@ -306,11 +304,11 @@ top_level_service_fn!(trace_service, TRACE);
|
|||
/// http::Request,
|
||||
/// routing::on,
|
||||
/// Router,
|
||||
/// body::Body,
|
||||
/// routing::{MethodFilter, on_service},
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -322,12 +320,11 @@ top_level_service_fn!(trace_service, TRACE);
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on_service<T, S, B>(filter: MethodFilter, svc: T) -> MethodRouter<S, B, T::Error>
|
||||
pub fn on_service<T, S>(filter: MethodFilter, svc: T) -> MethodRouter<S, T::Error>
|
||||
where
|
||||
T: Service<Request<B>> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
MethodRouter::new().on_service(filter, svc)
|
||||
|
@ -342,10 +339,10 @@ where
|
|||
/// http::Request,
|
||||
/// Router,
|
||||
/// routing::any_service,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -365,10 +362,10 @@ where
|
|||
/// http::Request,
|
||||
/// Router,
|
||||
/// routing::any_service,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// # Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -386,12 +383,11 @@ where
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn any_service<T, S, B>(svc: T) -> MethodRouter<S, B, T::Error>
|
||||
pub fn any_service<T, S>(svc: T) -> MethodRouter<S, T::Error>
|
||||
where
|
||||
T: Service<Request<B>> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
MethodRouter::new()
|
||||
|
@ -427,10 +423,9 @@ top_level_handler_fn!(trace, TRACE);
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on<H, T, S, B>(filter: MethodFilter, handler: H) -> MethodRouter<S, B, Infallible>
|
||||
pub fn on<H, T, S>(filter: MethodFilter, handler: H) -> MethodRouter<S, Infallible>
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
B: HttpBody + Send + 'static,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
|
@ -474,10 +469,9 @@ where
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn any<H, T, S, B>(handler: H) -> MethodRouter<S, B, Infallible>
|
||||
pub fn any<H, T, S>(handler: H) -> MethodRouter<S, Infallible>
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
B: HttpBody + Send + 'static,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
|
@ -514,16 +508,16 @@ where
|
|||
/// {}
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub struct MethodRouter<S = (), B = Body, E = Infallible> {
|
||||
get: MethodEndpoint<S, B, E>,
|
||||
head: MethodEndpoint<S, B, E>,
|
||||
delete: MethodEndpoint<S, B, E>,
|
||||
options: MethodEndpoint<S, B, E>,
|
||||
patch: MethodEndpoint<S, B, E>,
|
||||
post: MethodEndpoint<S, B, E>,
|
||||
put: MethodEndpoint<S, B, E>,
|
||||
trace: MethodEndpoint<S, B, E>,
|
||||
fallback: Fallback<S, B, E>,
|
||||
pub struct MethodRouter<S = (), E = Infallible> {
|
||||
get: MethodEndpoint<S, E>,
|
||||
head: MethodEndpoint<S, E>,
|
||||
delete: MethodEndpoint<S, E>,
|
||||
options: MethodEndpoint<S, E>,
|
||||
patch: MethodEndpoint<S, E>,
|
||||
post: MethodEndpoint<S, E>,
|
||||
put: MethodEndpoint<S, E>,
|
||||
trace: MethodEndpoint<S, E>,
|
||||
fallback: Fallback<S, E>,
|
||||
allow_header: AllowHeader,
|
||||
}
|
||||
|
||||
|
@ -553,7 +547,7 @@ impl AllowHeader {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> fmt::Debug for MethodRouter<S, B, E> {
|
||||
impl<S, E> fmt::Debug for MethodRouter<S, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("MethodRouter")
|
||||
.field("get", &self.get)
|
||||
|
@ -570,9 +564,8 @@ impl<S, B, E> fmt::Debug for MethodRouter<S, B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> MethodRouter<S, B, Infallible>
|
||||
impl<S> MethodRouter<S, Infallible>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
/// Chain an additional handler that will accept requests matching the given
|
||||
|
@ -601,7 +594,7 @@ where
|
|||
#[track_caller]
|
||||
pub fn on<H, T>(self, filter: MethodFilter, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
|
@ -623,7 +616,7 @@ where
|
|||
/// Add a fallback [`Handler`] to the router.
|
||||
pub fn fallback<H, T>(mut self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
|
@ -632,10 +625,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> MethodRouter<(), B, Infallible>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
impl MethodRouter<(), Infallible> {
|
||||
/// Convert the handler into a [`MakeService`].
|
||||
///
|
||||
/// This allows you to serve a single handler if you don't need any routing:
|
||||
|
@ -706,15 +696,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> MethodRouter<S, B, E>
|
||||
impl<S, E> MethodRouter<S, E>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
/// 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<B>| async {
|
||||
let fallback = Route::new(service_fn(|_: Request<Body>| async {
|
||||
Ok(StatusCode::METHOD_NOT_ALLOWED.into_response())
|
||||
}));
|
||||
|
||||
|
@ -733,7 +722,7 @@ where
|
|||
}
|
||||
|
||||
/// Provide the state for the router.
|
||||
pub fn with_state<S2>(self, state: S) -> MethodRouter<S2, B, E> {
|
||||
pub fn with_state<S2>(self, state: S) -> MethodRouter<S2, E> {
|
||||
MethodRouter {
|
||||
get: self.get.with_state(&state),
|
||||
head: self.head.with_state(&state),
|
||||
|
@ -758,10 +747,10 @@ where
|
|||
/// http::Request,
|
||||
/// Router,
|
||||
/// routing::{MethodFilter, on_service},
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use http::Response;
|
||||
/// use std::convert::Infallible;
|
||||
/// use hyper::Body;
|
||||
///
|
||||
/// let service = tower::service_fn(|request: Request<Body>| async {
|
||||
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
||||
|
@ -776,7 +765,7 @@ where
|
|||
#[track_caller]
|
||||
pub fn on_service<T>(self, filter: MethodFilter, svc: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = E> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = E> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -784,19 +773,19 @@ where
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
fn on_endpoint(mut self, filter: MethodFilter, endpoint: MethodEndpoint<S, B, E>) -> Self {
|
||||
fn on_endpoint(mut self, filter: MethodFilter, endpoint: MethodEndpoint<S, E>) -> Self {
|
||||
// written as a separate function to generate less IR
|
||||
#[track_caller]
|
||||
fn set_endpoint<S, B, E>(
|
||||
fn set_endpoint<S, E>(
|
||||
method_name: &str,
|
||||
out: &mut MethodEndpoint<S, B, E>,
|
||||
endpoint: &MethodEndpoint<S, B, E>,
|
||||
out: &mut MethodEndpoint<S, E>,
|
||||
endpoint: &MethodEndpoint<S, E>,
|
||||
endpoint_filter: MethodFilter,
|
||||
filter: MethodFilter,
|
||||
allow_header: &mut AllowHeader,
|
||||
methods: &[&'static str],
|
||||
) where
|
||||
MethodEndpoint<S, B, E>: Clone,
|
||||
MethodEndpoint<S, E>: Clone,
|
||||
S: Clone,
|
||||
{
|
||||
if endpoint_filter.contains(filter) {
|
||||
|
@ -908,7 +897,7 @@ where
|
|||
#[doc = include_str!("../docs/method_routing/fallback.md")]
|
||||
pub fn fallback_service<T>(mut self, svc: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = E> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = E> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -917,19 +906,18 @@ where
|
|||
}
|
||||
|
||||
#[doc = include_str!("../docs/method_routing/layer.md")]
|
||||
pub fn layer<L, NewReqBody, NewError>(self, layer: L) -> MethodRouter<S, NewReqBody, NewError>
|
||||
pub fn layer<L, NewError>(self, layer: L) -> MethodRouter<S, NewError>
|
||||
where
|
||||
L: Layer<Route<B, E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Error: Into<NewError> + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
|
||||
L: Layer<Route<E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<NewError> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
E: 'static,
|
||||
S: 'static,
|
||||
NewReqBody: HttpBody + 'static,
|
||||
NewError: 'static,
|
||||
{
|
||||
let layer_fn = move |route: Route<B, E>| route.layer(layer.clone());
|
||||
let layer_fn = move |route: Route<E>| route.layer(layer.clone());
|
||||
|
||||
MethodRouter {
|
||||
get: self.get.map(layer_fn.clone()),
|
||||
|
@ -947,12 +935,12 @@ where
|
|||
|
||||
#[doc = include_str!("../docs/method_routing/route_layer.md")]
|
||||
#[track_caller]
|
||||
pub fn route_layer<L>(mut self, layer: L) -> MethodRouter<S, B, E>
|
||||
pub fn route_layer<L>(mut self, layer: L) -> MethodRouter<S, E>
|
||||
where
|
||||
L: Layer<Route<B, E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<B>, Error = E> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<B>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<B>>>::Future: Send + 'static,
|
||||
L: Layer<Route<E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>, Error = E> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
E: 'static,
|
||||
S: 'static,
|
||||
{
|
||||
|
@ -990,19 +978,15 @@ where
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn merge_for_path(
|
||||
mut self,
|
||||
path: Option<&str>,
|
||||
other: MethodRouter<S, B, E>,
|
||||
) -> Self {
|
||||
pub(crate) fn merge_for_path(mut self, path: Option<&str>, other: MethodRouter<S, E>) -> Self {
|
||||
// written using inner functions to generate less IR
|
||||
#[track_caller]
|
||||
fn merge_inner<S, B, E>(
|
||||
fn merge_inner<S, E>(
|
||||
path: Option<&str>,
|
||||
name: &str,
|
||||
first: MethodEndpoint<S, B, E>,
|
||||
second: MethodEndpoint<S, B, E>,
|
||||
) -> MethodEndpoint<S, B, E> {
|
||||
first: MethodEndpoint<S, E>,
|
||||
second: MethodEndpoint<S, E>,
|
||||
) -> MethodEndpoint<S, E> {
|
||||
match (first, second) {
|
||||
(MethodEndpoint::None, MethodEndpoint::None) => MethodEndpoint::None,
|
||||
(pick, MethodEndpoint::None) | (MethodEndpoint::None, pick) => pick,
|
||||
|
@ -1042,22 +1026,21 @@ where
|
|||
|
||||
#[doc = include_str!("../docs/method_routing/merge.md")]
|
||||
#[track_caller]
|
||||
pub fn merge(self, other: MethodRouter<S, B, E>) -> Self {
|
||||
pub fn merge(self, other: MethodRouter<S, E>) -> Self {
|
||||
self.merge_for_path(None, other)
|
||||
}
|
||||
|
||||
/// Apply a [`HandleErrorLayer`].
|
||||
///
|
||||
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
|
||||
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, B, Infallible>
|
||||
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, Infallible>
|
||||
where
|
||||
F: Clone + Send + Sync + 'static,
|
||||
HandleError<Route<B, E>, F, T>: Service<Request<B>, Error = Infallible>,
|
||||
<HandleError<Route<B, E>, F, T> as Service<Request<B>>>::Future: Send,
|
||||
<HandleError<Route<B, E>, F, T> as Service<Request<B>>>::Response: IntoResponse + Send,
|
||||
HandleError<Route<E>, F, T>: Service<Request<Body>, Error = Infallible>,
|
||||
<HandleError<Route<E>, F, T> as Service<Request<Body>>>::Future: Send,
|
||||
<HandleError<Route<E>, F, T> as Service<Request<Body>>>::Response: IntoResponse + Send,
|
||||
T: 'static,
|
||||
E: 'static,
|
||||
B: 'static,
|
||||
S: 'static,
|
||||
{
|
||||
self.layer(HandleErrorLayer::new(f))
|
||||
|
@ -1068,7 +1051,7 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn call_with_state(&mut self, req: Request<B>, state: S) -> RouteFuture<B, E> {
|
||||
pub(crate) fn call_with_state(&mut self, req: Request<Body>, state: S) -> RouteFuture<E> {
|
||||
macro_rules! call {
|
||||
(
|
||||
$req:expr,
|
||||
|
@ -1157,7 +1140,7 @@ fn append_allow_header(allow_header: &mut AllowHeader, method: &'static str) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> Clone for MethodRouter<S, B, E> {
|
||||
impl<S, E> Clone for MethodRouter<S, E> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
get: self.get.clone(),
|
||||
|
@ -1174,9 +1157,8 @@ impl<S, B, E> Clone for MethodRouter<S, B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> Default for MethodRouter<S, B, E>
|
||||
impl<S, E> Default for MethodRouter<S, E>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone,
|
||||
{
|
||||
fn default() -> Self {
|
||||
|
@ -1184,13 +1166,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
enum MethodEndpoint<S, B, E> {
|
||||
enum MethodEndpoint<S, E> {
|
||||
None,
|
||||
Route(Route<B, E>),
|
||||
BoxedHandler(BoxedIntoRoute<S, B, E>),
|
||||
Route(Route<E>),
|
||||
BoxedHandler(BoxedIntoRoute<S, E>),
|
||||
}
|
||||
|
||||
impl<S, B, E> MethodEndpoint<S, B, E>
|
||||
impl<S, E> MethodEndpoint<S, E>
|
||||
where
|
||||
S: Clone,
|
||||
{
|
||||
|
@ -1202,13 +1184,11 @@ where
|
|||
matches!(self, Self::None)
|
||||
}
|
||||
|
||||
fn map<F, B2, E2>(self, f: F) -> MethodEndpoint<S, B2, E2>
|
||||
fn map<F, E2>(self, f: F) -> MethodEndpoint<S, E2>
|
||||
where
|
||||
S: 'static,
|
||||
B: 'static,
|
||||
E: 'static,
|
||||
F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + Send + 'static,
|
||||
B2: HttpBody + 'static,
|
||||
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
|
||||
E2: 'static,
|
||||
{
|
||||
match self {
|
||||
|
@ -1218,7 +1198,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn with_state<S2>(self, state: &S) -> MethodEndpoint<S2, B, E> {
|
||||
fn with_state<S2>(self, state: &S) -> MethodEndpoint<S2, E> {
|
||||
match self {
|
||||
MethodEndpoint::None => MethodEndpoint::None,
|
||||
MethodEndpoint::Route(route) => MethodEndpoint::Route(route),
|
||||
|
@ -1229,7 +1209,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> Clone for MethodEndpoint<S, B, E> {
|
||||
impl<S, E> Clone for MethodEndpoint<S, E> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::None => Self::None,
|
||||
|
@ -1239,7 +1219,7 @@ impl<S, B, E> Clone for MethodEndpoint<S, B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> fmt::Debug for MethodEndpoint<S, B, E> {
|
||||
impl<S, E> fmt::Debug for MethodEndpoint<S, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::None => f.debug_tuple("None").finish(),
|
||||
|
@ -1249,13 +1229,14 @@ impl<S, B, E> fmt::Debug for MethodEndpoint<S, B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, E> Service<Request<B>> for MethodRouter<(), B, E>
|
||||
impl<B, E> Service<Request<B>> for MethodRouter<(), E>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B: HttpBody<Data = Bytes> + Send + 'static,
|
||||
B::Error: Into<BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = E;
|
||||
type Future = RouteFuture<B, E>;
|
||||
type Future = RouteFuture<E>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
|
@ -1264,18 +1245,18 @@ where
|
|||
|
||||
#[inline]
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
self.call_with_state(req, ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, B> Handler<(), S, B> for MethodRouter<S, B>
|
||||
impl<S> Handler<(), S> for MethodRouter<S>
|
||||
where
|
||||
S: Clone + 'static,
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
type Future = InfallibleRouteFuture<B>;
|
||||
type Future = InfallibleRouteFuture;
|
||||
|
||||
fn call(mut self, req: Request<B>, state: S) -> Self::Future {
|
||||
fn call(mut self, req: Request<Body>, state: S) -> Self::Future {
|
||||
InfallibleRouteFuture::new(self.call_with_state(req, state))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use http::Request;
|
|||
use std::{
|
||||
convert::Infallible,
|
||||
fmt,
|
||||
task::{Context, Poll},
|
||||
task::{Context, Poll}, marker::PhantomData,
|
||||
};
|
||||
use sync_wrapper::SyncWrapper;
|
||||
use tower_layer::Layer;
|
||||
|
@ -56,13 +56,13 @@ pub(crate) struct RouteId(u32);
|
|||
|
||||
/// The router type for composing handlers and services.
|
||||
#[must_use]
|
||||
pub struct Router<S = (), B = Body> {
|
||||
path_router: PathRouter<S, B, false>,
|
||||
fallback_router: PathRouter<S, B, true>,
|
||||
pub struct Router<S = ()> {
|
||||
path_router: PathRouter<S, false>,
|
||||
fallback_router: PathRouter<S, true>,
|
||||
default_fallback: bool,
|
||||
}
|
||||
|
||||
impl<S, B> Clone for Router<S, B> {
|
||||
impl<S> Clone for Router<S> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
path_router: self.path_router.clone(),
|
||||
|
@ -72,9 +72,8 @@ impl<S, B> Clone for Router<S, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Default for Router<S, B>
|
||||
impl<S> Default for Router<S>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn default() -> Self {
|
||||
|
@ -82,7 +81,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> fmt::Debug for Router<S, B> {
|
||||
impl<S> fmt::Debug for Router<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Router")
|
||||
.field("path_router", &self.path_router)
|
||||
|
@ -96,9 +95,8 @@ pub(crate) const NEST_TAIL_PARAM: &str = "__private__axum_nest_tail_param";
|
|||
pub(crate) const NEST_TAIL_PARAM_CAPTURE: &str = "/*__private__axum_nest_tail_param";
|
||||
pub(crate) const FALLBACK_PARAM: &str = "__private__axum_fallback";
|
||||
|
||||
impl<S, B> Router<S, B>
|
||||
impl<S> Router<S>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
/// Create a new `Router`.
|
||||
|
@ -118,7 +116,7 @@ where
|
|||
|
||||
#[doc = include_str!("../docs/routing/route.md")]
|
||||
#[track_caller]
|
||||
pub fn route(mut self, path: &str, method_router: MethodRouter<S, B>) -> Self {
|
||||
pub fn route(mut self, path: &str, method_router: MethodRouter<S>) -> Self {
|
||||
panic_on_err!(self.path_router.route(path, method_router));
|
||||
self
|
||||
}
|
||||
|
@ -126,11 +124,11 @@ where
|
|||
#[doc = include_str!("../docs/routing/route_service.md")]
|
||||
pub fn route_service<T>(mut self, path: &str, service: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
let service = match try_downcast::<Router<S, B>, _>(service) {
|
||||
let service = match try_downcast::<Router<S>, _>(service) {
|
||||
Ok(_) => {
|
||||
panic!(
|
||||
"Invalid route: `Router::route_service` cannot be used with `Router`s. \
|
||||
|
@ -146,7 +144,7 @@ where
|
|||
|
||||
#[doc = include_str!("../docs/routing/nest.md")]
|
||||
#[track_caller]
|
||||
pub fn nest(mut self, path: &str, router: Router<S, B>) -> Self {
|
||||
pub fn nest(mut self, path: &str, router: Router<S>) -> Self {
|
||||
let Router {
|
||||
path_router,
|
||||
fallback_router,
|
||||
|
@ -166,7 +164,7 @@ where
|
|||
#[track_caller]
|
||||
pub fn nest_service<T>(mut self, path: &str, service: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -178,7 +176,7 @@ where
|
|||
#[track_caller]
|
||||
pub fn merge<R>(mut self, other: R) -> Self
|
||||
where
|
||||
R: Into<Router<S, B>>,
|
||||
R: Into<Router<S>>,
|
||||
{
|
||||
let Router {
|
||||
path_router,
|
||||
|
@ -212,14 +210,13 @@ where
|
|||
}
|
||||
|
||||
#[doc = include_str!("../docs/routing/layer.md")]
|
||||
pub fn layer<L, NewReqBody>(self, layer: L) -> Router<S, NewReqBody>
|
||||
pub fn layer<L>(self, layer: L) -> Router<S>
|
||||
where
|
||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
|
||||
NewReqBody: HttpBody + 'static,
|
||||
L: Layer<Route> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
{
|
||||
Router {
|
||||
path_router: self.path_router.layer(layer.clone()),
|
||||
|
@ -232,11 +229,11 @@ where
|
|||
#[track_caller]
|
||||
pub fn route_layer<L>(self, layer: L) -> Self
|
||||
where
|
||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<B>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<B>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<B>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<B>>>::Future: Send + 'static,
|
||||
L: Layer<Route> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
{
|
||||
Router {
|
||||
path_router: self.path_router.route_layer(layer),
|
||||
|
@ -249,7 +246,7 @@ where
|
|||
#[doc = include_str!("../docs/routing/fallback.md")]
|
||||
pub fn fallback<H, T>(self, handler: H) -> Self
|
||||
where
|
||||
H: Handler<T, S, B>,
|
||||
H: Handler<T, S>,
|
||||
T: 'static,
|
||||
{
|
||||
let endpoint = Endpoint::MethodRouter(any(handler));
|
||||
|
@ -261,14 +258,14 @@ where
|
|||
/// See [`Router::fallback`] for more details.
|
||||
pub fn fallback_service<T>(self, service: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
self.fallback_endpoint(Endpoint::Route(Route::new(service)))
|
||||
}
|
||||
|
||||
fn fallback_endpoint(mut self, endpoint: Endpoint<S, B>) -> Self {
|
||||
fn fallback_endpoint(mut self, endpoint: Endpoint<S>) -> Self {
|
||||
self.fallback_router.replace_endpoint("/", endpoint.clone());
|
||||
self.fallback_router
|
||||
.replace_endpoint(&format!("/*{FALLBACK_PARAM}"), endpoint);
|
||||
|
@ -277,7 +274,7 @@ where
|
|||
}
|
||||
|
||||
#[doc = include_str!("../docs/routing/with_state.md")]
|
||||
pub fn with_state<S2>(self, state: S) -> Router<S2, B> {
|
||||
pub fn with_state<S2>(self, state: S) -> Router<S2> {
|
||||
Router {
|
||||
path_router: self.path_router.with_state(state.clone()),
|
||||
fallback_router: self.fallback_router.with_state(state),
|
||||
|
@ -287,9 +284,9 @@ where
|
|||
|
||||
pub(crate) fn call_with_state(
|
||||
&mut self,
|
||||
mut req: Request<B>,
|
||||
mut req: Request<Body>,
|
||||
state: S,
|
||||
) -> RouteFuture<B, Infallible> {
|
||||
) -> RouteFuture<Infallible> {
|
||||
// required for opaque routers to still inherit the fallback
|
||||
// TODO(david): remove this feature in 0.7
|
||||
if !self.default_fallback {
|
||||
|
@ -303,7 +300,7 @@ where
|
|||
Err((mut req, state)) => {
|
||||
let super_fallback = req
|
||||
.extensions_mut()
|
||||
.remove::<SuperFallback<S, B>>()
|
||||
.remove::<SuperFallback<S>>()
|
||||
.map(|SuperFallback(path_router)| path_router.into_inner());
|
||||
|
||||
if let Some(mut super_fallback) = super_fallback {
|
||||
|
@ -324,12 +321,81 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the router into a borrowed [`Service`] with a fixed request body type, to aid type
|
||||
/// inference.
|
||||
///
|
||||
/// In some cases when calling methods from [`tower::ServiceExt`] on a [`Router`] you might get
|
||||
/// type inference errors along the lines of
|
||||
///
|
||||
/// ```not_rust
|
||||
/// let response = router.ready().await?.call(request).await?;
|
||||
/// ^^^^^ cannot infer type for type parameter `B`
|
||||
/// ```
|
||||
///
|
||||
/// This happens because `Router` implements [`Service`] with `impl<B> Service<Request<B>> for Router<()>`.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// use axum::{
|
||||
/// Router,
|
||||
/// routing::get,
|
||||
/// http::Request,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use tower::{Service, ServiceExt};
|
||||
///
|
||||
/// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let mut router = Router::new().route("/", get(|| async {}));
|
||||
/// let request = Request::new(Body::empty());
|
||||
/// let response = router.ready().await?.call(request).await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Calling `Router::as_service` fixes that:
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// Router,
|
||||
/// routing::get,
|
||||
/// http::Request,
|
||||
/// body::Body,
|
||||
/// };
|
||||
/// use tower::{Service, ServiceExt};
|
||||
///
|
||||
/// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let mut router = Router::new().route("/", get(|| async {}));
|
||||
/// let request = Request::new(Body::empty());
|
||||
/// let response = router.as_service().ready().await?.call(request).await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// This is mainly used when calling `Router` in tests. It shouldn't be necessary when running
|
||||
/// the `Router` normally via [`Router::into_make_service`].
|
||||
pub fn as_service<B>(&mut self) -> RouterAsService<'_, B, S> {
|
||||
RouterAsService {
|
||||
router: self,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the router into an owned [`Service`] with a fixed request body type, to aid type
|
||||
/// inference.
|
||||
///
|
||||
/// This is the same as [`Router::as_service`] instead it returns an owned [`Service`]. See
|
||||
/// that method for more details.
|
||||
pub fn into_service<B>(self) -> RouterIntoService<B, S> {
|
||||
RouterIntoService {
|
||||
router: self,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Router<(), B>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
{
|
||||
impl Router {
|
||||
/// Convert this router into a [`MakeService`], that is a [`Service`] whose
|
||||
/// response is another service.
|
||||
///
|
||||
|
@ -368,13 +434,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> Service<Request<B>> for Router<(), B>
|
||||
impl<B> Service<Request<B>> for Router<()>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B: HttpBody<Data = bytes::Bytes> + Send + 'static,
|
||||
B::Error: Into<axum_core::BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = Infallible;
|
||||
type Future = RouteFuture<B, Infallible>;
|
||||
type Future = RouteFuture<Infallible>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
|
@ -383,17 +450,96 @@ where
|
|||
|
||||
#[inline]
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
self.call_with_state(req, ())
|
||||
}
|
||||
}
|
||||
|
||||
enum Fallback<S, B, E = Infallible> {
|
||||
Default(Route<B, E>),
|
||||
Service(Route<B, E>),
|
||||
BoxedHandler(BoxedIntoRoute<S, B, E>),
|
||||
/// A [`Router`] converted into a borrowed [`Service`] with a fixed body type.
|
||||
///
|
||||
/// See [`Router::as_service`] for more details.
|
||||
pub struct RouterAsService<'a, B, S = ()> {
|
||||
router: &'a mut Router<S>,
|
||||
_marker: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<S, B, E> Fallback<S, B, E>
|
||||
impl<'a, B> Service<Request<B>> for RouterAsService<'a, B, ()>
|
||||
where
|
||||
B: HttpBody<Data = bytes::Bytes> + Send + 'static,
|
||||
B::Error: Into<axum_core::BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = Infallible;
|
||||
type Future = RouteFuture<Infallible>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
<Router as Service<Request<B>>>::poll_ready(self.router, cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
self.router.call(req)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B, S> fmt::Debug for RouterAsService<'a, B, S>
|
||||
where
|
||||
S: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("RouterAsService")
|
||||
.field("router", &self.router)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Router`] converted into an owned [`Service`] with a fixed body type.
|
||||
///
|
||||
/// See [`Router::into_service`] for more details.
|
||||
pub struct RouterIntoService<B, S = ()> {
|
||||
router: Router<S>,
|
||||
_marker: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<B> Service<Request<B>> for RouterIntoService<B, ()>
|
||||
where
|
||||
B: HttpBody<Data = bytes::Bytes> + Send + 'static,
|
||||
B::Error: Into<axum_core::BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = Infallible;
|
||||
type Future = RouteFuture<Infallible>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
<Router as Service<Request<B>>>::poll_ready(&mut self.router, cx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
self.router.call(req)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, S> fmt::Debug for RouterIntoService<B, S>
|
||||
where
|
||||
S: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("RouterIntoService")
|
||||
.field("router", &self.router)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
enum Fallback<S, E = Infallible> {
|
||||
Default(Route<E>),
|
||||
Service(Route<E>),
|
||||
BoxedHandler(BoxedIntoRoute<S, E>),
|
||||
}
|
||||
|
||||
impl<S, E> Fallback<S, E>
|
||||
where
|
||||
S: Clone,
|
||||
{
|
||||
|
@ -405,13 +551,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn map<F, B2, E2>(self, f: F) -> Fallback<S, B2, E2>
|
||||
fn map<F, E2>(self, f: F) -> Fallback<S, E2>
|
||||
where
|
||||
S: 'static,
|
||||
B: 'static,
|
||||
E: 'static,
|
||||
F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + Send + 'static,
|
||||
B2: HttpBody + 'static,
|
||||
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
|
||||
E2: 'static,
|
||||
{
|
||||
match self {
|
||||
|
@ -421,7 +565,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn with_state<S2>(self, state: S) -> Fallback<S2, B, E> {
|
||||
fn with_state<S2>(self, state: S) -> Fallback<S2, E> {
|
||||
match self {
|
||||
Fallback::Default(route) => Fallback::Default(route),
|
||||
Fallback::Service(route) => Fallback::Service(route),
|
||||
|
@ -430,7 +574,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> Clone for Fallback<S, B, E> {
|
||||
impl<S, E> Clone for Fallback<S, E> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Default(inner) => Self::Default(inner.clone()),
|
||||
|
@ -440,7 +584,7 @@ impl<S, B, E> Clone for Fallback<S, B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, E> fmt::Debug for Fallback<S, B, E> {
|
||||
impl<S, E> fmt::Debug for Fallback<S, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Default(inner) => f.debug_tuple("Default").field(inner).finish(),
|
||||
|
@ -451,24 +595,22 @@ impl<S, B, E> fmt::Debug for Fallback<S, B, E> {
|
|||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Endpoint<S, B> {
|
||||
MethodRouter(MethodRouter<S, B>),
|
||||
Route(Route<B>),
|
||||
enum Endpoint<S> {
|
||||
MethodRouter(MethodRouter<S>),
|
||||
Route(Route),
|
||||
}
|
||||
|
||||
impl<S, B> Endpoint<S, B>
|
||||
impl<S> Endpoint<S>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
fn layer<L, NewReqBody>(self, layer: L) -> Endpoint<S, NewReqBody>
|
||||
fn layer<L>(self, layer: L) -> Endpoint<S>
|
||||
where
|
||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
|
||||
NewReqBody: HttpBody + 'static,
|
||||
L: Layer<Route> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
{
|
||||
match self {
|
||||
Endpoint::MethodRouter(method_router) => {
|
||||
|
@ -479,7 +621,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> Clone for Endpoint<S, B> {
|
||||
impl<S> Clone for Endpoint<S> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::MethodRouter(inner) => Self::MethodRouter(inner.clone()),
|
||||
|
@ -488,7 +630,7 @@ impl<S, B> Clone for Endpoint<S, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B> fmt::Debug for Endpoint<S, B> {
|
||||
impl<S> fmt::Debug for Endpoint<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::MethodRouter(method_router) => {
|
||||
|
@ -499,11 +641,11 @@ impl<S, B> fmt::Debug for Endpoint<S, B> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SuperFallback<S, B>(SyncWrapper<PathRouter<S, B, true>>);
|
||||
struct SuperFallback<S>(SyncWrapper<PathRouter<S, true>>);
|
||||
|
||||
#[test]
|
||||
#[allow(warnings)]
|
||||
fn traits() {
|
||||
use crate::test_helpers::*;
|
||||
assert_send::<Router<(), ()>>();
|
||||
assert_send::<Router<()>>();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::body::HttpBody;
|
||||
use crate::body::Body;
|
||||
use axum_core::response::IntoResponse;
|
||||
use http::Request;
|
||||
use matchit::MatchError;
|
||||
|
@ -11,21 +11,20 @@ use super::{
|
|||
RouteId, NEST_TAIL_PARAM,
|
||||
};
|
||||
|
||||
pub(super) struct PathRouter<S, B, const IS_FALLBACK: bool> {
|
||||
routes: HashMap<RouteId, Endpoint<S, B>>,
|
||||
pub(super) struct PathRouter<S, const IS_FALLBACK: bool> {
|
||||
routes: HashMap<RouteId, Endpoint<S>>,
|
||||
node: Arc<Node>,
|
||||
prev_route_id: RouteId,
|
||||
}
|
||||
|
||||
impl<S, B, const IS_FALLBACK: bool> PathRouter<S, B, IS_FALLBACK>
|
||||
impl<S, const IS_FALLBACK: bool> PathRouter<S, IS_FALLBACK>
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
pub(super) fn route(
|
||||
&mut self,
|
||||
path: &str,
|
||||
method_router: MethodRouter<S, B>,
|
||||
method_router: MethodRouter<S>,
|
||||
) -> Result<(), Cow<'static, str>> {
|
||||
fn validate_path(path: &str) -> Result<(), &'static str> {
|
||||
if path.is_empty() {
|
||||
|
@ -72,7 +71,7 @@ where
|
|||
service: T,
|
||||
) -> Result<(), Cow<'static, str>>
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -82,7 +81,7 @@ where
|
|||
pub(super) fn route_endpoint(
|
||||
&mut self,
|
||||
path: &str,
|
||||
endpoint: Endpoint<S, B>,
|
||||
endpoint: Endpoint<S>,
|
||||
) -> Result<(), Cow<'static, str>> {
|
||||
if path.is_empty() {
|
||||
return Err("Paths must start with a `/`. Use \"/\" for root routes".into());
|
||||
|
@ -109,7 +108,7 @@ where
|
|||
|
||||
pub(super) fn merge(
|
||||
&mut self,
|
||||
other: PathRouter<S, B, IS_FALLBACK>,
|
||||
other: PathRouter<S, IS_FALLBACK>,
|
||||
) -> Result<(), Cow<'static, str>> {
|
||||
let PathRouter {
|
||||
routes,
|
||||
|
@ -134,7 +133,7 @@ where
|
|||
pub(super) fn nest(
|
||||
&mut self,
|
||||
path: &str,
|
||||
router: PathRouter<S, B, IS_FALLBACK>,
|
||||
router: PathRouter<S, IS_FALLBACK>,
|
||||
) -> Result<(), Cow<'static, str>> {
|
||||
let prefix = validate_nest_path(path);
|
||||
|
||||
|
@ -167,7 +166,7 @@ where
|
|||
|
||||
pub(super) fn nest_service<T>(&mut self, path: &str, svc: T) -> Result<(), Cow<'static, str>>
|
||||
where
|
||||
T: Service<Request<B>, Error = Infallible> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = Infallible> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -196,14 +195,13 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn layer<L, NewReqBody>(self, layer: L) -> PathRouter<S, NewReqBody, IS_FALLBACK>
|
||||
pub(super) fn layer<L>(self, layer: L) -> PathRouter<S, IS_FALLBACK>
|
||||
where
|
||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
|
||||
NewReqBody: HttpBody + 'static,
|
||||
L: Layer<Route> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
{
|
||||
let routes = self
|
||||
.routes
|
||||
|
@ -224,11 +222,11 @@ where
|
|||
#[track_caller]
|
||||
pub(super) fn route_layer<L>(self, layer: L) -> Self
|
||||
where
|
||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<B>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<B>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<B>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<B>>>::Future: Send + 'static,
|
||||
L: Layer<Route> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<Infallible> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
{
|
||||
if self.routes.is_empty() {
|
||||
panic!(
|
||||
|
@ -253,12 +251,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn with_state<S2>(self, state: S) -> PathRouter<S2, B, IS_FALLBACK> {
|
||||
pub(super) fn with_state<S2>(self, state: S) -> PathRouter<S2, IS_FALLBACK> {
|
||||
let routes = self
|
||||
.routes
|
||||
.into_iter()
|
||||
.map(|(id, endpoint)| {
|
||||
let endpoint: Endpoint<S2, B> = match endpoint {
|
||||
let endpoint: Endpoint<S2> = match endpoint {
|
||||
Endpoint::MethodRouter(method_router) => {
|
||||
Endpoint::MethodRouter(method_router.with_state(state.clone()))
|
||||
}
|
||||
|
@ -277,9 +275,9 @@ where
|
|||
|
||||
pub(super) fn call_with_state(
|
||||
&mut self,
|
||||
mut req: Request<B>,
|
||||
mut req: Request<Body>,
|
||||
state: S,
|
||||
) -> Result<RouteFuture<B, Infallible>, (Request<B>, S)> {
|
||||
) -> Result<RouteFuture<Infallible>, (Request<Body>, S)> {
|
||||
#[cfg(feature = "original-uri")]
|
||||
{
|
||||
use crate::extract::OriginalUri;
|
||||
|
@ -329,7 +327,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn replace_endpoint(&mut self, path: &str, endpoint: Endpoint<S, B>) {
|
||||
pub(super) fn replace_endpoint(&mut self, path: &str, endpoint: Endpoint<S>) {
|
||||
match self.node.at(path) {
|
||||
Ok(match_) => {
|
||||
let id = *match_.value;
|
||||
|
@ -352,7 +350,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, S, const IS_FALLBACK: bool> Default for PathRouter<S, B, IS_FALLBACK> {
|
||||
impl<S, const IS_FALLBACK: bool> Default for PathRouter<S, IS_FALLBACK> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
routes: Default::default(),
|
||||
|
@ -362,7 +360,7 @@ impl<B, S, const IS_FALLBACK: bool> Default for PathRouter<S, B, IS_FALLBACK> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, const IS_FALLBACK: bool> fmt::Debug for PathRouter<S, B, IS_FALLBACK> {
|
||||
impl<S, const IS_FALLBACK: bool> fmt::Debug for PathRouter<S, IS_FALLBACK> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PathRouter")
|
||||
.field("routes", &self.routes)
|
||||
|
@ -371,7 +369,7 @@ impl<S, B, const IS_FALLBACK: bool> fmt::Debug for PathRouter<S, B, IS_FALLBACK>
|
|||
}
|
||||
}
|
||||
|
||||
impl<S, B, const IS_FALLBACK: bool> Clone for PathRouter<S, B, IS_FALLBACK> {
|
||||
impl<S, const IS_FALLBACK: bool> Clone for PathRouter<S, IS_FALLBACK> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
routes: self.routes.clone(),
|
||||
|
|
|
@ -27,12 +27,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<B = Body, E = Infallible>(BoxCloneService<Request<B>, Response, E>);
|
||||
pub struct Route<E = Infallible>(BoxCloneService<Request<Body>, Response, E>);
|
||||
|
||||
impl<B, E> Route<B, E> {
|
||||
impl<E> Route<E> {
|
||||
pub(crate) fn new<T>(svc: T) -> Self
|
||||
where
|
||||
T: Service<Request<B>, Error = E> + Clone + Send + 'static,
|
||||
T: Service<Request<Body>, Error = E> + Clone + Send + 'static,
|
||||
T::Response: IntoResponse + 'static,
|
||||
T::Future: Send + 'static,
|
||||
{
|
||||
|
@ -43,22 +43,22 @@ impl<B, E> Route<B, E> {
|
|||
|
||||
pub(crate) fn oneshot_inner(
|
||||
&mut self,
|
||||
req: Request<B>,
|
||||
) -> Oneshot<BoxCloneService<Request<B>, Response, E>, Request<B>> {
|
||||
req: Request<Body>,
|
||||
) -> Oneshot<BoxCloneService<Request<Body>, Response, E>, Request<Body>> {
|
||||
self.0.clone().oneshot(req)
|
||||
}
|
||||
|
||||
pub(crate) fn layer<L, NewReqBody, NewError>(self, layer: L) -> Route<NewReqBody, NewError>
|
||||
pub(crate) fn layer<L, NewError>(self, layer: L) -> Route<NewError>
|
||||
where
|
||||
L: Layer<Route<B, E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Error: Into<NewError> + 'static,
|
||||
<L::Service as Service<Request<NewReqBody>>>::Future: Send + 'static,
|
||||
NewReqBody: 'static,
|
||||
L: Layer<Route<E>> + Clone + Send + 'static,
|
||||
L::Service: Service<Request<Body>> + Clone + Send + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Response: IntoResponse + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Error: Into<NewError> + 'static,
|
||||
<L::Service as Service<Request<Body>>>::Future: Send + 'static,
|
||||
NewError: 'static,
|
||||
{
|
||||
let layer = ServiceBuilder::new()
|
||||
.map_request(|req: Request<_>| req.map(Body::new))
|
||||
.map_err(Into::into)
|
||||
.layer(MapResponseLayer::new(IntoResponse::into_response))
|
||||
.layer(layer)
|
||||
|
@ -68,25 +68,26 @@ impl<B, E> Route<B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, E> Clone for Route<B, E> {
|
||||
impl<E> Clone for Route<E> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E> fmt::Debug for Route<B, E> {
|
||||
impl<E> fmt::Debug for Route<E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Route").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, E> Service<Request<B>> for Route<B, E>
|
||||
impl<B, E> Service<Request<B>> for Route<E>
|
||||
where
|
||||
B: HttpBody,
|
||||
B: HttpBody<Data = bytes::Bytes> + Send + 'static,
|
||||
B::Error: Into<axum_core::BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = E;
|
||||
type Future = RouteFuture<B, E>;
|
||||
type Future = RouteFuture<E>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
|
@ -95,15 +96,16 @@ where
|
|||
|
||||
#[inline]
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req = req.map(Body::new);
|
||||
RouteFuture::from_future(self.oneshot_inner(req))
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
/// Response future for [`Route`].
|
||||
pub struct RouteFuture<B, E> {
|
||||
pub struct RouteFuture<E> {
|
||||
#[pin]
|
||||
kind: RouteFutureKind<B, E>,
|
||||
kind: RouteFutureKind<E>,
|
||||
strip_body: bool,
|
||||
allow_header: Option<Bytes>,
|
||||
}
|
||||
|
@ -111,12 +113,12 @@ pin_project! {
|
|||
|
||||
pin_project! {
|
||||
#[project = RouteFutureKindProj]
|
||||
enum RouteFutureKind<B, E> {
|
||||
enum RouteFutureKind<E> {
|
||||
Future {
|
||||
#[pin]
|
||||
future: Oneshot<
|
||||
BoxCloneService<Request<B>, Response, E>,
|
||||
Request<B>,
|
||||
BoxCloneService<Request<Body>, Response, E>,
|
||||
Request<Body>,
|
||||
>,
|
||||
},
|
||||
Response {
|
||||
|
@ -125,9 +127,9 @@ pin_project! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, E> RouteFuture<B, E> {
|
||||
impl<E> RouteFuture<E> {
|
||||
pub(crate) fn from_future(
|
||||
future: Oneshot<BoxCloneService<Request<B>, Response, E>, Request<B>>,
|
||||
future: Oneshot<BoxCloneService<Request<Body>, Response, E>, Request<Body>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
kind: RouteFutureKind::Future { future },
|
||||
|
@ -147,10 +149,7 @@ impl<B, E> RouteFuture<B, E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B, E> Future for RouteFuture<B, E>
|
||||
where
|
||||
B: HttpBody,
|
||||
{
|
||||
impl<E> Future for RouteFuture<E> {
|
||||
type Output = Result<Response, E>;
|
||||
|
||||
#[inline]
|
||||
|
@ -217,22 +216,19 @@ fn set_content_length(size_hint: http_body::SizeHint, headers: &mut HeaderMap) {
|
|||
|
||||
pin_project! {
|
||||
/// A [`RouteFuture`] that always yields a [`Response`].
|
||||
pub struct InfallibleRouteFuture<B> {
|
||||
pub struct InfallibleRouteFuture {
|
||||
#[pin]
|
||||
future: RouteFuture<B, Infallible>,
|
||||
future: RouteFuture<Infallible>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> InfallibleRouteFuture<B> {
|
||||
pub(crate) fn new(future: RouteFuture<B, Infallible>) -> Self {
|
||||
impl InfallibleRouteFuture {
|
||||
pub(crate) fn new(future: RouteFuture<Infallible>) -> Self {
|
||||
Self { future }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Future for InfallibleRouteFuture<B>
|
||||
where
|
||||
B: HttpBody,
|
||||
{
|
||||
impl Future for InfallibleRouteFuture {
|
||||
type Output = Response;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
|
|
|
@ -176,7 +176,7 @@ async fn fallback_inherited_into_nested_router_service() {
|
|||
.with_state("inner");
|
||||
|
||||
// with a different state
|
||||
let app = Router::<()>::new()
|
||||
let app = Router::new()
|
||||
.nest_service("/foo", inner)
|
||||
.fallback(outer_fallback);
|
||||
|
||||
|
@ -198,7 +198,7 @@ async fn fallback_inherited_into_nested_opaque_service() {
|
|||
.boxed_clone();
|
||||
|
||||
// with a different state
|
||||
let app = Router::<()>::new()
|
||||
let app = Router::new()
|
||||
.nest_service("/foo", inner)
|
||||
.fallback(outer_fallback);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
body::{Bytes, Empty},
|
||||
body::{Body, Bytes, Empty},
|
||||
error_handling::HandleErrorLayer,
|
||||
extract::{self, DefaultBodyLimit, FromRef, Path, State},
|
||||
handler::{Handler, HandlerWithoutStateExt},
|
||||
|
@ -16,7 +16,6 @@ use crate::{
|
|||
};
|
||||
use futures_util::stream::StreamExt;
|
||||
use http::{header::ALLOW, header::CONTENT_LENGTH, HeaderMap, Request, Response, StatusCode, Uri};
|
||||
use hyper::Body;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::{
|
||||
|
@ -206,7 +205,7 @@ async fn middleware_on_single_route() {
|
|||
#[crate::test]
|
||||
async fn service_in_bottom() {
|
||||
async fn handler(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
|
||||
Ok(Response::new(hyper::Body::empty()))
|
||||
Ok(Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
let app = Router::new().route("/", get_service(service_fn(handler)));
|
||||
|
@ -659,7 +658,7 @@ async fn body_limited_by_default() {
|
|||
println!("calling {uri}");
|
||||
|
||||
let stream = futures_util::stream::repeat("a".repeat(1000)).map(Ok::<_, hyper::Error>);
|
||||
let body = Body::wrap_stream(stream);
|
||||
let body = reqwest::Body::wrap_stream(stream);
|
||||
|
||||
let res_future = client
|
||||
.post(uri)
|
||||
|
@ -683,7 +682,7 @@ async fn disabling_the_default_limit() {
|
|||
let client = TestClient::new(app);
|
||||
|
||||
// `DEFAULT_LIMIT` is 2mb so make a body larger than that
|
||||
let body = Body::from("a".repeat(3_000_000));
|
||||
let body = reqwest::Body::from("a".repeat(3_000_000));
|
||||
|
||||
let res = client.post("/").body(body).send().await;
|
||||
|
||||
|
@ -724,14 +723,14 @@ async fn changing_the_default_limit() {
|
|||
|
||||
let res = client
|
||||
.post("/")
|
||||
.body(Body::from("a".repeat(new_limit)))
|
||||
.body(reqwest::Body::from("a".repeat(new_limit)))
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let res = client
|
||||
.post("/")
|
||||
.body(Body::from("a".repeat(new_limit + 1)))
|
||||
.body(reqwest::Body::from("a".repeat(new_limit + 1)))
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
||||
|
@ -755,7 +754,7 @@ async fn limited_body_with_streaming_body() {
|
|||
let stream = futures_util::stream::iter(vec![Ok::<_, hyper::Error>("a".repeat(LIMIT))]);
|
||||
let res = client
|
||||
.post("/")
|
||||
.body(Body::wrap_stream(stream))
|
||||
.body(reqwest::Body::wrap_stream(stream))
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
@ -763,7 +762,7 @@ async fn limited_body_with_streaming_body() {
|
|||
let stream = futures_util::stream::iter(vec![Ok::<_, hyper::Error>("a".repeat(LIMIT * 2))]);
|
||||
let res = client
|
||||
.post("/")
|
||||
.body(Body::wrap_stream(stream))
|
||||
.body(reqwest::Body::wrap_stream(stream))
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
|
||||
|
|
|
@ -264,7 +264,7 @@ async fn multiple_top_level_nests() {
|
|||
#[crate::test]
|
||||
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
||||
async fn nest_cannot_contain_wildcards() {
|
||||
_ = Router::<(), Body>::new().nest("/one/*rest", Router::new());
|
||||
_ = Router::<()>::new().nest("/one/*rest", Router::new());
|
||||
}
|
||||
|
||||
#[crate::test]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{self, BoxBody, Bytes, Full},
|
||||
body::{Body, Bytes},
|
||||
extract::FromRequest,
|
||||
http::{Request, StatusCode},
|
||||
middleware::{self, Next},
|
||||
|
@ -16,7 +16,6 @@ use axum::{
|
|||
};
|
||||
use std::net::SocketAddr;
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::ServiceBuilderExt;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -29,11 +28,9 @@ async fn main() {
|
|||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let app = Router::new().route("/", post(handler)).layer(
|
||||
ServiceBuilder::new()
|
||||
.map_request_body(body::boxed)
|
||||
.layer(middleware::from_fn(print_request_body)),
|
||||
);
|
||||
let app = Router::new()
|
||||
.route("/", post(handler))
|
||||
.layer(ServiceBuilder::new().layer(middleware::from_fn(print_request_body)));
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
|
@ -45,8 +42,8 @@ async fn main() {
|
|||
|
||||
// middleware that shows how to consume the request body upfront
|
||||
async fn print_request_body(
|
||||
request: Request<BoxBody>,
|
||||
next: Next<BoxBody>,
|
||||
request: Request<Body>,
|
||||
next: Next<Body>,
|
||||
) -> Result<impl IntoResponse, Response> {
|
||||
let request = buffer_request_body(request).await?;
|
||||
|
||||
|
@ -55,7 +52,7 @@ async fn print_request_body(
|
|||
|
||||
// the trick is to take the request apart, buffer the body, do what you need to do, then put
|
||||
// the request back together
|
||||
async fn buffer_request_body(request: Request<BoxBody>) -> Result<Request<BoxBody>, Response> {
|
||||
async fn buffer_request_body(request: Request<Body>) -> Result<Request<Body>, Response> {
|
||||
let (parts, body) = request.into_parts();
|
||||
|
||||
// this wont work if the body is an long running stream
|
||||
|
@ -65,7 +62,7 @@ async fn buffer_request_body(request: Request<BoxBody>) -> Result<Request<BoxBod
|
|||
|
||||
do_thing_with_request_body(bytes.clone());
|
||||
|
||||
Ok(Request::from_parts(parts, body::boxed(Full::from(bytes))))
|
||||
Ok(Request::from_parts(parts, Body::from(bytes)))
|
||||
}
|
||||
|
||||
fn do_thing_with_request_body(bytes: Bytes) {
|
||||
|
@ -81,13 +78,13 @@ struct BufferRequestBody(Bytes);
|
|||
|
||||
// we must implement `FromRequest` (and not `FromRequestParts`) to consume the body
|
||||
#[async_trait]
|
||||
impl<S> FromRequest<S, BoxBody> for BufferRequestBody
|
||||
impl<S> FromRequest<S> for BufferRequestBody
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let body = Bytes::from_request(req, state)
|
||||
.await
|
||||
.map_err(|err| err.into_response())?;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//! - Complexity: Manually implementing `FromRequest` results on more complex code
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::Body,
|
||||
extract::{rejection::JsonRejection, FromRequest, MatchedPath},
|
||||
http::Request,
|
||||
http::StatusCode,
|
||||
|
@ -22,15 +23,14 @@ pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse {
|
|||
pub struct Json<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for Json<T>
|
||||
impl<S, T> FromRequest<S> for Json<T>
|
||||
where
|
||||
axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection>,
|
||||
axum::Json<T>: FromRequest<S, Rejection = JsonRejection>,
|
||||
S: Send + Sync,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Rejection = (StatusCode, axum::Json<Value>);
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let (mut parts, body) = req.into_parts();
|
||||
|
||||
// We can use other extractors to provide better rejection messages.
|
||||
|
|
|
@ -37,8 +37,9 @@ async fn main() {
|
|||
|
||||
let router_svc = Router::new().route("/", get(|| async { "Hello, World!" }));
|
||||
|
||||
let service = tower::service_fn(move |req: Request<Body>| {
|
||||
let service = tower::service_fn(move |req: Request<_>| {
|
||||
let router_svc = router_svc.clone();
|
||||
let req = req.map(Body::new);
|
||||
async move {
|
||||
if req.method() == Method::CONNECT {
|
||||
proxy(req).await
|
||||
|
|
|
@ -8,13 +8,11 @@ use axum::{routing::get, Router};
|
|||
use std::net::SocketAddr;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tower_hyper_http_body_compat::{
|
||||
HttpBody1ToHttpBody04, TowerService03HttpServiceAsHyper1HttpService,
|
||||
};
|
||||
use tower_hyper_http_body_compat::TowerService03HttpServiceAsHyper1HttpService;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
// this is hyper 1.0
|
||||
use hyper::{body::Incoming, server::conn::http1};
|
||||
use hyper::server::conn::http1;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -26,8 +24,7 @@ async fn main() {
|
|||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
// you have to use `HttpBody1ToHttpBody04<Incoming>` as the second type parameter to `Router`
|
||||
let app: Router<_, HttpBody1ToHttpBody04<Incoming>> = Router::new()
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { "Hello, World!" }))
|
||||
// we can still add regular tower middleware
|
||||
.layer(TraceLayer::new_for_http());
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod};
|
||||
use tokio_openssl::SslStream;
|
||||
|
||||
use axum::{extract::ConnectInfo, routing::get, Router};
|
||||
use axum::{body::Body, extract::ConnectInfo, http::Request, routing::get, Router};
|
||||
use futures_util::future::poll_fn;
|
||||
use hyper::server::{
|
||||
accept::Accept,
|
||||
|
@ -68,7 +68,7 @@ async fn main() {
|
|||
|
||||
let protocol = protocol.clone();
|
||||
|
||||
let svc = app.make_service(&stream);
|
||||
let svc = MakeService::<_, Request<Body>>::make_service(&mut app, &stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let ssl = Ssl::new(acceptor.context()).unwrap();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! cargo run -p example-low-level-rustls
|
||||
//! ```
|
||||
|
||||
use axum::{extract::ConnectInfo, routing::get, Router};
|
||||
use axum::{body::Body, extract::ConnectInfo, http::Request, routing::get, Router};
|
||||
use futures_util::future::poll_fn;
|
||||
use hyper::server::{
|
||||
accept::Accept,
|
||||
|
@ -24,7 +24,7 @@ use tokio_rustls::{
|
|||
rustls::{Certificate, PrivateKey, ServerConfig},
|
||||
TlsAcceptor,
|
||||
};
|
||||
use tower::MakeService;
|
||||
use tower::make::MakeService;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -53,7 +53,7 @@ async fn main() {
|
|||
|
||||
let protocol = Arc::new(Http::new());
|
||||
|
||||
let mut app = Router::new()
|
||||
let mut app = Router::<()>::new()
|
||||
.route("/", get(handler))
|
||||
.into_make_service_with_connect_info::<SocketAddr>();
|
||||
|
||||
|
@ -67,7 +67,7 @@ async fn main() {
|
|||
|
||||
let protocol = protocol.clone();
|
||||
|
||||
let svc = app.make_service(&stream);
|
||||
let svc = MakeService::<_, Request<Body>>::make_service(&mut app, &stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Ok(stream) = acceptor.accept(stream).await {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::Body,
|
||||
extract::FromRequest,
|
||||
http::{header::CONTENT_TYPE, Request, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
|
@ -51,17 +52,16 @@ async fn handler(JsonOrForm(payload): JsonOrForm<Payload>) {
|
|||
struct JsonOrForm<T>(T);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T> FromRequest<S, B> for JsonOrForm<T>
|
||||
impl<S, T> FromRequest<S> for JsonOrForm<T>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
Json<T>: FromRequest<(), B>,
|
||||
Form<T>: FromRequest<(), B>,
|
||||
Json<T>: FromRequest<()>,
|
||||
Form<T>: FromRequest<()>,
|
||||
T: 'static,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let content_type_header = req.headers().get(CONTENT_TYPE);
|
||||
let content_type = content_type_header.and_then(|value| value.to_str().ok());
|
||||
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
//! ```
|
||||
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::State,
|
||||
http::{uri::Uri, Request, Response},
|
||||
http::{uri::Uri, Request},
|
||||
response::{IntoResponse, Response},
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use hyper::{client::HttpConnector, Body};
|
||||
use hyper::client::HttpConnector;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
type Client = hyper::client::Client<HttpConnector, Body>;
|
||||
|
@ -22,7 +24,7 @@ type Client = hyper::client::Client<HttpConnector, Body>;
|
|||
async fn main() {
|
||||
tokio::spawn(server());
|
||||
|
||||
let client = Client::new();
|
||||
let client: Client = hyper::Client::builder().build(HttpConnector::new());
|
||||
|
||||
let app = Router::new().route("/", get(handler)).with_state(client);
|
||||
|
||||
|
@ -34,7 +36,7 @@ async fn main() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Response<Body> {
|
||||
async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Response {
|
||||
let path = req.uri().path();
|
||||
let path_query = req
|
||||
.uri()
|
||||
|
@ -46,7 +48,7 @@ async fn handler(State(client): State<Client>, mut req: Request<Body>) -> Respon
|
|||
|
||||
*req.uri_mut() = Uri::try_from(uri).unwrap();
|
||||
|
||||
client.request(req).await.unwrap()
|
||||
client.request(req).await.unwrap().into_response()
|
||||
}
|
||||
|
||||
async fn server() {
|
||||
|
|
|
@ -71,7 +71,10 @@ fn using_serve_dir_with_handler_as_service() -> Router {
|
|||
(StatusCode::NOT_FOUND, "Not found")
|
||||
}
|
||||
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(handle_404.into_service());
|
||||
// you can convert handler function to service
|
||||
let service = handle_404.into_service();
|
||||
|
||||
let serve_dir = ServeDir::new("assets").not_found_service(service);
|
||||
|
||||
Router::new()
|
||||
.route("/foo", get(|| async { "Hi from /foo" }))
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
//! ```
|
||||
|
||||
use axum::{
|
||||
body::Bytes,
|
||||
extract::{BodyStream, Multipart, Path},
|
||||
http::StatusCode,
|
||||
body::{Body, Bytes},
|
||||
extract::{Multipart, Path},
|
||||
http::{Request, StatusCode},
|
||||
response::{Html, Redirect},
|
||||
routing::{get, post},
|
||||
BoxError, Router,
|
||||
|
@ -52,9 +52,9 @@ async fn main() {
|
|||
// POST'ing to `/file/foo.txt` will create a file called `foo.txt`.
|
||||
async fn save_request_body(
|
||||
Path(file_name): Path<String>,
|
||||
body: BodyStream,
|
||||
request: Request<Body>,
|
||||
) -> Result<(), (StatusCode, String)> {
|
||||
stream_to_file(&file_name, body).await
|
||||
stream_to_file(&file_name, request.into_body()).await
|
||||
}
|
||||
|
||||
// Handler that returns HTML for a multipart form.
|
||||
|
|
|
@ -148,7 +148,7 @@ mod tests {
|
|||
.request(
|
||||
Request::builder()
|
||||
.uri(format!("http://{}", addr))
|
||||
.body(Body::empty())
|
||||
.body(hyper::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
|
@ -165,11 +165,21 @@ mod tests {
|
|||
let mut app = app();
|
||||
|
||||
let request = Request::builder().uri("/").body(Body::empty()).unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = ServiceExt::<Request<Body>>::ready(&mut app)
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
let request = Request::builder().uri("/").body(Body::empty()).unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = ServiceExt::<Request<Body>>::ready(&mut app)
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
|
@ -186,7 +196,14 @@ mod tests {
|
|||
.uri("/requires-connect-into")
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
let response = app.ready().await.unwrap().call(request).await.unwrap();
|
||||
let response = app
|
||||
.as_service()
|
||||
.ready()
|
||||
.await
|
||||
.unwrap()
|
||||
.call(request)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
use async_trait::async_trait;
|
||||
use axum::{
|
||||
body::Body,
|
||||
extract::{rejection::FormRejection, Form, FromRequest},
|
||||
http::{Request, StatusCode},
|
||||
response::{Html, IntoResponse, Response},
|
||||
|
@ -61,16 +62,15 @@ async fn handler(ValidatedForm(input): ValidatedForm<NameInput>) -> Html<String>
|
|||
pub struct ValidatedForm<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S, B> FromRequest<S, B> for ValidatedForm<T>
|
||||
impl<T, S> FromRequest<S> for ValidatedForm<T>
|
||||
where
|
||||
T: DeserializeOwned + Validate,
|
||||
S: Send + Sync,
|
||||
Form<T>: FromRequest<S, B, Rejection = FormRejection>,
|
||||
B: Send + 'static,
|
||||
Form<T>: FromRequest<S, Rejection = FormRejection>,
|
||||
{
|
||||
type Rejection = ServerError;
|
||||
|
||||
async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: Request<Body>, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let Form(value) = Form::<T>::from_request(req, state).await?;
|
||||
value.validate()?;
|
||||
Ok(ValidatedForm(value))
|
||||
|
|
Loading…
Reference in a new issue