mirror of https://github.com/tokio-rs/axum
Improve compile times (#184)
* Inline `handler::IntoService` * Inline `BoxResponseBody` * Add missing debug impl
This commit is contained in:
parent
292d174a73
commit
48afd30491
|
@ -1,43 +1,38 @@
|
|||
//! Handler future types.
|
||||
|
||||
use crate::body::{box_body, BoxBody};
|
||||
use futures_util::future::{BoxFuture, Either};
|
||||
use http::{Method, Request, Response};
|
||||
use http_body::Empty;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
fmt,
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tower::Service;
|
||||
|
||||
opaque_future! {
|
||||
/// The response future for [`IntoService`](super::IntoService).
|
||||
pub type IntoServiceFuture =
|
||||
futures_util::future::BoxFuture<'static, Result<Response<BoxBody>, Infallible>>;
|
||||
}
|
||||
use tower::{util::Oneshot, Service};
|
||||
|
||||
pin_project! {
|
||||
/// The response future for [`OnMethod`](super::OnMethod).
|
||||
#[derive(Debug)]
|
||||
pub struct OnMethodFuture<S, F, B>
|
||||
pub struct OnMethodFuture<F, B>
|
||||
where
|
||||
S: Service<Request<B>>,
|
||||
F: Service<Request<B>>
|
||||
{
|
||||
#[pin]
|
||||
pub(super) inner: crate::routing::future::RouteFuture<S, F, B>,
|
||||
pub(super) inner: Either<
|
||||
BoxFuture<'static, Result<Response<BoxBody>, F::Error>>,
|
||||
Oneshot<F, Request<B>>,
|
||||
>,
|
||||
pub(super) req_method: Method,
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, B> Future for OnMethodFuture<S, F, B>
|
||||
impl<F, B> Future for OnMethodFuture<F, B>
|
||||
where
|
||||
S: Service<Request<B>, Response = Response<BoxBody>>,
|
||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error>,
|
||||
F: Service<Request<B>, Response = Response<BoxBody>>,
|
||||
{
|
||||
type Output = Result<Response<BoxBody>, S::Error>;
|
||||
type Output = Result<Response<BoxBody>, F::Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
@ -50,3 +45,12 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, B> fmt::Debug for OnMethodFuture<F, B>
|
||||
where
|
||||
F: Service<Request<B>>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OnMethodFuture").finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@ use crate::{
|
|||
body::{box_body, BoxBody},
|
||||
extract::FromRequest,
|
||||
response::IntoResponse,
|
||||
routing::{future::RouteFuture, EmptyRouter, MethodFilter},
|
||||
routing::{EmptyRouter, MethodFilter},
|
||||
service::{HandleError, HandleErrorFromRouter},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use futures_util::future::Either;
|
||||
use http::{Request, Response};
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
|
@ -37,7 +38,7 @@ pub mod future;
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn any<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn any<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -47,7 +48,7 @@ where
|
|||
/// Route `CONNECT` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn connect<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn connect<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -57,7 +58,7 @@ where
|
|||
/// Route `DELETE` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn delete<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn delete<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -83,7 +84,7 @@ where
|
|||
/// Note that `get` routes will also be called for `HEAD` requests but will have
|
||||
/// the response body removed. Make sure to add explicit `HEAD` routes
|
||||
/// afterwards.
|
||||
pub fn get<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn get<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -93,7 +94,7 @@ where
|
|||
/// Route `HEAD` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn head<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn head<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -103,7 +104,7 @@ where
|
|||
/// Route `OPTIONS` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn options<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn options<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -113,7 +114,7 @@ where
|
|||
/// Route `PATCH` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn patch<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn patch<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -123,7 +124,7 @@ where
|
|||
/// Route `POST` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn post<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn post<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -133,7 +134,7 @@ where
|
|||
/// Route `PUT` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn put<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn put<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -143,7 +144,7 @@ where
|
|||
/// Route `TRACE` requests to the given handler.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn trace<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn trace<H, B, T>(handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
|
@ -165,14 +166,15 @@ where
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on<H, B, T>(method: MethodFilter, handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||
pub fn on<H, B, T>(method: MethodFilter, handler: H) -> OnMethod<H, B, T, EmptyRouter>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
{
|
||||
OnMethod {
|
||||
method,
|
||||
svc: handler.into_service(),
|
||||
handler,
|
||||
fallback: EmptyRouter::method_not_allowed(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +193,7 @@ pub(crate) mod sealed {
|
|||
///
|
||||
/// See the [module docs](crate::handler) for more details.
|
||||
#[async_trait]
|
||||
pub trait Handler<B, In>: Sized {
|
||||
pub trait Handler<B, T>: Clone + Send + Sized + 'static {
|
||||
// This seals the trait. We cannot use the regular "sealed super trait"
|
||||
// approach due to coherence.
|
||||
#[doc(hidden)]
|
||||
|
@ -231,23 +233,18 @@ pub trait Handler<B, In>: Sized {
|
|||
///
|
||||
/// When adding middleware that might fail its recommended to handle those
|
||||
/// errors. See [`Layered::handle_error`] for more details.
|
||||
fn layer<L>(self, layer: L) -> Layered<L::Service, In>
|
||||
fn layer<L>(self, layer: L) -> Layered<L::Service, T>
|
||||
where
|
||||
L: Layer<IntoService<Self, B, In>>,
|
||||
L: Layer<OnMethod<Self, B, T, EmptyRouter>>,
|
||||
{
|
||||
Layered::new(layer.layer(IntoService::new(self)))
|
||||
}
|
||||
|
||||
/// Convert the handler into a [`Service`].
|
||||
fn into_service(self) -> IntoService<Self, B, In> {
|
||||
IntoService::new(self)
|
||||
Layered::new(layer.layer(any(self)))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F, Fut, Res, B> Handler<B, ()> for F
|
||||
where
|
||||
F: FnOnce() -> Fut + Send + Sync,
|
||||
F: FnOnce() -> Fut + Clone + Send + Sync + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
Res: IntoResponse,
|
||||
B: Send + 'static,
|
||||
|
@ -268,7 +265,7 @@ macro_rules! impl_handler {
|
|||
#[allow(non_snake_case)]
|
||||
impl<F, Fut, B, Res, $head, $($tail,)*> Handler<B, ($head, $($tail,)*)> for F
|
||||
where
|
||||
F: FnOnce($head, $($tail,)*) -> Fut + Send + Sync,
|
||||
F: FnOnce($head, $($tail,)*) -> Fut + Clone + Send + Sync + 'static,
|
||||
Fut: Future<Output = Res> + Send,
|
||||
B: Send + 'static,
|
||||
Res: IntoResponse,
|
||||
|
@ -334,9 +331,10 @@ where
|
|||
#[async_trait]
|
||||
impl<S, T, ReqBody, ResBody> Handler<ReqBody, T> for Layered<S, T>
|
||||
where
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Send,
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||
S::Error: IntoResponse,
|
||||
S::Future: Send,
|
||||
T: 'static,
|
||||
ReqBody: Send + 'static,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||
|
@ -387,89 +385,59 @@ impl<S, T> Layered<S, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An adapter that makes a [`Handler`] into a [`Service`].
|
||||
///
|
||||
/// Created with [`Handler::into_service`].
|
||||
pub struct IntoService<H, B, T> {
|
||||
handler: H,
|
||||
_marker: PhantomData<fn() -> (B, T)>,
|
||||
/// A handler [`Service`] that accepts requests based on a [`MethodFilter`] and
|
||||
/// allows chaining additional handlers.
|
||||
pub struct OnMethod<H, B, T, F> {
|
||||
pub(crate) method: MethodFilter,
|
||||
pub(crate) handler: H,
|
||||
pub(crate) fallback: F,
|
||||
pub(crate) _marker: PhantomData<fn() -> (B, T)>,
|
||||
}
|
||||
|
||||
impl<H, B, T> IntoService<H, B, T> {
|
||||
fn new(handler: H) -> Self {
|
||||
Self {
|
||||
handler,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, B, T> fmt::Debug for IntoService<H, B, T>
|
||||
impl<H, B, T, F> fmt::Debug for OnMethod<H, B, T, F>
|
||||
where
|
||||
H: fmt::Debug,
|
||||
T: fmt::Debug,
|
||||
F: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("IntoService")
|
||||
.field("handler", &self.handler)
|
||||
f.debug_struct("OnMethod")
|
||||
.field("method", &self.method)
|
||||
.field("handler", &format_args!("{}", std::any::type_name::<H>()))
|
||||
.field("fallback", &self.fallback)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, B, T> Clone for IntoService<H, B, T>
|
||||
impl<H, B, T, F> Clone for OnMethod<H, B, T, F>
|
||||
where
|
||||
H: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
method: self.method,
|
||||
handler: self.handler.clone(),
|
||||
fallback: self.fallback.clone(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, T, B> Service<Request<B>> for IntoService<H, B, T>
|
||||
impl<H, B, T, F> Copy for OnMethod<H, B, T, F>
|
||||
where
|
||||
H: Handler<B, T> + Clone + Send + 'static,
|
||||
B: Send + 'static,
|
||||
H: Copy,
|
||||
F: Copy,
|
||||
{
|
||||
type Response = Response<BoxBody>;
|
||||
type Error = Infallible;
|
||||
type Future = future::IntoServiceFuture;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
// `IntoService` can only be constructed from async functions which are always ready, or from
|
||||
// `Layered` which bufferes in `<Layered as Handler>::call` and is therefore also always
|
||||
// ready.
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let handler = self.handler.clone();
|
||||
let future = Box::pin(async move {
|
||||
let res = Handler::call(handler, req).await;
|
||||
Ok(res)
|
||||
});
|
||||
future::IntoServiceFuture { future }
|
||||
}
|
||||
}
|
||||
|
||||
/// A handler [`Service`] that accepts requests based on a [`MethodFilter`] and
|
||||
/// allows chaining additional handlers.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OnMethod<S, F> {
|
||||
pub(crate) method: MethodFilter,
|
||||
pub(crate) svc: S,
|
||||
pub(crate) fallback: F,
|
||||
}
|
||||
|
||||
impl<S, F> OnMethod<S, F> {
|
||||
impl<H, B, T, F> OnMethod<H, B, T, F> {
|
||||
/// Chain an additional handler that will accept all requests regardless of
|
||||
/// its HTTP method.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn any<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn any<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::all(), handler)
|
||||
}
|
||||
|
@ -477,9 +445,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `CONNECT` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn connect<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn connect<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::CONNECT, handler)
|
||||
}
|
||||
|
@ -487,9 +455,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `DELETE` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn delete<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn delete<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::DELETE, handler)
|
||||
}
|
||||
|
@ -516,9 +484,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Note that `get` routes will also be called for `HEAD` requests but will have
|
||||
/// the response body removed. Make sure to add explicit `HEAD` routes
|
||||
/// afterwards.
|
||||
pub fn get<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn get<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::GET | MethodFilter::HEAD, handler)
|
||||
}
|
||||
|
@ -526,9 +494,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `HEAD` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn head<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn head<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::HEAD, handler)
|
||||
}
|
||||
|
@ -536,9 +504,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `OPTIONS` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn options<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn options<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::OPTIONS, handler)
|
||||
}
|
||||
|
@ -546,9 +514,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `PATCH` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn patch<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn patch<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::PATCH, handler)
|
||||
}
|
||||
|
@ -556,9 +524,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `POST` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn post<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn post<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::POST, handler)
|
||||
}
|
||||
|
@ -566,9 +534,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `PUT` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn put<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn put<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::PUT, handler)
|
||||
}
|
||||
|
@ -576,9 +544,9 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional handler that will only accept `TRACE` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn trace<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn trace<H2, T2>(self, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
self.on(MethodFilter::TRACE, handler)
|
||||
}
|
||||
|
@ -602,30 +570,28 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on<H, B, T>(
|
||||
self,
|
||||
method: MethodFilter,
|
||||
handler: H,
|
||||
) -> OnMethod<IntoService<H, B, T>, Self>
|
||||
pub fn on<H2, T2>(self, method: MethodFilter, handler: H2) -> OnMethod<H2, B, T2, Self>
|
||||
where
|
||||
H: Handler<B, T>,
|
||||
H2: Handler<B, T2>,
|
||||
{
|
||||
OnMethod {
|
||||
method,
|
||||
svc: handler.into_service(),
|
||||
handler,
|
||||
fallback: self,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, B> Service<Request<B>> for OnMethod<S, F>
|
||||
impl<H, B, T, F> Service<Request<B>> for OnMethod<H, B, T, F>
|
||||
where
|
||||
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||
H: Handler<B, T>,
|
||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||
B: Send + 'static,
|
||||
{
|
||||
type Response = Response<BoxBody>;
|
||||
type Error = Infallible;
|
||||
type Future = future::OnMethodFuture<S, F, B>;
|
||||
type Future = future::OnMethodFuture<F, B>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
|
@ -634,16 +600,20 @@ where
|
|||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
let req_method = req.method().clone();
|
||||
|
||||
let f = if self.method.matches(req.method()) {
|
||||
let fut = self.svc.clone().oneshot(req);
|
||||
RouteFuture::a(fut)
|
||||
let fut = if self.method.matches(req.method()) {
|
||||
let handler = self.handler.clone();
|
||||
let fut = Box::pin(async move {
|
||||
let res = Handler::call(handler, req).await;
|
||||
Ok::<_, F::Error>(res)
|
||||
}) as futures_util::future::BoxFuture<'static, _>;
|
||||
Either::Left(fut)
|
||||
} else {
|
||||
let fut = self.fallback.clone().oneshot(req);
|
||||
RouteFuture::b(fut)
|
||||
Either::Right(fut)
|
||||
};
|
||||
|
||||
future::OnMethodFuture {
|
||||
inner: f,
|
||||
inner: fut,
|
||||
req_method,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use crate::{
|
||||
body::{box_body, BoxBody},
|
||||
response::IntoResponse,
|
||||
util::{Either, EitherProj},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use futures_util::ready;
|
||||
|
@ -14,7 +15,7 @@ use std::{
|
|||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use tower::{BoxError, Service};
|
||||
use tower::{util::Oneshot, BoxError, Service};
|
||||
|
||||
pin_project! {
|
||||
/// Response future for [`HandleError`](super::HandleError).
|
||||
|
@ -52,54 +53,41 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
/// Response future for [`BoxResponseBody`].
|
||||
#[derive(Debug)]
|
||||
pub struct BoxResponseBodyFuture<F> {
|
||||
#[pin]
|
||||
pub(super) future: F,
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, B, E> Future for BoxResponseBodyFuture<F>
|
||||
where
|
||||
F: Future<Output = Result<Response<B>, E>>,
|
||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
||||
{
|
||||
type Output = Result<Response<BoxBody>, E>;
|
||||
|
||||
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let res = ready!(self.project().future.poll(cx))?;
|
||||
let res = res.map(box_body);
|
||||
Poll::Ready(Ok(res))
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
/// The response future for [`OnMethod`](super::OnMethod).
|
||||
#[derive(Debug)]
|
||||
pub struct OnMethodFuture<S, F, B>
|
||||
where
|
||||
S: Service<Request<B>>,
|
||||
F: Service<Request<B>>
|
||||
{
|
||||
#[pin]
|
||||
pub(super) inner: crate::routing::future::RouteFuture<S, F, B>,
|
||||
pub(super) inner: Either<
|
||||
Oneshot<S, Request<B>>,
|
||||
Oneshot<F, Request<B>>,
|
||||
>,
|
||||
// pub(super) inner: crate::routing::future::RouteFuture<S, F, B>,
|
||||
pub(super) req_method: Method,
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, B> Future for OnMethodFuture<S, F, B>
|
||||
impl<S, F, B, ResBody> Future for OnMethodFuture<S, F, B>
|
||||
where
|
||||
S: Service<Request<B>, Response = Response<BoxBody>>,
|
||||
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||
ResBody::Error: Into<BoxError>,
|
||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error>,
|
||||
{
|
||||
type Output = Result<Response<BoxBody>, S::Error>;
|
||||
|
||||
#[allow(warnings)]
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
let response = futures_util::ready!(this.inner.poll(cx))?;
|
||||
|
||||
let response = match this.inner.project() {
|
||||
EitherProj::A { inner } => ready!(inner.poll(cx))?.map(box_body),
|
||||
EitherProj::B { inner } => ready!(inner.poll(cx))?,
|
||||
};
|
||||
|
||||
if this.req_method == &Method::HEAD {
|
||||
let response = response.map(|_| box_body(Empty::new()));
|
||||
Poll::Ready(Ok(response))
|
||||
|
|
|
@ -105,7 +105,7 @@ pub mod future;
|
|||
/// Route requests to the given service regardless of the HTTP method.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn any<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn any<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ where
|
|||
/// Route `CONNECT` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn connect<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -125,7 +125,7 @@ where
|
|||
/// Route `DELETE` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn delete<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -156,7 +156,7 @@ where
|
|||
/// Note that `get` routes will also be called for `HEAD` requests but will have
|
||||
/// the response body removed. Make sure to add explicit `HEAD` routes
|
||||
/// afterwards.
|
||||
pub fn get<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn get<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -166,7 +166,7 @@ where
|
|||
/// Route `HEAD` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn head<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -176,7 +176,7 @@ where
|
|||
/// Route `OPTIONS` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn options<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -186,7 +186,7 @@ where
|
|||
/// Route `PATCH` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn patch<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -196,7 +196,7 @@ where
|
|||
/// Route `POST` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn post<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ where
|
|||
/// Route `PUT` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn put<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -216,7 +216,7 @@ where
|
|||
/// Route `TRACE` requests to the given service.
|
||||
///
|
||||
/// See [`get`] for an example.
|
||||
pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn trace<S, B>(svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -243,38 +243,49 @@ where
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on<S, B>(
|
||||
method: MethodFilter,
|
||||
svc: S,
|
||||
) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
|
||||
pub fn on<S, B>(method: MethodFilter, svc: S) -> OnMethod<S, EmptyRouter<S::Error>, B>
|
||||
where
|
||||
S: Service<Request<B>> + Clone,
|
||||
{
|
||||
OnMethod {
|
||||
method,
|
||||
svc: BoxResponseBody {
|
||||
inner: svc,
|
||||
_request_body: PhantomData,
|
||||
},
|
||||
svc,
|
||||
fallback: EmptyRouter::method_not_allowed(),
|
||||
_request_body: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Service`] that accepts requests based on a [`MethodFilter`] and allows
|
||||
/// chaining additional services.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OnMethod<S, F> {
|
||||
#[derive(Debug)] // TODO(david): don't require debug for B
|
||||
pub struct OnMethod<S, F, B> {
|
||||
pub(crate) method: MethodFilter,
|
||||
pub(crate) svc: S,
|
||||
pub(crate) fallback: F,
|
||||
pub(crate) _request_body: PhantomData<fn() -> B>,
|
||||
}
|
||||
|
||||
impl<S, F> OnMethod<S, F> {
|
||||
impl<S, F, B> Clone for OnMethod<S, F, B>
|
||||
where
|
||||
S: Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
method: self.method,
|
||||
svc: self.svc.clone(),
|
||||
fallback: self.fallback.clone(),
|
||||
_request_body: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, F, B> OnMethod<S, F, B> {
|
||||
/// Chain an additional service that will accept all requests regardless of
|
||||
/// its HTTP method.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn any<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn any<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -284,7 +295,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `CONNECT` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn connect<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn connect<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -294,7 +305,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `DELETE` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn delete<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn delete<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -330,7 +341,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Note that `get` routes will also be called for `HEAD` requests but will have
|
||||
/// the response body removed. Make sure to add explicit `HEAD` routes
|
||||
/// afterwards.
|
||||
pub fn get<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn get<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -340,7 +351,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `HEAD` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn head<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn head<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -350,7 +361,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `OPTIONS` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn options<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn options<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -360,7 +371,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `PATCH` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn patch<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn patch<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -370,7 +381,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `POST` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn post<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn post<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -380,7 +391,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `PUT` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn put<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn put<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -390,7 +401,7 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// Chain an additional service that will only accept `TRACE` requests.
|
||||
///
|
||||
/// See [`OnMethod::get`] for an example.
|
||||
pub fn trace<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn trace<T>(self, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
|
@ -422,17 +433,15 @@ impl<S, F> OnMethod<S, F> {
|
|||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
pub fn on<T, B>(self, method: MethodFilter, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||
pub fn on<T>(self, method: MethodFilter, svc: T) -> OnMethod<T, Self, B>
|
||||
where
|
||||
T: Service<Request<B>> + Clone,
|
||||
{
|
||||
OnMethod {
|
||||
method,
|
||||
svc: BoxResponseBody {
|
||||
inner: svc,
|
||||
_request_body: PhantomData,
|
||||
},
|
||||
svc,
|
||||
fallback: self,
|
||||
_request_body: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,9 +468,11 @@ impl<S, F> OnMethod<S, F> {
|
|||
|
||||
// this is identical to `routing::OnMethod`'s implementation. Would be nice to find a way to clean
|
||||
// that up, but not sure its possible.
|
||||
impl<S, F, B> Service<Request<B>> for OnMethod<S, F>
|
||||
impl<S, F, B, ResBody> Service<Request<B>> for OnMethod<S, F, B>
|
||||
where
|
||||
S: Service<Request<B>, Response = Response<BoxBody>> + Clone,
|
||||
S: Service<Request<B>, Response = Response<ResBody>> + Clone,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||
ResBody::Error: Into<BoxError>,
|
||||
F: Service<Request<B>, Response = Response<BoxBody>, Error = S::Error> + Clone,
|
||||
{
|
||||
type Response = Response<BoxBody>;
|
||||
|
@ -473,14 +484,16 @@ where
|
|||
}
|
||||
|
||||
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||
use crate::util::Either;
|
||||
|
||||
let req_method = req.method().clone();
|
||||
|
||||
let f = if self.method.matches(req.method()) {
|
||||
let fut = self.svc.clone().oneshot(req);
|
||||
RouteFuture::a(fut)
|
||||
Either::A { inner: fut }
|
||||
} else {
|
||||
let fut = self.fallback.clone().oneshot(req);
|
||||
RouteFuture::b(fut)
|
||||
Either::B { inner: fut }
|
||||
};
|
||||
|
||||
future::OnMethodFuture {
|
||||
|
@ -574,55 +587,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// A [`Service`] that boxes response bodies.
|
||||
pub struct BoxResponseBody<S, B> {
|
||||
inner: S,
|
||||
_request_body: PhantomData<fn() -> B>,
|
||||
}
|
||||
|
||||
impl<S, B> Clone for BoxResponseBody<S, B>
|
||||
where
|
||||
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
|
||||
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||
{
|
||||
type Response = Response<BoxBody>;
|
||||
type Error = S::Error;
|
||||
type Future = future::BoxResponseBodyFuture<Oneshot<S, Request<ReqBody>>>;
|
||||
|
||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
||||
let fut = self.inner.clone().oneshot(req);
|
||||
future::BoxResponseBodyFuture { future: fut }
|
||||
}
|
||||
}
|
||||
|
||||
/// ```compile_fail
|
||||
/// use crate::{service::ServiceExt, prelude::*};
|
||||
/// use tower::service_fn;
|
||||
|
|
|
@ -39,17 +39,19 @@ mod for_handlers {
|
|||
mod for_services {
|
||||
use super::*;
|
||||
use crate::service::get;
|
||||
use headers::HeaderValue;
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_handles_head() {
|
||||
let app = route(
|
||||
"/",
|
||||
get((|| async {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("x-some-header", "foobar".parse().unwrap());
|
||||
(headers, "you shouldn't see this")
|
||||
})
|
||||
.into_service()),
|
||||
get(service_fn(|req: Request<Body>| async move {
|
||||
let res = Response::builder()
|
||||
.header("x-some-header", "foobar".parse::<HeaderValue>().unwrap())
|
||||
.body(Body::from("you shouldn't see this"))
|
||||
.unwrap();
|
||||
Ok::<_, Infallible>(res)
|
||||
})),
|
||||
);
|
||||
|
||||
// don't use reqwest because it always strips bodies from HEAD responses
|
||||
|
|
|
@ -354,10 +354,7 @@ async fn routing_between_services() {
|
|||
}),
|
||||
),
|
||||
)
|
||||
.route(
|
||||
"/two",
|
||||
service::on(MethodFilter::GET, handle.into_service()),
|
||||
);
|
||||
.route("/two", service::on(MethodFilter::GET, any(handle)));
|
||||
|
||||
let addr = run_in_background(app).await;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use bytes::Bytes;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// A string like type backed by `Bytes` making it cheap to clone.
|
||||
|
@ -28,3 +29,11 @@ impl ByteStr {
|
|||
std::str::from_utf8(&self.0).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
#[project = EitherProj]
|
||||
pub(crate) enum Either<A, B> {
|
||||
A { #[pin] inner: A },
|
||||
B { #[pin] inner: B },
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue