Skip to content

Commit 53cce05

Browse files
authored
Support running extractors from middleware::from_fn (#1088)
1 parent 9ec32a7 commit 53cce05

2 files changed

Lines changed: 154 additions & 61 deletions

File tree

axum/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- **added:** Support resolving host name via `Forwarded` header in `Host`
1111
extractor ([#1078])
12+
- **added:** Support running extractors from `middleware::from_fn` functions ([#1088])
1213
- **breaking:** Allow `Error: Into<Infallible>` for `Route::{layer, route_layer}` ([#924])
1314
- **breaking:** Remove `extractor_middleware` which was previously deprecated.
1415
Use `axum::middleware::from_extractor` instead ([#1077])
1516

1617
[#924]: https://github.com/tokio-rs/axum/pull/924
17-
[#1078]: https://github.com/tokio-rs/axum/pull/1078
1818
[#1077]: https://github.com/tokio-rs/axum/pull/1077
19+
[#1078]: https://github.com/tokio-rs/axum/pull/1078
20+
[#1088]: https://github.com/tokio-rs/axum/pull/1088
1921

2022
# 0.5.7 (08. June, 2022)
2123

axum/src/middleware/from_fn.rs

Lines changed: 151 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ use crate::{
33
response::{IntoResponse, Response},
44
BoxError,
55
};
6+
use axum_core::extract::{FromRequest, RequestParts};
7+
use futures_util::future::BoxFuture;
68
use http::Request;
7-
use pin_project_lite::pin_project;
89
use std::{
910
any::type_name,
1011
convert::Infallible,
1112
fmt,
1213
future::Future,
14+
marker::PhantomData,
1315
pin::Pin,
1416
task::{Context, Poll},
1517
};
@@ -23,8 +25,8 @@ use tower_service::Service;
2325
/// `from_fn` requires the function given to
2426
///
2527
/// 1. Be an `async fn`.
26-
/// 2. Take [`Request<B>`](http::Request) as the first argument.
27-
/// 3. Take [`Next<B>`](Next) as the second argument.
28+
/// 2. Take one or more [extractors] as the first arguments.
29+
/// 3. Take [`Next<B>`](Next) as the final argument.
2830
/// 4. Return something that implements [`IntoResponse`].
2931
///
3032
/// # Example
@@ -62,6 +64,37 @@ use tower_service::Service;
6264
/// # let app: Router = app;
6365
/// ```
6466
///
67+
/// # Running extractors
68+
///
69+
/// ```rust
70+
/// use axum::{
71+
/// Router,
72+
/// extract::{TypedHeader, Query},
73+
/// headers::authorization::{Authorization, Bearer},
74+
/// http::Request,
75+
/// middleware::{self, Next},
76+
/// response::Response,
77+
/// routing::get,
78+
/// };
79+
/// use std::collections::HashMap;
80+
///
81+
/// async fn my_middleware<B>(
82+
/// TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
83+
/// Query(query_params): Query<HashMap<String, String>>,
84+
/// req: Request<B>,
85+
/// next: Next<B>,
86+
/// ) -> Response {
87+
/// // do something with `auth` and `query_params`...
88+
///
89+
/// next.run(req).await
90+
/// }
91+
///
92+
/// let app = Router::new()
93+
/// .route("/", get(|| async { /* ... */ }))
94+
/// .route_layer(middleware::from_fn(my_middleware));
95+
/// # let app: Router = app;
96+
/// ```
97+
///
6598
/// # Passing state
6699
///
67100
/// State can be passed to the function like so:
@@ -114,11 +147,10 @@ use tower_service::Service;
114147
/// struct State { /* ... */ }
115148
///
116149
/// async fn my_middleware<B>(
150+
/// Extension(state): Extension<State>,
117151
/// req: Request<B>,
118152
/// next: Next<B>,
119153
/// ) -> Response {
120-
/// let state: &State = req.extensions().get().unwrap();
121-
///
122154
/// // ...
123155
/// # ().into_response()
124156
/// }
@@ -134,35 +166,55 @@ use tower_service::Service;
134166
/// );
135167
/// # let app: Router = app;
136168
/// ```
137-
pub fn from_fn<F>(f: F) -> FromFnLayer<F> {
138-
FromFnLayer { f }
169+
///
170+
/// [extractors]: crate::extract::FromRequest
171+
pub fn from_fn<F, T>(f: F) -> FromFnLayer<F, T> {
172+
FromFnLayer {
173+
f,
174+
_extractor: PhantomData,
175+
}
139176
}
140177

141178
/// A [`tower::Layer`] from an async function.
142179
///
143180
/// [`tower::Layer`] is used to apply middleware to [`Router`](crate::Router)'s.
144181
///
145182
/// Created with [`from_fn`]. See that function for more details.
146-
#[derive(Clone, Copy)]
147-
pub struct FromFnLayer<F> {
183+
pub struct FromFnLayer<F, T> {
148184
f: F,
185+
_extractor: PhantomData<fn() -> T>,
149186
}
150187

151-
impl<S, F> Layer<S> for FromFnLayer<F>
188+
impl<F, T> Clone for FromFnLayer<F, T>
152189
where
153190
F: Clone,
154191
{
155-
type Service = FromFn<F, S>;
192+
fn clone(&self) -> Self {
193+
Self {
194+
f: self.f.clone(),
195+
_extractor: self._extractor,
196+
}
197+
}
198+
}
199+
200+
impl<F, T> Copy for FromFnLayer<F, T> where F: Copy {}
201+
202+
impl<S, F, T> Layer<S> for FromFnLayer<F, T>
203+
where
204+
F: Clone,
205+
{
206+
type Service = FromFn<F, S, T>;
156207

157208
fn layer(&self, inner: S) -> Self::Service {
158209
FromFn {
159210
f: self.f.clone(),
160211
inner,
212+
_extractor: PhantomData,
161213
}
162214
}
163215
}
164216

165-
impl<F> fmt::Debug for FromFnLayer<F> {
217+
impl<F, T> fmt::Debug for FromFnLayer<F, T> {
166218
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167219
f.debug_struct("FromFnLayer")
168220
// Write out the type name, without quoting it as `&type_name::<F>()` would
@@ -174,50 +226,94 @@ impl<F> fmt::Debug for FromFnLayer<F> {
174226
/// A middleware created from an async function.
175227
///
176228
/// Created with [`from_fn`]. See that function for more details.
177-
#[derive(Clone, Copy)]
178-
pub struct FromFn<F, S> {
229+
pub struct FromFn<F, S, T> {
179230
f: F,
180231
inner: S,
232+
_extractor: PhantomData<fn() -> T>,
181233
}
182234

183-
impl<F, Fut, Out, S, ReqBody, ResBody> Service<Request<ReqBody>> for FromFn<F, S>
235+
impl<F, S, T> Clone for FromFn<F, S, T>
184236
where
185-
F: FnMut(Request<ReqBody>, Next<ReqBody>) -> Fut,
186-
Fut: Future<Output = Out>,
187-
Out: IntoResponse,
188-
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible>
189-
+ Clone
190-
+ Send
191-
+ 'static,
192-
S::Future: Send + 'static,
193-
ResBody: HttpBody<Data = Bytes> + Send + 'static,
194-
ResBody::Error: Into<BoxError>,
237+
F: Clone,
238+
S: Clone,
195239
{
196-
type Response = Response;
197-
type Error = Infallible;
198-
type Future = ResponseFuture<Fut>;
199-
200-
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
201-
self.inner.poll_ready(cx)
240+
fn clone(&self) -> Self {
241+
Self {
242+
f: self.f.clone(),
243+
inner: self.inner.clone(),
244+
_extractor: self._extractor,
245+
}
202246
}
247+
}
248+
249+
impl<F, S, T> Copy for FromFn<F, S, T>
250+
where
251+
F: Copy,
252+
S: Copy,
253+
{
254+
}
255+
256+
macro_rules! impl_service {
257+
( $($ty:ident),* $(,)? ) => {
258+
#[allow(non_snake_case)]
259+
impl<F, Fut, Out, S, ReqBody, ResBody, $($ty,)*> Service<Request<ReqBody>> for FromFn<F, S, ($($ty,)*)>
260+
where
261+
F: FnMut($($ty),*, Next<ReqBody>) -> Fut + Clone + Send + 'static,
262+
$( $ty: FromRequest<ReqBody> + Send, )*
263+
Fut: Future<Output = Out> + Send + 'static,
264+
Out: IntoResponse + 'static,
265+
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible>
266+
+ Clone
267+
+ Send
268+
+ 'static,
269+
S::Future: Send + 'static,
270+
ReqBody: Send + 'static,
271+
ResBody: HttpBody<Data = Bytes> + Send + 'static,
272+
ResBody::Error: Into<BoxError>,
273+
{
274+
type Response = Response;
275+
type Error = Infallible;
276+
type Future = ResponseFuture;
203277

204-
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
205-
let not_ready_inner = self.inner.clone();
206-
let ready_inner = std::mem::replace(&mut self.inner, not_ready_inner);
278+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
279+
self.inner.poll_ready(cx)
280+
}
207281

208-
let inner = ServiceBuilder::new()
209-
.boxed_clone()
210-
.map_response_body(body::boxed)
211-
.service(ready_inner);
212-
let next = Next { inner };
282+
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
283+
let not_ready_inner = self.inner.clone();
284+
let ready_inner = std::mem::replace(&mut self.inner, not_ready_inner);
213285

214-
ResponseFuture {
215-
inner: (self.f)(req, next),
286+
let mut f = self.f.clone();
287+
288+
let future = Box::pin(async move {
289+
let mut parts = RequestParts::new(req);
290+
$(
291+
let $ty = match $ty::from_request(&mut parts).await {
292+
Ok(value) => value,
293+
Err(rejection) => return rejection.into_response(),
294+
};
295+
)*
296+
297+
let inner = ServiceBuilder::new()
298+
.boxed_clone()
299+
.map_response_body(body::boxed)
300+
.service(ready_inner);
301+
let next = Next { inner };
302+
303+
f($($ty),*, next).await.into_response()
304+
});
305+
306+
ResponseFuture {
307+
inner: future
308+
}
309+
}
216310
}
217-
}
311+
};
218312
}
219313

220-
impl<F, S> fmt::Debug for FromFn<F, S>
314+
all_the_tuples!(impl_service);
315+
316+
impl<F, S, T> fmt::Debug for FromFn<F, S, T>
221317
where
222318
S: fmt::Debug,
223319
{
@@ -252,27 +348,22 @@ impl<ReqBody> fmt::Debug for Next<ReqBody> {
252348
}
253349
}
254350

255-
pin_project! {
256-
/// Response future for [`FromFn`].
257-
pub struct ResponseFuture<F> {
258-
#[pin]
259-
inner: F,
260-
}
351+
/// Response future for [`FromFn`].
352+
pub struct ResponseFuture {
353+
inner: BoxFuture<'static, Response>,
261354
}
262355

263-
impl<F, Out> Future for ResponseFuture<F>
264-
where
265-
F: Future<Output = Out>,
266-
Out: IntoResponse,
267-
{
356+
impl Future for ResponseFuture {
268357
type Output = Result<Response, Infallible>;
269358

270-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
271-
self.project()
272-
.inner
273-
.poll(cx)
274-
.map(IntoResponse::into_response)
275-
.map(Ok)
359+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
360+
self.inner.as_mut().poll(cx).map(Ok)
361+
}
362+
}
363+
364+
impl fmt::Debug for ResponseFuture {
365+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366+
f.debug_struct("ResponseFuture").finish()
276367
}
277368
}
278369

0 commit comments

Comments
 (0)