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