use std::error::Error as StdError; use std::fmt; use std::marker::PhantomData; use futures::{future, Async, Future, IntoFuture, Poll}; use body::Payload; use common::Never; use ::{Request, Response}; /// An asynchronous function from `Request` to `Response`. pub trait Service { /// The `Payload` body of the `http::Request`. type ReqBody: Payload; /// The `Payload` body of the `http::Response`. type ResBody: Payload; /// The error type that can occur within this `Service`. /// /// Note: Returning an `Error` to a hyper server will cause the connection /// to be abruptly aborted. In most cases, it is better to return a `Response` /// with a 4xx or 5xx status code. type Error: Into>; /// The `Future` returned by this `Service`. type Future: Future, Error=Self::Error>; /// Returns `Ready` when the service is able to process requests. /// /// The implementation of this method is allowed to return a `Ready` even if /// the service is not ready to process. In this case, the future returned /// from `call` will resolve to an error. fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } /// Calls this `Service` with a request, returning a `Future` of the response. fn call(&mut self, req: Request) -> Self::Future; } /// Create a `Service` from a function. /// /// # Example /// /// ```rust /// use hyper::{Body, Request, Response, Version}; /// use hyper::service::service_fn; /// /// let service = service_fn(|req: Request| { /// if req.version() == Version::HTTP_11 { /// Ok(Response::new(Body::from("Hello World"))) /// } else { /// // Note: it's usually better to return a Response /// // with an appropriate StatusCode instead of an Err. /// Err("not HTTP/1.1, abort connection") /// } /// }); /// ``` pub fn service_fn(f: F) -> ServiceFn where F: FnMut(Request) -> S, S: IntoFuture, { ServiceFn { f, _req: PhantomData, } } /// Create a `Service` from a function that never errors. /// /// # Example /// /// ```rust /// use hyper::{Body, Request, Response}; /// use hyper::service::service_fn_ok; /// /// let service = service_fn_ok(|req: Request| { /// println!("request: {} {}", req.method(), req.uri()); /// Response::new(Body::from("Hello World")) /// }); /// ``` pub fn service_fn_ok(f: F) -> ServiceFnOk where F: FnMut(Request) -> Response, S: Payload, { ServiceFnOk { f, _req: PhantomData, } } // Not exported from crate as this will likely be replaced with `impl Service`. pub struct ServiceFn { f: F, _req: PhantomData, } impl Service for ServiceFn where F: FnMut(Request) -> Ret, ReqBody: Payload, Ret: IntoFuture>, Ret::Error: Into>, ResBody: Payload, { type ReqBody = ReqBody; type ResBody = ResBody; type Error = Ret::Error; type Future = Ret::Future; fn call(&mut self, req: Request) -> Self::Future { (self.f)(req).into_future() } } impl IntoFuture for ServiceFn { type Future = future::FutureResult; type Item = Self; type Error = Never; fn into_future(self) -> Self::Future { future::ok(self) } } impl fmt::Debug for ServiceFn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("impl Service") .finish() } } // Not exported from crate as this will likely be replaced with `impl Service`. pub struct ServiceFnOk { f: F, _req: PhantomData, } impl Service for ServiceFnOk where F: FnMut(Request) -> Response, ReqBody: Payload, ResBody: Payload, { type ReqBody = ReqBody; type ResBody = ResBody; type Error = Never; type Future = future::FutureResult, Never>; fn call(&mut self, req: Request) -> Self::Future { future::ok((self.f)(req)) } } impl IntoFuture for ServiceFnOk { type Future = future::FutureResult; type Item = Self; type Error = Never; fn into_future(self) -> Self::Future { future::ok(self) } } impl fmt::Debug for ServiceFnOk { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("impl Service") .finish() } } //#[cfg(test)] fn _assert_fn_mut() { fn assert_service(_t: &T) {} let mut val = 0; let svc = service_fn(move |_req: Request<::Body>| { val += 1; future::ok::<_, Never>(Response::new(::Body::empty())) }); assert_service(&svc); let svc = service_fn_ok(move |_req: Request<::Body>| { val += 1; Response::new(::Body::empty()) }); assert_service(&svc); }