http_srv/
lib.rs

1//! Http Server Crate
2//!
3//! This crate contains all the libraries necessary to run an HTTP Server
4//!
5//! # Example
6//! ```rust,no_run
7//! use http_srv::prelude::*;
8//!
9//! let config = ServerConfig::default();
10//!
11//! let mut handler = Handler::new();
12//! handler.add_default(HttpMethod::GET, handler::cat_handler);
13//! handler.get("/", handler::root_handler);
14//! handler.get("/hello", |req: &mut HttpRequest| {
15//!     let name = req.param("name").unwrap_or("friend");
16//!     let msg = format!("Hello {name}!");
17//!     req.respond_str(&msg)
18//! });
19//!
20//! let mut server = HttpServer::new(config).unwrap();
21//! server.set_handler(handler);
22//! server.run();
23//! ```
24
25#![deny(
26    clippy::unwrap_used,
27    clippy::panic,
28    clippy::expect_used,
29    unused_must_use
30)]
31#![warn(clippy::pedantic)]
32#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)]
33
34pub use http::{self, HttpRequest, HttpResponse, request, response};
35pub mod config;
36
37pub mod handler;
38
39#[doc(hidden)]
40pub mod prelude {
41    pub use http::{request::HttpRequest, response::*, *};
42
43    pub use crate::{
44        HttpServer,
45        config::*,
46        handler::{self, AuthConfig, Handler},
47    };
48}
49use prelude::*;
50
51/// Result type for the [`http_srv`](self) crate
52///
53/// It serves as a shortcut for an [`std::result::Result`]<T,[`HttpError`]>
54pub type Result<T> = std::result::Result<T, HttpError>;
55
56use std::{
57    net::{TcpListener, TcpStream},
58    sync::Arc,
59    time::{Duration, Instant},
60};
61
62pub use config::ServerConfig;
63use http::HttpStream;
64use pool::ThreadPool;
65
66mod log;
67use log::prelude::*;
68
69/// HTTP Server
70///
71/// Represents an HTTP Server, bound to a TCP Port
72///
73/// # Example
74/// ```rust,no_run
75/// use http_srv::HttpServer;
76/// use http_srv::ServerConfig;
77/// use http_srv::handler::Handler;
78/// use http_srv::request::HttpRequest;
79///
80/// let config = ServerConfig::default();
81/// let mut server = HttpServer::new(config).unwrap();
82/// let mut handler = Handler::new();
83/// handler.get("/", |req: &mut HttpRequest| {
84///     req.ok()
85/// });
86/// server.set_handler(handler);
87/// server.run();
88/// ```
89pub struct HttpServer {
90    listener: TcpListener,
91    pool: ThreadPool,
92    handler: Option<Handler>,
93    config: ServerConfig,
94}
95
96fn peek_stream(stream: &HttpStream, duration: Duration) -> bool {
97    if stream.set_read_timeout(Some(duration)).is_err() {
98        return false;
99    }
100    let mut buf: [u8; 1] = [0];
101    let result = match stream.peek(&mut buf) {
102        Ok(n) => n > 0,
103        Err(_) => false,
104    };
105    if stream.set_read_timeout(None).is_err() {
106        return false;
107    }
108    result
109}
110
111fn handle_connection(
112    stream: TcpStream,
113    handlers: &Handler,
114    keep_alive_timeout: Duration,
115    keep_alive_requests: u16,
116) -> Result<()> {
117    let mut req = HttpRequest::parse(stream)?;
118    handlers.handle(&mut req)?;
119    let connection = req.header("Connection");
120    let keep_alive = keep_alive_timeout.as_millis() > 0;
121    if connection.is_some_and(|conn| conn == "keep-alive") && keep_alive {
122        let start = Instant::now();
123        let mut n = 1;
124        while start.elapsed() < keep_alive_timeout && n < keep_alive_requests {
125            let offset = keep_alive_timeout - start.elapsed();
126            if !peek_stream(req.stream(), offset) {
127                break;
128            }
129
130            req = req.keep_alive()?;
131            handlers.handle(&mut req)?;
132            n += 1;
133
134            let connection = req.header("Connection");
135            if connection.is_some_and(|conn| conn == "close") {
136                break;
137            }
138        }
139    }
140    Ok(())
141}
142
143#[allow(clippy::unwrap_used)]
144#[allow(clippy::expect_used)]
145#[allow(clippy::panic)]
146impl HttpServer {
147    /// Create a new HTTP Server
148    ///
149    /// # Errors
150    /// - If the server fails to bind to the TCP port
151    /// - If the thread pool fails to initialize
152    ///
153    pub fn new(config: ServerConfig) -> Result<Self> {
154        let address = format!("::0:{}", config.port);
155        let listener = TcpListener::bind(address)
156            .map_err(|err| format!("Could not bind to port {}: {}", config.port, err))?;
157        let pool =
158            ThreadPool::new(config.pool_conf).map_err(|_| "Error initializing thread pool")?;
159        let handler = Some(Handler::new());
160        let srv = Self {
161            listener,
162            pool,
163            handler,
164            config,
165        };
166        Ok(srv)
167    }
168    /// Starts the server
169    #[allow(clippy::missing_panics_doc)]
170    pub fn run(mut self) {
171        let handler = Arc::new(self.handler.take().unwrap());
172        println!("Sever listening on port {}", self.config.port);
173        for stream in self.listener.incoming().flatten() {
174            let handler = Arc::clone(&handler);
175            let timeout = self.config.keep_alive_timeout;
176            let req = self.config.keep_alive_requests;
177            self.pool.execute(move || {
178                handle_connection(stream, &handler, timeout, req).unwrap_or_else(|err| {
179                    log_error!("{err}");
180                });
181            });
182        }
183        println!("Shutting down.");
184    }
185    /// Set a [Handler] for all the [requests](HttpRequest) on this [server](HttpServer)
186    pub fn set_handler(&mut self, handler: Handler) {
187        self.handler = Some(handler);
188    }
189}
190
191impl Default for HttpServer {
192    /// Default Server
193    ///
194    /// - Configuration: [`ServerConfig::default`]
195    /// - Handler: [`Handler::default`]
196    ///
197    /// # Panics
198    /// If the [`HttpServer`] fails to initialize
199    fn default() -> Self {
200        let conf = ServerConfig::default();
201        #[allow(clippy::expect_used)]
202        let mut srv = Self::new(conf)
203            .expect("Fatal error: HttpServer failed to initialize with default config");
204        let handler = Handler::default();
205        srv.set_handler(handler);
206        srv
207    }
208}