1use std::{
2 fmt,
3 marker::PhantomData,
4 net,
5 rc::Rc,
6 task::{Context, Poll},
7};
8
9use actix_codec::{AsyncRead, AsyncWrite, Framed};
10use actix_service::{
11 fn_service, IntoServiceFactory, Service, ServiceFactory, ServiceFactoryExt as _,
12};
13#[expect(deprecated, reason = "preserve the public ready future type")]
14use actix_utils::future::ready;
15use futures_core::future::LocalBoxFuture;
16use tokio::net::TcpStream;
17use tracing::error;
18
19use super::{codec::Codec, dispatcher::Dispatcher, ExpectHandler, UpgradeHandler};
20use crate::{
21 body::{BoxBody, MessageBody},
22 config::ServiceConfig,
23 error::DispatchError,
24 service::HttpServiceHandler,
25 ConnectCallback, OnConnectData, Request, Response,
26};
27
28pub struct H1Service<T, S, B, X = ExpectHandler, U = UpgradeHandler> {
30 srv: S,
31 cfg: ServiceConfig,
32 expect: X,
33 upgrade: Option<U>,
34 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
35 _phantom: PhantomData<B>,
36}
37
38impl<T, S, B> H1Service<T, S, B>
39where
40 S: ServiceFactory<Request, Config = ()>,
41 S::Error: Into<Response<BoxBody>>,
42 S::InitError: fmt::Debug,
43 S::Response: Into<Response<B>>,
44 B: MessageBody,
45{
46 pub(crate) fn with_config<F: IntoServiceFactory<S, Request>>(
48 cfg: ServiceConfig,
49 service: F,
50 ) -> Self {
51 H1Service {
52 cfg,
53 srv: service.into_factory(),
54 expect: ExpectHandler,
55 upgrade: None,
56 on_connect_ext: None,
57 _phantom: PhantomData,
58 }
59 }
60}
61
62impl<S, B, X, U> H1Service<TcpStream, S, B, X, U>
63where
64 S: ServiceFactory<Request, Config = ()>,
65 S::Future: 'static,
66 S::Error: Into<Response<BoxBody>>,
67 S::InitError: fmt::Debug,
68 S::Response: Into<Response<B>>,
69
70 B: MessageBody,
71
72 X: ServiceFactory<Request, Config = (), Response = Request>,
73 X::Future: 'static,
74 X::Error: Into<Response<BoxBody>>,
75 X::InitError: fmt::Debug,
76
77 U: ServiceFactory<(Request, Framed<TcpStream, Codec>), Config = (), Response = ()>,
78 U::Future: 'static,
79 U::Error: fmt::Display + Into<Response<BoxBody>>,
80 U::InitError: fmt::Debug,
81{
82 #[expect(deprecated, reason = "preserve the public ready future type")]
84 pub fn tcp(
85 self,
86 ) -> impl ServiceFactory<TcpStream, Config = (), Response = (), Error = DispatchError, InitError = ()>
87 {
88 fn_service(|io: TcpStream| {
89 let peer_addr = io.peer_addr().ok();
90 ready(Ok((io, peer_addr)))
91 })
92 .and_then(self)
93 }
94}
95
96#[cfg(feature = "openssl")]
97mod openssl {
98 use actix_tls::accept::{
99 openssl::{
100 reexports::{Error as SslError, SslAcceptor},
101 Acceptor, TlsStream,
102 },
103 TlsError,
104 };
105
106 use super::*;
107
108 impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
109 where
110 S: ServiceFactory<Request, Config = ()>,
111 S::Future: 'static,
112 S::Error: Into<Response<BoxBody>>,
113 S::InitError: fmt::Debug,
114 S::Response: Into<Response<B>>,
115
116 B: MessageBody,
117
118 X: ServiceFactory<Request, Config = (), Response = Request>,
119 X::Future: 'static,
120 X::Error: Into<Response<BoxBody>>,
121 X::InitError: fmt::Debug,
122
123 U: ServiceFactory<
124 (Request, Framed<TlsStream<TcpStream>, Codec>),
125 Config = (),
126 Response = (),
127 >,
128 U::Future: 'static,
129 U::Error: fmt::Display + Into<Response<BoxBody>>,
130 U::InitError: fmt::Debug,
131 {
132 pub fn openssl(
134 self,
135 acceptor: SslAcceptor,
136 ) -> impl ServiceFactory<
137 TcpStream,
138 Config = (),
139 Response = (),
140 Error = TlsError<SslError, DispatchError>,
141 InitError = (),
142 > {
143 Acceptor::new(acceptor)
144 .map_init_err(|_| {
145 unreachable!("TLS acceptor service factory does not error on init")
146 })
147 .map_err(TlsError::into_service_error)
148 .map(|io: TlsStream<TcpStream>| {
149 let peer_addr = io.get_ref().peer_addr().ok();
150 (io, peer_addr)
151 })
152 .and_then(self.map_err(TlsError::Service))
153 }
154 }
155}
156
157#[cfg(feature = "rustls-0_20")]
158mod rustls_0_20 {
159 use std::io;
160
161 use actix_tls::accept::{
162 rustls_0_20::{reexports::ServerConfig, Acceptor, TlsStream},
163 TlsError,
164 };
165
166 use super::*;
167
168 impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
169 where
170 S: ServiceFactory<Request, Config = ()>,
171 S::Future: 'static,
172 S::Error: Into<Response<BoxBody>>,
173 S::InitError: fmt::Debug,
174 S::Response: Into<Response<B>>,
175
176 B: MessageBody,
177
178 X: ServiceFactory<Request, Config = (), Response = Request>,
179 X::Future: 'static,
180 X::Error: Into<Response<BoxBody>>,
181 X::InitError: fmt::Debug,
182
183 U: ServiceFactory<
184 (Request, Framed<TlsStream<TcpStream>, Codec>),
185 Config = (),
186 Response = (),
187 >,
188 U::Future: 'static,
189 U::Error: fmt::Display + Into<Response<BoxBody>>,
190 U::InitError: fmt::Debug,
191 {
192 pub fn rustls(
194 self,
195 config: ServerConfig,
196 ) -> impl ServiceFactory<
197 TcpStream,
198 Config = (),
199 Response = (),
200 Error = TlsError<io::Error, DispatchError>,
201 InitError = (),
202 > {
203 Acceptor::new(config)
204 .map_init_err(|_| {
205 unreachable!("TLS acceptor service factory does not error on init")
206 })
207 .map_err(TlsError::into_service_error)
208 .map(|io: TlsStream<TcpStream>| {
209 let peer_addr = io.get_ref().0.peer_addr().ok();
210 (io, peer_addr)
211 })
212 .and_then(self.map_err(TlsError::Service))
213 }
214 }
215}
216
217#[cfg(feature = "rustls-0_21")]
218mod rustls_0_21 {
219 use std::io;
220
221 use actix_tls::accept::{
222 rustls_0_21::{reexports::ServerConfig, Acceptor, TlsStream},
223 TlsError,
224 };
225
226 use super::*;
227
228 impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
229 where
230 S: ServiceFactory<Request, Config = ()>,
231 S::Future: 'static,
232 S::Error: Into<Response<BoxBody>>,
233 S::InitError: fmt::Debug,
234 S::Response: Into<Response<B>>,
235
236 B: MessageBody,
237
238 X: ServiceFactory<Request, Config = (), Response = Request>,
239 X::Future: 'static,
240 X::Error: Into<Response<BoxBody>>,
241 X::InitError: fmt::Debug,
242
243 U: ServiceFactory<
244 (Request, Framed<TlsStream<TcpStream>, Codec>),
245 Config = (),
246 Response = (),
247 >,
248 U::Future: 'static,
249 U::Error: fmt::Display + Into<Response<BoxBody>>,
250 U::InitError: fmt::Debug,
251 {
252 pub fn rustls_021(
254 self,
255 config: ServerConfig,
256 ) -> impl ServiceFactory<
257 TcpStream,
258 Config = (),
259 Response = (),
260 Error = TlsError<io::Error, DispatchError>,
261 InitError = (),
262 > {
263 Acceptor::new(config)
264 .map_init_err(|_| {
265 unreachable!("TLS acceptor service factory does not error on init")
266 })
267 .map_err(TlsError::into_service_error)
268 .map(|io: TlsStream<TcpStream>| {
269 let peer_addr = io.get_ref().0.peer_addr().ok();
270 (io, peer_addr)
271 })
272 .and_then(self.map_err(TlsError::Service))
273 }
274 }
275}
276
277#[cfg(feature = "rustls-0_22")]
278mod rustls_0_22 {
279 use std::io;
280
281 use actix_tls::accept::{
282 rustls_0_22::{reexports::ServerConfig, Acceptor, TlsStream},
283 TlsError,
284 };
285
286 use super::*;
287
288 impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
289 where
290 S: ServiceFactory<Request, Config = ()>,
291 S::Future: 'static,
292 S::Error: Into<Response<BoxBody>>,
293 S::InitError: fmt::Debug,
294 S::Response: Into<Response<B>>,
295
296 B: MessageBody,
297
298 X: ServiceFactory<Request, Config = (), Response = Request>,
299 X::Future: 'static,
300 X::Error: Into<Response<BoxBody>>,
301 X::InitError: fmt::Debug,
302
303 U: ServiceFactory<
304 (Request, Framed<TlsStream<TcpStream>, Codec>),
305 Config = (),
306 Response = (),
307 >,
308 U::Future: 'static,
309 U::Error: fmt::Display + Into<Response<BoxBody>>,
310 U::InitError: fmt::Debug,
311 {
312 pub fn rustls_0_22(
314 self,
315 config: ServerConfig,
316 ) -> impl ServiceFactory<
317 TcpStream,
318 Config = (),
319 Response = (),
320 Error = TlsError<io::Error, DispatchError>,
321 InitError = (),
322 > {
323 Acceptor::new(config)
324 .map_init_err(|_| {
325 unreachable!("TLS acceptor service factory does not error on init")
326 })
327 .map_err(TlsError::into_service_error)
328 .map(|io: TlsStream<TcpStream>| {
329 let peer_addr = io.get_ref().0.peer_addr().ok();
330 (io, peer_addr)
331 })
332 .and_then(self.map_err(TlsError::Service))
333 }
334 }
335}
336
337#[cfg(feature = "rustls-0_23")]
338mod rustls_0_23 {
339 use std::io;
340
341 use actix_tls::accept::{
342 rustls_0_23::{reexports::ServerConfig, Acceptor, TlsStream},
343 TlsError,
344 };
345
346 use super::*;
347
348 impl<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
349 where
350 S: ServiceFactory<Request, Config = ()>,
351 S::Future: 'static,
352 S::Error: Into<Response<BoxBody>>,
353 S::InitError: fmt::Debug,
354 S::Response: Into<Response<B>>,
355
356 B: MessageBody,
357
358 X: ServiceFactory<Request, Config = (), Response = Request>,
359 X::Future: 'static,
360 X::Error: Into<Response<BoxBody>>,
361 X::InitError: fmt::Debug,
362
363 U: ServiceFactory<
364 (Request, Framed<TlsStream<TcpStream>, Codec>),
365 Config = (),
366 Response = (),
367 >,
368 U::Future: 'static,
369 U::Error: fmt::Display + Into<Response<BoxBody>>,
370 U::InitError: fmt::Debug,
371 {
372 pub fn rustls_0_23(
374 self,
375 config: ServerConfig,
376 ) -> impl ServiceFactory<
377 TcpStream,
378 Config = (),
379 Response = (),
380 Error = TlsError<io::Error, DispatchError>,
381 InitError = (),
382 > {
383 Acceptor::new(config)
384 .map_init_err(|_| {
385 unreachable!("TLS acceptor service factory does not error on init")
386 })
387 .map_err(TlsError::into_service_error)
388 .map(|io: TlsStream<TcpStream>| {
389 let peer_addr = io.get_ref().0.peer_addr().ok();
390 (io, peer_addr)
391 })
392 .and_then(self.map_err(TlsError::Service))
393 }
394 }
395}
396
397impl<T, S, B, X, U> H1Service<T, S, B, X, U>
398where
399 S: ServiceFactory<Request, Config = ()>,
400 S::Error: Into<Response<BoxBody>>,
401 S::Response: Into<Response<B>>,
402 S::InitError: fmt::Debug,
403 B: MessageBody,
404{
405 pub fn expect<X1>(self, expect: X1) -> H1Service<T, S, B, X1, U>
406 where
407 X1: ServiceFactory<Request, Response = Request>,
408 X1::Error: Into<Response<BoxBody>>,
409 X1::InitError: fmt::Debug,
410 {
411 H1Service {
412 expect,
413 cfg: self.cfg,
414 srv: self.srv,
415 upgrade: self.upgrade,
416 on_connect_ext: self.on_connect_ext,
417 _phantom: PhantomData,
418 }
419 }
420
421 pub fn upgrade<U1>(self, upgrade: Option<U1>) -> H1Service<T, S, B, X, U1>
422 where
423 U1: ServiceFactory<(Request, Framed<T, Codec>), Response = ()>,
424 U1::Error: fmt::Display,
425 U1::InitError: fmt::Debug,
426 {
427 H1Service {
428 upgrade,
429 cfg: self.cfg,
430 srv: self.srv,
431 expect: self.expect,
432 on_connect_ext: self.on_connect_ext,
433 _phantom: PhantomData,
434 }
435 }
436
437 pub(crate) fn on_connect_ext(mut self, f: Option<Rc<ConnectCallback<T>>>) -> Self {
439 self.on_connect_ext = f;
440 self
441 }
442}
443
444impl<T, S, B, X, U> ServiceFactory<(T, Option<net::SocketAddr>)> for H1Service<T, S, B, X, U>
445where
446 T: AsyncRead + AsyncWrite + Unpin + 'static,
447
448 S: ServiceFactory<Request, Config = ()>,
449 S::Future: 'static,
450 S::Error: Into<Response<BoxBody>>,
451 S::Response: Into<Response<B>>,
452 S::InitError: fmt::Debug,
453
454 B: MessageBody,
455
456 X: ServiceFactory<Request, Config = (), Response = Request>,
457 X::Future: 'static,
458 X::Error: Into<Response<BoxBody>>,
459 X::InitError: fmt::Debug,
460
461 U: ServiceFactory<(Request, Framed<T, Codec>), Config = (), Response = ()>,
462 U::Future: 'static,
463 U::Error: fmt::Display + Into<Response<BoxBody>>,
464 U::InitError: fmt::Debug,
465{
466 type Response = ();
467 type Error = DispatchError;
468 type Config = ();
469 type Service = H1ServiceHandler<T, S::Service, B, X::Service, U::Service>;
470 type InitError = ();
471 type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
472
473 fn new_service(&self, _: ()) -> Self::Future {
474 let service = self.srv.new_service(());
475 let expect = self.expect.new_service(());
476 let upgrade = self.upgrade.as_ref().map(|s| s.new_service(()));
477 let on_connect_ext = self.on_connect_ext.clone();
478 let cfg = self.cfg.clone();
479
480 Box::pin(async move {
481 let expect = expect.await.map_err(|err| {
482 tracing::error!("Initialization of HTTP expect service error: {err:?}");
483 })?;
484
485 let upgrade = match upgrade {
486 Some(upgrade) => {
487 let upgrade = upgrade.await.map_err(|err| {
488 tracing::error!("Initialization of HTTP upgrade service error: {err:?}");
489 })?;
490 Some(upgrade)
491 }
492 None => None,
493 };
494
495 let service = service
496 .await
497 .map_err(|err| error!("Initialization of HTTP service error: {err:?}"))?;
498
499 Ok(H1ServiceHandler::new(
500 cfg,
501 service,
502 expect,
503 upgrade,
504 on_connect_ext,
505 ))
506 })
507 }
508}
509
510pub type H1ServiceHandler<T, S, B, X, U> = HttpServiceHandler<T, S, B, X, U>;
512
513impl<T, S, B, X, U> Service<(T, Option<net::SocketAddr>)> for HttpServiceHandler<T, S, B, X, U>
514where
515 T: AsyncRead + AsyncWrite + Unpin,
516
517 S: Service<Request>,
518 S::Error: Into<Response<BoxBody>>,
519 S::Response: Into<Response<B>>,
520
521 B: MessageBody,
522
523 X: Service<Request, Response = Request>,
524 X::Error: Into<Response<BoxBody>>,
525
526 U: Service<(Request, Framed<T, Codec>), Response = ()>,
527 U::Error: fmt::Display + Into<Response<BoxBody>>,
528{
529 type Response = ();
530 type Error = DispatchError;
531 type Future = Dispatcher<T, S, B, X, U>;
532
533 fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
534 self._poll_ready(cx).map_err(|err| {
535 error!("HTTP/1 service readiness error: {:?}", err);
536 DispatchError::Service(err)
537 })
538 }
539
540 fn call(&self, (io, addr): (T, Option<net::SocketAddr>)) -> Self::Future {
541 let conn_data = OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
542 Dispatcher::new(io, Rc::clone(&self.flow), self.cfg.clone(), addr, conn_data)
543 }
544}