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