scuffle_http/service/
mod.rs

1//! HTTP service and service factory traits.
2use std::future::Future;
3use std::net::SocketAddr;
4
5use crate::IncomingRequest;
6
7mod clone_factory;
8mod function;
9#[cfg(feature = "tower")]
10#[cfg_attr(docsrs, doc(cfg(feature = "tower")))]
11mod tower_factory;
12
13pub use clone_factory::*;
14pub use function::*;
15#[cfg(feature = "tower")]
16#[cfg_attr(docsrs, doc(cfg(feature = "tower")))]
17pub use tower_factory::*;
18
19/// A trait representing an HTTP service.
20///
21/// This trait must be used in combination with [`HttpServiceFactory`].
22/// It is very similar to tower's service trait and implemented
23/// for all types that implement [`tower::Service<IncomingRequest>`](https://docs.rs/tower/latest/tower/trait.Service.html).
24pub trait HttpService {
25    /// The error type that can be returned by [`call`](HttpService::call).
26    type Error;
27    /// The response body type that is returned by [`call`](HttpService::call).
28    type ResBody: http_body::Body;
29
30    /// Handle an incoming request.
31    ///
32    /// This method is called for each incoming request.
33    /// The service must return a response for the given request.
34    fn call(
35        &mut self,
36        req: IncomingRequest,
37    ) -> impl Future<Output = Result<http::Response<Self::ResBody>, Self::Error>> + Send;
38}
39
40// Implement for tower services
41#[cfg(feature = "tower")]
42#[cfg_attr(docsrs, doc(cfg(feature = "tower")))]
43impl<T, B> HttpService for T
44where
45    T: tower::Service<IncomingRequest, Response = http::Response<B>> + Send,
46    T::Future: Send,
47    B: http_body::Body,
48{
49    type Error = T::Error;
50    type ResBody = B;
51
52    async fn call(&mut self, req: IncomingRequest) -> Result<http::Response<Self::ResBody>, Self::Error> {
53        // wait for the tower service to be ready
54        futures::future::poll_fn(|cx| self.poll_ready(cx)).await?;
55
56        self.call(req).await
57    }
58}
59
60/// A trait representing an HTTP service factory.
61///
62/// This trait must be implemented by types that can create new instances of [`HttpService`].
63/// It is conceptually similar to tower's [`MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html) trait.
64///
65/// It is intended to create a new service for each incoming connection.
66/// If you don't need to implement any custom factory logic, you can use [`ServiceCloneFactory`] to make a factory that clones the given service for each new connection.
67pub trait HttpServiceFactory {
68    /// The error type that can be returned by [`new_service`](HttpServiceFactory::new_service).
69    type Error;
70    /// The service type that is created by this factory.
71    type Service: HttpService;
72
73    /// Create a new service for a new connection.
74    ///
75    /// `remote_addr` is the address of the connecting remote peer.
76    fn new_service(&mut self, remote_addr: SocketAddr) -> impl Future<Output = Result<Self::Service, Self::Error>> + Send;
77}