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
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Types that represent HTTP transports and binding


mod concurrent_listener;
mod failover_listener;
#[cfg(feature = "h1-server")]
mod parsed_listener;
#[cfg(feature = "h1-server")]
mod tcp_listener;
mod to_listener;
#[cfg(feature = "h1-server")]
mod to_listener_impls;
#[cfg(all(unix, feature = "h1-server"))]
mod unix_listener;

use std::fmt::{Debug, Display};

use async_std::io;
use async_trait::async_trait;

use crate::Server;

pub use concurrent_listener::ConcurrentListener;
pub use failover_listener::FailoverListener;
pub use to_listener::ToListener;

#[cfg(feature = "h1-server")]
pub(crate) use parsed_listener::ParsedListener;
#[cfg(feature = "h1-server")]
pub(crate) use tcp_listener::TcpListener;
#[cfg(all(unix, feature = "h1-server"))]
pub(crate) use unix_listener::UnixListener;

/// The Listener trait represents an implementation of http transport for a tide

/// application. In order to provide a Listener to tide, you will also need to

/// implement at least one [`ToListener`](crate::listener::ToListener) that

/// outputs your Listener type.

#[async_trait]
pub trait Listener<State>: Debug + Display + Send + Sync + 'static
where
    State: Send + Sync + 'static,
{
    /// Bind the listener. This starts the listening process by opening the

    /// necessary network ports, but not yet accepting incoming connections. This

    /// method must be called before `accept`.

    async fn bind(&mut self, app: Server<State>) -> io::Result<()>;

    /// Start accepting incoming connections. This method must be called only

    /// after `bind` has succeeded.

    async fn accept(&mut self) -> io::Result<()>;

    /// Expose information about the connection. This should always return valid

    /// data after `bind` has succeeded.

    fn info(&self) -> Vec<ListenInfo>;
}

#[async_trait]
impl<L, State> Listener<State> for Box<L>
where
    L: Listener<State>,
    State: Send + Sync + 'static,
{
    async fn bind(&mut self, app: Server<State>) -> io::Result<()> {
        self.as_mut().bind(app).await
    }

    async fn accept(&mut self) -> io::Result<()> {
        self.as_mut().accept().await
    }

    fn info(&self) -> Vec<ListenInfo> {
        self.as_ref().info()
    }
}

/// crate-internal shared logic used by tcp and unix listeners to

/// determine if an io::Error needs a backoff delay. Transient error

/// types do not require a delay.

#[cfg(feature = "h1-server")]
pub(crate) fn is_transient_error(e: &io::Error) -> bool {
    use io::ErrorKind::*;

    matches!(
        e.kind(),
        ConnectionRefused | ConnectionAborted | ConnectionReset
    )
}

/// Information about the `Listener`.

///

/// See [`Report`](../listener/trait.Report.html) for more.

#[derive(Debug, Clone)]
pub struct ListenInfo {
    conn_string: String,
    transport: String,
    tls: bool,
}

impl ListenInfo {
    /// Create a new instance of `ListenInfo`.

    ///

    /// This method should only be called when implementing a new Tide `listener`

    /// strategy.

    pub fn new(conn_string: String, transport: String, tls: bool) -> Self {
        Self {
            conn_string,
            transport,
            tls,
        }
    }

    /// Get the connection string.

    pub fn connection(&self) -> &str {
        self.conn_string.as_str()
    }

    /// The underlying transport this connection listens on.

    ///

    /// Examples are: "tcp", "uds", etc.

    pub fn transport(&self) -> &str {
        self.transport.as_str()
    }

    /// Is the connection encrypted?

    pub fn is_encrypted(&self) -> bool {
        self.tls
    }
}

impl Display for ListenInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.conn_string)
    }
}