1use std::{
2 fmt,
3 future::Future,
4 marker::PhantomData,
5 net,
6 pin::Pin,
7 rc::Rc,
8 task::{Context, Poll},
9};
10
11use actix_codec::{AsyncRead, AsyncWrite, Framed};
12use actix_service::{
13 fn_service, IntoServiceFactory, Service, ServiceFactory, ServiceFactoryExt as _,
14};
15use futures_core::{future::LocalBoxFuture, ready};
16use pin_project_lite::pin_project;
17use tokio::net::TcpStream;
18use tracing::error;
19
20use crate::{
21 body::{BoxBody, MessageBody},
22 builder::HttpServiceBuilder,
23 error::DispatchError,
24 h1, ConnectCallback, OnConnectData, Protocol, Request, Response, ServiceConfig,
25};
26
27#[inline]
28fn desired_nodelay(tcp_nodelay: Option<bool>) -> Option<bool> {
29 tcp_nodelay
30}
31
32#[inline]
33fn set_nodelay(stream: &TcpStream, nodelay: bool) {
34 let _ = stream.set_nodelay(nodelay);
35}
36
37pub struct HttpService<T, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler> {
71 srv: S,
72 cfg: ServiceConfig,
73 expect: X,
74 upgrade: Option<U>,
75 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
76 _phantom: PhantomData<B>,
77}
78
79impl<T, S, B> HttpService<T, S, B>
80where
81 S: ServiceFactory<Request, Config = ()>,
82 S::Error: Into<Response<BoxBody>> + 'static,
83 S::InitError: fmt::Debug,
84 S::Response: Into<Response<B>> + 'static,
85 <S::Service as Service<Request>>::Future: 'static,
86 B: MessageBody + 'static,
87{
88 pub fn build() -> HttpServiceBuilder<T, S> {
90 HttpServiceBuilder::default()
91 }
92}
93
94impl<T, S, B> HttpService<T, S, B>
95where
96 S: ServiceFactory<Request, Config = ()>,
97 S::Error: Into<Response<BoxBody>> + 'static,
98 S::InitError: fmt::Debug,
99 S::Response: Into<Response<B>> + 'static,
100 <S::Service as Service<Request>>::Future: 'static,
101 B: MessageBody + 'static,
102{
103 pub fn new<F: IntoServiceFactory<S, Request>>(service: F) -> Self {
105 HttpService {
106 cfg: ServiceConfig::default(),
107 srv: service.into_factory(),
108 expect: h1::ExpectHandler,
109 upgrade: None,
110 on_connect_ext: None,
111 _phantom: PhantomData,
112 }
113 }
114
115 pub(crate) fn with_config<F: IntoServiceFactory<S, Request>>(
117 cfg: ServiceConfig,
118 service: F,
119 ) -> Self {
120 HttpService {
121 cfg,
122 srv: service.into_factory(),
123 expect: h1::ExpectHandler,
124 upgrade: None,
125 on_connect_ext: None,
126 _phantom: PhantomData,
127 }
128 }
129}
130
131impl<T, S, B, X, U> HttpService<T, S, B, X, U>
132where
133 S: ServiceFactory<Request, Config = ()>,
134 S::Error: Into<Response<BoxBody>> + 'static,
135 S::InitError: fmt::Debug,
136 S::Response: Into<Response<B>> + 'static,
137 <S::Service as Service<Request>>::Future: 'static,
138 B: MessageBody,
139{
140 pub fn expect<X1>(self, expect: X1) -> HttpService<T, S, B, X1, U>
145 where
146 X1: ServiceFactory<Request, Config = (), Response = Request>,
147 X1::Error: Into<Response<BoxBody>>,
148 X1::InitError: fmt::Debug,
149 {
150 HttpService {
151 expect,
152 cfg: self.cfg,
153 srv: self.srv,
154 upgrade: self.upgrade,
155 on_connect_ext: self.on_connect_ext,
156 _phantom: PhantomData,
157 }
158 }
159
160 pub fn upgrade<U1>(self, upgrade: Option<U1>) -> HttpService<T, S, B, X, U1>
165 where
166 U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
167 U1::Error: fmt::Display,
168 U1::InitError: fmt::Debug,
169 {
170 HttpService {
171 upgrade,
172 cfg: self.cfg,
173 srv: self.srv,
174 expect: self.expect,
175 on_connect_ext: self.on_connect_ext,
176 _phantom: PhantomData,
177 }
178 }
179
180 pub(crate) fn on_connect_ext(mut self, f: Option<Rc<ConnectCallback<T>>>) -> Self {
182 self.on_connect_ext = f;
183 self
184 }
185}
186
187impl<S, B, X, U> HttpService<TcpStream, S, B, X, U>
188where
189 S: ServiceFactory<Request, Config = ()>,
190 S::Future: 'static,
191 S::Error: Into<Response<BoxBody>> + 'static,
192 S::InitError: fmt::Debug,
193 S::Response: Into<Response<B>> + 'static,
194 <S::Service as Service<Request>>::Future: 'static,
195
196 B: MessageBody + 'static,
197
198 X: ServiceFactory<Request, Config = (), Response = Request>,
199 X::Future: 'static,
200 X::Error: Into<Response<BoxBody>>,
201 X::InitError: fmt::Debug,
202
203 U: ServiceFactory<(Request, Framed<TcpStream, h1::Codec>), Config = (), Response = ()>,
204 U::Future: 'static,
205 U::Error: fmt::Display + Into<Response<BoxBody>>,
206 U::InitError: fmt::Debug,
207{
208 pub fn tcp(
212 self,
213 ) -> impl ServiceFactory<TcpStream, Config = (), Response = (), Error = DispatchError, InitError = ()>
214 {
215 let tcp_nodelay = self.cfg.tcp_nodelay();
216
217 fn_service(move |io: TcpStream| async move {
218 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
219 set_nodelay(&io, nodelay);
220 }
221
222 let peer_addr = io.peer_addr().ok();
223 Ok((io, Protocol::Http1, peer_addr))
224 })
225 .and_then(self)
226 }
227
228 #[cfg(feature = "http2")]
231 pub fn tcp_auto_h2c(
232 self,
233 ) -> impl ServiceFactory<TcpStream, Config = (), Response = (), Error = DispatchError, InitError = ()>
234 {
235 let tcp_nodelay = self.cfg.tcp_nodelay();
236
237 fn_service(move |io: TcpStream| async move {
238 const H2_PREFACE: &[u8] = b"PRI * HTTP/2";
243
244 let mut buf = [0; 12];
245
246 io.peek(&mut buf).await?;
247
248 let proto = if buf == H2_PREFACE {
249 Protocol::Http2
250 } else {
251 Protocol::Http1
252 };
253
254 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
255 set_nodelay(&io, nodelay);
256 }
257
258 let peer_addr = io.peer_addr().ok();
259 Ok((io, proto, peer_addr))
260 })
261 .and_then(self)
262 }
263}
264
265#[cfg(feature = "__tls")]
267#[derive(Debug, Default)]
268pub struct TlsAcceptorConfig {
269 pub(crate) handshake_timeout: Option<std::time::Duration>,
270}
271
272#[cfg(feature = "__tls")]
273impl TlsAcceptorConfig {
274 pub fn handshake_timeout(self, dur: std::time::Duration) -> Self {
276 Self {
277 handshake_timeout: Some(dur),
278 }
280 }
281}
282
283#[cfg(feature = "openssl")]
284mod openssl {
285 use actix_tls::accept::{
286 openssl::{
287 reexports::{Error as SslError, SslAcceptor},
288 Acceptor, TlsStream,
289 },
290 TlsError,
291 };
292
293 use super::*;
294
295 impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
296 where
297 S: ServiceFactory<Request, Config = ()>,
298 S::Future: 'static,
299 S::Error: Into<Response<BoxBody>> + 'static,
300 S::InitError: fmt::Debug,
301 S::Response: Into<Response<B>> + 'static,
302 <S::Service as Service<Request>>::Future: 'static,
303
304 B: MessageBody + 'static,
305
306 X: ServiceFactory<Request, Config = (), Response = Request>,
307 X::Future: 'static,
308 X::Error: Into<Response<BoxBody>>,
309 X::InitError: fmt::Debug,
310
311 U: ServiceFactory<
312 (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
313 Config = (),
314 Response = (),
315 >,
316 U::Future: 'static,
317 U::Error: fmt::Display + Into<Response<BoxBody>>,
318 U::InitError: fmt::Debug,
319 {
320 pub fn openssl(
322 self,
323 acceptor: SslAcceptor,
324 ) -> impl ServiceFactory<
325 TcpStream,
326 Config = (),
327 Response = (),
328 Error = TlsError<SslError, DispatchError>,
329 InitError = (),
330 > {
331 self.openssl_with_config(acceptor, TlsAcceptorConfig::default())
332 }
333
334 pub fn openssl_with_config(
336 self,
337 acceptor: SslAcceptor,
338 tls_acceptor_config: TlsAcceptorConfig,
339 ) -> impl ServiceFactory<
340 TcpStream,
341 Config = (),
342 Response = (),
343 Error = TlsError<SslError, DispatchError>,
344 InitError = (),
345 > {
346 let tcp_nodelay = self.cfg.tcp_nodelay();
347 let mut acceptor = Acceptor::new(acceptor);
348
349 if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
350 acceptor.set_handshake_timeout(handshake_timeout);
351 }
352
353 acceptor
354 .map_init_err(|_| {
355 unreachable!("TLS acceptor service factory does not error on init")
356 })
357 .map_err(TlsError::into_service_error)
358 .map(move |io: TlsStream<TcpStream>| {
359 let proto = if let Some(protos) = io.ssl().selected_alpn_protocol() {
360 if protos.windows(2).any(|window| window == b"h2") {
361 Protocol::Http2
362 } else {
363 Protocol::Http1
364 }
365 } else {
366 Protocol::Http1
367 };
368
369 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
370 set_nodelay(io.get_ref(), nodelay);
371 }
372
373 let peer_addr = io.get_ref().peer_addr().ok();
374 (io, proto, peer_addr)
375 })
376 .and_then(self.map_err(TlsError::Service))
377 }
378 }
379}
380
381#[cfg(feature = "rustls-0_20")]
382mod rustls_0_20 {
383 use std::io;
384
385 use actix_tls::accept::{
386 rustls_0_20::{reexports::ServerConfig, Acceptor, TlsStream},
387 TlsError,
388 };
389
390 use super::*;
391
392 impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
393 where
394 S: ServiceFactory<Request, Config = ()>,
395 S::Future: 'static,
396 S::Error: Into<Response<BoxBody>> + 'static,
397 S::InitError: fmt::Debug,
398 S::Response: Into<Response<B>> + 'static,
399 <S::Service as Service<Request>>::Future: 'static,
400
401 B: MessageBody + 'static,
402
403 X: ServiceFactory<Request, Config = (), Response = Request>,
404 X::Future: 'static,
405 X::Error: Into<Response<BoxBody>>,
406 X::InitError: fmt::Debug,
407
408 U: ServiceFactory<
409 (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
410 Config = (),
411 Response = (),
412 >,
413 U::Future: 'static,
414 U::Error: fmt::Display + Into<Response<BoxBody>>,
415 U::InitError: fmt::Debug,
416 {
417 pub fn rustls(
419 self,
420 config: ServerConfig,
421 ) -> impl ServiceFactory<
422 TcpStream,
423 Config = (),
424 Response = (),
425 Error = TlsError<io::Error, DispatchError>,
426 InitError = (),
427 > {
428 self.rustls_with_config(config, TlsAcceptorConfig::default())
429 }
430
431 pub fn rustls_with_config(
433 self,
434 mut config: ServerConfig,
435 tls_acceptor_config: TlsAcceptorConfig,
436 ) -> impl ServiceFactory<
437 TcpStream,
438 Config = (),
439 Response = (),
440 Error = TlsError<io::Error, DispatchError>,
441 InitError = (),
442 > {
443 let tcp_nodelay = self.cfg.tcp_nodelay();
444 let mut protos = vec![b"http/1.1".to_vec()];
445 #[cfg(feature = "http2")]
446 protos.insert(0, b"h2".to_vec());
447 protos.extend_from_slice(&config.alpn_protocols);
448 config.alpn_protocols = protos;
449
450 let mut acceptor = Acceptor::new(config);
451
452 if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
453 acceptor.set_handshake_timeout(handshake_timeout);
454 }
455
456 acceptor
457 .map_init_err(|_| {
458 unreachable!("TLS acceptor service factory does not error on init")
459 })
460 .map_err(TlsError::into_service_error)
461 .and_then(move |io: TlsStream<TcpStream>| async move {
462 let proto = if let Some(protos) = io.get_ref().1.alpn_protocol() {
463 if protos.windows(2).any(|window| window == b"h2") {
464 Protocol::Http2
465 } else {
466 Protocol::Http1
467 }
468 } else {
469 Protocol::Http1
470 };
471
472 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
473 set_nodelay(io.get_ref().0, nodelay);
474 }
475
476 let peer_addr = io.get_ref().0.peer_addr().ok();
477 Ok((io, proto, peer_addr))
478 })
479 .and_then(self.map_err(TlsError::Service))
480 }
481 }
482}
483
484#[cfg(feature = "rustls-0_21")]
485mod rustls_0_21 {
486 use std::io;
487
488 use actix_tls::accept::{
489 rustls_0_21::{reexports::ServerConfig, Acceptor, TlsStream},
490 TlsError,
491 };
492
493 use super::*;
494
495 impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
496 where
497 S: ServiceFactory<Request, Config = ()>,
498 S::Future: 'static,
499 S::Error: Into<Response<BoxBody>> + 'static,
500 S::InitError: fmt::Debug,
501 S::Response: Into<Response<B>> + 'static,
502 <S::Service as Service<Request>>::Future: 'static,
503
504 B: MessageBody + 'static,
505
506 X: ServiceFactory<Request, Config = (), Response = Request>,
507 X::Future: 'static,
508 X::Error: Into<Response<BoxBody>>,
509 X::InitError: fmt::Debug,
510
511 U: ServiceFactory<
512 (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
513 Config = (),
514 Response = (),
515 >,
516 U::Future: 'static,
517 U::Error: fmt::Display + Into<Response<BoxBody>>,
518 U::InitError: fmt::Debug,
519 {
520 pub fn rustls_021(
522 self,
523 config: ServerConfig,
524 ) -> impl ServiceFactory<
525 TcpStream,
526 Config = (),
527 Response = (),
528 Error = TlsError<io::Error, DispatchError>,
529 InitError = (),
530 > {
531 self.rustls_021_with_config(config, TlsAcceptorConfig::default())
532 }
533
534 pub fn rustls_021_with_config(
536 self,
537 mut config: ServerConfig,
538 tls_acceptor_config: TlsAcceptorConfig,
539 ) -> impl ServiceFactory<
540 TcpStream,
541 Config = (),
542 Response = (),
543 Error = TlsError<io::Error, DispatchError>,
544 InitError = (),
545 > {
546 let tcp_nodelay = self.cfg.tcp_nodelay();
547 let mut protos = vec![b"http/1.1".to_vec()];
548 #[cfg(feature = "http2")]
549 protos.insert(0, b"h2".to_vec());
550 protos.extend_from_slice(&config.alpn_protocols);
551 config.alpn_protocols = protos;
552
553 let mut acceptor = Acceptor::new(config);
554
555 if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
556 acceptor.set_handshake_timeout(handshake_timeout);
557 }
558
559 acceptor
560 .map_init_err(|_| {
561 unreachable!("TLS acceptor service factory does not error on init")
562 })
563 .map_err(TlsError::into_service_error)
564 .and_then(move |io: TlsStream<TcpStream>| async move {
565 let proto = if let Some(protos) = io.get_ref().1.alpn_protocol() {
566 if protos.windows(2).any(|window| window == b"h2") {
567 Protocol::Http2
568 } else {
569 Protocol::Http1
570 }
571 } else {
572 Protocol::Http1
573 };
574
575 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
576 set_nodelay(io.get_ref().0, nodelay);
577 }
578
579 let peer_addr = io.get_ref().0.peer_addr().ok();
580 Ok((io, proto, peer_addr))
581 })
582 .and_then(self.map_err(TlsError::Service))
583 }
584 }
585}
586
587#[cfg(feature = "rustls-0_22")]
588mod rustls_0_22 {
589 use std::io;
590
591 use actix_tls::accept::{
592 rustls_0_22::{reexports::ServerConfig, Acceptor, TlsStream},
593 TlsError,
594 };
595
596 use super::*;
597
598 impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
599 where
600 S: ServiceFactory<Request, Config = ()>,
601 S::Future: 'static,
602 S::Error: Into<Response<BoxBody>> + 'static,
603 S::InitError: fmt::Debug,
604 S::Response: Into<Response<B>> + 'static,
605 <S::Service as Service<Request>>::Future: 'static,
606
607 B: MessageBody + 'static,
608
609 X: ServiceFactory<Request, Config = (), Response = Request>,
610 X::Future: 'static,
611 X::Error: Into<Response<BoxBody>>,
612 X::InitError: fmt::Debug,
613
614 U: ServiceFactory<
615 (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
616 Config = (),
617 Response = (),
618 >,
619 U::Future: 'static,
620 U::Error: fmt::Display + Into<Response<BoxBody>>,
621 U::InitError: fmt::Debug,
622 {
623 pub fn rustls_0_22(
625 self,
626 config: ServerConfig,
627 ) -> impl ServiceFactory<
628 TcpStream,
629 Config = (),
630 Response = (),
631 Error = TlsError<io::Error, DispatchError>,
632 InitError = (),
633 > {
634 self.rustls_0_22_with_config(config, TlsAcceptorConfig::default())
635 }
636
637 pub fn rustls_0_22_with_config(
639 self,
640 mut config: ServerConfig,
641 tls_acceptor_config: TlsAcceptorConfig,
642 ) -> impl ServiceFactory<
643 TcpStream,
644 Config = (),
645 Response = (),
646 Error = TlsError<io::Error, DispatchError>,
647 InitError = (),
648 > {
649 let tcp_nodelay = self.cfg.tcp_nodelay();
650 let mut protos = vec![b"http/1.1".to_vec()];
651 #[cfg(feature = "http2")]
652 protos.insert(0, b"h2".to_vec());
653 protos.extend_from_slice(&config.alpn_protocols);
654 config.alpn_protocols = protos;
655
656 let mut acceptor = Acceptor::new(config);
657
658 if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
659 acceptor.set_handshake_timeout(handshake_timeout);
660 }
661
662 acceptor
663 .map_init_err(|_| {
664 unreachable!("TLS acceptor service factory does not error on init")
665 })
666 .map_err(TlsError::into_service_error)
667 .and_then(move |io: TlsStream<TcpStream>| async move {
668 let proto = if let Some(protos) = io.get_ref().1.alpn_protocol() {
669 if protos.windows(2).any(|window| window == b"h2") {
670 Protocol::Http2
671 } else {
672 Protocol::Http1
673 }
674 } else {
675 Protocol::Http1
676 };
677
678 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
679 set_nodelay(io.get_ref().0, nodelay);
680 }
681
682 let peer_addr = io.get_ref().0.peer_addr().ok();
683 Ok((io, proto, peer_addr))
684 })
685 .and_then(self.map_err(TlsError::Service))
686 }
687 }
688}
689
690#[cfg(feature = "rustls-0_23")]
691mod rustls_0_23 {
692 use std::io;
693
694 use actix_tls::accept::{
695 rustls_0_23::{reexports::ServerConfig, Acceptor, TlsStream},
696 TlsError,
697 };
698
699 use super::*;
700
701 impl<S, B, X, U> HttpService<TlsStream<TcpStream>, S, B, X, U>
702 where
703 S: ServiceFactory<Request, Config = ()>,
704 S::Future: 'static,
705 S::Error: Into<Response<BoxBody>> + 'static,
706 S::InitError: fmt::Debug,
707 S::Response: Into<Response<B>> + 'static,
708 <S::Service as Service<Request>>::Future: 'static,
709
710 B: MessageBody + 'static,
711
712 X: ServiceFactory<Request, Config = (), Response = Request>,
713 X::Future: 'static,
714 X::Error: Into<Response<BoxBody>>,
715 X::InitError: fmt::Debug,
716
717 U: ServiceFactory<
718 (Request, Framed<TlsStream<TcpStream>, h1::Codec>),
719 Config = (),
720 Response = (),
721 >,
722 U::Future: 'static,
723 U::Error: fmt::Display + Into<Response<BoxBody>>,
724 U::InitError: fmt::Debug,
725 {
726 pub fn rustls_0_23(
728 self,
729 config: ServerConfig,
730 ) -> impl ServiceFactory<
731 TcpStream,
732 Config = (),
733 Response = (),
734 Error = TlsError<io::Error, DispatchError>,
735 InitError = (),
736 > {
737 self.rustls_0_23_with_config(config, TlsAcceptorConfig::default())
738 }
739
740 pub fn rustls_0_23_with_config(
742 self,
743 mut config: ServerConfig,
744 tls_acceptor_config: TlsAcceptorConfig,
745 ) -> impl ServiceFactory<
746 TcpStream,
747 Config = (),
748 Response = (),
749 Error = TlsError<io::Error, DispatchError>,
750 InitError = (),
751 > {
752 let tcp_nodelay = self.cfg.tcp_nodelay();
753 let mut protos = vec![b"http/1.1".to_vec()];
754 #[cfg(feature = "http2")]
755 protos.insert(0, b"h2".to_vec());
756 protos.extend_from_slice(&config.alpn_protocols);
757 config.alpn_protocols = protos;
758
759 let mut acceptor = Acceptor::new(config);
760
761 if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout {
762 acceptor.set_handshake_timeout(handshake_timeout);
763 }
764
765 acceptor
766 .map_init_err(|_| {
767 unreachable!("TLS acceptor service factory does not error on init")
768 })
769 .map_err(TlsError::into_service_error)
770 .and_then(move |io: TlsStream<TcpStream>| async move {
771 let proto = if let Some(protos) = io.get_ref().1.alpn_protocol() {
772 if protos.windows(2).any(|window| window == b"h2") {
773 Protocol::Http2
774 } else {
775 Protocol::Http1
776 }
777 } else {
778 Protocol::Http1
779 };
780
781 if let Some(nodelay) = desired_nodelay(tcp_nodelay) {
782 set_nodelay(io.get_ref().0, nodelay);
783 }
784
785 let peer_addr = io.get_ref().0.peer_addr().ok();
786 Ok((io, proto, peer_addr))
787 })
788 .and_then(self.map_err(TlsError::Service))
789 }
790 }
791}
792
793impl<T, S, B, X, U> ServiceFactory<(T, Protocol, Option<net::SocketAddr>)>
794 for HttpService<T, S, B, X, U>
795where
796 T: AsyncRead + AsyncWrite + Unpin + 'static,
797
798 S: ServiceFactory<Request, Config = ()>,
799 S::Future: 'static,
800 S::Error: Into<Response<BoxBody>> + 'static,
801 S::InitError: fmt::Debug,
802 S::Response: Into<Response<B>> + 'static,
803 <S::Service as Service<Request>>::Future: 'static,
804
805 B: MessageBody + 'static,
806
807 X: ServiceFactory<Request, Config = (), Response = Request>,
808 X::Future: 'static,
809 X::Error: Into<Response<BoxBody>>,
810 X::InitError: fmt::Debug,
811
812 U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
813 U::Future: 'static,
814 U::Error: fmt::Display + Into<Response<BoxBody>>,
815 U::InitError: fmt::Debug,
816{
817 type Response = ();
818 type Error = DispatchError;
819 type Config = ();
820 type Service = HttpServiceHandler<T, S::Service, B, X::Service, U::Service>;
821 type InitError = ();
822 type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
823
824 fn new_service(&self, _: ()) -> Self::Future {
825 let service = self.srv.new_service(());
826 let expect = self.expect.new_service(());
827 let upgrade = self.upgrade.as_ref().map(|s| s.new_service(()));
828 let on_connect_ext = self.on_connect_ext.clone();
829 let cfg = self.cfg.clone();
830
831 Box::pin(async move {
832 let expect = expect.await.map_err(|err| {
833 tracing::error!("Initialization of HTTP expect service error: {err:?}");
834 })?;
835
836 let upgrade = match upgrade {
837 Some(upgrade) => {
838 let upgrade = upgrade.await.map_err(|err| {
839 tracing::error!("Initialization of HTTP upgrade service error: {err:?}");
840 })?;
841 Some(upgrade)
842 }
843 None => None,
844 };
845
846 let service = service.await.map_err(|err| {
847 tracing::error!("Initialization of HTTP service error: {err:?}");
848 })?;
849
850 Ok(HttpServiceHandler::new(
851 cfg,
852 service,
853 expect,
854 upgrade,
855 on_connect_ext,
856 ))
857 })
858 }
859}
860
861pub struct HttpServiceHandler<T, S, B, X, U>
863where
864 S: Service<Request>,
865 X: Service<Request>,
866 U: Service<(Request, Framed<T, h1::Codec>)>,
867{
868 pub(super) flow: Rc<HttpFlow<S, X, U>>,
869 pub(super) cfg: ServiceConfig,
870 pub(super) on_connect_ext: Option<Rc<ConnectCallback<T>>>,
871 _phantom: PhantomData<B>,
872}
873
874impl<T, S, B, X, U> HttpServiceHandler<T, S, B, X, U>
875where
876 S: Service<Request>,
877 S::Error: Into<Response<BoxBody>>,
878 X: Service<Request>,
879 X::Error: Into<Response<BoxBody>>,
880 U: Service<(Request, Framed<T, h1::Codec>)>,
881 U::Error: Into<Response<BoxBody>>,
882{
883 pub(super) fn new(
884 cfg: ServiceConfig,
885 service: S,
886 expect: X,
887 upgrade: Option<U>,
888 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
889 ) -> HttpServiceHandler<T, S, B, X, U> {
890 HttpServiceHandler {
891 cfg,
892 on_connect_ext,
893 flow: HttpFlow::new(service, expect, upgrade),
894 _phantom: PhantomData,
895 }
896 }
897
898 pub(super) fn _poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Response<BoxBody>>> {
899 ready!(self.flow.expect.poll_ready(cx).map_err(Into::into))?;
900
901 ready!(self.flow.service.poll_ready(cx).map_err(Into::into))?;
902
903 if let Some(ref upg) = self.flow.upgrade {
904 ready!(upg.poll_ready(cx).map_err(Into::into))?;
905 };
906
907 Poll::Ready(Ok(()))
908 }
909}
910
911pub(super) struct HttpFlow<S, X, U> {
913 pub(super) service: S,
914 pub(super) expect: X,
915 pub(super) upgrade: Option<U>,
916}
917
918impl<S, X, U> HttpFlow<S, X, U> {
919 pub(super) fn new(service: S, expect: X, upgrade: Option<U>) -> Rc<Self> {
920 Rc::new(Self {
921 service,
922 expect,
923 upgrade,
924 })
925 }
926}
927
928impl<T, S, B, X, U> Service<(T, Protocol, Option<net::SocketAddr>)>
929 for HttpServiceHandler<T, S, B, X, U>
930where
931 T: AsyncRead + AsyncWrite + Unpin,
932
933 S: Service<Request>,
934 S::Error: Into<Response<BoxBody>> + 'static,
935 S::Future: 'static,
936 S::Response: Into<Response<B>> + 'static,
937
938 B: MessageBody + 'static,
939
940 X: Service<Request, Response = Request>,
941 X::Error: Into<Response<BoxBody>>,
942
943 U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
944 U::Error: fmt::Display + Into<Response<BoxBody>>,
945{
946 type Response = ();
947 type Error = DispatchError;
948 type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
949
950 fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
951 self._poll_ready(cx).map_err(|err| {
952 error!("HTTP service readiness error: {:?}", err);
953 DispatchError::Service(err)
954 })
955 }
956
957 fn call(&self, (io, proto, peer_addr): (T, Protocol, Option<net::SocketAddr>)) -> Self::Future {
958 let conn_data = OnConnectData::from_io(&io, self.on_connect_ext.as_deref());
959
960 match proto {
961 #[cfg(feature = "http2")]
962 Protocol::Http2 => HttpServiceHandlerResponse {
963 state: State::H2Handshake {
964 handshake: Some((
965 crate::h2::handshake_with_timeout(io, &self.cfg),
966 self.cfg.clone(),
967 Rc::clone(&self.flow),
968 conn_data,
969 peer_addr,
970 )),
971 },
972 },
973
974 #[cfg(not(feature = "http2"))]
975 Protocol::Http2 => {
976 panic!("HTTP/2 support is disabled (enable with the `http2` feature flag)")
977 }
978
979 Protocol::Http1 => HttpServiceHandlerResponse {
980 state: State::H1 {
981 dispatcher: h1::Dispatcher::new(
982 io,
983 Rc::clone(&self.flow),
984 self.cfg.clone(),
985 peer_addr,
986 conn_data,
987 ),
988 },
989 },
990
991 proto => unimplemented!("Unsupported HTTP version: {:?}.", proto),
992 }
993 }
994}
995
996#[cfg(not(feature = "http2"))]
997pin_project! {
998 #[project = StateProj]
999 enum State<T, S, B, X, U>
1000 where
1001 T: AsyncRead,
1002 T: AsyncWrite,
1003 T: Unpin,
1004
1005 S: Service<Request>,
1006 S::Future: 'static,
1007 S::Error: Into<Response<BoxBody>>,
1008
1009 B: MessageBody,
1010
1011 X: Service<Request, Response = Request>,
1012 X::Error: Into<Response<BoxBody>>,
1013
1014 U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
1015 U::Error: fmt::Display,
1016 {
1017 H1 { #[pin] dispatcher: h1::Dispatcher<T, S, B, X, U> },
1018 }
1019}
1020
1021#[cfg(feature = "http2")]
1022pin_project! {
1023 #[project = StateProj]
1024 enum State<T, S, B, X, U>
1025 where
1026 T: AsyncRead,
1027 T: AsyncWrite,
1028 T: Unpin,
1029
1030 S: Service<Request>,
1031 S::Future: 'static,
1032 S::Error: Into<Response<BoxBody>>,
1033
1034 B: MessageBody,
1035
1036 X: Service<Request, Response = Request>,
1037 X::Error: Into<Response<BoxBody>>,
1038
1039 U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
1040 U::Error: fmt::Display,
1041 {
1042 H1 { #[pin] dispatcher: h1::Dispatcher<T, S, B, X, U> },
1043
1044 H2 { #[pin] dispatcher: crate::h2::Dispatcher<T, S, B, X, U> },
1045
1046 H2Handshake {
1047 handshake: Option<(
1048 crate::h2::HandshakeWithTimeout<T>,
1049 ServiceConfig,
1050 Rc<HttpFlow<S, X, U>>,
1051 OnConnectData,
1052 Option<net::SocketAddr>,
1053 )>,
1054 },
1055 }
1056}
1057
1058pin_project! {
1059 pub struct HttpServiceHandlerResponse<T, S, B, X, U>
1060 where
1061 T: AsyncRead,
1062 T: AsyncWrite,
1063 T: Unpin,
1064
1065 S: Service<Request>,
1066 S::Error: Into<Response<BoxBody>>,
1067 S::Error: 'static,
1068 S::Future: 'static,
1069 S::Response: Into<Response<B>>,
1070 S::Response: 'static,
1071
1072 B: MessageBody,
1073
1074 X: Service<Request, Response = Request>,
1075 X::Error: Into<Response<BoxBody>>,
1076
1077 U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
1078 U::Error: fmt::Display,
1079 {
1080 #[pin]
1081 state: State<T, S, B, X, U>,
1082 }
1083}
1084
1085impl<T, S, B, X, U> Future for HttpServiceHandlerResponse<T, S, B, X, U>
1086where
1087 T: AsyncRead + AsyncWrite + Unpin,
1088
1089 S: Service<Request>,
1090 S::Error: Into<Response<BoxBody>> + 'static,
1091 S::Future: 'static,
1092 S::Response: Into<Response<B>> + 'static,
1093
1094 B: MessageBody + 'static,
1095
1096 X: Service<Request, Response = Request>,
1097 X::Error: Into<Response<BoxBody>>,
1098
1099 U: Service<(Request, Framed<T, h1::Codec>), Response = ()>,
1100 U::Error: fmt::Display,
1101{
1102 type Output = Result<(), DispatchError>;
1103
1104 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1105 match self.as_mut().project().state.project() {
1106 StateProj::H1 { dispatcher } => dispatcher.poll(cx),
1107
1108 #[cfg(feature = "http2")]
1109 StateProj::H2 { dispatcher } => dispatcher.poll(cx),
1110
1111 #[cfg(feature = "http2")]
1112 StateProj::H2Handshake { handshake: data } => {
1113 match ready!(Pin::new(&mut data.as_mut().unwrap().0).poll(cx)) {
1114 Ok((conn, timer)) => {
1115 let (_, config, flow, conn_data, peer_addr) = data.take().unwrap();
1116
1117 self.as_mut().project().state.set(State::H2 {
1118 dispatcher: crate::h2::Dispatcher::new(
1119 conn, flow, config, peer_addr, conn_data, timer,
1120 ),
1121 });
1122 self.poll(cx)
1123 }
1124 Err(err) => {
1125 tracing::trace!("H2 handshake error: {}", err);
1126 Poll::Ready(Err(err))
1127 }
1128 }
1129 }
1130 }
1131 }
1132}