diff --git a/Cargo.toml b/Cargo.toml index 61c4414f74..8ea63cfaf5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ log = "0.4" pin-project = "0.4" time = "0.1" tower-service = "=0.3.0-alpha.2" -tower-make = { version = "=0.3.0-alpha.2a", features = ['io'] } tokio-executor = "=0.2.0-alpha.6" tokio-io = "=0.2.0-alpha.6" tokio-sync = "=0.2.0-alpha.6" diff --git a/examples/tower_client.rs b/examples/tower_client.rs index 634099f86e..ce4a0348c4 100644 --- a/examples/tower_client.rs +++ b/examples/tower_client.rs @@ -1,7 +1,9 @@ +#![deny(warnings)] -use hyper::client::service::{Connect, Service, MakeService}; +use hyper::client::service::Connect; use hyper::client::conn::Builder; use hyper::client::connect::HttpConnector; +use hyper::service::Service; use hyper::{Body, Request}; #[tokio::main] @@ -13,7 +15,7 @@ async fn main() -> Result<(), Box> { let uri = "http://127.0.0.1:8080".parse::()?; - let mut svc = mk_svc.make_service(uri.clone()).await?; + let mut svc = mk_svc.call(uri.clone()).await?; let body = Body::empty(); diff --git a/examples/tower_server.rs b/examples/tower_server.rs index ddc34f00a6..b8816bf0dc 100644 --- a/examples/tower_server.rs +++ b/examples/tower_server.rs @@ -1,10 +1,11 @@ #![deny(warnings)] -use hyper::{Body, Request, Response, Server}; -use tower_service::Service; -use futures_util::future; use std::task::{Context, Poll}; +use futures_util::future; +use hyper::{Body, Request, Response, Server}; +use hyper::service::Service; + const ROOT: &'static str = "/"; #[derive(Debug)] diff --git a/src/client/service.rs b/src/client/service.rs index 169f911415..bfb77e1405 100644 --- a/src/client/service.rs +++ b/src/client/service.rs @@ -1,17 +1,13 @@ //! Utilities used to interact with the Tower ecosystem. //! -//! This module provides exports of `Service`, `MakeService` and `Connect` which -//! all provide hook-ins into the Tower ecosystem. +//! This module provides `Connect` which hook-ins into the Tower ecosystem. -use super::conn::{SendRequest, Builder}; use std::marker::PhantomData; -use crate::{common::{Poll, task, Pin}, body::Payload}; use std::future::Future; use std::error::Error as StdError; -use tower_make::MakeConnection; -pub use tower_service::Service; -pub use tower_make::MakeService; +use crate::{common::{Poll, task, Pin}, body::Payload, service::{MakeConnection, Service}}; +use super::conn::{SendRequest, Builder}; /// Creates a connection via `SendRequest`. /// diff --git a/src/common/exec.rs b/src/common/exec.rs index 0fbe591e09..cba551a10f 100644 --- a/src/common/exec.rs +++ b/src/common/exec.rs @@ -8,13 +8,13 @@ use tokio_executor::{SpawnError, TypedExecutor}; use crate::body::{Payload, Body}; use crate::proto::h2::server::H2Stream; use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; -use crate::service::Service; +use crate::service::HttpService; pub trait H2Exec: Clone { fn execute_h2stream(&mut self, fut: H2Stream) -> crate::Result<()>; } -pub trait NewSvcExec, E, W: Watcher>: Clone { +pub trait NewSvcExec, E, W: Watcher>: Clone { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()>; } @@ -119,7 +119,7 @@ where impl NewSvcExec for Exec where NewSvcTask: Future + Send + 'static, - S: Service, + S: HttpService, W: Watcher, { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()> { @@ -148,7 +148,7 @@ impl NewSvcExec for E where E: TypedExecutor> + Clone, NewSvcTask: Future, - S: Service, + S: HttpService, W: Watcher, { fn execute_new_svc(&mut self, fut: NewSvcTask) -> crate::Result<()> { diff --git a/src/proto/h1/dispatch.rs b/src/proto/h1/dispatch.rs index 4329208b10..ff103a5c01 100644 --- a/src/proto/h1/dispatch.rs +++ b/src/proto/h1/dispatch.rs @@ -8,7 +8,7 @@ use crate::body::{Body, Payload}; use crate::common::{Future, Never, Poll, Pin, Unpin, task}; use crate::proto::{BodyLength, DecodedLength, Conn, Dispatched, MessageHead, RequestHead, RequestLine, ResponseHead}; use super::Http1Transaction; -use crate::service::Service; +use crate::service::HttpService; pub(crate) struct Dispatcher { conn: Conn, @@ -29,7 +29,7 @@ pub(crate) trait Dispatch { fn should_poll(&self) -> bool; } -pub struct Server, B> { +pub struct Server, B> { in_flight: Pin>>, pub(crate) service: S, } @@ -407,7 +407,7 @@ impl<'a, T> Drop for OptGuard<'a, T> { impl Server where - S: Service, + S: HttpService, { pub fn new(service: S) -> Server { Server { @@ -422,11 +422,11 @@ where } // Service is never pinned -impl, B> Unpin for Server {} +impl, B> Unpin for Server {} impl Dispatch for Server where - S: Service, + S: HttpService, S::Error: Into>, Bs: Payload, { diff --git a/src/proto/h2/server.rs b/src/proto/h2/server.rs index 8f7d23d82f..31215fba39 100644 --- a/src/proto/h2/server.rs +++ b/src/proto/h2/server.rs @@ -11,7 +11,7 @@ use crate::common::exec::H2Exec; use crate::common::{Future, Pin, Poll, task}; use crate::headers; use crate::headers::content_length_parse_all; -use crate::service::Service; +use crate::service::HttpService; use crate::proto::Dispatched; use super::{PipeToSendStream, SendBuf}; @@ -19,7 +19,7 @@ use crate::{Body, Response}; pub(crate) struct Server where - S: Service, + S: HttpService, B: Payload, { exec: E, @@ -28,7 +28,7 @@ where } // TODO: fix me -impl, B: Payload, E> Unpin for Server {} +impl, B: Payload, E> Unpin for Server {} enum State where @@ -51,7 +51,7 @@ where impl Server where T: AsyncRead + AsyncWrite + Unpin, - S: Service, + S: HttpService, S::Error: Into>, B: Payload, B::Data: Unpin, @@ -89,7 +89,7 @@ where impl Future for Server where T: AsyncRead + AsyncWrite + Unpin, - S: Service, + S: HttpService, S::Error: Into>, B: Payload, B::Data: Unpin, @@ -131,7 +131,7 @@ where { fn poll_server(&mut self, cx: &mut task::Context<'_>, service: &mut S, exec: &mut E) -> Poll> where - S: Service< + S: HttpService< Body, ResBody=B, >, diff --git a/src/server/conn.rs b/src/server/conn.rs index 01ec692c9e..523b0d44da 100644 --- a/src/server/conn.rs +++ b/src/server/conn.rs @@ -26,7 +26,7 @@ use crate::common::io::Rewind; use crate::common::{Future, Pin, Poll, Unpin, task}; use crate::error::{Kind, Parse}; use crate::proto; -use crate::service::{MakeServiceRef, Service}; +use crate::service::{MakeServiceRef, HttpService}; use crate::upgrade::Upgraded; use super::Accept; @@ -117,7 +117,7 @@ pub(super) struct SpawnAll { #[pin_project] pub struct Connection where - S: Service, + S: HttpService, { pub(super) conn: Option Http { /// # async fn run(some_io: I, some_service: S) /// # where /// # I: AsyncRead + AsyncWrite + Unpin + Send + 'static, - /// # S: Service + Send + 'static, - /// # S::Future: Send + /// # S: Service, Response=hyper::Response> + Send + 'static, + /// # S::Error: Into>, + /// # S::Future: Send, /// # { /// let http = Http::new(); /// let conn = http.serve_connection(some_io, some_service); @@ -376,7 +377,7 @@ impl Http { /// ``` pub fn serve_connection(&self, io: I, service: S) -> Connection where - S: Service, + S: HttpService, S::Error: Into>, Bd: Payload, Bd::Data: Unpin, @@ -431,8 +432,9 @@ impl Http { ResBody=Bd, >, S::Error: Into>, + S::Service: HttpService, Bd: Payload, - E: H2Exec<>::Future, Bd>, + E: H2Exec<>::Future, Bd>, { let mut incoming = AddrIncoming::new(addr, None)?; if self.keep_alive { @@ -454,7 +456,7 @@ impl Http { >, S::Error: Into>, Bd: Payload, - E: H2Exec<>::Future, Bd>, + E: H2Exec<>::Future, Bd>, { let mut incoming = AddrIncoming::new(addr, Some(handle))?; if self.keep_alive { @@ -477,7 +479,7 @@ impl Http { >, S::Error: Into>, Bd: Payload, - E: H2Exec<>::Future, Bd>, + E: H2Exec<>::Future, Bd>, { Serve { incoming, @@ -498,7 +500,7 @@ impl Http { >, S::Error: Into>, Bd: Payload, - E: H2Exec<>::Future, Bd>, + E: H2Exec<>::Future, Bd>, { Serve { incoming, @@ -513,7 +515,7 @@ impl Http { impl Connection where - S: Service, + S: HttpService, S::Error: Into>, I: AsyncRead + AsyncWrite + Unpin, B: Payload + 'static, @@ -662,7 +664,7 @@ where impl Future for Connection where - S: Service, + S: HttpService, S::Error: Into>, I: AsyncRead + AsyncWrite + Unpin + 'static, B: Payload + 'static, @@ -700,7 +702,7 @@ where impl fmt::Debug for Connection where - S: Service, + S: HttpService, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Connection") @@ -740,7 +742,7 @@ where IE: Into>, S: MakeServiceRef, B: Payload, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, { fn poll_next_(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll>>> { let me = self.project(); @@ -774,7 +776,7 @@ where IE: Into>, S: MakeServiceRef, B: Payload, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, { type Item = crate::Result>; @@ -790,7 +792,7 @@ impl Future for Connecting where I: AsyncRead + AsyncWrite + Unpin, F: Future>, - S: Service, + S: HttpService, B: Payload, B::Data: Unpin, E: H2Exec, @@ -831,7 +833,7 @@ where ResBody=B, >, B: Payload, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, { pub(super) fn poll_watch(self: Pin<&mut Self>, cx: &mut task::Context<'_>, watcher: &W) -> Poll> where @@ -875,7 +877,7 @@ pub(crate) mod spawn_all { use crate::body::{Body, Payload}; use crate::common::exec::H2Exec; use crate::common::{Future, Pin, Poll, Unpin, task}; - use crate::service::Service; + use crate::service::HttpService; use super::{Connecting, UpgradeableConnection}; use pin_project::{pin_project, project}; @@ -887,7 +889,7 @@ pub(crate) mod spawn_all { // The `Server::with_graceful_shutdown` needs to keep track of all active // connections, and signal that they start to shutdown when prompted, so // it has a `GracefulWatcher` implementation to do that. - pub trait Watcher, E>: Clone { + pub trait Watcher, E>: Clone { type Future: Future>; fn watch(&self, conn: UpgradeableConnection) -> Self::Future; @@ -900,7 +902,7 @@ pub(crate) mod spawn_all { impl Watcher for NoopWatcher where I: AsyncRead + AsyncWrite + Unpin + Send + 'static, - S: Service + 'static, + S: HttpService + 'static, ::Data: Unpin, E: H2Exec, { @@ -923,18 +925,18 @@ pub(crate) mod spawn_all { #[pin_project] #[allow(missing_debug_implementations)] - pub struct NewSvcTask, E, W: Watcher> { + pub struct NewSvcTask, E, W: Watcher> { #[pin] state: State, } #[pin_project] - pub enum State, E, W: Watcher> { + pub enum State, E, W: Watcher> { Connecting(#[pin] Connecting, W), Connected(#[pin] W::Future), } - impl, E, W: Watcher> NewSvcTask { + impl, E, W: Watcher> NewSvcTask { pub(super) fn new(connecting: Connecting, watcher: W) -> Self { NewSvcTask { state: State::Connecting(connecting, watcher), @@ -947,7 +949,7 @@ pub(crate) mod spawn_all { I: AsyncRead + AsyncWrite + Unpin + Send + 'static, N: Future>, NE: Into>, - S: Service, + S: HttpService, B: Payload, B::Data: Unpin, E: H2Exec, @@ -1008,14 +1010,14 @@ mod upgrades { #[allow(missing_debug_implementations)] pub struct UpgradeableConnection where - S: Service, + S: HttpService, { pub(super) inner: Connection, } impl UpgradeableConnection where - S: Service,// + 'static, + S: HttpService,// + 'static, S::Error: Into>, I: AsyncRead + AsyncWrite + Unpin, B: Payload + 'static, @@ -1033,7 +1035,7 @@ mod upgrades { impl Future for UpgradeableConnection where - S: Service + 'static, + S: HttpService + 'static, S::Error: Into>, I: AsyncRead + AsyncWrite + Unpin + Send + 'static, B: Payload + 'static, diff --git a/src/server/mod.rs b/src/server/mod.rs index 5d7ac6886a..fb11b686f0 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -65,7 +65,7 @@ use pin_project::pin_project; use crate::body::{Body, Payload}; use crate::common::exec::{Exec, H2Exec, NewSvcExec}; use crate::common::{Future, Pin, Poll, Unpin, task}; -use crate::service::{MakeServiceRef, Service}; +use crate::service::{MakeServiceRef, HttpService}; use self::accept::Accept; // Renamed `Http` as `Http_` for now so that people upgrading don't see an // error that `hyper::server::Http` is private... @@ -152,7 +152,7 @@ where S::Service: 'static, B: Payload, B::Data: Unpin, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, E: NewSvcExec, { /// Prepares a server to handle graceful shutdown when the provided future @@ -209,7 +209,7 @@ where S::Service: 'static, B: Payload, B::Data: Unpin, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, E: NewSvcExec, { type Output = crate::Result<()>; @@ -396,7 +396,7 @@ impl Builder { B: Payload, B::Data: Unpin, E: NewSvcExec, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, { let serve = self.protocol.serve(self.incoming, new_service); let spawn_all = serve.spawn_all(); diff --git a/src/server/shutdown.rs b/src/server/shutdown.rs index fec48e9044..703e71843b 100644 --- a/src/server/shutdown.rs +++ b/src/server/shutdown.rs @@ -7,7 +7,7 @@ use crate::body::{Body, Payload}; use crate::common::drain::{self, Draining, Signal, Watch, Watching}; use crate::common::exec::{H2Exec, NewSvcExec}; use crate::common::{Future, Pin, Poll, Unpin, task}; -use crate::service::{MakeServiceRef, Service}; +use crate::service::{MakeServiceRef, HttpService}; use super::Accept; use super::conn::{SpawnAll, UpgradeableConnection, Watcher}; @@ -55,7 +55,7 @@ where B: Payload, B::Data: Unpin, F: Future, - E: H2Exec<>::Future, B>, + E: H2Exec<>::Future, B>, E: NewSvcExec, { type Output = crate::Result<()>; @@ -106,7 +106,7 @@ pub struct GracefulWatcher(Watch); impl Watcher for GracefulWatcher where I: AsyncRead + AsyncWrite + Unpin + Send + 'static, - S: Service + 'static, + S: HttpService + 'static, ::Data: Unpin, E: H2Exec, { @@ -122,7 +122,7 @@ where fn on_drain(conn: Pin<&mut UpgradeableConnection>) where - S: Service, + S: HttpService, S::Error: Into>, I: AsyncRead + AsyncWrite + Unpin, S::ResBody: Payload + 'static, diff --git a/src/service/http.rs b/src/service/http.rs new file mode 100644 index 0000000000..bb146016c4 --- /dev/null +++ b/src/service/http.rs @@ -0,0 +1,58 @@ +use std::error::Error as StdError; + +use crate::body::Payload; +use crate::common::{Future, Poll, task}; +use crate::{Request, Response}; + +/// An asynchronous function from `Request` to `Response`. +pub trait HttpService: sealed::Sealed { + /// 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, Self::Error>>; + + #[doc(hidden)] + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll>; + + #[doc(hidden)] + fn call(&mut self, req: Request) -> Self::Future; +} + +impl HttpService for T +where + T: tower_service::Service, Response = Response>, + B2: Payload, + T::Error: Into>, +{ + type ResBody = B2; + + type Error = T::Error; + type Future = T::Future; + + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { + tower_service::Service::poll_ready(self, cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + tower_service::Service::call(self, req) + } +} + +impl sealed::Sealed for T +where + T: tower_service::Service, Response = Response>, + B2: Payload, +{} + +mod sealed { + pub trait Sealed {} +} + diff --git a/src/service/make_service.rs b/src/service/make.rs similarity index 58% rename from src/service/make_service.rs rename to src/service/make.rs index 731c38b0af..4a7ce75cfe 100644 --- a/src/service/make_service.rs +++ b/src/service/make.rs @@ -1,81 +1,50 @@ use std::error::Error as StdError; use std::fmt; +use tokio_io::{AsyncRead, AsyncWrite}; + use crate::body::Payload; use crate::common::{Future, Poll, task}; -use super::Service; - -/// An asynchronous constructor of `Service`s. -pub trait MakeService: sealed::Sealed { - /// The `Payload` body of the `http::Response`. - type ResBody: Payload; - - /// The error type that can be returned by `Service`s. - type Error: Into>; - - /// The resolved `Service` from `make_service()`. - type Service: Service< - ReqBody, - ResBody=Self::ResBody, - Error=Self::Error, - >; +use super::{HttpService, Service}; - /// The future returned from `new_service` of a `Service`. - type Future: Future>; +// The same "trait alias" as tower::MakeConnection, but inlined to reduce +// dependencies. +pub trait MakeConnection: self::sealed::Sealed<(Target,)> { + type Connection: AsyncRead + AsyncWrite; + type Error; + type Future: Future>; - /// The error type that can be returned when creating a new `Service`. - type MakeError: Into>; - - /// Returns `Ready` when the constructor is ready to create a new `Service`. - /// - /// The implementation of this method is allowed to return a `Ready` even if - /// the factory is not ready to create a new service. In this case, the future - /// returned from `make_service` will resolve to an error. - fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll>; + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll>; - /// Create a new `Service`. - fn make_service(&mut self, target: Target) -> Self::Future; + fn make_connection(&mut self, target: Target) -> Self::Future; } -impl MakeService for T +impl self::sealed::Sealed<(Target,)> for S where S: Service {} + +impl MakeConnection for S where - T: for<'a> tower_service::Service<&'a Target, Response = S, Error = E, Future = F>, - S: tower_service::Service, Response = crate::Response>, - E: Into>, - S::Error: Into>, - B1: Payload, - B2: Payload, - F: Future>, + S: Service, + S::Response: AsyncRead + AsyncWrite, { - type ResBody = B2; + type Connection = S::Response; type Error = S::Error; - type Service = S; - type Future = F; - type MakeError = E; + type Future = S::Future; - fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { - tower_service::Service::poll_ready(self, cx) + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { + Service::poll_ready(self, cx) } - fn make_service(&mut self, req: Target) -> Self::Future { - tower_service::Service::call(self, &req) + fn make_connection(&mut self, target: Target) -> Self::Future { + Service::call(self, target) } } -impl sealed::Sealed for T -where - T: for<'a> tower_service::Service<&'a Target, Response = S>, - S: tower_service::Service, Response = crate::Response> -{ -} - // Just a sort-of "trait alias" of `MakeService`, not to be implemented // by anyone, only used as bounds. -#[doc(hidden)] -pub trait MakeServiceRef: self::sealed::Sealed { +pub trait MakeServiceRef: self::sealed::Sealed<(Target, ReqBody)> { type ResBody: Payload; type Error: Into>; - type Service: Service< + type Service: HttpService< ReqBody, ResBody=Self::ResBody, Error=Self::Error, @@ -101,10 +70,10 @@ pub trait MakeServiceRef: self::sealed::Sealed impl MakeServiceRef for T where - T: for<'a> tower_service::Service<&'a Target, Error=ME, Response=S, Future=F>, + T: for<'a> Service<&'a Target, Error=ME, Response=S, Future=F>, E: Into>, ME: Into>, - S: tower_service::Service, Response=crate::Response, Error=E>, + S: HttpService, F: Future>, IB: Payload, OB: Payload, @@ -126,17 +95,24 @@ where } } +impl self::sealed::Sealed<(Target, B1)> for T +where + T: for<'a> Service<&'a Target, Response = S>, + S: HttpService, + B1: Payload, + B2: Payload, +{ +} + /// Create a `MakeService` from a function. /// /// # Example /// -/// ```rust,no_run +/// ``` /// # #[cfg(feature = "runtime")] -/// # #[tokio::main] -/// # async fn main() { -/// use std::net::TcpStream; -/// use hyper::{Body, Error, Request, Response, Server}; -/// use hyper::rt::{self, Future}; +/// # async fn run() { +/// use std::convert::Infallible; +/// use hyper::{Body, Request, Response, Server}; /// use hyper::server::conn::AddrStream; /// use hyper::service::{make_service_fn, service_fn}; /// @@ -145,8 +121,8 @@ where /// let make_svc = make_service_fn(|socket: &AddrStream| { /// let remote_addr = socket.remote_addr(); /// async move { -/// Ok::<_, Error>(service_fn(move |_: Request| async move { -/// Ok::<_, Error>( +/// Ok::<_, Infallible>(service_fn(move |_: Request| async move { +/// Ok::<_, Infallible>( /// Response::new(Body::from(format!("Hello, {}!", remote_addr))) /// ) /// })) @@ -162,7 +138,7 @@ where /// eprintln!("server error: {}", e); /// } /// # } -/// # #[cfg(not(feature = "runtime"))] fn main() {} +/// # fn main() {} /// ``` pub fn make_service_fn(f: F) -> MakeServiceFn where @@ -179,7 +155,7 @@ pub struct MakeServiceFn { f: F, } -impl<'t, F, Ret, Target, Svc, MkErr> tower_service::Service<&'t Target> for MakeServiceFn +impl<'t, F, Ret, Target, Svc, MkErr> Service<&'t Target> for MakeServiceFn where F: FnMut(&Target) -> Ret, Ret: Future>, @@ -206,7 +182,7 @@ impl fmt::Debug for MakeServiceFn { } mod sealed { - pub trait Sealed {} + pub trait Sealed {} pub trait CantImpl {} diff --git a/src/service/mod.rs b/src/service/mod.rs index 4f6d48afff..82d7f10325 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,15 +1,21 @@ -//! Services and MakeServices +//! Asynchronous Services //! -//! - A [`Service`](service::Service) is a trait representing an asynchronous -//! function of a request to a response. It's similar to -//! `async fn(Request) -> Result`. -//! - A [`MakeService`](service::MakeService) is a trait creating specific -//! instances of a `Service`. +//! A [`Service`](service::Service) is a trait representing an asynchronous +//! function of a request to a response. It's similar to +//! `async fn(Request) -> Result`. //! -//! These types are conceptually similar to those in -//! [tower](https://crates.io/crates/tower), while being specific to hyper. +//! The argument and return value isn't strictly required to be for HTTP. +//! Therefore, hyper uses several "trait aliases" to reduce clutter around +//! bounds. These are: //! -//! # Service +//! - `HttpService`: This is blanketly implemented for all types that +//! implement `Service, Response = http::Response>`. +//! - `MakeService`: When a `Service` returns a new `Service` as its "response", +//! we consider it a `MakeService`. Again, blanketly implemented in those cases. +//! - `MakeConnection`: A `Service` that returns a "connection", a type that +//! implements `AsyncRead` and `AsyncWrite`. +//! +//! # HttpService //! //! In hyper, especially in the server setting, a `Service` is usually bound //! to a single connection. It defines how to respond to **all** requests that @@ -25,11 +31,17 @@ //! `MakeService` does. //! //! Resources that need to be shared by all `Service`s can be put into a -//! `MakeService`, and then passed to individual `Service`s when `make_service` +//! `MakeService`, and then passed to individual `Service`s when `call` //! is called. -mod make_service; -mod service; +pub use tower_service::Service; + +mod http; +mod make; +mod util; + +pub(crate) use self::make::{MakeConnection, MakeServiceRef}; +pub(crate) use self::http::HttpService; -pub use self::make_service::{make_service_fn, MakeService, MakeServiceRef}; -pub use self::service::{service_fn, Service}; +pub use self::make::make_service_fn; +pub use self::util::service_fn; diff --git a/src/service/service.rs b/src/service/service.rs deleted file mode 100644 index 171135a05c..0000000000 --- a/src/service/service.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::error::Error as StdError; -use std::fmt; -use std::marker::PhantomData; - -use crate::body::Payload; -use crate::common::{Future, Poll, task}; -use crate::{Request, Response}; - -/// An asynchronous function from `Request` to `Response`. -pub trait Service: sealed::Sealed { - /// 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, 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, cx: &mut task::Context<'_>) -> Poll>; - - /// Calls this `Service` with a request, returning a `Future` of the response. - fn call(&mut self, req: Request) -> Self::Future; -} - -impl Service for T -where - T: tower_service::Service, Response = Response>, - B2: Payload, - T::Error: Into>, -{ - type ResBody = B2; - - type Error = T::Error; - type Future = T::Future; - - fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { - tower_service::Service::poll_ready(self, cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - tower_service::Service::call(self, req) - } -} - -impl sealed::Sealed for T -where - T: tower_service::Service, Response = Response>, - B2: Payload, -{} - -mod sealed { - pub trait Sealed {} -} - - -/// 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| async move{ -/// 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: Future, -{ - ServiceFn { - f, - _req: PhantomData, - } -} - -// Not exported from crate as this will likely be replaced with `impl Service`. -pub struct ServiceFn { - f: F, - _req: PhantomData, -} - -impl tower_service::Service> for ServiceFn -where - F: FnMut(Request) -> Ret, - ReqBody: Payload, - Ret: Future, E>>, - E: Into>, - ResBody: Payload, -{ - type Response = crate::Response; - type Error = E; - type Future = Ret; - - fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, req: Request) -> Self::Future { - (self.f)(req) - } -} - -impl fmt::Debug for ServiceFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("impl Service") - .finish() - } -} diff --git a/src/service/util.rs b/src/service/util.rs new file mode 100644 index 0000000000..7c658176da --- /dev/null +++ b/src/service/util.rs @@ -0,0 +1,70 @@ +use std::error::Error as StdError; +use std::fmt; +use std::marker::PhantomData; + +use crate::body::Payload; +use crate::common::{Future, Poll, task}; +use crate::{Request, Response}; + +/// Create a `Service` from a function. +/// +/// # Example +/// +/// ``` +/// use hyper::{Body, Request, Response, Version}; +/// use hyper::service::service_fn; +/// +/// let service = service_fn(|req: Request| async move { +/// 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: Future, +{ + ServiceFn { + f, + _req: PhantomData, + } +} + +// Not exported from crate as this will likely be replaced with `impl Service`. +pub struct ServiceFn { + f: F, + _req: PhantomData, +} + +impl tower_service::Service> for ServiceFn +where + F: FnMut(Request) -> Ret, + ReqBody: Payload, + Ret: Future, E>>, + E: Into>, + ResBody: Payload, +{ + type Response = crate::Response; + type Error = E; + type Future = Ret; + + fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: Request) -> Self::Future { + (self.f)(req) + } +} + +impl fmt::Debug for ServiceFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("impl Service") + .finish() + } +}