1use std::fmt::Debug;
2use std::net::SocketAddr;
3
4use crate::error::HttpError;
5use crate::service::{HttpService, HttpServiceFactory};
6
7#[derive(Debug, Clone, bon::Builder)]
13#[builder(state_mod(vis = "pub(crate)"))]
14#[allow(dead_code)]
15pub struct HttpServer<F> {
16 #[builder(default = scuffle_context::Context::global())]
18 ctx: scuffle_context::Context,
19 #[builder(default = 1)]
21 worker_tasks: usize,
22 service_factory: F,
24 bind: SocketAddr,
29 #[builder(default = true)]
31 #[cfg(feature = "http1")]
32 enable_http1: bool,
33 #[builder(default = true)]
35 #[cfg(feature = "http2")]
36 enable_http2: bool,
37 #[builder(default = false, setters(vis = "", name = enable_http3_internal))]
38 #[cfg(feature = "http3")]
39 enable_http3: bool,
40 #[builder(default = false, setters(vis = "", name = enable_webtransport_internal))]
41 #[cfg(feature = "webtransport")]
42 enable_webtransport: bool,
43 #[builder(default = 1, setters(vis = "", name = max_webtransport_sessions_internal))]
44 #[cfg(feature = "webtransport")]
45 max_webtransport_sessions: u64,
46 #[cfg(feature = "tls-rustls")]
51 rustls_config: Option<tokio_rustls::rustls::ServerConfig>,
52}
53
54#[cfg(feature = "http3")]
55impl<F, S> HttpServerBuilder<F, S>
56where
57 S: http_server_builder::State,
58 S::EnableHttp3: http_server_builder::IsUnset,
59 S::RustlsConfig: http_server_builder::IsSet,
60{
61 pub fn enable_http3(self, enable_http3: bool) -> HttpServerBuilder<F, http_server_builder::SetEnableHttp3<S>> {
65 self.enable_http3_internal(enable_http3)
66 }
67}
68
69#[cfg(feature = "webtransport")]
70impl<F, S> HttpServerBuilder<F, S>
71where
72 S: http_server_builder::State,
73 S::EnableWebtransport: http_server_builder::IsUnset,
74 S::EnableHttp3: http_server_builder::IsSet,
75{
76 pub fn enable_webtransport(
80 self,
81 enable_webtransport: bool,
82 ) -> HttpServerBuilder<F, http_server_builder::SetEnableWebtransport<S>> {
83 self.enable_webtransport_internal(enable_webtransport)
84 }
85}
86
87#[cfg(feature = "webtransport")]
88impl<F, S> HttpServerBuilder<F, S>
89where
90 S: http_server_builder::State,
91 S::MaxWebtransportSessions: http_server_builder::IsUnset,
92 S::EnableWebtransport: http_server_builder::IsSet,
93{
94 pub fn max_webtransport_sessions(
100 self,
101 max_webtransport_sessions: u64,
102 ) -> HttpServerBuilder<F, http_server_builder::SetMaxWebtransportSessions<S>> {
103 self.max_webtransport_sessions_internal(max_webtransport_sessions)
104 }
105}
106
107#[cfg(feature = "tower")]
108impl<M, S> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, ()>, S>
109where
110 M: tower::MakeService<(), crate::IncomingRequest> + Send,
111 M::Future: Send,
112 M::Service: crate::service::HttpService,
113 S: http_server_builder::State,
114 S::ServiceFactory: http_server_builder::IsUnset,
115{
116 pub fn tower_make_service_factory(
123 self,
124 tower_make_service: M,
125 ) -> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, ()>, http_server_builder::SetServiceFactory<S>> {
126 self.service_factory(crate::service::tower_make_service_factory(tower_make_service))
127 }
128}
129
130#[cfg(feature = "tower")]
131impl<M, S> HttpServerBuilder<crate::service::TowerMakeServiceWithAddrFactory<M>, S>
132where
133 M: tower::MakeService<SocketAddr, crate::IncomingRequest> + Send,
134 M::Future: Send,
135 M::Service: crate::service::HttpService,
136 S: http_server_builder::State,
137 S::ServiceFactory: http_server_builder::IsUnset,
138{
139 pub fn tower_make_service_with_addr(
146 self,
147 tower_make_service: M,
148 ) -> HttpServerBuilder<crate::service::TowerMakeServiceWithAddrFactory<M>, http_server_builder::SetServiceFactory<S>>
149 {
150 self.service_factory(crate::service::tower_make_service_with_addr_factory(tower_make_service))
151 }
152}
153
154#[cfg(feature = "tower")]
155impl<M, T, S> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, T>, S>
156where
157 M: tower::MakeService<T, crate::IncomingRequest> + Send,
158 M::Future: Send,
159 M::Service: crate::service::HttpService,
160 T: Clone + Send,
161 S: http_server_builder::State,
162 S::ServiceFactory: http_server_builder::IsUnset,
163{
164 pub fn custom_tower_make_service_factory(
171 self,
172 tower_make_service: M,
173 target: T,
174 ) -> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, T>, http_server_builder::SetServiceFactory<S>> {
175 self.service_factory(crate::service::custom_tower_make_service_factory(tower_make_service, target))
176 }
177}
178
179impl<F> HttpServer<F>
180where
181 F: HttpServiceFactory + Clone + Send + 'static,
182 F::Error: std::error::Error + Send,
183 F::Service: Clone + Send + 'static,
184 <F::Service as HttpService>::Error: std::error::Error + Send + Sync,
185 <F::Service as HttpService>::ResBody: Send,
186 <<F::Service as HttpService>::ResBody as http_body::Body>::Data: Send,
187 <<F::Service as HttpService>::ResBody as http_body::Body>::Error: std::error::Error + Send + Sync,
188{
189 #[cfg(feature = "tls-rustls")]
190 fn set_alpn_protocols(&mut self) {
191 let Some(rustls_config) = &mut self.rustls_config else {
192 return;
193 };
194
195 if rustls_config.alpn_protocols.is_empty() {
197 #[cfg(feature = "http1")]
198 if self.enable_http1 {
199 rustls_config.alpn_protocols.push(b"http/1.0".to_vec());
200 rustls_config.alpn_protocols.push(b"http/1.1".to_vec());
201 }
202
203 #[cfg(feature = "http2")]
204 if self.enable_http2 {
205 rustls_config.alpn_protocols.push(b"h2".to_vec());
206 rustls_config.alpn_protocols.push(b"h2c".to_vec());
207 }
208
209 #[cfg(feature = "http3")]
210 if self.enable_http3 {
211 rustls_config.alpn_protocols.push(b"h3".to_vec());
212 rustls_config.alpn_protocols.push(b"h3-32".to_vec());
213 rustls_config.alpn_protocols.push(b"h3-31".to_vec());
214 rustls_config.alpn_protocols.push(b"h3-30".to_vec());
215 rustls_config.alpn_protocols.push(b"h3-29".to_vec());
216 }
217 }
218 }
219
220 pub async fn run(#[allow(unused_mut)] mut self) -> Result<(), HttpError<F>> {
228 #[cfg(feature = "tls-rustls")]
229 self.set_alpn_protocols();
230
231 #[cfg(all(not(any(feature = "http1", feature = "http2")), feature = "tls-rustls"))]
232 let start_tcp_backend = false;
233 #[cfg(all(feature = "http1", not(feature = "http2")))]
234 let start_tcp_backend = self.enable_http1;
235 #[cfg(all(not(feature = "http1"), feature = "http2"))]
236 let start_tcp_backend = self.enable_http2;
237 #[cfg(all(feature = "http1", feature = "http2"))]
238 let start_tcp_backend = self.enable_http1 || self.enable_http2;
239
240 #[cfg(feature = "tls-rustls")]
241 if let Some(_rustls_config) = self.rustls_config {
242 #[cfg(not(feature = "http3"))]
243 let enable_http3 = false;
244 #[cfg(feature = "http3")]
245 let enable_http3 = self.enable_http3;
246
247 match (start_tcp_backend, enable_http3) {
248 #[cfg(feature = "http3")]
249 (false, true) => {
250 let builder = crate::backend::h3::Http3Backend::builder()
251 .ctx(self.ctx)
252 .worker_tasks(self.worker_tasks)
253 .service_factory(self.service_factory)
254 .bind(self.bind)
255 .rustls_config(_rustls_config);
256
257 #[cfg(feature = "webtransport")]
258 let builder = builder
259 .enable_webtransport(self.enable_webtransport)
260 .max_webtransport_sessions(self.max_webtransport_sessions);
261
262 return builder.build().run().await;
263 }
264 #[cfg(any(feature = "http1", feature = "http2"))]
265 (true, false) => {
266 let builder = crate::backend::hyper::HyperBackend::builder()
267 .ctx(self.ctx)
268 .worker_tasks(self.worker_tasks)
269 .service_factory(self.service_factory)
270 .bind(self.bind)
271 .rustls_config(_rustls_config);
272
273 #[cfg(feature = "http1")]
274 let builder = builder.http1_enabled(self.enable_http1);
275
276 #[cfg(feature = "http2")]
277 let builder = builder.http2_enabled(self.enable_http2);
278
279 return builder.build().run().await;
280 }
281 #[cfg(all(any(feature = "http1", feature = "http2"), feature = "http3"))]
282 (true, true) => {
283 let builder = crate::backend::hyper::HyperBackend::builder()
284 .ctx(self.ctx.clone())
285 .worker_tasks(self.worker_tasks)
286 .service_factory(self.service_factory.clone())
287 .bind(self.bind)
288 .rustls_config(_rustls_config.clone());
289
290 #[cfg(feature = "http1")]
291 let builder = builder.http1_enabled(self.enable_http1);
292
293 #[cfg(feature = "http2")]
294 let builder = builder.http2_enabled(self.enable_http2);
295
296 let hyper = std::pin::pin!(builder.build().run());
297
298 let http3_builder = crate::backend::h3::Http3Backend::builder()
299 .ctx(self.ctx)
300 .worker_tasks(self.worker_tasks)
301 .service_factory(self.service_factory)
302 .bind(self.bind)
303 .rustls_config(_rustls_config);
304
305 #[cfg(feature = "webtransport")]
306 let http3_builder = http3_builder
307 .enable_webtransport(self.enable_webtransport)
308 .max_webtransport_sessions(self.max_webtransport_sessions);
309
310 let http3 = http3_builder.build().run();
311 let http3 = std::pin::pin!(http3);
312
313 let res = futures::future::select(hyper, http3).await;
314 match res {
315 futures::future::Either::Left((res, _)) => return res,
316 futures::future::Either::Right((res, _)) => return res,
317 }
318 }
319 _ => return Ok(()),
320 }
321
322 }
324
325 #[cfg(any(feature = "http1", feature = "http2"))]
330 if start_tcp_backend {
331 let builder = crate::backend::hyper::HyperBackend::builder()
332 .ctx(self.ctx)
333 .worker_tasks(self.worker_tasks)
334 .service_factory(self.service_factory)
335 .bind(self.bind);
336
337 #[cfg(feature = "http1")]
338 let builder = builder.http1_enabled(self.enable_http1);
339
340 #[cfg(feature = "http2")]
341 let builder = builder.http2_enabled(self.enable_http2);
342
343 return builder.build().run().await;
344 }
345
346 Ok(())
347 }
348}