pub mod h1;
pub mod h2;
pub(crate) mod event;
use crate::courierust_body::Body;
use crate::courierust_http::request::Request;
use crate::courierust_http::response::Response;
use crate::courierust_pool::ThreadPool;
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct TlsSettings {
pub identity: crate::courierust_tls::Identity,
pub alpn: Vec<Vec<u8>>,
}
#[derive(Debug, Clone)]
pub struct ServerConfig {
pub read_timeout: Option<Duration>,
pub max_header_list: usize,
pub max_body: usize,
pub http2: bool,
pub threads: usize,
pub tls: Option<TlsSettings>,
pub event_driven: bool,
pub event_workers: usize,
pub event_poll_timeout_ms: u64,
pub max_connections: usize,
pub handshake_timeout: Option<Duration>,
pub idle_timeout: Option<Duration>,
pub h2_settings_timeout: Option<Duration>,
pub h2_ping_interval: Option<Duration>,
pub h2_ping_timeout: Option<Duration>,
pub h2_idle_timeout: Option<Duration>,
pub h2_max_concurrent_streams: u32,
pub auto_release_credit: bool,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
read_timeout: Some(Duration::from_secs(120)),
max_header_list: 1 << 20,
max_body: 16 * 1024 * 1024,
http2: true,
threads: 0, tls: None,
event_driven: true,
event_workers: 0,
event_poll_timeout_ms: 50,
max_connections: 0,
handshake_timeout: Some(Duration::from_secs(10)),
idle_timeout: Some(Duration::from_secs(300)),
h2_settings_timeout: Some(Duration::from_secs(10)),
h2_ping_interval: Some(Duration::from_secs(30)),
h2_ping_timeout: Some(Duration::from_secs(15)),
h2_idle_timeout: Some(Duration::from_secs(300)),
h2_max_concurrent_streams: 1024,
auto_release_credit: true,
}
}
}
pub trait Handler: Send + Sync + 'static {
fn handle(&self, req: Request<Body>) -> Response<Body>;
}
impl<F> Handler for F
where
F: Fn(Request<Body>) -> Response<Body> + Send + Sync + 'static,
{
fn handle(&self, req: Request<Body>) -> Response<Body> {
self(req)
}
}
pub struct Server {
listener: TcpListener,
pool: Arc<ThreadPool>,
config: ServerConfig,
}
impl Server {
pub fn bind(addr: impl std::net::ToSocketAddrs) -> std::io::Result<Self> {
let listener = TcpListener::bind(addr)?;
Ok(Self {
listener,
pool: Arc::new(
ThreadPool::new().unwrap_or_else(|_| ThreadPool::with_size(2).expect("pool")),
),
config: ServerConfig::default(),
})
}
pub fn bind_with_config(
addr: impl std::net::ToSocketAddrs,
config: ServerConfig,
) -> std::io::Result<Self> {
let listener = TcpListener::bind(addr)?;
let size = if config.threads == 0 {
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4)
} else {
config.threads
};
Ok(Self {
listener,
pool: Arc::new(
ThreadPool::with_size(size)
.unwrap_or_else(|_| ThreadPool::with_size(2).expect("pool")),
),
config,
})
}
pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
self.listener.local_addr()
}
pub fn serve<H: Handler>(self, handler: H) -> std::io::Result<()> {
self.serve_with_config(handler)
}
pub fn serve_with_config<H: Handler>(self, handler: H) -> std::io::Result<()> {
let handler = Arc::new(handler);
let config = self.config;
let pool = self.pool;
if config.event_driven {
return event::serve_event(self.listener, handler, config, pool);
}
for stream in self.listener.incoming() {
match stream {
Ok(stream) => {
let h = handler.clone();
let c = config.clone();
let p = pool.clone();
p.spawn(move || {
let _ = serve_accepted(stream, h.as_ref(), &c);
});
}
Err(_) => continue,
}
}
Ok(())
}
pub fn serve_background<H: Handler>(self, handler: H) -> std::io::Result<ServerHandle> {
let (tx, rx) = std::sync::mpsc::channel();
std::thread::Builder::new()
.name("courierust-server".into())
.spawn(move || {
let res = self.serve_with_config(handler);
let _ = tx.send(res);
})?;
Ok(ServerHandle { done: rx })
}
}
pub struct ServerHandle {
done: std::sync::mpsc::Receiver<std::io::Result<()>>,
}
impl ServerHandle {
pub fn join(self) -> std::io::Result<()> {
self.done.recv().unwrap_or(Ok(()))
}
}
pub(crate) fn serve_accepted(
stream: TcpStream,
handler: &dyn Handler,
config: &ServerConfig,
) -> crate::Result<()> {
if config.tls.is_some() {
crate::courierust_net::configure(&stream, config.handshake_timeout)?;
} else {
crate::courierust_net::configure(&stream, config.read_timeout)?;
}
match &config.tls {
Some(t) => {
let acceptor =
crate::courierust_tls::TlsAcceptor::new(crate::courierust_tls::ServerConfig {
identity: t.identity.clone(),
alpn: t.alpn.clone(),
});
let arc = Arc::new(stream);
let peer = arc
.peer_addr()
.unwrap_or_else(|_| SocketAddr::from(([0, 0, 0, 0], 0)));
let tls = acceptor.accept(arc.clone(), arc.clone()).map_err(|e| {
crate::courierust_error::Error::with_message(
crate::courierust_error::ErrorKind::Other,
e.to_string(),
)
})?;
let conn = crate::courierust_net::ConnStream::tls_server(tls, peer);
let _ = conn.configure(config.read_timeout);
serve_connection(conn, handler, config)
}
None => serve_connection(
crate::courierust_net::ConnStream::plain(stream),
handler,
config,
),
}
}
pub(crate) fn serve_connection(
stream: crate::courierust_net::ConnStream,
handler: &dyn Handler,
config: &ServerConfig,
) -> crate::Result<()> {
if let Some(alpn) = stream.alpn() {
if config.http2 && alpn == b"h2" {
return h2::serve(&stream, handler, config);
}
return h1::serve(&stream, handler, config);
}
let mut prefix = [0u8; 24];
let n = stream.peek(&mut prefix).unwrap_or(0);
if config.http2 && n == 24 && crate::courierust_h2::connection::is_preface(&prefix) {
h2::serve(&stream, handler, config)
} else {
h1::serve(&stream, handler, config)
}
}