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 #[cfg(feature = "tls-rustls")]
45 rustls_config: Option<rustls::ServerConfig>,
46}
47
48#[cfg(feature = "http3")]
49impl<F, S> HttpServerBuilder<F, S>
50where
51 S: http_server_builder::State,
52 S::EnableHttp3: http_server_builder::IsUnset,
53 S::RustlsConfig: http_server_builder::IsSet,
54{
55 pub fn enable_http3(self, enable_http3: bool) -> HttpServerBuilder<F, http_server_builder::SetEnableHttp3<S>> {
59 self.enable_http3_internal(enable_http3)
60 }
61}
62
63#[cfg(feature = "tower")]
64impl<M, S> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, ()>, S>
65where
66 M: tower::MakeService<(), crate::IncomingRequest> + Send,
67 M::Future: Send,
68 M::Service: crate::service::HttpService,
69 S: http_server_builder::State,
70 S::ServiceFactory: http_server_builder::IsUnset,
71{
72 pub fn tower_make_service_factory(
79 self,
80 tower_make_service: M,
81 ) -> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, ()>, http_server_builder::SetServiceFactory<S>> {
82 self.service_factory(crate::service::tower_make_service_factory(tower_make_service))
83 }
84}
85
86#[cfg(feature = "tower")]
87impl<M, S> HttpServerBuilder<crate::service::TowerMakeServiceWithAddrFactory<M>, S>
88where
89 M: tower::MakeService<SocketAddr, crate::IncomingRequest> + Send,
90 M::Future: Send,
91 M::Service: crate::service::HttpService,
92 S: http_server_builder::State,
93 S::ServiceFactory: http_server_builder::IsUnset,
94{
95 pub fn tower_make_service_with_addr(
102 self,
103 tower_make_service: M,
104 ) -> HttpServerBuilder<crate::service::TowerMakeServiceWithAddrFactory<M>, http_server_builder::SetServiceFactory<S>>
105 {
106 self.service_factory(crate::service::tower_make_service_with_addr_factory(tower_make_service))
107 }
108}
109
110#[cfg(feature = "tower")]
111impl<M, T, S> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, T>, S>
112where
113 M: tower::MakeService<T, crate::IncomingRequest> + Send,
114 M::Future: Send,
115 M::Service: crate::service::HttpService,
116 T: Clone + Send,
117 S: http_server_builder::State,
118 S::ServiceFactory: http_server_builder::IsUnset,
119{
120 pub fn custom_tower_make_service_factory(
127 self,
128 tower_make_service: M,
129 target: T,
130 ) -> HttpServerBuilder<crate::service::TowerMakeServiceFactory<M, T>, http_server_builder::SetServiceFactory<S>> {
131 self.service_factory(crate::service::custom_tower_make_service_factory(tower_make_service, target))
132 }
133}
134
135impl<F> HttpServer<F>
136where
137 F: HttpServiceFactory + Clone + Send + 'static,
138 F::Error: std::error::Error + Send,
139 F::Service: Clone + Send + 'static,
140 <F::Service as HttpService>::Error: std::error::Error + Send + Sync,
141 <F::Service as HttpService>::ResBody: Send,
142 <<F::Service as HttpService>::ResBody as http_body::Body>::Data: Send,
143 <<F::Service as HttpService>::ResBody as http_body::Body>::Error: std::error::Error + Send + Sync,
144{
145 #[cfg(feature = "tls-rustls")]
146 fn set_alpn_protocols(&mut self) {
147 let Some(rustls_config) = &mut self.rustls_config else {
148 return;
149 };
150
151 if rustls_config.alpn_protocols.is_empty() {
153 #[cfg(feature = "http1")]
154 if self.enable_http1 {
155 rustls_config.alpn_protocols.push(b"http/1.0".to_vec());
156 rustls_config.alpn_protocols.push(b"http/1.1".to_vec());
157 }
158
159 #[cfg(feature = "http2")]
160 if self.enable_http2 {
161 rustls_config.alpn_protocols.push(b"h2".to_vec());
162 rustls_config.alpn_protocols.push(b"h2c".to_vec());
163 }
164
165 #[cfg(feature = "http3")]
166 if self.enable_http3 {
167 rustls_config.alpn_protocols.push(b"h3".to_vec());
168 }
169 }
170 }
171
172 pub async fn run(#[allow(unused_mut)] mut self) -> Result<(), HttpError<F>> {
180 #[cfg(feature = "tls-rustls")]
181 self.set_alpn_protocols();
182
183 #[cfg(all(not(any(feature = "http1", feature = "http2")), feature = "tls-rustls"))]
184 let start_tcp_backend = false;
185 #[cfg(all(feature = "http1", not(feature = "http2")))]
186 let start_tcp_backend = self.enable_http1;
187 #[cfg(all(not(feature = "http1"), feature = "http2"))]
188 let start_tcp_backend = self.enable_http2;
189 #[cfg(all(feature = "http1", feature = "http2"))]
190 let start_tcp_backend = self.enable_http1 || self.enable_http2;
191
192 #[cfg(feature = "tls-rustls")]
193 if let Some(_rustls_config) = self.rustls_config {
194 #[cfg(not(feature = "http3"))]
195 let enable_http3 = false;
196 #[cfg(feature = "http3")]
197 let enable_http3 = self.enable_http3;
198
199 match (start_tcp_backend, enable_http3) {
200 #[cfg(feature = "http3")]
201 (false, true) => {
202 let backend = crate::backend::h3::Http3Backend::builder()
203 .ctx(self.ctx)
204 .worker_tasks(self.worker_tasks)
205 .service_factory(self.service_factory)
206 .bind(self.bind)
207 .rustls_config(_rustls_config)
208 .build();
209
210 return backend.run().await;
211 }
212 #[cfg(any(feature = "http1", feature = "http2"))]
213 (true, false) => {
214 let builder = crate::backend::hyper::HyperBackend::builder()
215 .ctx(self.ctx)
216 .worker_tasks(self.worker_tasks)
217 .service_factory(self.service_factory)
218 .bind(self.bind)
219 .rustls_config(_rustls_config);
220
221 #[cfg(feature = "http1")]
222 let builder = builder.http1_enabled(self.enable_http1);
223
224 #[cfg(feature = "http2")]
225 let builder = builder.http2_enabled(self.enable_http2);
226
227 return builder.build().run().await;
228 }
229 #[cfg(all(any(feature = "http1", feature = "http2"), feature = "http3"))]
230 (true, true) => {
231 let builder = crate::backend::hyper::HyperBackend::builder()
232 .ctx(self.ctx.clone())
233 .worker_tasks(self.worker_tasks)
234 .service_factory(self.service_factory.clone())
235 .bind(self.bind)
236 .rustls_config(_rustls_config.clone());
237
238 #[cfg(feature = "http1")]
239 let builder = builder.http1_enabled(self.enable_http1);
240
241 #[cfg(feature = "http2")]
242 let builder = builder.http2_enabled(self.enable_http2);
243
244 let hyper = std::pin::pin!(builder.build().run());
245
246 let http3 = crate::backend::h3::Http3Backend::builder()
247 .ctx(self.ctx)
248 .worker_tasks(self.worker_tasks)
249 .service_factory(self.service_factory)
250 .bind(self.bind)
251 .rustls_config(_rustls_config)
252 .build()
253 .run();
254 let http3 = std::pin::pin!(http3);
255
256 let res = futures::future::select(hyper, http3).await;
257 match res {
258 futures::future::Either::Left((res, _)) => return res,
259 futures::future::Either::Right((res, _)) => return res,
260 }
261 }
262 _ => return Ok(()),
263 }
264
265 }
267
268 #[cfg(any(feature = "http1", feature = "http2"))]
273 if start_tcp_backend {
274 let builder = crate::backend::hyper::HyperBackend::builder()
275 .ctx(self.ctx)
276 .worker_tasks(self.worker_tasks)
277 .service_factory(self.service_factory)
278 .bind(self.bind);
279
280 #[cfg(feature = "http1")]
281 let builder = builder.http1_enabled(self.enable_http1);
282
283 #[cfg(feature = "http2")]
284 let builder = builder.http2_enabled(self.enable_http2);
285
286 return builder.build().run().await;
287 }
288
289 Ok(())
290 }
291}