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 {
method,
svc: handler.into_service(),
fallback: EmptyRouter,
fallback: EmptyRouter::new(),
}
}

View file

@ -679,13 +679,13 @@ pub mod prelude {
/// # Panics
///
/// 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
S: Service<Request<B>> + Clone,
{
use routing::RoutingDsl;
routing::EmptyRouter.route(description, service)
routing::EmptyRouter::new().route(description, service)
}
mod sealed {

View file

@ -12,6 +12,7 @@ use std::{
convert::Infallible,
fmt,
future::Future,
marker::PhantomData,
pin::Pin,
sync::Arc,
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
/// use to manually.
#[derive(Debug, Clone, Copy)]
pub struct EmptyRouter;
pub struct EmptyRouter<E = Infallible>(PhantomData<fn() -> E>);
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 Error = Infallible;
type Future = EmptyRouterFuture;
type Error = E;
type Future = EmptyRouterFuture<E>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
@ -387,8 +407,8 @@ impl<B> Service<Request<B>> for EmptyRouter {
opaque_future! {
/// Response future for [`EmptyRouter`].
pub type EmptyRouterFuture =
future::Ready<Result<Response<BoxBody>, Infallible>>;
pub type EmptyRouterFuture<E> =
future::Ready<Result<Response<BoxBody>, E>>;
}
#[derive(Debug, Clone)]
@ -744,14 +764,14 @@ where
/// 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
/// `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
S: Service<Request<B>> + Clone,
{
Nested {
pattern: PathPattern::new(description),
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.
///
/// 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
S: Service<Request<B>> + Clone,
{
@ -119,7 +119,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>
pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where
S: Service<Request<B>> + Clone,
{
@ -129,7 +129,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>
pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where
S: Service<Request<B>> + Clone,
{
@ -156,7 +156,7 @@ where
/// # 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
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>
pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
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>
pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
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>
pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
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>
pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
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>
pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
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>
pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter<S::Error>>
where
S: Service<Request<B>> + Clone,
{
@ -243,7 +243,10 @@ where
/// # 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
S: Service<Request<B>> + Clone,
{
@ -253,7 +256,7 @@ where
inner: svc,
_request_body: PhantomData,
},
fallback: EmptyRouter,
fallback: EmptyRouter::new(),
}
}

View file

@ -653,6 +653,17 @@ async fn different_request_body_types() {
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.
async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr
where