mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-26 00:00:23 +02:00
checkpoint
This commit is contained in:
@@ -60,29 +60,30 @@ mod tuple;
|
||||
/// [`http::Request<B>`]: http::Request
|
||||
/// [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html
|
||||
#[async_trait]
|
||||
pub trait FromRequest<B>: Sized {
|
||||
pub trait FromRequest<S, B>: 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: &mut RequestParts<B>) -> Result<Self, Self::Rejection>;
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection>;
|
||||
}
|
||||
|
||||
/// The type used with [`FromRequest`] to extract data from requests.
|
||||
///
|
||||
/// Has several convenience methods for getting owned parts of the request.
|
||||
#[derive(Debug)]
|
||||
pub struct RequestParts<B> {
|
||||
pub struct RequestParts<S, B> {
|
||||
method: Method,
|
||||
uri: Uri,
|
||||
version: Version,
|
||||
headers: HeaderMap,
|
||||
extensions: Extensions,
|
||||
body: Option<B>,
|
||||
state: S,
|
||||
}
|
||||
|
||||
impl<B> RequestParts<B> {
|
||||
impl<S, B> RequestParts<S, B> {
|
||||
/// Create a new `RequestParts`.
|
||||
///
|
||||
/// You generally shouldn't need to construct this type yourself, unless
|
||||
@@ -90,7 +91,10 @@ impl<B> RequestParts<B> {
|
||||
/// [`tower::Service`].
|
||||
///
|
||||
/// [`tower::Service`]: https://docs.rs/tower/lastest/tower/trait.Service.html
|
||||
pub fn new(req: Request<B>) -> Self {
|
||||
pub fn new(state: S, req: Request<B>) -> Self
|
||||
where
|
||||
S: Send + Sync + 'static,
|
||||
{
|
||||
let (
|
||||
http::request::Parts {
|
||||
method,
|
||||
@@ -110,6 +114,7 @@ impl<B> RequestParts<B> {
|
||||
headers,
|
||||
extensions,
|
||||
body: Some(body),
|
||||
state,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +146,10 @@ impl<B> RequestParts<B> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn extract<E: FromRequest<B>>(&mut self) -> Result<E, E::Rejection> {
|
||||
pub async fn extract<E>(&mut self) -> Result<E, E::Rejection>
|
||||
where
|
||||
E: FromRequest<S, B>,
|
||||
{
|
||||
E::from_request(self).await
|
||||
}
|
||||
|
||||
@@ -159,6 +167,7 @@ impl<B> RequestParts<B> {
|
||||
headers,
|
||||
extensions,
|
||||
mut body,
|
||||
state: _,
|
||||
} = self;
|
||||
|
||||
let mut req = if let Some(body) = body.take() {
|
||||
@@ -245,46 +254,36 @@ impl<B> RequestParts<B> {
|
||||
pub fn take_body(&mut self) -> Option<B> {
|
||||
self.body.take()
|
||||
}
|
||||
|
||||
pub fn state(&self) -> &S {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Option<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Option<T>
|
||||
where
|
||||
T: FromRequest<B>,
|
||||
T: FromRequest<S, B>,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Option<T>, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Option<T>, Self::Rejection> {
|
||||
Ok(T::from_request(req).await.ok())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Result<T, T::Rejection>
|
||||
impl<T, S, B> FromRequest<S, B> for Result<T, T::Rejection>
|
||||
where
|
||||
T: FromRequest<B>,
|
||||
T: FromRequest<S, B>,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(T::from_request(req).await)
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO(david): docs
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct State<S>(pub S);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<B> for State<S>
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ use http::{Extensions, HeaderMap, Method, Request, Uri, Version};
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Request<B>
|
||||
impl<S, B> FromRequest<S, B> for Request<B>
|
||||
where
|
||||
B: Send,
|
||||
S: Clone + Send,
|
||||
{
|
||||
type Rejection = BodyAlreadyExtracted;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let req = std::mem::replace(
|
||||
req,
|
||||
RequestParts {
|
||||
@@ -22,6 +23,7 @@ where
|
||||
headers: HeaderMap::new(),
|
||||
extensions: Extensions::default(),
|
||||
body: None,
|
||||
state: req.state.clone(),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -30,37 +32,40 @@ where
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Method
|
||||
impl<S, B> FromRequest<S, B> for Method
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(req.method().clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Uri
|
||||
impl<S, B> FromRequest<S, B> for Uri
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(req.uri().clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Version
|
||||
impl<S, B> FromRequest<S, B> for Version
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(req.version())
|
||||
}
|
||||
}
|
||||
@@ -71,27 +76,29 @@ where
|
||||
///
|
||||
/// [`TypedHeader`]: https://docs.rs/axum/latest/axum/extract/struct.TypedHeader.html
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for HeaderMap
|
||||
impl<S, B> FromRequest<S, B> for HeaderMap
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(req.headers().clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Bytes
|
||||
impl<S, B> FromRequest<S, B> for Bytes
|
||||
where
|
||||
B: http_body::Body + Send,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = BytesRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let body = take_body(req)?;
|
||||
|
||||
let bytes = crate::body::to_bytes(body)
|
||||
@@ -103,15 +110,16 @@ where
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for String
|
||||
impl<S, B> FromRequest<S, B> for String
|
||||
where
|
||||
B: http_body::Body + Send,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = StringRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let body = take_body(req)?;
|
||||
|
||||
let bytes = crate::body::to_bytes(body)
|
||||
@@ -126,13 +134,14 @@ where
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for http::request::Parts
|
||||
impl<S, B> FromRequest<S, B> for http::request::Parts
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let method = unwrap_infallible(Method::from_request(req).await);
|
||||
let uri = unwrap_infallible(Uri::from_request(req).await);
|
||||
let version = unwrap_infallible(Version::from_request(req).await);
|
||||
@@ -159,6 +168,6 @@ fn unwrap_infallible<T>(result: Result<T, Infallible>) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_body<B>(req: &mut RequestParts<B>) -> Result<B, BodyAlreadyExtracted> {
|
||||
pub(crate) fn take_body<S, B>(req: &mut RequestParts<S, B>) -> Result<B, BodyAlreadyExtracted> {
|
||||
req.take_body().ok_or(BodyAlreadyExtracted)
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@ use async_trait::async_trait;
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for ()
|
||||
impl<S, B> FromRequest<S, B> for ()
|
||||
where
|
||||
S: Send,
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(_: &mut RequestParts<B>) -> Result<(), Self::Rejection> {
|
||||
async fn from_request(_: &mut RequestParts<S, B>) -> Result<(), Self::Rejection> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -21,14 +22,15 @@ macro_rules! impl_from_request {
|
||||
( $($ty:ident),* $(,)? ) => {
|
||||
#[async_trait]
|
||||
#[allow(non_snake_case)]
|
||||
impl<B, $($ty,)*> FromRequest<B> for ($($ty,)*)
|
||||
impl<S, B, $($ty,)*> FromRequest<S, B> for ($($ty,)*)
|
||||
where
|
||||
$( $ty: FromRequest<B> + Send, )*
|
||||
$( $ty: FromRequest<S, B> + Send, )*
|
||||
S: Send,
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
$( let $ty = $ty::from_request(req).await.map_err(|err| err.into_response())?; )*
|
||||
Ok(($($ty,)*))
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ use tower_service::Service;
|
||||
/// that handles errors by converting them into responses.
|
||||
///
|
||||
/// See [module docs](self) for more details on axum's error handling model.
|
||||
// TODO(david): cannot access state, is that bad? It leads to inference issues and one has to
|
||||
// specify the type manually and risk getting it wrong. So its basically an Extension at that point
|
||||
pub struct HandleErrorLayer<F, T> {
|
||||
f: F,
|
||||
_extractor: PhantomData<fn() -> T>,
|
||||
@@ -49,7 +51,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, E> fmt::Debug for HandleErrorLayer<F, E> {
|
||||
impl<F, T> fmt::Debug for HandleErrorLayer<F, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("HandleErrorLayer")
|
||||
.field("f", &format_args!("{}", std::any::type_name::<F>()))
|
||||
@@ -57,13 +59,13 @@ impl<F, E> fmt::Debug for HandleErrorLayer<F, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, T> Layer<S> for HandleErrorLayer<F, T>
|
||||
impl<Svc, F, T> Layer<Svc> for HandleErrorLayer<F, T>
|
||||
where
|
||||
F: Clone,
|
||||
{
|
||||
type Service = HandleError<S, F, T>;
|
||||
type Service = HandleError<Svc, F, T>;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
fn layer(&self, inner: Svc) -> Self::Service {
|
||||
HandleError::new(inner, self.f.clone())
|
||||
}
|
||||
}
|
||||
@@ -71,15 +73,15 @@ where
|
||||
/// A [`Service`] adapter that handles errors by converting them into responses.
|
||||
///
|
||||
/// See [module docs](self) for more details on axum's error handling model.
|
||||
pub struct HandleError<S, F, T> {
|
||||
inner: S,
|
||||
pub struct HandleError<Svc, F, T> {
|
||||
inner: Svc,
|
||||
f: F,
|
||||
_extractor: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<S, F, T> HandleError<S, F, T> {
|
||||
impl<Svc, F, T> HandleError<Svc, F, T> {
|
||||
/// Create a new `HandleError`.
|
||||
pub fn new(inner: S, f: F) -> Self {
|
||||
pub fn new(inner: Svc, f: F) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
f,
|
||||
@@ -88,9 +90,9 @@ impl<S, F, T> HandleError<S, F, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, T> Clone for HandleError<S, F, T>
|
||||
impl<Svc, F, T> Clone for HandleError<Svc, F, T>
|
||||
where
|
||||
S: Clone,
|
||||
Svc: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@@ -102,9 +104,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, E> fmt::Debug for HandleError<S, F, E>
|
||||
impl<Svc, F, E> fmt::Debug for HandleError<Svc, F, E>
|
||||
where
|
||||
S: fmt::Debug,
|
||||
Svc: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("HandleError")
|
||||
@@ -114,12 +116,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, ReqBody, ResBody, Fut, Res> Service<Request<ReqBody>> for HandleError<S, F, ()>
|
||||
impl<Svc, F, ReqBody, ResBody, Fut, Res> Service<Request<ReqBody>> for HandleError<Svc, F, ()>
|
||||
where
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||
S::Error: Send,
|
||||
S::Future: Send,
|
||||
F: FnOnce(S::Error) -> Fut + Clone + Send + 'static,
|
||||
Svc: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||
Svc::Error: Send,
|
||||
Svc::Future: Send,
|
||||
F: FnOnce(Svc::Error) -> Fut + Clone + Send + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
Res: IntoResponse,
|
||||
ReqBody: Send + 'static,
|
||||
@@ -154,16 +156,16 @@ where
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! impl_service {
|
||||
( $($ty:ident),* $(,)? ) => {
|
||||
impl<S, F, ReqBody, ResBody, Res, Fut, $($ty,)*> Service<Request<ReqBody>>
|
||||
for HandleError<S, F, ($($ty,)*)>
|
||||
impl<Svc, F, ReqBody, ResBody, Res, Fut, $($ty,)*> Service<Request<ReqBody>>
|
||||
for HandleError<Svc, F, ($($ty,)*)>
|
||||
where
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||
S::Error: Send,
|
||||
S::Future: Send,
|
||||
F: FnOnce($($ty),*, S::Error) -> Fut + Clone + Send + 'static,
|
||||
Svc: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||
Svc::Error: Send,
|
||||
Svc::Future: Send,
|
||||
F: FnOnce($($ty),*, Svc::Error) -> Fut + Clone + Send + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
Res: IntoResponse,
|
||||
$( $ty: FromRequest<ReqBody> + Send,)*
|
||||
$( $ty: FromRequest<(), ReqBody> + Send,)*
|
||||
ReqBody: Send + 'static,
|
||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<BoxError>,
|
||||
@@ -185,7 +187,7 @@ macro_rules! impl_service {
|
||||
let inner = std::mem::replace(&mut self.inner, clone);
|
||||
|
||||
let future = Box::pin(async move {
|
||||
let mut req = RequestParts::new(req);
|
||||
let mut req = RequestParts::new((), req);
|
||||
|
||||
$(
|
||||
let $ty = match $ty::from_request(&mut req).await {
|
||||
|
||||
@@ -73,14 +73,15 @@ use tower_service::Service;
|
||||
pub struct Extension<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Extension<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Extension<T>
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = ExtensionRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let value = req
|
||||
.extensions()
|
||||
.get::<T>()
|
||||
|
||||
@@ -128,14 +128,15 @@ opaque_future! {
|
||||
pub struct ConnectInfo<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<B, T> FromRequest<B> for ConnectInfo<T>
|
||||
impl<B, S, T> FromRequest<S, B> for ConnectInfo<T>
|
||||
where
|
||||
B: Send,
|
||||
T: Clone + Send + Sync + 'static,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = <Extension<Self> as FromRequest<B>>::Rejection;
|
||||
type Rejection = <Extension<Self> as FromRequest<S, B>>::Rejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let Extension(connect_info) = Extension::<Self>::from_request(req).await?;
|
||||
Ok(connect_info)
|
||||
}
|
||||
|
||||
@@ -36,15 +36,16 @@ use std::ops::Deref;
|
||||
pub struct ContentLengthLimit<T, const N: u64>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B, const N: u64> FromRequest<B> for ContentLengthLimit<T, N>
|
||||
impl<T, S, B, const N: u64> FromRequest<S, B> for ContentLengthLimit<T, N>
|
||||
where
|
||||
T: FromRequest<B>,
|
||||
T: FromRequest<S, B>,
|
||||
T::Rejection: IntoResponse,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = ContentLengthLimitRejection<T::Rejection>;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let content_length = req
|
||||
.headers()
|
||||
.get(http::header::CONTENT_LENGTH)
|
||||
|
||||
@@ -21,13 +21,14 @@ const X_FORWARDED_HOST_HEADER_KEY: &str = "X-Forwarded-Host";
|
||||
pub struct Host(pub String);
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Host
|
||||
impl<S, B> FromRequest<S, B> for Host
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = HostRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
if let Some(host) = parse_forwarded(req.headers()) {
|
||||
return Ok(Host(host.to_owned()));
|
||||
}
|
||||
|
||||
@@ -64,13 +64,14 @@ impl MatchedPath {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for MatchedPath
|
||||
impl<S, B> FromRequest<S, B> for MatchedPath
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = MatchedPathRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let matched_path = req
|
||||
.extensions()
|
||||
.get::<Self>()
|
||||
|
||||
@@ -14,9 +14,10 @@ mod content_length_limit;
|
||||
mod host;
|
||||
mod raw_query;
|
||||
mod request_parts;
|
||||
mod state;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use axum_core::extract::{FromRequest, RequestParts, State};
|
||||
pub use axum_core::extract::{FromRequest, RequestParts};
|
||||
|
||||
#[doc(inline)]
|
||||
#[allow(deprecated)]
|
||||
@@ -27,6 +28,7 @@ pub use self::{
|
||||
path::Path,
|
||||
raw_query::RawQuery,
|
||||
request_parts::{BodyStream, RawBody},
|
||||
state::State,
|
||||
};
|
||||
|
||||
#[doc(no_inline)]
|
||||
@@ -73,13 +75,13 @@ pub use self::ws::WebSocketUpgrade;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::TypedHeader;
|
||||
|
||||
pub(crate) fn take_body<B>(req: &mut RequestParts<B>) -> Result<B, BodyAlreadyExtracted> {
|
||||
pub(crate) fn take_body<S, B>(req: &mut RequestParts<S, B>) -> Result<B, BodyAlreadyExtracted> {
|
||||
req.take_body().ok_or_else(BodyAlreadyExtracted::default)
|
||||
}
|
||||
|
||||
// this is duplicated in `axum-extra/src/extract/form.rs`
|
||||
pub(super) fn has_content_type<B>(
|
||||
req: &RequestParts<B>,
|
||||
pub(super) fn has_content_type<S, B>(
|
||||
req: &RequestParts<S, B>,
|
||||
expected_content_type: &mime::Mime,
|
||||
) -> bool {
|
||||
let content_type = if let Some(content_type) = req.headers().get(header::CONTENT_TYPE) {
|
||||
|
||||
@@ -50,14 +50,15 @@ pub struct Multipart {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for Multipart
|
||||
impl<S, B> FromRequest<S, B> for Multipart
|
||||
where
|
||||
B: HttpBody<Data = Bytes> + Default + Unpin + Send + 'static,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = MultipartRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let stream = BodyStream::from_request(req).await?;
|
||||
let headers = req.headers();
|
||||
let boundary = parse_boundary(headers).ok_or(InvalidBoundary)?;
|
||||
|
||||
@@ -163,14 +163,15 @@ impl<T> DerefMut for Path<T> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Path<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Path<T>
|
||||
where
|
||||
T: DeserializeOwned + Send,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = PathRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let params = match req.extensions_mut().get::<UrlParams>() {
|
||||
Some(UrlParams::Params(params)) => params,
|
||||
Some(UrlParams::InvalidUtf8InPathParam { key }) => {
|
||||
|
||||
@@ -49,14 +49,15 @@ use std::ops::Deref;
|
||||
pub struct Query<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Query<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Query<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = QueryRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let query = req.uri().query().unwrap_or_default();
|
||||
let value = serde_urlencoded::from_str(query)
|
||||
.map_err(FailedToDeserializeQueryString::__private_new::<T, _>)?;
|
||||
@@ -80,8 +81,12 @@ mod tests {
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Debug;
|
||||
|
||||
async fn check<T: DeserializeOwned + PartialEq + Debug>(uri: impl AsRef<str>, value: T) {
|
||||
let mut req = RequestParts::new(Request::builder().uri(uri.as_ref()).body(()).unwrap());
|
||||
async fn check<T>(uri: impl AsRef<str>, value: T)
|
||||
where
|
||||
T: DeserializeOwned + PartialEq + Debug,
|
||||
{
|
||||
let req = Request::builder().uri(uri.as_ref()).body(()).unwrap();
|
||||
let mut req = RequestParts::new((), req);
|
||||
assert_eq!(Query::<T>::from_request(&mut req).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,14 @@ use std::convert::Infallible;
|
||||
pub struct RawQuery(pub Option<String>);
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for RawQuery
|
||||
impl<S, B> FromRequest<S, B> for RawQuery
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let query = req.uri().query().map(|query| query.to_owned());
|
||||
Ok(Self(query))
|
||||
}
|
||||
|
||||
@@ -86,13 +86,14 @@ pub struct OriginalUri(pub Uri);
|
||||
|
||||
#[cfg(feature = "original-uri")]
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for OriginalUri
|
||||
impl<S, B> FromRequest<S, B> for OriginalUri
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let uri = Extension::<Self>::from_request(req)
|
||||
.await
|
||||
.unwrap_or_else(|_| Extension(OriginalUri(req.uri().clone())))
|
||||
@@ -140,15 +141,16 @@ impl Stream for BodyStream {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for BodyStream
|
||||
impl<S, B> FromRequest<S, B> for BodyStream
|
||||
where
|
||||
B: HttpBody + Send + 'static,
|
||||
B::Data: Into<Bytes>,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = BodyAlreadyExtracted;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let body = take_body(req)?
|
||||
.map_data(Into::into)
|
||||
.map_err(|err| Error::new(err.into()));
|
||||
@@ -196,13 +198,14 @@ fn body_stream_traits() {
|
||||
pub struct RawBody<B = Body>(pub B);
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for RawBody<B>
|
||||
impl<S, B> FromRequest<S, B> for RawBody<B>
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = BodyAlreadyExtracted;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
let body = take_body(req)?;
|
||||
Ok(Self(body))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
use super::{FromRequest, RequestParts};
|
||||
use async_trait::async_trait;
|
||||
use std::convert::Infallible;
|
||||
|
||||
/// TODO(david): docs
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct State<S>(pub S);
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B> FromRequest<S, B> for State<S>
|
||||
where
|
||||
B: Send,
|
||||
S: Clone + Send,
|
||||
{
|
||||
type Rejection = Infallible;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
Ok(Self(req.state().clone()))
|
||||
}
|
||||
}
|
||||
@@ -244,13 +244,14 @@ impl WebSocketUpgrade {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for WebSocketUpgrade
|
||||
impl<S, B> FromRequest<S, B> for WebSocketUpgrade
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = WebSocketUpgradeRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
if req.method() != Method::GET {
|
||||
return Err(MethodNotGet.into());
|
||||
}
|
||||
@@ -288,7 +289,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn header_eq<B>(req: &RequestParts<B>, key: HeaderName, value: &'static str) -> bool {
|
||||
fn header_eq<S, B>(req: &RequestParts<S, B>, key: HeaderName, value: &'static str) -> bool {
|
||||
if let Some(header) = req.headers().get(&key) {
|
||||
header.as_bytes().eq_ignore_ascii_case(value.as_bytes())
|
||||
} else {
|
||||
@@ -296,7 +297,7 @@ fn header_eq<B>(req: &RequestParts<B>, key: HeaderName, value: &'static str) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn header_contains<B>(req: &RequestParts<B>, key: HeaderName, value: &'static str) -> bool {
|
||||
fn header_contains<S, B>(req: &RequestParts<S, B>, key: HeaderName, value: &'static str) -> bool {
|
||||
let header = if let Some(header) = req.headers().get(&key) {
|
||||
header
|
||||
} else {
|
||||
|
||||
+34
-36
@@ -56,16 +56,17 @@ use std::ops::Deref;
|
||||
pub struct Form<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Form<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Form<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: HttpBody + Send,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = FormRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
if req.method() == Method::GET {
|
||||
let query = req.uri().query().unwrap_or_default();
|
||||
let value = serde_urlencoded::from_str(query)
|
||||
@@ -125,29 +126,27 @@ mod tests {
|
||||
}
|
||||
|
||||
async fn check_query<T: DeserializeOwned + PartialEq + Debug>(uri: impl AsRef<str>, value: T) {
|
||||
let mut req = RequestParts::new(
|
||||
Request::builder()
|
||||
.uri(uri.as_ref())
|
||||
.body(Empty::<Bytes>::new())
|
||||
.unwrap(),
|
||||
);
|
||||
let req = Request::builder()
|
||||
.uri(uri.as_ref())
|
||||
.body(Empty::<Bytes>::new())
|
||||
.unwrap();
|
||||
let mut req = RequestParts::new((), req);
|
||||
assert_eq!(Form::<T>::from_request(&mut req).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
async fn check_body<T: Serialize + DeserializeOwned + PartialEq + Debug>(value: T) {
|
||||
let mut req = RequestParts::new(
|
||||
Request::builder()
|
||||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(
|
||||
http::header::CONTENT_TYPE,
|
||||
mime::APPLICATION_WWW_FORM_URLENCODED.as_ref(),
|
||||
)
|
||||
.body(Full::<Bytes>::new(
|
||||
serde_urlencoded::to_string(&value).unwrap().into(),
|
||||
))
|
||||
.unwrap(),
|
||||
);
|
||||
let req = Request::builder()
|
||||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(
|
||||
http::header::CONTENT_TYPE,
|
||||
mime::APPLICATION_WWW_FORM_URLENCODED.as_ref(),
|
||||
)
|
||||
.body(Full::<Bytes>::new(
|
||||
serde_urlencoded::to_string(&value).unwrap().into(),
|
||||
))
|
||||
.unwrap();
|
||||
let mut req = RequestParts::new((), req);
|
||||
assert_eq!(Form::<T>::from_request(&mut req).await.unwrap().0, value);
|
||||
}
|
||||
|
||||
@@ -204,21 +203,20 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_incorrect_content_type() {
|
||||
let mut req = RequestParts::new(
|
||||
Request::builder()
|
||||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(http::header::CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
|
||||
.body(Full::<Bytes>::new(
|
||||
serde_urlencoded::to_string(&Pagination {
|
||||
size: Some(10),
|
||||
page: None,
|
||||
})
|
||||
.unwrap()
|
||||
.into(),
|
||||
))
|
||||
.unwrap(),
|
||||
);
|
||||
let req = Request::builder()
|
||||
.uri("http://example.com/test")
|
||||
.method(Method::POST)
|
||||
.header(http::header::CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
|
||||
.body(Full::<Bytes>::new(
|
||||
serde_urlencoded::to_string(&Pagination {
|
||||
size: Some(10),
|
||||
page: None,
|
||||
})
|
||||
.unwrap()
|
||||
.into(),
|
||||
))
|
||||
.unwrap();
|
||||
let mut req = RequestParts::new((), req);
|
||||
assert!(matches!(
|
||||
Form::<Pagination>::from_request(&mut req)
|
||||
.await
|
||||
|
||||
@@ -244,13 +244,14 @@ macro_rules! impl_handler {
|
||||
Fut: Future<Output = Res> + Send,
|
||||
B: Send + 'static,
|
||||
Res: IntoResponse,
|
||||
$( $ty: FromRequest<B> + Send,)*
|
||||
$( $ty: FromRequest<S, B> + Send,)*
|
||||
S: Send + Sync + 'static
|
||||
{
|
||||
type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
|
||||
|
||||
fn call(self, state: S, req: Request<B>) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
let mut req = RequestParts::new(req);
|
||||
let mut req = RequestParts::new(state, req);
|
||||
|
||||
$(
|
||||
let $ty = match $ty::from_request(&mut req).await {
|
||||
|
||||
+4
-3
@@ -93,16 +93,17 @@ use std::ops::{Deref, DerefMut};
|
||||
pub struct Json<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Json<T>
|
||||
impl<T, S, B> FromRequest<S, B> for Json<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: HttpBody + Send,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = JsonRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
if json_content_type(req) {
|
||||
let bytes = Bytes::from_request(req).await?;
|
||||
|
||||
@@ -135,7 +136,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn json_content_type<B>(req: &RequestParts<B>) -> bool {
|
||||
fn json_content_type<S, B>(req: &RequestParts<S, B>) -> bool {
|
||||
let content_type = if let Some(content_type) = req.headers().get(header::CONTENT_TYPE) {
|
||||
content_type
|
||||
} else {
|
||||
|
||||
@@ -116,10 +116,10 @@ impl<E> fmt::Debug for FromExtractorLayer<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, S> Layer<S> for FromExtractorLayer<E> {
|
||||
type Service = FromExtractor<S, E>;
|
||||
impl<E, T> Layer<T> for FromExtractorLayer<E> {
|
||||
type Service = FromExtractor<T, E>;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
fn layer(&self, inner: T) -> Self::Service {
|
||||
FromExtractor {
|
||||
inner,
|
||||
_extractor: PhantomData,
|
||||
@@ -130,8 +130,8 @@ impl<E, S> Layer<S> for FromExtractorLayer<E> {
|
||||
/// Middleware that runs an extractor and discards the value.
|
||||
///
|
||||
/// See [`from_extractor`] for more details.
|
||||
pub struct FromExtractor<S, E> {
|
||||
inner: S,
|
||||
pub struct FromExtractor<T, E> {
|
||||
inner: T,
|
||||
_extractor: PhantomData<fn() -> E>,
|
||||
}
|
||||
|
||||
@@ -142,9 +142,9 @@ fn traits() {
|
||||
assert_sync::<FromExtractor<(), NotSendSync>>();
|
||||
}
|
||||
|
||||
impl<S, E> Clone for FromExtractor<S, E>
|
||||
impl<T, E> Clone for FromExtractor<T, E>
|
||||
where
|
||||
S: Clone,
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@@ -154,9 +154,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, E> fmt::Debug for FromExtractor<S, E>
|
||||
impl<T, E> fmt::Debug for FromExtractor<T, E>
|
||||
where
|
||||
S: fmt::Debug,
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("FromExtractor")
|
||||
@@ -166,17 +166,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, E, ReqBody, ResBody> Service<Request<ReqBody>> for FromExtractor<S, E>
|
||||
impl<T, E, ReqBody, ResBody> Service<Request<ReqBody>> for FromExtractor<T, E>
|
||||
where
|
||||
E: FromRequest<ReqBody> + 'static,
|
||||
E: FromRequest<(), ReqBody> + 'static,
|
||||
ReqBody: Default + Send + 'static,
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<BoxError>,
|
||||
{
|
||||
type Response = Response;
|
||||
type Error = S::Error;
|
||||
type Future = ResponseFuture<ReqBody, S, E>;
|
||||
type Error = T::Error;
|
||||
type Future = ResponseFuture<ReqBody, T, E>;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
@@ -185,7 +185,7 @@ where
|
||||
|
||||
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
||||
let extract_future = Box::pin(async move {
|
||||
let mut req = RequestParts::new(req);
|
||||
let mut req = RequestParts::new((), req);
|
||||
let extracted = E::from_request(&mut req).await;
|
||||
(req, extracted)
|
||||
});
|
||||
@@ -202,38 +202,41 @@ where
|
||||
pin_project! {
|
||||
/// Response future for [`FromExtractor`].
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct ResponseFuture<ReqBody, S, E>
|
||||
pub struct ResponseFuture<ReqBody, T, E>
|
||||
where
|
||||
E: FromRequest<ReqBody>,
|
||||
S: Service<Request<ReqBody>>,
|
||||
E: FromRequest<(), ReqBody>,
|
||||
T: Service<Request<ReqBody>>,
|
||||
{
|
||||
#[pin]
|
||||
state: State<ReqBody, S, E>,
|
||||
svc: Option<S>,
|
||||
state: State<ReqBody, T, E>,
|
||||
svc: Option<T>,
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[project = StateProj]
|
||||
enum State<ReqBody, S, E>
|
||||
enum State<ReqBody, T, E>
|
||||
where
|
||||
E: FromRequest<ReqBody>,
|
||||
S: Service<Request<ReqBody>>,
|
||||
E: FromRequest<(), ReqBody>,
|
||||
T: Service<Request<ReqBody>>,
|
||||
{
|
||||
Extracting { future: BoxFuture<'static, (RequestParts<ReqBody>, Result<E, E::Rejection>)> },
|
||||
Call { #[pin] future: S::Future },
|
||||
Extracting {
|
||||
future: BoxFuture<'static, (RequestParts<(), ReqBody>, Result<E, E::Rejection>)>
|
||||
},
|
||||
Call { #[pin] future: T::Future },
|
||||
Error { response: Option<Response> }
|
||||
}
|
||||
}
|
||||
|
||||
impl<ReqBody, S, E, ResBody> Future for ResponseFuture<ReqBody, S, E>
|
||||
impl<ReqBody, T, E, ResBody> Future for ResponseFuture<ReqBody, T, E>
|
||||
where
|
||||
E: FromRequest<ReqBody>,
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
||||
E: FromRequest<(), ReqBody>,
|
||||
T: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
||||
ReqBody: Default,
|
||||
ResBody: HttpBody<Data = Bytes> + Send + 'static,
|
||||
ResBody::Error: Into<BoxError>,
|
||||
{
|
||||
type Output = Result<Response, S::Error>;
|
||||
type Output = Result<Response, T::Error>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
loop {
|
||||
@@ -261,6 +264,11 @@ where
|
||||
.poll(cx)
|
||||
.map(|result| result.map(|response| response.map(crate::body::boxed)));
|
||||
}
|
||||
StateProj::Error { response } => {
|
||||
return Poll::Ready(Ok(response
|
||||
.take()
|
||||
.expect("future polled after completion")))
|
||||
}
|
||||
};
|
||||
|
||||
this.state.set(new_state);
|
||||
@@ -279,13 +287,14 @@ mod tests {
|
||||
struct RequireAuth;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<B> FromRequest<B> for RequireAuth
|
||||
impl<S, B> FromRequest<S, B> for RequireAuth
|
||||
where
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = StatusCode;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
if let Some(auth) = req
|
||||
.headers()
|
||||
.get(header::AUTHORIZATION)
|
||||
@@ -317,4 +326,9 @@ mod tests {
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extracting_state() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,4 +313,9 @@ mod tests {
|
||||
let body = hyper::body::to_bytes(res).await.unwrap();
|
||||
assert_eq!(&body[..], b"ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extracting_state() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +52,15 @@ use std::{convert::Infallible, ops::Deref};
|
||||
pub struct TypedHeader<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for TypedHeader<T>
|
||||
impl<T, S, B> FromRequest<S, B> for TypedHeader<T>
|
||||
where
|
||||
T: headers::Header,
|
||||
B: Send,
|
||||
S: Send,
|
||||
{
|
||||
type Rejection = TypedHeaderRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
async fn from_request(req: &mut RequestParts<S, B>) -> Result<Self, Self::Rejection> {
|
||||
match req.headers().typed_try_get::<T>() {
|
||||
Ok(Some(value)) => Ok(Self(value)),
|
||||
Ok(None) => Err(TypedHeaderRejection {
|
||||
|
||||
Reference in New Issue
Block a user