1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::time::Duration;

use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;

use crate::accept::{AcceptorInner, HttpOrHttpsAcceptor};

pub struct Http;
pub struct Https {
    tls_acceptor: tokio_rustls::TlsAcceptor,
    max_handshakes: usize,
    timeout: Duration,
}

/// Build an `HttpOrHttpsAcceptor`
///
/// Defaults to accepting HTTP connections, call the `https` method to accept HTTPS connections instead
pub struct AcceptorBuilder<State> {
    state: State,
    listener: TcpListener,
}

impl AcceptorBuilder<Http> {
    /// Create a new builder for an `HttpOrHttpsAcceptor`
    ///
    /// Defaults to accepting HTTP
    pub const fn new(listener: TcpListener) -> Self {
        Self {
            state: Http,
            listener,
        }
    }

    /// Converts the builder into accepting HTTPS using the provided `TlsAcceptor`
    pub fn https(self, tls_acceptor: TlsAcceptor) -> AcceptorBuilder<Https> {
        AcceptorBuilder {
            state: Https {
                tls_acceptor,
                max_handshakes: tls_listener::DEFAULT_MAX_HANDSHAKES,
                timeout: tls_listener::DEFAULT_HANDSHAKE_TIMEOUT,
            },
            listener: self.listener,
        }
    }

    /// Builds an `HttpOrHttpsAcceptor` to accept HTTP connections
    pub fn build(self) -> HttpOrHttpsAcceptor {
        HttpOrHttpsAcceptor(AcceptorInner::Http(self.listener))
    }
}

impl AcceptorBuilder<Https> {
    /// Set the maximum number of handshakes that will be processed concurrently
    ///
    /// Defaults to 64
    #[must_use]
    pub const fn max_handshakes(mut self, num: usize) -> Self {
        self.state.max_handshakes = num;
        self
    }

    /// Set the maximum amount of time that a handshake can take before being aborted.
    /// Setting it to 0 will not disable the timeout, but will instead instantly drop every connection.
    ///
    /// Defaults to 10 seconds
    #[must_use]
    pub const fn timeout(mut self, timeout: Duration) -> Self {
        self.state.timeout = timeout;
        self
    }

    /// Builds an `HttpOrHttpsAcceptor` to accept HTTPS connections
    pub fn build(self) -> HttpOrHttpsAcceptor {
        let mut tls_builder = tls_listener::builder(self.state.tls_acceptor);

        tls_builder
            .max_handshakes(self.state.max_handshakes)
            .handshake_timeout(self.state.timeout);

        let tls_listener = tls_builder.listen(self.listener);

        HttpOrHttpsAcceptor(AcceptorInner::Https(tls_listener))
    }
}