tower_hyper_http_body_compat/
http_service.rs

1use std::{
2    fmt::Debug,
3    future::Future,
4    marker::PhantomData,
5    pin::Pin,
6    task::{Context, Poll},
7};
8
9use http::{Request, Response};
10use pin_project_lite::pin_project;
11use tower::{util::Oneshot, ServiceExt};
12
13use crate::{HttpBody04ToHttpBody1, HttpBody1ToHttpBody04};
14
15// --- tower-service 0.3 (http) to hyper 1.0 (http) ---
16
17/// Converts a [tower-service 0.3 HTTP `Service`] to a [hyper 1.0 HTTP `Service`].
18///
19/// An HTTP `Service` is a `Service` where the request is [`http::Request<_>`][Request] and the
20/// response is [`http::Response<_>`][Response].
21///
22/// # Example
23///
24/// ```no_run
25/// use http::{Request, Response, StatusCode};
26/// use hyper_1::{server::conn::http1, service::service_fn, body, body::Bytes};
27/// use std::{net::SocketAddr, convert::Infallible};
28/// use tokio::net::TcpListener;
29/// use tower_hyper_http_body_compat::TowerService03HttpServiceAsHyper1HttpService;
30///
31/// // a service function that uses hyper 0.14, tower-service 0.3, and http-body 0.4
32/// async fn handler<B>(req: Request<B>) -> Result<Response<hyper_014::body::Body>, Infallible>
33/// where
34///     B: hyper_014::body::HttpBody<Data = hyper_014::body::Bytes>,
35///     B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
36/// {
37///    let body = req.into_body();
38///    let body = http_body_04::Limited::new(body, 1024);
39///    let bytes = match hyper_014::body::to_bytes(body).await {
40///        Ok(bytes) => bytes,
41///        Err(err) => {
42///            let res = Response::builder()
43///                .status(StatusCode::BAD_REQUEST)
44///                .body(hyper_014::body::Body::empty())
45///                .unwrap();
46///            return Ok(res)
47///        }
48///    };
49///
50///    let res = Response::builder()
51///        .body(hyper_014::body::Body::from(format!("Received {} bytes", bytes.len())))
52///        .unwrap();
53///    Ok(res)
54/// }
55///
56/// // run `handler` on hyper 1.0
57/// #[tokio::main]
58/// async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
59///     let addr: SocketAddr = ([127, 0, 0, 1], 8080).into();
60///
61///     let service = tower::service_fn(handler);
62///     let service = TowerService03HttpServiceAsHyper1HttpService::new(service);
63///
64///     let mut tcp_listener = TcpListener::bind(addr).await?;
65///     loop {
66///         let (tcp_stream, _) = tcp_listener.accept().await?;
67///         let tcp_stream = hyper_util::rt::TokioIo::new(tcp_stream);
68///         let service = service.clone();
69///         tokio::task::spawn(async move {
70///             if let Err(http_err) = http1::Builder::new()
71///                     .keep_alive(true)
72///                     .serve_connection(tcp_stream, service)
73///                     .await {
74///                 eprintln!("Error while serving HTTP connection: {}", http_err);
75///             }
76///         });
77///     }
78/// }
79/// ```
80///
81/// [tower-service 0.3 HTTP `Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
82/// [hyper 1.0 HTTP `Service`]: https://docs.rs/hyper/1.0.0-rc.4/hyper/service/trait.Service.html
83pub struct TowerService03HttpServiceAsHyper1HttpService<S, B> {
84    service: S,
85    _marker: PhantomData<fn() -> B>,
86}
87
88impl<S, B> TowerService03HttpServiceAsHyper1HttpService<S, B> {
89    /// Create a new `TowerService03HttpServiceAsHyper1HttpService`.
90    #[inline]
91    pub fn new(service: S) -> Self {
92        Self {
93            service,
94            _marker: PhantomData,
95        }
96    }
97}
98
99impl<S, B> Copy for TowerService03HttpServiceAsHyper1HttpService<S, B> where S: Copy {}
100
101impl<S, B> Clone for TowerService03HttpServiceAsHyper1HttpService<S, B>
102where
103    S: Clone,
104{
105    fn clone(&self) -> Self {
106        Self {
107            service: self.service.clone(),
108            _marker: self._marker,
109        }
110    }
111}
112
113impl<S, B> Debug for TowerService03HttpServiceAsHyper1HttpService<S, B>
114where
115    S: Debug,
116{
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        f.debug_struct("TowerService03HttpServiceAsHyper1HttpService")
119            .field("service", &self.service)
120            .finish()
121    }
122}
123
124impl<S, ReqBody, ResBody> hyper_1::service::Service<Request<ReqBody>>
125    for TowerService03HttpServiceAsHyper1HttpService<S, HttpBody1ToHttpBody04<ReqBody>>
126where
127    S: tower_service_03::Service<
128            Request<HttpBody1ToHttpBody04<ReqBody>>,
129            Response = Response<ResBody>,
130        > + Clone,
131{
132    type Response = Response<HttpBody04ToHttpBody1<ResBody>>;
133    type Error = S::Error;
134    type Future = TowerService03HttpServiceAsHyper1HttpServiceFuture<
135        S,
136        Request<HttpBody1ToHttpBody04<ReqBody>>,
137    >;
138
139    #[inline]
140    fn call(&self, req: Request<ReqBody>) -> Self::Future {
141        let req = req.map(HttpBody1ToHttpBody04::new);
142        TowerService03HttpServiceAsHyper1HttpServiceFuture {
143            future: self.service.clone().oneshot(req),
144        }
145    }
146}
147
148pin_project! {
149    /// Response future for [`TowerService03HttpServiceAsHyper1HttpService`].
150    pub struct TowerService03HttpServiceAsHyper1HttpServiceFuture<S, R>
151    where
152        S: tower_service_03::Service<R>,
153    {
154        #[pin]
155        future: Oneshot<S, R>,
156    }
157}
158
159impl<S, R, B> Future for TowerService03HttpServiceAsHyper1HttpServiceFuture<S, R>
160where
161    S: tower_service_03::Service<R, Response = Response<B>>,
162{
163    type Output = Result<Response<HttpBody04ToHttpBody1<B>>, S::Error>;
164
165    #[inline]
166    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
167        let res = ready!(self.project().future.poll(cx))?;
168        Poll::Ready(Ok(res.map(HttpBody04ToHttpBody1::new)))
169    }
170}
171
172// --- hyper 1.0 (http) to tower-service 0.3 (http) ---
173
174/// Converts a [hyper 1.0 HTTP `Service`] to a [tower-service 0.3 HTTP `Service`].
175///
176/// An HTTP `Service` is a `Service` where the request is [`http::Request<_>`][Request] and the
177/// response is [`http::Response<_>`][Response].
178///
179/// [tower-service 0.3 HTTP `Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
180/// [hyper 1.0 HTTP `Service`]: https://docs.rs/hyper/1.0.0-rc.4/hyper/service/trait.Service.html
181pub struct Hyper1HttpServiceAsTowerService03HttpService<S, B> {
182    service: S,
183    _marker: PhantomData<fn() -> B>,
184}
185
186impl<S, B> Hyper1HttpServiceAsTowerService03HttpService<S, B> {
187    /// Create a new `Hyper1HttpServiceAsTowerService03HttpService`.
188    pub fn new(service: S) -> Self {
189        Self {
190            service,
191            _marker: PhantomData,
192        }
193    }
194}
195
196impl<S, B> Debug for Hyper1HttpServiceAsTowerService03HttpService<S, B>
197where
198    S: Debug,
199{
200    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201        f.debug_struct("Hyper1HttpServiceAsTowerService03HttpService")
202            .field("service", &self.service)
203            .finish()
204    }
205}
206
207impl<S, B> Clone for Hyper1HttpServiceAsTowerService03HttpService<S, B>
208where
209    S: Clone,
210{
211    fn clone(&self) -> Self {
212        Self {
213            service: self.service.clone(),
214            _marker: self._marker,
215        }
216    }
217}
218
219impl<S, B> Copy for Hyper1HttpServiceAsTowerService03HttpService<S, B> where S: Copy {}
220
221impl<S, ReqBody, ResBody> tower_service_03::Service<Request<ReqBody>>
222    for Hyper1HttpServiceAsTowerService03HttpService<S, ReqBody>
223where
224    S: hyper_1::service::Service<
225        Request<HttpBody04ToHttpBody1<ReqBody>>,
226        Response = Response<ResBody>,
227    >,
228{
229    type Response = Response<HttpBody1ToHttpBody04<ResBody>>;
230    type Error = S::Error;
231    type Future = Hyper1HttpServiceAsTowerService03HttpServiceFuture<S::Future>;
232
233    #[inline]
234    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
235        Poll::Ready(Ok(()))
236    }
237
238    fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
239        let req = req.map(HttpBody04ToHttpBody1::new);
240        Hyper1HttpServiceAsTowerService03HttpServiceFuture {
241            future: self.service.call(req),
242        }
243    }
244}
245
246pin_project! {
247    /// Response future for [`Hyper1HttpServiceAsTowerService03HttpService`].
248    pub struct Hyper1HttpServiceAsTowerService03HttpServiceFuture<F> {
249        #[pin]
250        future: F,
251    }
252}
253
254impl<F, B, E> Future for Hyper1HttpServiceAsTowerService03HttpServiceFuture<F>
255where
256    F: Future<Output = Result<Response<B>, E>>,
257{
258    type Output = Result<Response<HttpBody1ToHttpBody04<B>>, E>;
259
260    #[inline]
261    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
262        let res = ready!(self.project().future.poll(cx))?;
263        Poll::Ready(Ok(res.map(HttpBody1ToHttpBody04::new)))
264    }
265}