1use core::{fmt, marker::PhantomData};
2
3use xitca_io::net;
4use xitca_service::Service;
5
6use super::{
7 body::RequestBody,
8 config::{DEFAULT_HEADER_LIMIT, DEFAULT_READ_BUF_LIMIT, DEFAULT_WRITE_BUF_LIMIT, HttpServiceConfig},
9 service::HttpService,
10 tls,
11};
12
13#[doc(hidden)]
16pub(crate) mod marker {
17 pub struct Http;
18 #[cfg(feature = "http1")]
19 pub struct Http1;
20 #[cfg(all(feature = "io-uring", feature = "http1"))]
21 pub struct Http1Uring;
22 #[cfg(all(feature = "io-uring", feature = "http2"))]
23 pub struct Http2Uring;
24 #[cfg(feature = "http2")]
25 pub struct Http2;
26}
27
28pub struct HttpServiceBuilder<
31 V,
32 St,
33 FA,
34 const HEADER_LIMIT: usize,
35 const READ_BUF_LIMIT: usize,
36 const WRITE_BUF_LIMIT: usize,
37> {
38 pub(crate) tls_factory: FA,
39 pub(crate) config: HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>,
40 pub(crate) _body: PhantomData<fn(V, St)>,
41}
42
43impl
44 HttpServiceBuilder<
45 marker::Http,
46 net::Stream,
47 tls::NoOpTlsAcceptorBuilder,
48 DEFAULT_HEADER_LIMIT,
49 DEFAULT_READ_BUF_LIMIT,
50 DEFAULT_WRITE_BUF_LIMIT,
51 >
52{
53 pub const fn new() -> Self {
55 Self::with_config(HttpServiceConfig::new())
56 }
57
58 pub const fn with_config<const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>(
60 config: HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>,
61 ) -> HttpServiceBuilder<
62 marker::Http,
63 net::Stream,
64 tls::NoOpTlsAcceptorBuilder,
65 HEADER_LIMIT,
66 READ_BUF_LIMIT,
67 WRITE_BUF_LIMIT,
68 > {
69 HttpServiceBuilder {
70 tls_factory: tls::NoOpTlsAcceptorBuilder,
71 config,
72 _body: PhantomData,
73 }
74 }
75
76 #[cfg(feature = "http1")]
77 pub fn h1() -> HttpServiceBuilder<
79 marker::Http1,
80 net::TcpStream,
81 tls::NoOpTlsAcceptorBuilder,
82 DEFAULT_HEADER_LIMIT,
83 DEFAULT_READ_BUF_LIMIT,
84 DEFAULT_WRITE_BUF_LIMIT,
85 > {
86 HttpServiceBuilder {
87 tls_factory: tls::NoOpTlsAcceptorBuilder,
88 config: HttpServiceConfig::default(),
89 _body: PhantomData,
90 }
91 }
92
93 #[cfg(feature = "http2")]
94 pub fn h2() -> HttpServiceBuilder<
96 marker::Http2,
97 net::TcpStream,
98 tls::NoOpTlsAcceptorBuilder,
99 DEFAULT_HEADER_LIMIT,
100 DEFAULT_READ_BUF_LIMIT,
101 DEFAULT_WRITE_BUF_LIMIT,
102 > {
103 HttpServiceBuilder {
104 tls_factory: tls::NoOpTlsAcceptorBuilder,
105 config: HttpServiceConfig::default(),
106 _body: PhantomData,
107 }
108 }
109
110 #[cfg(feature = "http3")]
111 pub fn h3() -> super::h3::H3ServiceBuilder {
113 super::h3::H3ServiceBuilder::new()
114 }
115}
116
117impl<V, St, FA, const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>
118 HttpServiceBuilder<V, St, FA, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
119{
120 pub fn config<const HEADER_LIMIT_2: usize, const READ_BUF_LIMIT_2: usize, const WRITE_BUF_LIMIT_2: usize>(
122 self,
123 config: HttpServiceConfig<HEADER_LIMIT_2, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT_2>,
124 ) -> HttpServiceBuilder<V, St, FA, HEADER_LIMIT_2, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT_2> {
125 HttpServiceBuilder {
126 tls_factory: self.tls_factory,
127 config,
128 _body: PhantomData,
129 }
130 }
131
132 pub fn with_tls<TlsF>(
134 self,
135 tls_factory: TlsF,
136 ) -> HttpServiceBuilder<V, St, TlsF, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT> {
137 HttpServiceBuilder {
138 tls_factory,
139 config: self.config,
140 _body: PhantomData,
141 }
142 }
143
144 #[cfg(feature = "openssl")]
145 pub fn openssl(
147 self,
148 acceptor: tls::openssl::TlsAcceptor,
149 ) -> HttpServiceBuilder<V, St, tls::openssl::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
150 {
151 self.with_tls(tls::openssl::TlsAcceptorBuilder::new(acceptor))
152 }
153
154 #[cfg(feature = "rustls")]
155 pub fn rustls(
157 self,
158 config: tls::rustls::RustlsConfig,
159 ) -> HttpServiceBuilder<V, St, tls::rustls::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT> {
160 self.with_tls(tls::rustls::TlsAcceptorBuilder::new(config))
161 }
162
163 #[cfg(feature = "rustls-uring")]
164 pub fn rustls_uring(
166 self,
167 config: tls::rustls::RustlsConfig,
168 ) -> HttpServiceBuilder<V, St, tls::rustls_uring::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
169 {
170 self.with_tls(tls::rustls_uring::TlsAcceptorBuilder::new(config))
171 }
172
173 #[cfg(feature = "native-tls")]
174 pub fn native_tls(
176 self,
177 acceptor: tls::native_tls::TlsAcceptor,
178 ) -> HttpServiceBuilder<V, St, tls::native_tls::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
179 {
180 self.with_tls(tls::native_tls::TlsAcceptorBuilder::new(acceptor))
181 }
182}
183
184type Error = Box<dyn fmt::Debug>;
185
186impl<FA, S, E, const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>
187 Service<Result<S, E>>
188 for HttpServiceBuilder<marker::Http, net::Stream, FA, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
189where
190 FA: Service,
191 FA::Error: fmt::Debug + 'static,
192 E: fmt::Debug + 'static,
193{
194 type Response =
195 HttpService<net::Stream, S, RequestBody, FA::Response, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>;
196 type Error = Error;
197
198 async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
199 let service = res.map_err(|e| Box::new(e) as Error)?;
200 let tls_acceptor = self.tls_factory.call(()).await.map_err(|e| Box::new(e) as Error)?;
201 Ok(HttpService::new(self.config, service, tls_acceptor))
202 }
203}