Skip to main content

rust_web_server/server/
mod.rs

1#[cfg(all(test, not(target_arch = "wasm32")))]
2pub mod tests;
3#[cfg(all(test, not(target_arch = "wasm32")))]
4mod example;
5
6// The TCP/thread-pool accept loop below (`Server::setup`/`run`/`process`/…) needs
7// `std::net::TcpListener` and OS threads, neither available on `wasm32-wasip2`.
8// `ConnectionInfo`/`Address` further down have no socket dependency and stay
9// compiled on every target — see spec/WASM_SHIM.md for the guest-adapter that
10// replaces this accept loop under WASI.
11#[cfg(not(target_arch = "wasm32"))]
12use std::io::prelude::*;
13#[cfg(not(target_arch = "wasm32"))]
14use std::borrow::Borrow;
15#[cfg(not(target_arch = "wasm32"))]
16use std::net::{IpAddr, SocketAddr, TcpListener};
17#[cfg(not(target_arch = "wasm32"))]
18use std::str::FromStr;
19#[cfg(not(target_arch = "wasm32"))]
20use std::time::Duration;
21
22#[cfg(not(target_arch = "wasm32"))]
23use crate::request::{METHOD, Request};
24#[cfg(not(target_arch = "wasm32"))]
25use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
26#[cfg(not(target_arch = "wasm32"))]
27use crate::app::App;
28#[cfg(not(target_arch = "wasm32"))]
29use crate::application::Application;
30#[cfg(not(target_arch = "wasm32"))]
31use crate::entry_point::{bootstrap, get_ip_port_thread_count, get_request_allocation_size, set_default_values};
32#[cfg(not(target_arch = "wasm32"))]
33use crate::header::Header;
34#[cfg(not(target_arch = "wasm32"))]
35use crate::log::Log;
36#[cfg(not(target_arch = "wasm32"))]
37use crate::mime_type::MimeType;
38#[cfg(not(target_arch = "wasm32"))]
39use crate::range::{ContentRange, Range};
40#[cfg(not(target_arch = "wasm32"))]
41use crate::symbol::SYMBOL;
42#[cfg(not(target_arch = "wasm32"))]
43use crate::thread_pool::ThreadPool;
44
45#[cfg(not(target_arch = "wasm32"))]
46pub struct Server {}
47#[cfg(not(target_arch = "wasm32"))]
48impl Server {
49    pub fn process_request(mut stream: impl Read + Write + Unpin, peer_addr: SocketAddr) -> Vec<u8> {
50        let request_allocation_size = get_request_allocation_size();
51        let mut buffer = vec![0; request_allocation_size as usize];
52        let boxed_read = stream.read(&mut buffer);
53        if boxed_read.is_err() {
54            let message = boxed_read.err().unwrap().to_string();
55            eprintln!("unable to read TCP stream {}", &message);
56
57            let raw_response = Server::bad_request_response(message);
58            let boxed_stream = stream.write(raw_response.borrow());
59            if boxed_stream.is_ok() {
60                stream.flush().unwrap();
61            };
62            return raw_response;
63        }
64
65        boxed_read.unwrap();
66        let request : &[u8] = &buffer;
67
68        // let raw_request = String::from_utf8(Vec::from(request)).unwrap();
69        // println!("\n\n______{}______\n\n", raw_request);
70
71
72        let boxed_request = Request::parse_request(request);
73        if boxed_request.is_err() {
74            let message = boxed_request.err().unwrap();
75            eprintln!("unable to parse request: {}", &message);
76
77            let raw_response = Server::bad_request_response(message);
78            let boxed_stream = stream.write(raw_response.borrow());
79            if boxed_stream.is_ok() {
80                stream.flush().unwrap();
81            };
82            return raw_response;
83        }
84
85
86        let request: Request = boxed_request.unwrap();
87        let (response, request) = App::handle_request(request);
88
89
90        let log_request_response = Log::combined(&request, &response, &peer_addr);
91        println!("{}", log_request_response);
92        let raw_response = Response::generate_response(response, request);
93
94        let boxed_stream = stream.write(raw_response.borrow());
95        if boxed_stream.is_ok() {
96            stream.flush().unwrap();
97        };
98
99        raw_response
100    }
101
102    pub fn bad_request_response(message: String) -> Vec<u8> {
103        let error_request = Request {
104            method: METHOD.get.to_string(),
105            request_uri: "".to_string(),
106            http_version: "".to_string(),
107            headers: vec![],
108            body: vec![],
109        };
110
111        let size = message.chars().count() as u64;
112        let content_range = ContentRange {
113            unit: Range::BYTES.to_string(),
114            range: Range { start: 0, end: size },
115            size: size.to_string(),
116            body: Vec::from(message.as_bytes()),
117            content_type: MimeType::TEXT_PLAIN.to_string(),
118        };
119
120        let header_list = Header::get_header_list(&error_request);
121        let error_response: Response = Response::get_response(
122            STATUS_CODE_REASON_PHRASE.n400_bad_request,
123            Some(header_list),
124            Some(vec![content_range])
125        );
126
127        let response = Response::generate_response(error_response, error_request);
128        return response;
129    }
130
131    /// Builds a `413 Payload Too Large` raw response for a request whose declared
132    /// `Content-Length` exceeds `RWS_CONFIG_MAX_BODY_SIZE_IN_BYTES`. The connection
133    /// is always closed after this is sent (see [`Server::process`]) — the client's
134    /// unread body bytes are still queued on the socket, so keep-alive framing
135    /// can't be trusted.
136    pub fn payload_too_large_response(message: String) -> Vec<u8> {
137        let error_request = Request {
138            method: METHOD.get.to_string(),
139            request_uri: "".to_string(),
140            http_version: "".to_string(),
141            headers: vec![],
142            body: vec![],
143        };
144
145        let size = message.chars().count() as u64;
146        let content_range = ContentRange {
147            unit: Range::BYTES.to_string(),
148            range: Range { start: 0, end: size },
149            size: size.to_string(),
150            body: Vec::from(message.as_bytes()),
151            content_type: MimeType::TEXT_PLAIN.to_string(),
152        };
153
154        let mut header_list = Header::get_header_list(&error_request);
155        header_list.push(Header { name: Header::_CONNECTION.to_string(), value: "close".to_string() });
156        let error_response: Response = Response::get_response(
157            STATUS_CODE_REASON_PHRASE.n413_payload_too_large,
158            Some(header_list),
159            Some(vec![content_range])
160        );
161
162        Response::generate_response(error_response, error_request)
163    }
164
165    /// Builds the `100 Continue` interim response (RFC 9110 §15.2.1) — no
166    /// headers, no body, just the status line. Sent immediately after parsing
167    /// a request with `Expect: 100-continue`, before reading its body, so the
168    /// client (which is waiting for this before it uploads the body) doesn't
169    /// stall or time out. See [`Server::process`] for where this is sent from.
170    pub fn continue_response() -> Vec<u8> {
171        let dummy_request = Request {
172            method: METHOD.get.to_string(),
173            request_uri: "".to_string(),
174            http_version: "".to_string(),
175            headers: vec![],
176            body: vec![],
177        };
178        let response = Response::get_response(STATUS_CODE_REASON_PHRASE.n100_continue, None, None);
179        Response::generate_response(response, dummy_request)
180    }
181
182    /// Builds a `417 Expectation Failed` raw response for an `Expect` header
183    /// value other than `100-continue` (RFC 9110 §10.1.1) — the only
184    /// expectation this server understands. Sent instead of reading the
185    /// request body, since the expectation can't be met either way.
186    pub fn expectation_failed_response(message: String) -> Vec<u8> {
187        let error_request = Request {
188            method: METHOD.get.to_string(),
189            request_uri: "".to_string(),
190            http_version: "".to_string(),
191            headers: vec![],
192            body: vec![],
193        };
194
195        let size = message.chars().count() as u64;
196        let content_range = ContentRange {
197            unit: Range::BYTES.to_string(),
198            range: Range { start: 0, end: size },
199            size: size.to_string(),
200            body: Vec::from(message.as_bytes()),
201            content_type: MimeType::TEXT_PLAIN.to_string(),
202        };
203
204        let mut header_list = Header::get_header_list(&error_request);
205        header_list.push(Header { name: Header::_CONNECTION.to_string(), value: "close".to_string() });
206        let error_response: Response = Response::get_response(
207            STATUS_CODE_REASON_PHRASE.n417_expectation_failed,
208            Some(header_list),
209            Some(vec![content_range])
210        );
211
212        Response::generate_response(error_response, error_request)
213    }
214
215    pub fn process(mut stream: impl Read + Write + Unpin,
216                   connection: ConnectionInfo,
217                   app: impl Application) -> Result<(), String> {
218        use crate::http::VERSION;
219
220        let request_allocation_size = connection.request_size;
221        let client = connection.client.clone();
222        let client_addr = SocketAddr::new(IpAddr::from_str(client.ip.as_str()).unwrap(), client.port as u16);
223
224        let max_body_size = crate::entry_point::get_max_body_size();
225
226        loop {
227            let mut buffer = vec![0; request_allocation_size as usize];
228            let boxed_read = stream.read(&mut buffer);
229            let n = match boxed_read {
230                // timeout or client closed — normal end of keep-alive session
231                Err(_) => break,
232                Ok(0) => break,
233                Ok(n) => n,
234            };
235
236            // Trim to the bytes actually read — passing the zero-padded rest of
237            // `buffer` to Request::parse would append trailing NUL bytes to the body.
238            let mut request = match Request::parse(&buffer[..n]) {
239                Ok(r) => r,
240                Err(message) => {
241                    let raw_response = Server::bad_request_response(message.clone());
242                    let boxed_stream = stream.write(raw_response.borrow());
243                    if boxed_stream.is_ok() { stream.flush().unwrap(); }
244                    return Err(message);
245                }
246            };
247
248            // RFC 9110 §10.1.1 `Expect` — the only expectation this server
249            // understands is `100-continue`; anything else fails fast with a
250            // final status instead of reading a body we can't act on.
251            let expects_continue = match request.get_header(Header::_EXPECT.to_string()) {
252                Some(h) if h.value.trim().eq_ignore_ascii_case("100-continue") => true,
253                Some(h) => {
254                    let raw_response = Server::expectation_failed_response(format!(
255                        "417 Expectation Failed: unsupported Expect value '{}'", h.value.trim()
256                    ));
257                    let boxed_stream = stream.write(raw_response.borrow());
258                    if boxed_stream.is_ok() { stream.flush().unwrap(); }
259                    break;
260                }
261                None => false,
262            };
263
264            // If Content-Length declares more body than this one read delivered,
265            // keep reading until it's fully received — a single `request_allocation_size`
266            // read is not big enough for bodies larger than that buffer.
267            if let Some(declared_len) = request
268                .get_header(Header::_CONTENT_LENGTH.to_string())
269                .and_then(|h| h.value.trim().parse::<u64>().ok())
270            {
271                if max_body_size > 0 && declared_len > max_body_size {
272                    let raw_response = Server::payload_too_large_response(format!(
273                        "413 Payload Too Large: declared Content-Length {} exceeds the {} byte limit",
274                        declared_len, max_body_size
275                    ));
276                    let boxed_stream = stream.write(raw_response.borrow());
277                    if boxed_stream.is_ok() { stream.flush().unwrap(); }
278                    break;
279                }
280
281                // Tell the client to go ahead and send the body now, before we
282                // block waiting for it below.
283                if expects_continue {
284                    let raw_response = Server::continue_response();
285                    match stream.write(raw_response.borrow()) {
286                        Ok(_) => stream.flush().unwrap(),
287                        Err(_) => break,
288                    }
289                }
290
291                while (request.body.len() as u64) < declared_len {
292                    let mut more = vec![0u8; request_allocation_size as usize];
293                    match stream.read(&mut more) {
294                        Ok(0) | Err(_) => break, // peer closed early; proceed with the short body
295                        Ok(k) => request.body.extend_from_slice(&more[..k]),
296                    }
297                }
298            }
299
300            let keep_alive = {
301                let conn_hdr = request.get_header(Header::_CONNECTION.to_string());
302                match conn_hdr {
303                    Some(h) => h.value.to_lowercase() != "close",
304                    None => request.http_version == VERSION.http_1_1,
305                }
306            };
307
308            let mut response = match app.execute(&request, &connection) {
309                Ok(r) => r,
310                Err(message) => {
311                    let raw_response = Server::bad_request_response(message.clone());
312                    let boxed_stream = stream.write(raw_response.borrow());
313                    if boxed_stream.is_ok() { stream.flush().unwrap(); }
314                    return Err(message);
315                }
316            };
317
318            crate::metrics::record_request();
319            crate::compression::apply_gzip(&request, &mut response);
320
321            response.headers.push(Header {
322                name: Header::_CONNECTION.to_string(),
323                value: if keep_alive { "keep-alive".to_string() } else { "close".to_string() },
324            });
325
326            Log::log_access(&request, &response, &client_addr);
327
328            if let Some(reader) = response.stream_pipe.take() {
329                if let Err(e) = Server::pipe_stream(&mut stream, response, request, reader) {
330                    return Err(e);
331                }
332            } else if let Some(ref filepath) = response.stream_file.clone() {
333                if let Err(e) = Server::write_chunked_file(&mut stream, response, request, filepath) {
334                    return Err(e);
335                }
336            } else {
337                let raw_response = Response::generate_response(response, request);
338                if let Err(e) = stream.write(raw_response.borrow()) {
339                    return Err(e.to_string());
340                }
341                stream.flush().unwrap();
342            }
343
344            if !keep_alive { break; }
345        }
346
347        Ok(())
348    }
349
350    /// Streams a file to `stream` using HTTP/1.1 chunked transfer encoding.
351    /// The response headers are written first, then the file is read and written in 64 KB chunks.
352    pub(crate) fn write_chunked_file(
353        stream: &mut impl Write,
354        mut response: Response,
355        request: Request,
356        filepath: &str,
357    ) -> Result<(), String> {
358        use std::fs::File;
359        use std::io::Read as _;
360
361        response.headers.push(Header {
362            name: Header::_TRANSFER_ENCODING.to_string(),
363            value: "chunked".to_string(),
364        });
365
366        // build status line + headers (no body)
367        let status = [
368            response.http_version.clone(),
369            response.status_code.to_string(),
370            response.reason_phrase.clone(),
371        ].join(SYMBOL.whitespace);
372
373        let mut headers_str = SYMBOL.new_line_carriage_return.to_string();
374        for header in &response.headers {
375            headers_str.push_str(&header.name);
376            headers_str.push_str(Header::NAME_VALUE_SEPARATOR);
377            headers_str.push_str(&header.value);
378            headers_str.push_str(SYMBOL.new_line_carriage_return);
379        }
380        let head = format!("{}{}{}", status, headers_str, SYMBOL.new_line_carriage_return);
381
382        stream.write_all(head.as_bytes()).map_err(|e| e.to_string())?;
383
384        if request.method != METHOD.head && request.method != METHOD.options {
385            let mut file = File::open(filepath).map_err(|e| e.to_string())?;
386            let mut buf = vec![0u8; 65536];
387            loop {
388                let n = file.read(&mut buf).map_err(|e| e.to_string())?;
389                if n == 0 { break; }
390                // chunk header: hex size + CRLF
391                stream.write_all(format!("{:x}\r\n", n).as_bytes()).map_err(|e| e.to_string())?;
392                stream.write_all(&buf[..n]).map_err(|e| e.to_string())?;
393                stream.write_all(b"\r\n").map_err(|e| e.to_string())?;
394            }
395            // terminal chunk
396            stream.write_all(b"0\r\n\r\n").map_err(|e| e.to_string())?;
397        }
398
399        stream.flush().map_err(|e| e.to_string())
400    }
401
402    /// Streams a `Read` source to `stream` using HTTP/1.1 chunked transfer encoding.
403    ///
404    /// Called when `response.stream_pipe` is set (proxy passthrough for SSE, AI token
405    /// streams, and large downloads). The response headers are written first (with
406    /// `Transfer-Encoding: chunked` injected and any `Content-Length` stripped), then
407    /// bytes are read from `reader` and forwarded in 8 KB chunks. Each chunk is flushed
408    /// immediately so the client sees data as it arrives.
409    pub(crate) fn pipe_stream(
410        stream: &mut impl Write,
411        mut response: Response,
412        request: Request,
413        mut reader: Box<dyn std::io::Read + Send>,
414    ) -> Result<(), String> {
415        // If the backend already uses chunked encoding we pass the raw chunk
416        // frames through; otherwise we wrap the raw bytes in our own chunked
417        // framing so the client can receive data incrementally.
418        let backend_is_chunked = response.headers.iter().any(|h| {
419            h.name.eq_ignore_ascii_case("transfer-encoding")
420                && h.value.to_lowercase().contains("chunked")
421        });
422
423        response.headers.retain(|h| !h.name.eq_ignore_ascii_case("content-length"));
424        if !backend_is_chunked {
425            response.headers.push(Header {
426                name: Header::_TRANSFER_ENCODING.to_string(),
427                value: "chunked".to_string(),
428            });
429        }
430
431        let status = [
432            response.http_version.clone(),
433            response.status_code.to_string(),
434            response.reason_phrase.clone(),
435        ].join(SYMBOL.whitespace);
436
437        let mut head = format!("{}\r\n", status);
438        for header in &response.headers {
439            head.push_str(&header.name);
440            head.push_str(Header::NAME_VALUE_SEPARATOR);
441            head.push_str(&header.value);
442            head.push_str(SYMBOL.new_line_carriage_return);
443        }
444        head.push_str(SYMBOL.new_line_carriage_return);
445        stream.write_all(head.as_bytes()).map_err(|e| e.to_string())?;
446
447        if request.method != METHOD.head && request.method != METHOD.options {
448            let mut buf = [0u8; 8192];
449            if backend_is_chunked {
450                // Passthrough: forward raw chunk frames as-is; the client
451                // decodes them itself (avoids double-chunking).
452                loop {
453                    match reader.read(&mut buf) {
454                        Ok(0) | Err(_) => break,
455                        Ok(n) => {
456                            stream.write_all(&buf[..n]).map_err(|e| e.to_string())?;
457                            stream.flush().map_err(|e| e.to_string())?;
458                        }
459                    }
460                }
461            } else {
462                // Re-encode: wrap the raw byte stream in chunked framing so
463                // the client can receive each fragment as it arrives (SSE,
464                // large downloads).
465                loop {
466                    match reader.read(&mut buf) {
467                        Ok(0) | Err(_) => break,
468                        Ok(n) => {
469                            stream
470                                .write_all(format!("{:x}\r\n", n).as_bytes())
471                                .map_err(|e| e.to_string())?;
472                            stream.write_all(&buf[..n]).map_err(|e| e.to_string())?;
473                            stream.write_all(b"\r\n").map_err(|e| e.to_string())?;
474                            stream.flush().map_err(|e| e.to_string())?;
475                        }
476                    }
477                }
478                stream.write_all(b"0\r\n\r\n").map_err(|e| e.to_string())?;
479            }
480        }
481
482        stream.flush().map_err(|e| e.to_string())
483    }
484
485    /// Reads configuration (IP, port, thread count, TLS paths) from the layered config system
486    /// and returns a bound `TcpListener` and a sized `ThreadPool`. Call once at startup.
487    pub fn setup() -> Result<(TcpListener, ThreadPool), String> {
488        let info = Log::info("Rust Web Server");
489        println!("{}", info);
490
491        let usage_info = Log::usage_information();
492        println!("{}", usage_info);
493
494
495        println!("RWS Configuration Start: \n");
496
497        set_default_values();
498        bootstrap();
499
500        #[cfg(feature = "secrets")]
501        crate::secrets::resolve_env_vars().map_err(|e| e.to_string())?;
502
503        println!("\nRWS Configuration End\n\n");
504
505
506        let (ip, port, thread_count) = get_ip_port_thread_count();
507
508
509        let mut ip_readable = ip.to_string();
510
511        if ip.contains(":") {
512            ip_readable = [SYMBOL.opening_square_bracket, &ip, SYMBOL.closing_square_bracket].join("");
513        }
514
515        let bind_addr = [ip_readable, SYMBOL.colon.to_string(), port.to_string()].join(SYMBOL.empty_string);
516
517        #[cfg(feature = "http2")]
518        let protocol = {
519            let cert = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE).unwrap_or_default();
520            if cert.is_empty() { "http" } else { "https" }
521        };
522        #[cfg(not(feature = "http2"))]
523        let protocol = "http";
524
525        println!("Setting up {}://{}...", protocol, &bind_addr);
526
527        let boxed_listener = TcpListener::bind(&bind_addr);
528        if boxed_listener.is_err() {
529            let message = format!("unable to set up TCP listener: {}", boxed_listener.err().unwrap());
530            return Err(message);
531        }
532
533        let listener = boxed_listener.unwrap();
534        let pool = ThreadPool::new(thread_count as usize);
535
536
537        let server_url_thread_count = Log::server_url_thread_count(protocol, &bind_addr, thread_count);
538        println!("{}", server_url_thread_count);
539
540        Ok((listener, pool))
541    }
542
543    /// Accepts TCP connections in a loop and dispatches each to the thread pool.
544    ///
545    /// When built with the `http1` feature, Ctrl+C and SIGTERM stop the accept
546    /// loop gracefully: `SERVER_READY` is cleared and the pool drains all
547    /// in-flight connections before returning.
548    ///
549    /// For TLS/HTTP2/HTTP3 use [`Server::run_tls`].
550    pub fn run(listener: TcpListener,
551               pool: ThreadPool,
552               app: impl Application + Send + 'static + Clone) {
553        #[cfg(feature = "http1")]
554        {
555            use std::sync::Arc;
556            use std::sync::atomic::{AtomicBool, Ordering};
557
558            let shutdown = Arc::new(AtomicBool::new(false));
559            let s = shutdown.clone();
560            if let Err(e) = ctrlc::set_handler(move || {
561                s.store(true, Ordering::SeqCst);
562            }) {
563                eprintln!("unable to install signal handler: {}", e);
564            }
565            crate::config_reload::install_sighup_handler();
566            if let Err(e) = listener.set_nonblocking(true) {
567                eprintln!("unable to set non-blocking listener: {}", e);
568            }
569
570            loop {
571                if shutdown.load(Ordering::SeqCst) {
572                    break;
573                }
574                if crate::config_reload::RELOAD_REQUESTED
575                    .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed)
576                    .is_ok()
577                {
578                    crate::config_reload::reload();
579                }
580                match listener.accept() {
581                    Ok((stream, peer_addr)) => {
582                        Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
583                    }
584                    Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
585                        std::thread::sleep(Duration::from_millis(10));
586                    }
587                    Err(e) => {
588                        eprintln!("accept error: {}", e);
589                        break;
590                    }
591                }
592            }
593
594            crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
595            println!("Shutting down — waiting for in-flight connections to finish");
596            pool.join();
597            println!("Server stopped");
598        }
599
600        #[cfg(not(feature = "http1"))]
601        {
602            for boxed_stream in listener.incoming() {
603                match boxed_stream {
604                    Err(e) => {
605                        eprintln!("unable to get TCP stream: {}", e);
606                        return;
607                    }
608                    Ok(stream) => {
609                        let peer_addr = match stream.peer_addr() {
610                            Ok(a) => a,
611                            Err(e) => {
612                                eprintln!("unable to read peer addr: {}", e);
613                                return;
614                            }
615                        };
616                        Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
617                    }
618                }
619            }
620        }
621    }
622
623    fn dispatch_connection(
624        stream: std::net::TcpStream,
625        peer_addr: std::net::SocketAddr,
626        pool: &ThreadPool,
627        app: impl Application + Send + 'static + Clone,
628    ) {
629        print!("Connection established, ");
630        if let Ok(local) = stream.local_addr() {
631            print!("local addr: {}", local);
632        }
633        println!(", peer addr: {}", peer_addr);
634
635        let (server_ip, server_port, _thread_count) = get_ip_port_thread_count();
636        let connection = ConnectionInfo {
637            client: Address {
638                ip: peer_addr.ip().to_string(),
639                port: peer_addr.port() as i32,
640            },
641            server: Address {
642                ip: server_ip,
643                port: server_port,
644            },
645            request_size: get_request_allocation_size(),
646            sni_hostname: None,
647        };
648
649        if let Err(e) = stream.set_read_timeout(Some(Duration::from_secs(30))) {
650            eprintln!("failed to set read timeout: {}", e);
651        }
652
653        pool.execute(move || {
654            crate::metrics::connection_open();
655            let result = Server::process(stream, connection, app);
656            crate::metrics::connection_close();
657            if let Err(msg) = result {
658                crate::metrics::record_error();
659                eprintln!("{}", msg);
660            }
661        });
662    }
663
664}
665
666/// Network context for the current connection, passed into every [`Controller`](crate::controller::Controller).
667#[derive(Clone)]
668pub struct ConnectionInfo {
669    /// Client (peer) address.
670    pub client: Address,
671    /// Server (local) address.
672    pub server: Address,
673    /// Bytes allocated for reading the request.
674    pub request_size: i64,
675    /// SNI hostname sent by the client during the TLS handshake, if any.
676    /// `None` for plain-HTTP connections or when the client omits SNI.
677    pub sni_hostname: Option<String>,
678}
679
680/// IP address and port pair.
681#[derive(Clone)]
682pub struct Address {
683    pub ip: String,
684    pub port: i32
685}
686
687impl ConnectionInfo {
688    /// Parse the client address into a [`std::net::SocketAddr`], if the stored
689    /// IP and port are valid. Returns `None` if parsing fails.
690    pub fn peer_addr(&self) -> Option<std::net::SocketAddr> {
691        self.client.to_socket_addr()
692    }
693}
694
695impl Address {
696    /// Parse this address into a [`std::net::SocketAddr`]. Returns `None` if
697    /// the IP string or port value cannot be converted.
698    pub fn to_socket_addr(&self) -> Option<std::net::SocketAddr> {
699        let ip: std::net::IpAddr = self.ip.parse().ok()?;
700        let port = u16::try_from(self.port).ok()?;
701        Some(std::net::SocketAddr::new(ip, port))
702    }
703}
704
705/// Resolves when SIGTERM is received on Unix, or never on other platforms.
706/// Enables a single `select!` branch to handle both SIGTERM and Ctrl+C.
707#[cfg(feature = "http2")]
708async fn sigterm() {
709    #[cfg(unix)]
710    {
711        if let Ok(mut s) = tokio::signal::unix::signal(
712            tokio::signal::unix::SignalKind::terminate()
713        ) {
714            s.recv().await;
715        } else {
716            std::future::pending::<()>().await
717        }
718    }
719    #[cfg(not(unix))]
720    std::future::pending::<()>().await
721}
722
723/// Returns a stream that fires on each SIGHUP on Unix; never fires elsewhere.
724#[cfg(feature = "http2")]
725async fn sighup() {
726    #[cfg(unix)]
727    {
728        if let Ok(mut s) = tokio::signal::unix::signal(
729            tokio::signal::unix::SignalKind::hangup()
730        ) {
731            s.recv().await;
732        } else {
733            std::future::pending::<()>().await
734        }
735    }
736    #[cfg(not(unix))]
737    std::future::pending::<()>().await
738}
739
740/// Bind `port` for both IPv4 and IPv6 when `ip` is the wildcard `0.0.0.0`
741/// (otherwise just `ip`). Let's Encrypt validates HTTP-01 over IPv6 when a
742/// domain has an AAAA record, so a v4-only challenge/redirect listener fails
743/// validation on dual-stack hosts. On Linux/macOS `[::]` already accepts
744/// IPv4 too and the second bind reports "address in use", which is fine; on
745/// Windows (`IPV6_V6ONLY` by default) both binds succeed.
746#[cfg(feature = "http2")]
747pub(crate) async fn bind_all_families(ip: &str, port: u16) -> Result<Vec<tokio::net::TcpListener>, String> {
748    use tokio::net::TcpListener;
749    if ip != "0.0.0.0" {
750        let addr = if ip.contains(':') { format!("[{ip}]:{port}") } else { format!("{ip}:{port}") };
751        return TcpListener::bind(&addr).await.map(|l| vec![l]).map_err(|e| format!("{addr}: {e}"));
752    }
753    let mut listeners = Vec::new();
754    let mut errors = Vec::new();
755    for addr in [format!("[::]:{port}"), format!("0.0.0.0:{port}")] {
756        match TcpListener::bind(&addr).await {
757            Ok(l) => listeners.push(l),
758            Err(e) => errors.push(format!("{addr}: {e}")),
759        }
760    }
761    if listeners.is_empty() {
762        return Err(errors.join("; "));
763    }
764    Ok(listeners)
765}
766
767#[cfg(feature = "http2")]
768impl Server {
769    pub async fn run_tls(
770        listener: TcpListener,
771        pool: ThreadPool,
772        app: impl Application + Send + 'static + Clone,
773    ) {
774        use crate::tls::create_tls_acceptor_from_vhosts;
775        use crate::h2_handler;
776
777        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
778            .unwrap_or_default();
779        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
780            .unwrap_or_default();
781
782        if cert_path.is_empty() || key_path.is_empty() {
783            println!("No TLS certificate configured — serving plain HTTP/1.1.");
784            tokio::task::block_in_place(|| Server::run(listener, pool, app));
785            return;
786        }
787
788        let vhosts = crate::entry_point::get_virtual_hosts();
789        let mut tls_acceptor = match create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
790            Ok(a) => a,
791            Err(e) => {
792                eprintln!("TLS setup failed: {}", e);
793                return;
794            }
795        };
796
797        listener
798            .set_nonblocking(true)
799            .expect("failed to set TCP listener to non-blocking");
800        let tokio_listener = tokio::net::TcpListener::from_std(listener)
801            .expect("failed to convert TCP listener to tokio");
802
803        println!("Listening for TLS connections (HTTP/1.1 + HTTP/2)...");
804
805        loop {
806            tokio::select! {
807                result = tokio_listener.accept() => {
808                    match result {
809                        Ok((tcp_stream, peer_addr)) => {
810                            let acceptor = tls_acceptor.clone();
811                            let app = app.clone();
812                            tokio::spawn(async move {
813                                match acceptor.accept(tcp_stream).await {
814                                    Ok(tls_stream) => {
815                                        let server_conn = tls_stream.get_ref().1;
816                                        let sni = server_conn.server_name().map(|s| s.to_string());
817                                        let protocol = server_conn
818                                            .alpn_protocol()
819                                            .map(|p| p.to_vec());
820
821                                        match protocol.as_deref() {
822                                            Some(b"h2") => {
823                                                if let Err(e) =
824                                                    h2_handler::handle_connection(tls_stream, peer_addr, sni, app)
825                                                        .await
826                                                {
827                                                    eprintln!("H2 connection error: {}", e);
828                                                }
829                                            }
830                                            _ => {
831                                                if let Err(e) =
832                                                    Server::process_h1_tls(tls_stream, peer_addr, sni, app).await
833                                                {
834                                                    eprintln!("H1 TLS error: {}", e);
835                                                }
836                                            }
837                                        }
838                                    }
839                                    Err(e) => eprintln!("TLS handshake failed: {}", e),
840                                }
841                            });
842                        }
843                        Err(e) => eprintln!("TCP accept error: {}", e),
844                    }
845                }
846                _ = tokio::signal::ctrl_c() => {
847                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
848                    println!("\nShutting down gracefully (SIGINT).");
849                    break;
850                }
851                _ = sigterm() => {
852                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
853                    println!("\nShutting down gracefully (SIGTERM).");
854                    break;
855                }
856                _ = sighup() => {
857                    crate::config_reload::reload();
858                    let vhosts = crate::entry_point::get_virtual_hosts();
859                    if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
860                        tls_acceptor = new_acceptor;
861                        println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
862                    }
863                }
864            }
865        }
866    }
867
868    /// Binds a plain-HTTP listener on the port in `RWS_CONFIG_HTTP_REDIRECT_PORT` and sends
869    /// `301 Moved Permanently` to the HTTPS equivalent of every incoming URL.
870    /// Returns immediately if TLS is not configured or the redirect port is not set.
871    pub async fn run_redirect() {
872        use std::env;
873
874        let cert_path = env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
875            .unwrap_or_default();
876        if cert_path.is_empty() {
877            return;
878        }
879
880        let redirect_port_str = env::var(crate::entry_point::Config::RWS_CONFIG_HTTP_REDIRECT_PORT)
881            .unwrap_or_default();
882        if redirect_port_str.is_empty() {
883            return;
884        }
885
886        let redirect_port: u16 = match redirect_port_str.parse() {
887            Ok(p) => p,
888            Err(_) => {
889                eprintln!("Invalid RWS_CONFIG_HTTP_REDIRECT_PORT: {}", redirect_port_str);
890                return;
891            }
892        };
893
894        let (server_ip, server_port, _) = get_ip_port_thread_count();
895        let listeners = match bind_all_families(&server_ip, redirect_port).await {
896            Ok(l) => l,
897            Err(e) => {
898                eprintln!("HTTP redirect listener error on port {}: {}", redirect_port, e);
899                return;
900            }
901        };
902
903        println!("HTTP→HTTPS redirect listening on http://{}:{}", server_ip, redirect_port);
904        #[cfg(feature = "acme")]
905        crate::acme::note_redirect_listener(redirect_port);
906
907        for listener in listeners {
908            tokio::spawn(async move {
909                loop {
910                    match listener.accept().await {
911                        Ok((stream, _peer)) => {
912                            tokio::spawn(Server::handle_redirect_connection(stream, server_port));
913                        }
914                        Err(e) => eprintln!("HTTP redirect accept error: {}", e),
915                    }
916                }
917            });
918        }
919
920        loop {
921            tokio::select! {
922                _ = tokio::signal::ctrl_c() => {
923                    println!("\nShutting down HTTP redirect listener (SIGINT).");
924                    break;
925                }
926                _ = sigterm() => {
927                    println!("\nShutting down HTTP redirect listener (SIGTERM).");
928                    break;
929                }
930                _ = sighup() => {
931                    crate::config_reload::reload();
932                }
933            }
934        }
935    }
936
937    /// One redirect-listener connection: answer a pending ACME HTTP-01
938    /// challenge, or `301` to the HTTPS equivalent of the requested URL.
939    pub(crate) async fn handle_redirect_connection(mut stream: tokio::net::TcpStream, https_port: i32) {
940        use tokio::io::{AsyncReadExt, AsyncWriteExt};
941        let mut buf = vec![0u8; 4096];
942        let n = match stream.read(&mut buf).await {
943            Ok(n) => n,
944            Err(_) => return,
945        };
946        let text = String::from_utf8_lossy(&buf[..n]);
947
948        let uri = text.lines()
949            .next()
950            .and_then(|line| line.split_whitespace().nth(1))
951            .unwrap_or("/")
952            .to_string();
953
954        // ACME HTTP-01 challenges must be answered over
955        // plain HTTP, not redirected.
956        #[cfg(feature = "acme")]
957        if let Some(challenge) = crate::acme::challenge_http_response(&uri) {
958            let _ = stream.write_all(challenge.as_bytes()).await;
959            return;
960        }
961
962        let host_header = text.lines()
963            .find(|l| l.to_lowercase().starts_with("host:"))
964            .map(|l| l[5..].trim().to_string());
965
966        let location = match host_header {
967            Some(h) => {
968                // strip existing port from Host header
969                let h_no_port = if h.starts_with('[') {
970                    // IPv6: [::1] or [::1]:port
971                    h.find(']')
972                        .map(|i| h[..=i].to_string())
973                        .unwrap_or(h.clone())
974                } else {
975                    h.rfind(':')
976                        .map(|i| h[..i].to_string())
977                        .unwrap_or(h.clone())
978                };
979                if https_port == 443 {
980                    format!("https://{}{}", h_no_port, uri)
981                } else {
982                    format!("https://{}:{}{}", h_no_port, https_port, uri)
983                }
984            }
985            None => format!("https://localhost:{}{}", https_port, uri),
986        };
987
988        let response = format!(
989            "HTTP/1.1 301 Moved Permanently\r\nLocation: {}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
990            location
991        );
992        let _ = stream.write_all(response.as_bytes()).await;
993    }
994
995    async fn process_h1_tls(
996        mut stream: tokio_rustls::server::TlsStream<tokio::net::TcpStream>,
997        peer_addr: std::net::SocketAddr,
998        sni_hostname: Option<String>,
999        app: impl Application,
1000    ) -> Result<(), String> {
1001        use tokio::io::{AsyncReadExt, AsyncWriteExt};
1002
1003        let (server_ip, server_port, _) = get_ip_port_thread_count();
1004        let request_allocation_size = get_request_allocation_size();
1005
1006        let mut buffer = vec![0u8; request_allocation_size as usize];
1007        let n = match stream.read(&mut buffer).await {
1008            Ok(n) => n,
1009            Err(e) => {
1010                let raw = Server::bad_request_response(e.to_string());
1011                let _ = stream.write_all(&raw).await;
1012                return Ok(());
1013            }
1014        };
1015
1016        // Trim to the bytes actually read — passing the zero-padded rest of
1017        // `buffer` to Request::parse would append trailing NUL bytes to the body.
1018        let mut request = match Request::parse(&buffer[..n]) {
1019            Ok(r) => r,
1020            Err(message) => {
1021                let raw = Server::bad_request_response(message);
1022                let _ = stream.write_all(&raw).await;
1023                return Ok(());
1024            }
1025        };
1026
1027        // RFC 9110 §10.1.1 `Expect` — the only expectation this server
1028        // understands is `100-continue`; anything else fails fast with a
1029        // final status instead of reading a body we can't act on.
1030        let expects_continue = match request.get_header(Header::_EXPECT.to_string()) {
1031            Some(h) if h.value.trim().eq_ignore_ascii_case("100-continue") => true,
1032            Some(h) => {
1033                let raw = Server::expectation_failed_response(format!(
1034                    "417 Expectation Failed: unsupported Expect value '{}'", h.value.trim()
1035                ));
1036                let _ = stream.write_all(&raw).await;
1037                return Ok(());
1038            }
1039            None => false,
1040        };
1041
1042        // If Content-Length declares more body than this one read delivered,
1043        // keep reading until it's fully received — a single `request_allocation_size`
1044        // read is not big enough for bodies larger than that buffer.
1045        if let Some(declared_len) = request
1046            .get_header(Header::_CONTENT_LENGTH.to_string())
1047            .and_then(|h| h.value.trim().parse::<u64>().ok())
1048        {
1049            let max_body_size = crate::entry_point::get_max_body_size();
1050            if max_body_size > 0 && declared_len > max_body_size {
1051                let raw = Server::payload_too_large_response(format!(
1052                    "413 Payload Too Large: declared Content-Length {} exceeds the {} byte limit",
1053                    declared_len, max_body_size
1054                ));
1055                let _ = stream.write_all(&raw).await;
1056                return Ok(());
1057            }
1058
1059            // Tell the client to go ahead and send the body now, before we
1060            // block waiting for it below.
1061            if expects_continue {
1062                let raw = Server::continue_response();
1063                if stream.write_all(&raw).await.is_err() {
1064                    return Ok(());
1065                }
1066            }
1067
1068            while (request.body.len() as u64) < declared_len {
1069                let mut more = vec![0u8; request_allocation_size as usize];
1070                match stream.read(&mut more).await {
1071                    Ok(0) | Err(_) => break, // peer closed early; proceed with the short body
1072                    Ok(k) => request.body.extend_from_slice(&more[..k]),
1073                }
1074            }
1075        }
1076
1077        let connection = ConnectionInfo {
1078            client: Address {
1079                ip: peer_addr.ip().to_string(),
1080                port: peer_addr.port() as i32,
1081            },
1082            server: Address {
1083                ip: server_ip,
1084                port: server_port,
1085            },
1086            request_size: request_allocation_size,
1087            sni_hostname,
1088        };
1089
1090        let mut response = match app.execute(&request, &connection) {
1091            Ok(r) => r,
1092            Err(message) => {
1093                let raw = Server::bad_request_response(message);
1094                let _ = stream.write_all(&raw).await;
1095                return Ok(());
1096            }
1097        };
1098
1099        crate::metrics::record_request();
1100        crate::compression::apply_gzip(&request, &mut response);
1101        response.headers.push(Header::get_hsts_header());
1102
1103        #[cfg(feature = "http3")]
1104        response.headers.push(Header {
1105            name: Header::_ALT_SVC.to_string(),
1106            value: format!("h3=\":{}\"", server_port),
1107        });
1108        #[cfg(not(feature = "http3"))]
1109        response.headers.push(Header {
1110            name: Header::_ALT_SVC.to_string(),
1111            value: format!("h2=\":{}\"", server_port),
1112        });
1113
1114        Log::log_access(&request, &response, &peer_addr);
1115
1116        let raw = Response::generate_response(response, request);
1117        stream
1118            .write_all(&raw)
1119            .await
1120            .map_err(|e| e.to_string())?;
1121        stream.flush().await.map_err(|e| e.to_string())?;
1122
1123        Ok(())
1124    }
1125}
1126
1127#[cfg(feature = "http3")]
1128impl Server {
1129    pub async fn run_quic(
1130        app: impl Application + Send + 'static + Clone,
1131    ) {
1132        use crate::tls::create_quinn_server_config_from_vhosts;
1133        use crate::h3_handler;
1134
1135        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1136            .unwrap_or_default();
1137        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
1138            .unwrap_or_default();
1139
1140        if cert_path.is_empty() || key_path.is_empty() {
1141            return;
1142        }
1143
1144        let vhosts = crate::entry_point::get_virtual_hosts();
1145        let server_config = match create_quinn_server_config_from_vhosts(&vhosts, &cert_path, &key_path) {
1146            Ok(c) => c,
1147            Err(e) => {
1148                eprintln!("QUIC TLS setup failed: {}", e);
1149                return;
1150            }
1151        };
1152
1153        let (server_ip, server_port, _) = get_ip_port_thread_count();
1154        let bind_addr = format!("{}:{}", server_ip, server_port);
1155        let addr: std::net::SocketAddr = match bind_addr.parse() {
1156            Ok(a) => a,
1157            Err(e) => {
1158                eprintln!("Invalid QUIC bind address '{}': {}", bind_addr, e);
1159                return;
1160            }
1161        };
1162
1163        let endpoint = match quinn::Endpoint::server(server_config, addr) {
1164            Ok(e) => e,
1165            Err(e) => {
1166                eprintln!("QUIC endpoint error: {}", e);
1167                return;
1168            }
1169        };
1170
1171        println!("Listening for QUIC/HTTP3 on UDP {}:{}", server_ip, server_port);
1172
1173        loop {
1174            tokio::select! {
1175                maybe = endpoint.accept() => {
1176                    match maybe {
1177                        Some(incoming) => {
1178                            let app = app.clone();
1179                            tokio::spawn(async move {
1180                                match incoming.await {
1181                                    Ok(conn) => {
1182                                        let peer_addr = conn.remote_address();
1183                                        if let Err(e) = h3_handler::handle_connection(conn, peer_addr, app).await {
1184                                            eprintln!("H3 connection error: {}", e);
1185                                        }
1186                                    }
1187                                    Err(e) => eprintln!("QUIC connection error: {}", e),
1188                                }
1189                            });
1190                        }
1191                        None => break,
1192                    }
1193                }
1194                _ = tokio::signal::ctrl_c() => {
1195                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1196                    println!("\nShutting down QUIC (SIGINT).");
1197                    endpoint.close(0u32.into(), b"shutdown");
1198                    break;
1199                }
1200                _ = sigterm() => {
1201                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1202                    println!("\nShutting down QUIC (SIGTERM).");
1203                    endpoint.close(0u32.into(), b"shutdown");
1204                    break;
1205                }
1206                _ = sighup() => {
1207                    crate::config_reload::reload();
1208                }
1209            }
1210        }
1211    }
1212}
1213
1214