Skip to main content

rust_web_server/server/
mod.rs

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