Skip to content

Commit fee7d36

Browse files
authored
feat(service): create own Service trait (#2920)
This removes the dependency on `tower-service`, and simplifies the `Service` trait to be used by hyper's server connections. Closes #2853 BREAKING CHANGE: Change any manual `impl tower::Service` to implement `hyper::service::Service` instead. The `poll_ready` method has been removed.
1 parent fae97ce commit fee7d36

File tree

10 files changed

+54
-170
lines changed

10 files changed

+54
-170
lines changed

Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ h2 = { version = "0.3.9", optional = true }
3535
itoa = "1"
3636
tracing = { version = "0.1", default-features = false, features = ["std"] }
3737
pin-project-lite = "0.2.4"
38-
tower-service = "0.3"
3938
tokio = { version = "1", features = ["sync"] }
4039
want = "0.3"
4140

@@ -65,7 +64,6 @@ tokio = { version = "1", features = [
6564
] }
6665
tokio-test = "0.4"
6766
tokio-util = { version = "0.7", features = ["codec"] }
68-
tower = { version = "0.4", features = ["make", "util"] }
6967
url = "2.2"
7068

7169
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dev-dependencies]

examples/service_struct_impl.rs

-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use tokio::net::TcpListener;
88
use std::future::Future;
99
use std::net::SocketAddr;
1010
use std::pin::Pin;
11-
use std::task::{Context, Poll};
1211

1312
type Counter = i32;
1413

@@ -42,10 +41,6 @@ impl Service<Request<Recv>> for Svc {
4241
type Error = hyper::Error;
4342
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
4443

45-
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
46-
Poll::Ready(Ok(()))
47-
}
48-
4944
fn call(&mut self, req: Request<Recv>) -> Self::Future {
5045
fn mk_response(s: String) -> Result<Response<Full<Bytes>>, hyper::Error> {
5146
Ok(Response::builder().body(Full::new(Bytes::from(s))).unwrap())

src/client/conn/mod.rs

-22
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
//! use http_body_util::Empty;
1919
//! use hyper::client::conn;
2020
//! use tokio::net::TcpStream;
21-
//! use tower::ServiceExt;
2221
//!
2322
//! #[tokio::main]
2423
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
@@ -41,9 +40,6 @@
4140
//! let response = request_sender.send_request(request).await?;
4241
//! assert!(response.status() == StatusCode::OK);
4342
//!
44-
//! // To send via the same connection again, it may not work as it may not be ready,
45-
//! // so we have to wait until the request_sender becomes ready.
46-
//! request_sender.ready().await?;
4743
//! let request = Request::builder()
4844
//! .header("Host", "example.com")
4945
//! .method("GET")
@@ -69,7 +65,6 @@ use futures_util::future;
6965
use httparse::ParserConfig;
7066
use pin_project_lite::pin_project;
7167
use tokio::io::{AsyncRead, AsyncWrite};
72-
use tower_service::Service;
7368
use tracing::{debug, trace};
7469

7570
use super::dispatch;
@@ -266,23 +261,6 @@ where
266261
}
267262
}
268263

269-
impl<B> Service<Request<B>> for SendRequest<B>
270-
where
271-
B: Body + 'static,
272-
{
273-
type Response = Response<Recv>;
274-
type Error = crate::Error;
275-
type Future = ResponseFuture;
276-
277-
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
278-
self.poll_ready(cx)
279-
}
280-
281-
fn call(&mut self, req: Request<B>) -> Self::Future {
282-
self.send_request(req)
283-
}
284-
}
285-
286264
impl<B> fmt::Debug for SendRequest<B> {
287265
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288266
f.debug_struct("SendRequest").finish()

src/proto/h1/dispatch.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ where
233233
}
234234

