Skip to main content

actix_http/
service.rs

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
37/// A [`ServiceFactory`] for HTTP/1.1 and, when enabled, HTTP/2 connections.
38///
39/// Use [`build`](Self::build) to begin constructing service. Also see [`HttpServiceBuilder`].
40///
41/// # Automatic HTTP Version Selection
42/// There are two ways to select the HTTP version of an incoming connection:
43/// - One is to rely on the ALPN information that is provided when using TLS (HTTPS); HTTP/1.x is
44///   always supported, and HTTP/2 is supported when the `http2` feature is enabled. Use either of
45///   the `.rustls()` or `.openssl()` finalizing methods.
46/// - The other is to read the first few bytes of the TCP stream. This is the only viable approach
47///   for supporting H2C, which allows the HTTP/2 protocol to work over plaintext connections. Use
48///   the `.tcp_auto_h2c()` finalizing method to enable this behavior.
49///
50/// # Examples
51/// ```
52/// # use std::convert::Infallible;
53/// use actix_http::{HttpService, Request, Response, StatusCode};
54///
55/// // this service would constructed in an actix_server::Server
56///
57/// # actix_rt::System::new().block_on(async {
58/// HttpService::build()
59///     // the builder finalizing method, other finalizers would not return an `HttpService`
60///     .finish(|_req: Request| async move {
61///         Ok::<_, Infallible>(
62///             Response::build(StatusCode::OK).body("Hello!")
63///         )
64///     })
65///     // the service finalizing method method
66///     // you can use `.tcp_auto_h2c()`, `.rustls()`, or `.openssl()` instead of `.tcp()`
67///     .tcp();
68/// # })
69/// ```
70pub 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    /// Constructs builder for `HttpService` instance.
89    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    /// Constructs new `HttpService` instance from service with default config.
104    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    /// Constructs new `HttpService` instance from config and service.
116    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    /// Sets service for `Expect: 100-Continue` handling.
141    ///
142    /// An expect service is called with requests that contain an `Expect` header. A successful
143    /// response type is also a request which will be forwarded to the main service.
144    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    /// Sets service for custom `Connection: Upgrade` handling.
161    ///
162    /// If service is provided then normal requests handling get halted and this service get called
163    /// with original request and framed object.
164    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    /// Set connect callback with mutable access to request data container.
181    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    /// Creates TCP stream service from HTTP service.
209    ///
210    /// The resulting service only supports HTTP/1.x.
211    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    /// Creates TCP stream service from HTTP service that automatically selects HTTP/1.x or HTTP/2
229    /// on plaintext connections.
230    #[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            // subset of HTTP/2 preface defined by RFC 9113 ยง3.4
239            // this subset was chosen to maximize likelihood that peeking only once will allow us to
240            // reliably determine version or else it should fallback to h1 and fail quickly if data
241            // on the wire is junk
242            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/// Configuration options used when accepting TLS connection.
266#[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    /// Set TLS handshake timeout duration.
275    pub fn handshake_timeout(self, dur: std::time::Duration) -> Self {
276        Self {
277            handshake_timeout: Some(dur),
278            // ..self
279        }
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        /// Create OpenSSL based service.
321        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        /// Create OpenSSL based service with custom TLS acceptor configuration.
335        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        /// Create Rustls v0.20 based service.
418        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        /// Create Rustls v0.20 based service with custom TLS acceptor configuration.
432        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        /// Create Rustls v0.21 based service.
521        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        /// Create Rustls v0.21 based service with custom TLS acceptor configuration.
535        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        /// Create Rustls v0.22 based service.
624        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        /// Create Rustls v0.22 based service with custom TLS acceptor configuration.
638        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        /// Create Rustls v0.23 based service.
727        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        /// Create Rustls v0.23 based service with custom TLS acceptor configuration.
741        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
861/// `Service` implementation for HTTP/1 and HTTP/2 transport
862pub 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
911/// A collection of services that describe an HTTP request flow.
912pub(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}