Fix for service as bottom handler (#27)

Would previously fail because of a mismatch in error types.
This commit is contained in:
David Pedersen 2021-07-06 09:40:25 +02:00 committed by GitHub
parent c4d266e94d
commit 3cd4a1d6a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 60 additions and 26 deletions

View File

@ -206,7 +206,7 @@ where
OnMethod { OnMethod {
method, method,
svc: handler.into_service(), svc: handler.into_service(),
fallback: EmptyRouter, fallback: EmptyRouter::new(),
} }
} }

View File

@ -679,13 +679,13 @@ pub mod prelude {
/// # Panics /// # Panics
/// ///
/// Panics if `description` doesn't start with `/`. /// Panics if `description` doesn't start with `/`.
pub fn route<S, B>(description: &str, service: S) -> Route<S, EmptyRouter> pub fn route<S, B>(description: &str, service: S) -> Route<S, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
use routing::RoutingDsl; use routing::RoutingDsl;
routing::EmptyRouter.route(description, service) routing::EmptyRouter::new().route(description, service)
} }
mod sealed { mod sealed {

View File

@ -12,6 +12,7 @@ use std::{
convert::Infallible, convert::Infallible,
fmt, fmt,
future::Future, future::Future,
marker::PhantomData,
pin::Pin, pin::Pin,
sync::Arc, sync::Arc,
task::{Context, Poll}, task::{Context, Poll},
@ -362,17 +363,36 @@ fn insert_url_params<B>(req: &mut Request<B>, params: Vec<(String, String)>) {
/// ///
/// This is used as the bottom service in a router stack. You shouldn't have to /// This is used as the bottom service in a router stack. You shouldn't have to
/// use to manually. /// use to manually.
#[derive(Debug, Clone, Copy)] pub struct EmptyRouter<E = Infallible>(PhantomData<fn() -> E>);
pub struct EmptyRouter;
impl RoutingDsl for EmptyRouter {} impl<E> EmptyRouter<E> {
pub(crate) fn new() -> Self {
Self(PhantomData)
}
}
impl crate::sealed::Sealed for EmptyRouter {} impl<E> Clone for EmptyRouter<E> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}
impl<B> Service<Request<B>> for EmptyRouter { impl<E> Copy for EmptyRouter<E> {}
impl<E> fmt::Debug for EmptyRouter<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("EmptyRouter").finish()
}
}
impl<E> RoutingDsl for EmptyRouter<E> {}
impl<E> crate::sealed::Sealed for EmptyRouter<E> {}
impl<B, E> Service<Request<B>> for EmptyRouter<E> {
type Response = Response<BoxBody>; type Response = Response<BoxBody>;
type Error = Infallible; type Error = E;
type Future = EmptyRouterFuture; type Future = EmptyRouterFuture<E>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
@ -387,8 +407,8 @@ impl<B> Service<Request<B>> for EmptyRouter {
opaque_future! { opaque_future! {
/// Response future for [`EmptyRouter`]. /// Response future for [`EmptyRouter`].
pub type EmptyRouterFuture = pub type EmptyRouterFuture<E> =
future::Ready<Result<Response<BoxBody>, Infallible>>; future::Ready<Result<Response<BoxBody>, E>>;
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -744,14 +764,14 @@ where
/// If necessary you can use [`RoutingDsl::boxed`] to box a group of routes /// If necessary you can use [`RoutingDsl::boxed`] to box a group of routes
/// making the type easier to name. This is sometimes useful when working with /// making the type easier to name. This is sometimes useful when working with
/// `nest`. /// `nest`.
pub fn nest<S, B>(description: &str, svc: S) -> Nested<S, EmptyRouter> pub fn nest<S, B>(description: &str, svc: S) -> Nested<S, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
Nested { Nested {
pattern: PathPattern::new(description), pattern: PathPattern::new(description),
svc, svc,
fallback: EmptyRouter, fallback: EmptyRouter::new(),
} }
} }

View File

@ -109,7 +109,7 @@ pub mod future;
/// Route requests to the given service regardless of the HTTP method. /// Route requests to the given service regardless of the HTTP method.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn any<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn any<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -119,7 +119,7 @@ where
/// Route `CONNECT` requests to the given service. /// Route `CONNECT` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -129,7 +129,7 @@ where
/// Route `DELETE` requests to the given service. /// Route `DELETE` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -156,7 +156,7 @@ where
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
/// # }; /// # };
/// ``` /// ```
pub fn get<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn get<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -166,7 +166,7 @@ where
/// Route `HEAD` requests to the given service. /// Route `HEAD` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -176,7 +176,7 @@ where
/// Route `OPTIONS` requests to the given service. /// Route `OPTIONS` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -186,7 +186,7 @@ where
/// Route `PATCH` requests to the given service. /// Route `PATCH` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -196,7 +196,7 @@ where
/// Route `POST` requests to the given service. /// Route `POST` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -206,7 +206,7 @@ where
/// Route `PUT` requests to the given service. /// Route `PUT` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -216,7 +216,7 @@ where
/// Route `TRACE` requests to the given service. /// Route `TRACE` requests to the given service.
/// ///
/// See [`get`] for an example. /// See [`get`] for an example.
pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter> pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -243,7 +243,10 @@ where
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # hyper::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> pub fn on<S, B>(
method: MethodFilter,
svc: S,
) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where where
S: Service<Request<B>> + Clone, S: Service<Request<B>> + Clone,
{ {
@ -253,7 +256,7 @@ where
inner: svc, inner: svc,
_request_body: PhantomData, _request_body: PhantomData,
}, },
fallback: EmptyRouter, fallback: EmptyRouter::new(),
} }
} }

View File

@ -653,6 +653,17 @@ async fn different_request_body_types() {
assert_eq!(body, "foo"); assert_eq!(body, "foo");
} }
#[tokio::test]
async fn service_in_bottom() {
async fn handler(_req: Request<hyper::Body>) -> Result<Response<hyper::Body>, hyper::Error> {
Ok(Response::new(hyper::Body::empty()))
}
let app = route("/", service::get(service_fn(handler)));
run_in_background(app).await;
}
/// Run a `tower::Service` in the background and get a URI for it. /// Run a `tower::Service` in the background and get a URI for it.
async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr
where where