235235
fn poll_read_head(&mut self, cx: &mut task::Context<'_>) -> Poll<crate::Result<()>> {
236-
// can dispatch receive, or does it still care about, an incoming message?
236+
// can dispatch receive, or does it still care about other incoming message?
237237
match ready!(self.dispatch.poll_ready(cx)) {
238238
Ok(()) => (),
239239
Err(()) => {
@@ -242,6 +242,7 @@ where
242242
return Poll::Ready(Ok(()));
243243
}
244244
}
245+
245246
// dispatch is ready for a message, try to read one
246247
match ready!(self.conn.poll_read_head(cx)) {
247248
Some(Ok((mut head, body_len, wants))) => {
@@ -511,14 +512,11 @@ cfg_server! {
511512
Ok(())
512513
}
513514

514-
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> {
515+
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), ()>> {
515516
if self.in_flight.is_some() {
516517
Poll::Pending
517518
} else {
518-
self.service.poll_ready(cx).map_err(|_e| {
519-
// FIXME: return error value.
520-
trace!("service closed");
521-
})
519+
Poll::Ready(Ok(()))
522520
}
523521
}
524522

src/proto/h2/server.rs

-32
Original file line numberDiff line numberDiff line change
@@ -257,38 +257,6 @@ where
257257
loop {
258258
self.poll_ping(cx);
259259

260-
// Check that the service is ready to accept a new request.
261-
//
262-
// - If not, just drive the connection some.
263-
// - If ready, try to accept a new request from the connection.
264-
match service.poll_ready(cx) {
265-
Poll::Ready(Ok(())) => (),
266-
Poll::Pending => {
267-
// use `poll_closed` instead of `poll_accept`,
268-
// in order to avoid accepting a request.
269-
ready!(self.conn.poll_closed(cx).map_err(crate::Error::new_h2))?;
270-
trace!("incoming connection complete");
271-
return Poll::Ready(Ok(()));
272-
}
273-
Poll::Ready(Err(err)) => {
274-
let err = crate::Error::new_user_service(err);
275-
debug!("service closed: {}", err);
276-
277-
let reason = err.h2_reason();
278-
if reason == Reason::NO_ERROR {
279-
// NO_ERROR is only used for graceful shutdowns...
280-
trace!("interpreting NO_ERROR user error as graceful_shutdown");
281-
self.conn.graceful_shutdown();
282-
} else {
283-
trace!("abruptly shutting down with {:?}", reason);
284-
self.conn.abrupt_shutdown(reason);
285-
}
286-
self.closing = Some(err);
287-
break;
288-
}
289-
}
290-
291-
// When the service is ready, accepts an incoming request.
292260
match ready!(self.conn.poll_accept(cx)) {
293261
Some(Ok((req, mut respond))) => {
294262
trace!("incoming request");

src/service/http.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::error::Error as StdError;
22

33
use crate::body::Body;
4-
use crate::common::{task, Future, Poll};
4+
use crate::common::Future;
5+
use crate::service::service::Service;
56
use crate::{Request, Response};
67

78
/// An asynchronous function from `Request` to `Response`.
@@ -19,16 +20,13 @@ pub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {
1920
/// The `Future` returned by this `Service`.
2021
type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>;
2122

22-
#[doc(hidden)]
23-
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
24-
2523
#[doc(hidden)]
2624
fn call(&mut self, req: Request<ReqBody>) -> Self::Future;
2725
}
2826

2927
impl<T, B1, B2> HttpService<B1> for T
3028
where
31-
T: tower_service::Service<Request<B1>, Response = Response<B2>>,
29+
T: Service<Request<B1>, Response = Response<B2>>,
3230
B2: Body,
3331
T::Error: Into<Box<dyn StdError + Send + Sync>>,
3432
{
@@ -37,18 +35,14 @@ where
3735
type Error = T::Error;
3836
type Future = T::Future;
3937

40-
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
41-
tower_service::Service::poll_ready(self, cx)
42-
}
43-
4438
fn call(&mut self, req: Request<B1>) -> Self::Future {
45-
tower_service::Service::call(self, req)
39+
Service::call(self, req)
4640
}
4741
}
4842

4943
impl<T, B1, B2> sealed::Sealed<B1> for T
5044
where
51-
T: tower_service::Service<Request<B1>, Response = Response<B2>>,
45+
T: Service<Request<B1>, Response = Response<B2>>,
5246
B2: Body,
5347
{
5448
}

src/service/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121
//! if you need to implement `Service` for a type manually, you can follow the example
2222
//! in `service_struct_impl.rs`.
2323
24-
pub use tower_service::Service;
25-
2624
mod http;
25+
mod service;
2726
mod util;
2827

2928
#[cfg(all(any(feature = "http1", feature = "http2"), feature = "server"))]
3029
pub(super) use self::http::HttpService;
30+
#[cfg(all(
31+
any(feature = "http1", feature = "http2"),
32+
any(feature = "server", feature = "client")
33+
))]
34+
pub use self::service::Service;
3135

3236
pub use self::util::service_fn;

src/service/service.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::future::Future;
2+
3+
/// An asynchronous function from a `Request` to a `Response`.
4+
///
5+
/// The `Service` trait is a simplified interface making it easy to write
6+
/// network applications in a modular and reusable way, decoupled from the
7+
/// underlying protocol.
8+
///
9+
/// # Functional
10+
///
11+
/// A `Service` is a function of a `Request`. It immediately returns a
12+
/// `Future` representing the eventual completion of processing the
13+
/// request. The actual request processing may happen at any time in the
14+
/// future, on any thread or executor. The processing may depend on calling
15+
/// other services. At some point in the future, the processing will complete,
16+
/// and the `Future` will resolve to a response or error.
17+
///
18+
/// At a high level, the `Service::call` function represents an RPC request. The
19+
/// `Service` value can be a server or a client.
20+
pub trait Service<Request> {
21+
/// Responses given by the service.
22+
type Response;
23+
24+
/// Errors produced by the service.
25+
type Error;
26+
27+
/// The future response value.
28+
type Future: Future<Output = Result<Self::Response, Self::Error>>;
29+
30+
/// Process the request and return the response asynchronously.
31+
fn call(&mut self, req: Request) -> Self::Future;
32+
}

src/service/util.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use std::fmt;
33
use std::marker::PhantomData;
44

55
use crate::body::Body;
6-
use crate::common::{task, Future, Poll};
6+
use crate::common::Future;
7+
use crate::service::service::Service;
78
use crate::{Request, Response};
89

910
/// Create a `Service` from a function.
@@ -43,8 +44,7 @@ pub struct ServiceFn<F, R> {
4344
_req: PhantomData<fn(R)>,
4445
}
4546

46-
impl<F, ReqBody, Ret, ResBody, E> tower_service::Service<crate::Request<ReqBody>>
47-
for ServiceFn<F, ReqBody>
47+
impl<F, ReqBody, Ret, ResBody, E> Service<Request<ReqBody>> for ServiceFn<F, ReqBody>
4848
where
4949
F: FnMut(Request<ReqBody>) -> Ret,
5050
ReqBody: Body,
@@ -56,10 +56,6 @@ where
5656
type Error = E;
5757
type Future = Ret;
5858

59-
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
60-
Poll::Ready(Ok(()))
61-
}
62-
6359
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
6460
(self.f)(req)
6561
}

0 commit comments

Comments
 (0)