2021-06-08 12:43:16 +02:00
|
|
|
//! Use Tower [`Service`]s to handl requests.
|
|
|
|
|
//!
|
|
|
|
|
//! Most of the time applications will be written by composing
|
|
|
|
|
//! [handlers](crate::handler), however sometimes you might have some general
|
|
|
|
|
//! [`Service`] that you want to route requests to. That is enabled by the
|
|
|
|
|
//! functions in this module.
|
|
|
|
|
//!
|
|
|
|
|
//! # Example
|
|
|
|
|
//!
|
|
|
|
|
//! Using [`Redirect`] to redirect requests can be done like so:
|
|
|
|
|
//!
|
|
|
|
|
//! ```
|
|
|
|
|
//! use tower_http::services::Redirect;
|
2021-07-09 21:36:14 +02:00
|
|
|
//! use axum::{service, handler, prelude::*};
|
2021-06-08 12:43:16 +02:00
|
|
|
//!
|
|
|
|
|
//! async fn handler(request: Request<Body>) { /* ... */ }
|
|
|
|
|
//!
|
|
|
|
|
//! let redirect_service = Redirect::<Body>::permanent("/new".parse().unwrap());
|
|
|
|
|
//!
|
|
|
|
|
//! let app = route("/old", service::get(redirect_service))
|
|
|
|
|
//! .route("/new", handler::get(handler));
|
|
|
|
|
//! # async {
|
2021-06-19 12:50:33 +02:00
|
|
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
2021-06-08 12:43:16 +02:00
|
|
|
//! # };
|
|
|
|
|
//! ```
|
|
|
|
|
//!
|
2021-06-08 23:55:25 +02:00
|
|
|
//! # Regarding backpressure and `Service::poll_ready`
|
|
|
|
|
//!
|
|
|
|
|
//! Generally routing to one of multiple services and backpressure doesn't mix
|
|
|
|
|
//! well. Ideally you would want ensure a service is ready to receive a request
|
2021-06-09 07:52:04 +02:00
|
|
|
//! before calling the it. However in order to know which service to call you
|
|
|
|
|
//! need the request...
|
2021-06-08 23:55:25 +02:00
|
|
|
//!
|
|
|
|
|
//! One approach is to not consider the router service itself ready until all
|
|
|
|
|
//! destination services are ready. That is the approach used by
|
|
|
|
|
//! [`tower::steer::Steer`].
|
|
|
|
|
//!
|
|
|
|
|
//! Another approach is to always consider all services ready (always return
|
|
|
|
|
//! `Poll::Ready(Ok(()))`) from `Service::poll_ready` and then actually drive
|
2021-06-09 07:52:04 +02:00
|
|
|
//! readiness inside the response future returned by `Service::call`. This works
|
|
|
|
|
//! well when your services don't care about backpressure and are always ready
|
|
|
|
|
//! anyway.
|
2021-06-08 23:55:25 +02:00
|
|
|
//!
|
2021-07-09 21:36:14 +02:00
|
|
|
//! axum expects that all services used in your app wont care about
|
2021-06-08 23:55:25 +02:00
|
|
|
//! backpressure and so it uses the latter strategy. However that means you
|
|
|
|
|
//! should avoid routing to a service (or using a middleware) that _does_ care
|
|
|
|
|
//! about backpressure. At the very least you should [load shed] so requests are
|
|
|
|
|
//! dropped quickly and don't keep piling up.
|
|
|
|
|
//!
|
2021-06-09 07:52:04 +02:00
|
|
|
//! It also means if `poll_ready` returns an error that error will be returned
|
|
|
|
|
//! in the response future from `call`, and _not_ from `poll_ready`. In that
|
|
|
|
|
//! case the underlying service will _not_ be discarded and will continue to be
|
|
|
|
|
//! used for future requests. Services that expect to be discarded if
|
2021-07-09 21:36:14 +02:00
|
|
|
//! `poll_ready` fails should _not_ be used with axum.
|
2021-06-09 07:52:04 +02:00
|
|
|
//!
|
2021-06-08 23:55:25 +02:00
|
|
|
//! One possible approach is to only apply backpressure sensitive middleware
|
2021-07-09 21:36:14 +02:00
|
|
|
//! around your entire app. This is possible because axum applications are
|
2021-06-08 23:55:25 +02:00
|
|
|
//! themselves services:
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust
|
2021-07-09 21:36:14 +02:00
|
|
|
//! use axum::prelude::*;
|
2021-06-08 23:55:25 +02:00
|
|
|
//! use tower::ServiceBuilder;
|
|
|
|
|
//! # let some_backpressure_sensitive_middleware =
|
|
|
|
|
//! # tower::layer::util::Identity::new();
|
|
|
|
|
//!
|
2021-06-09 09:03:09 +02:00
|
|
|
//! async fn handler() { /* ... */ }
|
2021-06-08 23:55:25 +02:00
|
|
|
//!
|
|
|
|
|
//! let app = route("/", get(handler));
|
|
|
|
|
//!
|
|
|
|
|
//! let app = ServiceBuilder::new()
|
|
|
|
|
//! .layer(some_backpressure_sensitive_middleware)
|
|
|
|
|
//! .service(app);
|
2021-06-19 12:50:33 +02:00
|
|
|
//! # async {
|
|
|
|
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
//! # };
|
2021-06-08 23:55:25 +02:00
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! However when applying middleware around your whole application in this way
|
2021-06-09 07:52:04 +02:00
|
|
|
//! you have to take care that errors are still being handled with
|
|
|
|
|
//! appropriately.
|
2021-06-08 23:55:25 +02:00
|
|
|
//!
|
|
|
|
|
//! Also note that handlers created from async functions don't care about
|
|
|
|
|
//! backpressure and are always ready. So if you're not using any Tower
|
2021-06-09 07:52:04 +02:00
|
|
|
//! middleware you don't have to worry about any of this.
|
2021-06-08 23:55:25 +02:00
|
|
|
//!
|
2021-06-08 12:43:16 +02:00
|
|
|
//! [`Redirect`]: tower_http::services::Redirect
|
2021-06-08 23:55:25 +02:00
|
|
|
//! [load shed]: tower::load_shed
|
2021-06-08 12:43:16 +02:00
|
|
|
|
|
|
|
|
use crate::{
|
2021-07-22 13:23:50 +02:00
|
|
|
body::{box_body, BoxBody},
|
2021-06-08 12:43:16 +02:00
|
|
|
response::IntoResponse,
|
2021-06-12 23:59:18 +02:00
|
|
|
routing::{EmptyRouter, MethodFilter, RouteFuture},
|
2021-06-08 12:43:16 +02:00
|
|
|
};
|
|
|
|
|
use bytes::Bytes;
|
2021-06-13 10:10:37 +02:00
|
|
|
use futures_util::ready;
|
2021-06-08 12:43:16 +02:00
|
|
|
use http::{Request, Response};
|
2021-06-13 10:10:37 +02:00
|
|
|
use pin_project::pin_project;
|
2021-06-08 12:43:16 +02:00
|
|
|
use std::{
|
|
|
|
|
convert::Infallible,
|
|
|
|
|
fmt,
|
2021-06-13 10:10:37 +02:00
|
|
|
future::Future,
|
2021-06-19 12:50:33 +02:00
|
|
|
marker::PhantomData,
|
2021-06-08 12:43:16 +02:00
|
|
|
task::{Context, Poll},
|
|
|
|
|
};
|
|
|
|
|
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
|
|
|
|
|
|
|
|
|
|
pub mod future;
|
|
|
|
|
|
2021-06-13 10:10:37 +02:00
|
|
|
/// Route requests to the given service regardless of the HTTP method.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn any<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-13 10:10:37 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-13 10:10:37 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Any, svc)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 12:43:16 +02:00
|
|
|
/// Route `CONNECT` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Connect, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `DELETE` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Delete, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `GET` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{service, prelude::*};
|
2021-06-08 12:43:16 +02:00
|
|
|
/// 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()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// // Requests to `GET /` will go to `service`.
|
|
|
|
|
/// let app = route("/", service::get(service));
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn get<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Get, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `HEAD` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Head, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `OPTIONS` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Options, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `PATCH` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Patch, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `POST` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Post, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `PUT` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Put, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route `TRACE` requests to the given service.
|
|
|
|
|
///
|
|
|
|
|
/// See [`get`] for an example.
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
on(MethodFilter::Trace, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Route requests with the given method to the service.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{handler::on, service, routing::MethodFilter, prelude::*};
|
2021-06-08 12:43:16 +02:00
|
|
|
/// 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()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// // Requests to `POST /` will go to `service`.
|
|
|
|
|
/// let app = route("/", service::on(MethodFilter::Post, service));
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-07-06 09:40:25 +02:00
|
|
|
pub fn on<S, B>(
|
|
|
|
|
method: MethodFilter,
|
|
|
|
|
svc: S,
|
|
|
|
|
) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
OnMethod {
|
|
|
|
|
method,
|
2021-06-19 12:50:33 +02:00
|
|
|
svc: BoxResponseBody {
|
|
|
|
|
inner: svc,
|
|
|
|
|
_request_body: PhantomData,
|
|
|
|
|
},
|
2021-07-06 09:40:25 +02:00
|
|
|
fallback: EmptyRouter::new(),
|
2021-06-08 12:43:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A [`Service`] that accepts requests based on a [`MethodFilter`] and allows
|
|
|
|
|
/// chaining additional services.
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct OnMethod<S, F> {
|
|
|
|
|
pub(crate) method: MethodFilter,
|
|
|
|
|
pub(crate) svc: S,
|
|
|
|
|
pub(crate) fallback: F,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, F> OnMethod<S, F> {
|
|
|
|
|
/// Chain an additional service that will accept all requests regardless of
|
|
|
|
|
/// its HTTP method.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn any<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Any, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `CONNECT` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn connect<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Connect, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `DELETE` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn delete<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Delete, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `GET` requests.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{handler::on, service, routing::MethodFilter, prelude::*};
|
2021-06-08 12:43:16 +02:00
|
|
|
/// 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()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// let other_service = tower::service_fn(|request: Request<Body>| async {
|
|
|
|
|
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// // Requests to `GET /` will go to `service` and `POST /` will go to
|
|
|
|
|
/// // `other_service`.
|
|
|
|
|
/// let app = route("/", service::post(service).get(other_service));
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn get<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Get, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `HEAD` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn head<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Head, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `OPTIONS` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn options<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Options, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `PATCH` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn patch<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Patch, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `POST` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn post<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Post, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `PUT` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn put<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Put, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will only accept `TRACE` requests.
|
|
|
|
|
///
|
|
|
|
|
/// See [`OnMethod::get`] for an example.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn trace<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
self.on(MethodFilter::Trace, svc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Chain an additional service that will accept requests matching the given
|
|
|
|
|
/// `MethodFilter`.
|
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{handler::on, service, routing::MethodFilter, prelude::*};
|
2021-06-08 12:43:16 +02:00
|
|
|
/// 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()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// let other_service = tower::service_fn(|request: Request<Body>| async {
|
|
|
|
|
/// Ok::<_, Infallible>(Response::new(Body::empty()))
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// // Requests to `DELETE /` will go to `service`
|
|
|
|
|
/// let app = route("/", service::on(MethodFilter::Delete, service));
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-06-19 12:50:33 +02:00
|
|
|
pub fn on<T, B>(self, method: MethodFilter, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
T: Service<Request<B>> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
OnMethod {
|
|
|
|
|
method,
|
2021-06-19 12:50:33 +02:00
|
|
|
svc: BoxResponseBody {
|
|
|
|
|
inner: svc,
|
|
|
|
|
_request_body: PhantomData,
|
|
|
|
|
},
|
2021-06-08 12:43:16 +02:00
|
|
|
fallback: self,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this is identical to `routing::OnMethod`'s implementation. Would be nice to find a way to clean
|
|
|
|
|
// that up, but not sure its possible.
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, F, B> Service<Request<B>> for OnMethod<S, F>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<B>, Response = Response<BoxBody>> + Clone,
|
|
|
|
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
2021-06-13 10:10:37 +02:00
|
|
|
type Response = Response<BoxBody>;
|
2021-07-05 16:18:39 +02:00
|
|
|
type Error = S::Error;
|
2021-06-19 12:50:33 +02:00
|
|
|
type Future = RouteFuture<S, F, B>;
|
2021-06-08 12:43:16 +02:00
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
2021-06-12 23:59:18 +02:00
|
|
|
if self.method.matches(req.method()) {
|
|
|
|
|
let fut = self.svc.clone().oneshot(req);
|
|
|
|
|
RouteFuture::a(fut)
|
2021-06-08 12:43:16 +02:00
|
|
|
} else {
|
2021-06-12 23:59:18 +02:00
|
|
|
let fut = self.fallback.clone().oneshot(req);
|
|
|
|
|
RouteFuture::b(fut)
|
|
|
|
|
}
|
2021-06-08 12:43:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A [`Service`] adapter that handles errors with a closure.
|
|
|
|
|
///
|
|
|
|
|
/// Created with
|
|
|
|
|
/// [`handler::Layered::handle_error`](crate::handler::Layered::handle_error) or
|
|
|
|
|
/// [`routing::Layered::handle_error`](crate::routing::Layered::handle_error).
|
|
|
|
|
/// See those methods for more details.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub struct HandleError<S, F, B> {
|
|
|
|
|
inner: S,
|
|
|
|
|
f: F,
|
|
|
|
|
_marker: PhantomData<fn() -> B>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, F, B> Clone for HandleError<S, F, B>
|
|
|
|
|
where
|
|
|
|
|
S: Clone,
|
|
|
|
|
F: Clone,
|
|
|
|
|
{
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self::new(self.inner.clone(), self.f.clone())
|
|
|
|
|
}
|
2021-06-08 12:43:16 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, F, B> crate::routing::RoutingDsl for HandleError<S, F, B> {}
|
2021-06-08 12:43:16 +02:00
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, F, B> crate::sealed::Sealed for HandleError<S, F, B> {}
|
2021-06-08 12:43:16 +02:00
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, F, B> HandleError<S, F, B> {
|
2021-06-08 12:43:16 +02:00
|
|
|
pub(crate) fn new(inner: S, f: F) -> Self {
|
2021-06-19 12:50:33 +02:00
|
|
|
Self {
|
|
|
|
|
inner,
|
|
|
|
|
f,
|
|
|
|
|
_marker: PhantomData,
|
|
|
|
|
}
|
2021-06-08 12:43:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, F, B> fmt::Debug for HandleError<S, F, B>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
|
|
|
|
S: fmt::Debug,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("HandleError")
|
|
|
|
|
.field("inner", &self.inner)
|
|
|
|
|
.field("f", &format_args!("{}", std::any::type_name::<F>()))
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-22 15:00:33 +02:00
|
|
|
impl<S, F, ReqBody, ResBody, Res, E> Service<Request<ReqBody>> for HandleError<S, F, ReqBody>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
2021-06-19 12:50:33 +02:00
|
|
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
2021-07-22 15:00:33 +02:00
|
|
|
F: FnOnce(S::Error) -> Result<Res, E> + Clone,
|
2021-06-08 12:43:16 +02:00
|
|
|
Res: IntoResponse,
|
2021-06-19 12:50:33 +02:00
|
|
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
type Response = Response<BoxBody>;
|
2021-07-22 15:00:33 +02:00
|
|
|
type Error = E;
|
2021-06-19 12:50:33 +02:00
|
|
|
type Future = future::HandleErrorFuture<Oneshot<S, Request<ReqBody>>, F>;
|
2021-06-08 12:43:16 +02:00
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
2021-06-08 12:43:16 +02:00
|
|
|
future::HandleErrorFuture {
|
|
|
|
|
f: Some(self.f.clone()),
|
|
|
|
|
inner: self.inner.clone().oneshot(req),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Extension trait that adds additional methods to [`Service`].
|
2021-06-19 12:50:33 +02:00
|
|
|
pub trait ServiceExt<ReqBody, ResBody>:
|
|
|
|
|
Service<Request<ReqBody>, Response = Response<ResBody>>
|
|
|
|
|
{
|
2021-06-08 12:43:16 +02:00
|
|
|
/// Handle errors from a service.
|
|
|
|
|
///
|
|
|
|
|
/// `handle_error` takes a closure that will map errors from the service
|
2021-07-22 15:00:33 +02:00
|
|
|
/// into responses. The closure's return type must be `Result<T, E>` where
|
|
|
|
|
/// `T` implements [`IntoIntoResponse`](crate::response::IntoResponse).
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust,no_run
|
2021-07-09 21:36:14 +02:00
|
|
|
/// use axum::{service::{self, ServiceExt}, prelude::*};
|
2021-07-22 15:00:33 +02:00
|
|
|
/// use http::{Response, StatusCode};
|
2021-06-08 12:43:16 +02:00
|
|
|
/// use tower::{service_fn, BoxError};
|
2021-07-22 15:00:33 +02:00
|
|
|
/// use std::convert::Infallible;
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
|
|
|
|
/// // A service that might fail with `std::io::Error`
|
|
|
|
|
/// let service = service_fn(|_: Request<Body>| async {
|
|
|
|
|
/// let res = Response::new(Body::empty());
|
|
|
|
|
/// Ok::<_, std::io::Error>(res)
|
|
|
|
|
/// });
|
|
|
|
|
///
|
|
|
|
|
/// let app = route(
|
|
|
|
|
/// "/",
|
|
|
|
|
/// service.handle_error(|error: std::io::Error| {
|
2021-07-22 15:00:33 +02:00
|
|
|
/// Ok::<_, Infallible>((
|
|
|
|
|
/// StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
/// error.to_string(),
|
|
|
|
|
/// ))
|
2021-06-08 12:43:16 +02:00
|
|
|
/// }),
|
|
|
|
|
/// );
|
|
|
|
|
/// #
|
|
|
|
|
/// # async {
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
2021-06-08 12:43:16 +02:00
|
|
|
/// # };
|
|
|
|
|
/// ```
|
2021-07-22 15:00:33 +02:00
|
|
|
///
|
|
|
|
|
/// It works similarly to [`routing::Layered::handle_error`]. See that for more details.
|
|
|
|
|
///
|
|
|
|
|
/// [`routing::Layered::handle_error`]: crate::routing::Layered::handle_error
|
|
|
|
|
fn handle_error<F, Res, E>(self, f: F) -> HandleError<Self, F, ReqBody>
|
2021-06-08 12:43:16 +02:00
|
|
|
where
|
|
|
|
|
Self: Sized,
|
2021-07-22 15:00:33 +02:00
|
|
|
F: FnOnce(Self::Error) -> Result<Res, E>,
|
2021-06-08 12:43:16 +02:00
|
|
|
Res: IntoResponse,
|
2021-06-19 12:50:33 +02:00
|
|
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
2021-06-08 12:43:16 +02:00
|
|
|
{
|
|
|
|
|
HandleError::new(self, f)
|
|
|
|
|
}
|
2021-07-05 16:18:39 +02:00
|
|
|
|
|
|
|
|
/// Check that your service cannot fail.
|
|
|
|
|
///
|
|
|
|
|
/// That is its error type is [`Infallible`].
|
|
|
|
|
fn check_infallible(self) -> Self
|
|
|
|
|
where
|
|
|
|
|
Self: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible> + Sized,
|
|
|
|
|
{
|
|
|
|
|
self
|
|
|
|
|
}
|
2021-06-08 12:43:16 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, ReqBody, ResBody> ServiceExt<ReqBody, ResBody> for S where
|
|
|
|
|
S: Service<Request<ReqBody>, Response = Response<ResBody>>
|
|
|
|
|
{
|
|
|
|
|
}
|
2021-06-13 10:10:37 +02:00
|
|
|
|
|
|
|
|
/// A [`Service`] that boxes response bodies.
|
2021-06-19 12:50:33 +02:00
|
|
|
pub struct BoxResponseBody<S, B> {
|
|
|
|
|
inner: S,
|
|
|
|
|
_request_body: PhantomData<fn() -> B>,
|
|
|
|
|
}
|
2021-06-13 10:10:37 +02:00
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
impl<S, B> Clone for BoxResponseBody<S, B>
|
2021-06-13 10:10:37 +02:00
|
|
|
where
|
2021-06-19 12:50:33 +02:00
|
|
|
S: Clone,
|
|
|
|
|
{
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
inner: self.inner.clone(),
|
|
|
|
|
_request_body: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, B> fmt::Debug for BoxResponseBody<S, B>
|
|
|
|
|
where
|
|
|
|
|
S: fmt::Debug,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("BoxResponseBody")
|
|
|
|
|
.field("inner", &self.inner)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for BoxResponseBody<S, ReqBody>
|
|
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
2021-06-19 12:50:33 +02:00
|
|
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
2021-06-13 10:10:37 +02:00
|
|
|
{
|
|
|
|
|
type Response = Response<BoxBody>;
|
2021-07-05 16:18:39 +02:00
|
|
|
type Error = S::Error;
|
2021-06-19 12:50:33 +02:00
|
|
|
type Future = BoxResponseBodyFuture<Oneshot<S, Request<ReqBody>>>;
|
2021-06-13 10:10:37 +02:00
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-19 12:50:33 +02:00
|
|
|
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
|
|
|
|
let fut = self.inner.clone().oneshot(req);
|
2021-06-13 10:10:37 +02:00
|
|
|
BoxResponseBodyFuture(fut)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Response future for [`BoxResponseBody`].
|
|
|
|
|
#[pin_project]
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct BoxResponseBodyFuture<F>(#[pin] F);
|
|
|
|
|
|
2021-07-05 16:18:39 +02:00
|
|
|
impl<F, B, E> Future for BoxResponseBodyFuture<F>
|
2021-06-13 10:10:37 +02:00
|
|
|
where
|
2021-07-05 16:18:39 +02:00
|
|
|
F: Future<Output = Result<Response<B>, E>>,
|
2021-06-13 10:10:37 +02:00
|
|
|
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
B::Error: Into<BoxError> + Send + Sync + 'static,
|
|
|
|
|
{
|
2021-07-05 16:18:39 +02:00
|
|
|
type Output = Result<Response<BoxBody>, E>;
|
2021-06-13 10:10:37 +02:00
|
|
|
|
|
|
|
|
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
|
let res = ready!(self.project().0.poll(cx))?;
|
2021-07-22 13:23:50 +02:00
|
|
|
let res = res.map(box_body);
|
2021-06-13 10:10:37 +02:00
|
|
|
Poll::Ready(Ok(res))
|
|
|
|
|
}
|
|
|
|
|
}
|