Skip to main content

rust_web_server/server/
mod.rs

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