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        // A socket systemd passed (socket activation), else our own.
695        #[cfg(unix)]
696        let inherited = bind_addr.parse::<std::net::SocketAddr>().ok().and_then(|addr| crate::systemd::tcp(addr, Some(protocol)));
697        #[cfg(not(unix))]
698        let inherited: Option<TcpListener> = None;
699        let boxed_listener = match inherited {
700            Some(listener) => Ok(listener),
701            None => TcpListener::bind(&bind_addr),
702        };
703        if boxed_listener.is_err() {
704            let message = format!("unable to set up TCP listener: {}", boxed_listener.err().unwrap());
705            return Err(message);
706        }
707
708        let listener = boxed_listener.unwrap();
709        let pool = ThreadPool::new(thread_count as usize);
710
711
712        let server_url_thread_count = Log::server_url_thread_count(protocol, &bind_addr, thread_count);
713        println!("{}", server_url_thread_count);
714
715        Ok((listener, pool))
716    }
717
718    /// Accepts TCP connections in a loop and dispatches each to the thread pool.
719    ///
720    /// When built with the `http1` feature, Ctrl+C and SIGTERM stop the accept
721    /// loop gracefully: `SERVER_READY` is cleared and the pool drains all
722    /// in-flight connections before returning.
723    ///
724    /// For TLS/HTTP2/HTTP3 use [`Server::run_tls`].
725    pub fn run(listener: TcpListener,
726               pool: ThreadPool,
727               app: impl Application + Send + 'static + Clone) {
728        #[cfg(feature = "http1")]
729        {
730            use std::sync::Arc;
731            use std::sync::atomic::{AtomicBool, Ordering};
732
733            let shutdown = Arc::new(AtomicBool::new(false));
734            let s = shutdown.clone();
735            if let Err(e) = ctrlc::set_handler(move || {
736                s.store(true, Ordering::SeqCst);
737            }) {
738                eprintln!("unable to install signal handler: {}", e);
739            }
740            crate::config_reload::install_sighup_handler();
741            if let Err(e) = listener.set_nonblocking(true) {
742                eprintln!("unable to set non-blocking listener: {}", e);
743            }
744
745            loop {
746                if shutdown.load(Ordering::SeqCst) {
747                    break;
748                }
749                if crate::config_reload::RELOAD_REQUESTED
750                    .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed)
751                    .is_ok()
752                {
753                    crate::config_reload::reload();
754                }
755                match listener.accept() {
756                    Ok((stream, peer_addr)) => {
757                        Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
758                    }
759                    Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
760                        std::thread::sleep(Duration::from_millis(10));
761                    }
762                    Err(e) => {
763                        eprintln!("accept error: {}", e);
764                        break;
765                    }
766                }
767            }
768
769            crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
770            #[cfg(unix)]
771            crate::systemd::stopping();
772            println!("Shutting down — waiting for in-flight connections to finish");
773            pool.join();
774            println!("Server stopped");
775        }
776
777        #[cfg(not(feature = "http1"))]
778        {
779            for boxed_stream in listener.incoming() {
780                match boxed_stream {
781                    Err(e) => {
782                        eprintln!("unable to get TCP stream: {}", e);
783                        return;
784                    }
785                    Ok(stream) => {
786                        let peer_addr = match stream.peer_addr() {
787                            Ok(a) => a,
788                            Err(e) => {
789                                eprintln!("unable to read peer addr: {}", e);
790                                return;
791                            }
792                        };
793                        Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
794                    }
795                }
796            }
797        }
798    }
799
800    fn dispatch_connection(
801        stream: std::net::TcpStream,
802        peer_addr: std::net::SocketAddr,
803        pool: &ThreadPool,
804        app: impl Application + Send + 'static + Clone,
805    ) {
806        print!("Connection established, ");
807        if let Ok(local) = stream.local_addr() {
808            print!("local addr: {}", local);
809        }
810        println!(", peer addr: {}", peer_addr);
811
812        let (server_ip, server_port, _thread_count) = get_ip_port_thread_count();
813        let connection = ConnectionInfo {
814            client: Address {
815                ip: peer_addr.ip().to_string(),
816                port: peer_addr.port() as i32,
817            },
818            server: Address {
819                ip: server_ip,
820                port: server_port,
821            },
822            request_size: get_request_allocation_size(),
823            sni_hostname: None,
824            tls: false,
825        };
826
827        if let Err(e) = stream.set_read_timeout(Some(Duration::from_secs(30))) {
828            eprintln!("failed to set read timeout: {}", e);
829        }
830
831        pool.execute(move || {
832            let mut stream = stream;
833            let mut connection = connection;
834            if proxy_protocol::enabled() {
835                // Read on the worker: a slow load balancer mustn't hold the accept loop.
836                match proxy_protocol::read_blocking(&mut stream) {
837                    Ok(Some(source)) => {
838                        connection.client = Address { ip: source.ip().to_string(), port: source.port() as i32 };
839                    }
840                    Ok(None) => {}
841                    Err(e) => {
842                        eprintln!("PROXY protocol header from {}: {}", peer_addr, e);
843                        return;
844                    }
845                }
846            }
847            crate::metrics::connection_open();
848            let result = Server::process_upgradable(stream, connection, app, |stream| {
849                let reader = stream.try_clone().ok()?;
850                let writer = stream.try_clone().ok()?;
851                // The 30 s request read timeout doesn't apply to a WebSocket.
852                let _ = reader.set_read_timeout(None);
853                Some((Box::new(reader) as Box<dyn Read + Send>, Box::new(writer) as Box<dyn Write + Send>))
854            });
855            crate::metrics::connection_close();
856            if let Err(msg) = result {
857                crate::metrics::record_error();
858                eprintln!("{}", msg);
859            }
860        });
861    }
862
863}
864
865/// Network context for the current connection, passed into every [`Controller`](crate::controller::Controller).
866#[derive(Clone)]
867pub struct ConnectionInfo {
868    /// Client (peer) address.
869    pub client: Address,
870    /// Server (local) address.
871    pub server: Address,
872    /// Bytes allocated for reading the request.
873    pub request_size: i64,
874    /// SNI hostname sent by the client during the TLS handshake, if any.
875    /// `None` for plain-HTTP connections or when the client omits SNI.
876    pub sni_hostname: Option<String>,
877    /// The client connected over TLS (HTTPS, HTTP/2 over TLS, HTTP/3).
878    /// Proxies send it on as `X-Forwarded-Proto` (18.9.0).
879    pub tls: bool,
880}
881
882impl Default for ConnectionInfo {
883    /// Unknown addresses (`0.0.0.0:0`), no SNI, not TLS: for building one
884    /// with `..Default::default()` in tests and adapters.
885    fn default() -> Self {
886        let unknown = Address { ip: "0.0.0.0".to_string(), port: 0 };
887        ConnectionInfo { client: unknown.clone(), server: unknown, request_size: 0, sni_hostname: None, tls: false }
888    }
889}
890
891/// IP address and port pair.
892#[derive(Clone)]
893pub struct Address {
894    pub ip: String,
895    pub port: i32
896}
897
898impl ConnectionInfo {
899    /// A connection from `client` to `server`; plain (not TLS), no SNI, the
900    /// default request allocation size. Set `tls`/`sni_hostname` after.
901    pub fn new(client: Address, server: Address) -> Self {
902        ConnectionInfo { client, server, request_size: 0, sni_hostname: None, tls: false }
903    }
904
905    /// Parse the client address into a [`std::net::SocketAddr`], if the stored
906    /// IP and port are valid. Returns `None` if parsing fails.
907    pub fn peer_addr(&self) -> Option<std::net::SocketAddr> {
908        self.client.to_socket_addr()
909    }
910}
911
912impl Address {
913    /// Parse this address into a [`std::net::SocketAddr`]. Returns `None` if
914    /// the IP string or port value cannot be converted.
915    pub fn to_socket_addr(&self) -> Option<std::net::SocketAddr> {
916        let ip: std::net::IpAddr = self.ip.parse().ok()?;
917        let port = u16::try_from(self.port).ok()?;
918        Some(std::net::SocketAddr::new(ip, port))
919    }
920}
921
922/// One accepted TLS connection: handshake (bounded by
923/// `TLS_HANDSHAKE_TIMEOUT`), then HTTP/2 or HTTP/1.1 by ALPN.
924#[cfg(feature = "http2")]
925pub(crate) async fn serve_tls_connection(
926    mut tcp_stream: tokio::net::TcpStream,
927    peer_addr: std::net::SocketAddr,
928    acceptor: tokio_rustls::TlsAcceptor,
929    app: impl Application + Send + 'static + Clone,
930) {
931    let _ = tcp_stream.set_nodelay(true);
932    let Some(peer_addr) = client_address(&mut tcp_stream, peer_addr).await else { return };
933    let timed_out = || std::io::Error::from(std::io::ErrorKind::TimedOut);
934    let handshake = async {
935        #[cfg(feature = "acme")]
936        if crate::acme::on_demand::enabled() {
937            // On-demand TLS: read the ClientHello, get a certificate for
938            // its name if it should have one (bounded by
939            // `on_demand::HANDSHAKE_WAIT`), then finish the handshake.
940            let lazy = tokio_rustls::LazyConfigAcceptor::new(rustls::server::Acceptor::default(), tcp_stream);
941            let start = tokio::time::timeout(http1_async::TLS_HANDSHAKE_TIMEOUT, lazy).await.map_err(|_| timed_out())??;
942            let hello = start.client_hello();
943            let name = hello.server_name().filter(|_| !crate::acme::tls_alpn::is_challenge(&hello)).map(str::to_string);
944            if let Some(name) = name {
945                crate::acme::on_demand::ensure(&name).await;
946            }
947            let finish = start.into_stream(acceptor.config().clone());
948            return tokio::time::timeout(http1_async::TLS_HANDSHAKE_TIMEOUT, finish).await.map_err(|_| timed_out())?;
949        }
950        tokio::time::timeout(http1_async::TLS_HANDSHAKE_TIMEOUT, acceptor.accept(tcp_stream)).await.map_err(|_| timed_out())?
951    };
952    match handshake.await {
953        Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {} // client never finished the handshake
954        Err(e) => {
955            crate::metrics::tls::record_handshake_failure();
956            eprintln!("TLS handshake failed: {}", e)
957        }
958        Ok(tls_stream) => {
959            let server_conn = tls_stream.get_ref().1;
960            crate::metrics::tls::record_rustls(server_conn);
961            let sni = server_conn.server_name().map(|s| s.to_string());
962            let protocol = server_conn.alpn_protocol().map(|p| p.to_vec());
963
964            match protocol.as_deref() {
965                // A TLS-ALPN-01 validation: the handshake was the answer.
966                #[cfg(feature = "acme")]
967                Some(crate::acme::tls_alpn::ALPN) => {}
968                Some(b"h2") => {
969                    if let Err(e) = crate::h2_server::handle_connection(tls_stream, peer_addr, sni, app).await {
970                        eprintln!("H2 connection error: {}", e);
971                    }
972                }
973                _ => {
974                    crate::metrics::connection_open();
975                    let result = http1_async::serve(tls_stream, peer_addr, sni, true, app).await;
976                    crate::metrics::connection_close();
977                    if let Err(e) = result {
978                        crate::metrics::record_error();
979                        eprintln!("H1 TLS error: {}", e);
980                    }
981                }
982            }
983        }
984    }
985}
986
987/// One accepted plain-HTTP connection.
988#[cfg(feature = "http2")]
989pub(crate) async fn serve_plain_connection(
990    tcp_stream: tokio::net::TcpStream,
991    peer_addr: std::net::SocketAddr,
992    app: impl Application + Send + 'static + Clone,
993) {
994    // Head and body go out as separate writes: don't let Nagle hold the
995    // body back waiting for an ACK.
996    let mut tcp_stream = tcp_stream;
997    let _ = tcp_stream.set_nodelay(true);
998    let Some(peer_addr) = client_address(&mut tcp_stream, peer_addr).await else { return };
999    if starts_with_h2_preface(&tcp_stream).await {
1000        if let Err(e) = crate::h2_server::serve(tcp_stream, peer_addr, None, false, app).await {
1001            eprintln!("H2C connection error: {}", e);
1002        }
1003        return;
1004    }
1005    crate::metrics::connection_open();
1006    let result = http1_async::serve(tcp_stream, peer_addr, None, false, app).await;
1007    crate::metrics::connection_close();
1008    if let Err(e) = result {
1009        crate::metrics::record_error();
1010        eprintln!("{}", e);
1011    }
1012}
1013
1014/// The client's address: the peer's, or with `proxy_protocol = true` the one
1015/// in the PROXY protocol header the connection starts with. `None`: no valid
1016/// header (in time) — close the connection.
1017#[cfg(feature = "http2")]
1018async fn client_address(tcp_stream: &mut tokio::net::TcpStream, peer_addr: std::net::SocketAddr) -> Option<std::net::SocketAddr> {
1019    if !proxy_protocol::enabled() {
1020        return Some(peer_addr);
1021    }
1022    match tokio::time::timeout(http1_async::TLS_HANDSHAKE_TIMEOUT, proxy_protocol::read_async(tcp_stream)).await {
1023        Ok(Ok(source)) => Some(source.unwrap_or(peer_addr)),
1024        Ok(Err(e)) => {
1025            eprintln!("PROXY protocol header from {}: {}", peer_addr, e);
1026            None
1027        }
1028        Err(_) => None,
1029    }
1030}
1031
1032/// Whether a plain connection opens with the HTTP/2 connection preface —
1033/// cleartext HTTP/2 with prior knowledge (h2c), as `grpcurl -plaintext` and
1034/// gRPC clients without TLS speak it. Looks without consuming; an HTTP/1.1
1035/// request differs within its first two bytes.
1036#[cfg(feature = "http2")]
1037async fn starts_with_h2_preface(tcp_stream: &tokio::net::TcpStream) -> bool {
1038    const PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
1039    let mut seen = [0u8; 24];
1040    let deadline = tokio::time::Instant::now() + http1_async::READ_TIMEOUT;
1041    loop {
1042        let n = match tokio::time::timeout_at(deadline, tcp_stream.peek(&mut seen)).await {
1043            Ok(Ok(n)) => n,
1044            _ => return false,
1045        };
1046        if n == 0 || seen[..n] != PREFACE[..n] {
1047            return false;
1048        }
1049        if n == PREFACE.len() {
1050            return true;
1051        }
1052        // A preface arriving in pieces: look again shortly.
1053        tokio::time::sleep(std::time::Duration::from_millis(5)).await;
1054    }
1055}
1056
1057/// An accept error (e.g. out of file descriptors): report it and back off
1058/// briefly instead of ending the loop.
1059#[cfg(feature = "http2")]
1060async fn accept_backoff(e: std::io::Error) {
1061    eprintln!("TCP accept error: {}", e);
1062    tokio::time::sleep(std::time::Duration::from_millis(50)).await;
1063}
1064
1065/// Set once by [`request_shutdown`]; every receiver sees it, however late.
1066#[cfg(feature = "http2")]
1067fn shutdown_requests() -> &'static tokio::sync::watch::Sender<bool> {
1068    static REQUESTS: std::sync::OnceLock<tokio::sync::watch::Sender<bool>> = std::sync::OnceLock::new();
1069    REQUESTS.get_or_init(|| tokio::sync::watch::channel(false).0)
1070}
1071
1072/// Shut the server down gracefully, as SIGTERM does — for hosts that stop a
1073/// process some other way (a Windows service's Stop control). The accept
1074/// loops of `run_tls`, `run_plain`, `run_quic` and `run_redirect` end.
1075#[cfg(feature = "http2")]
1076pub fn request_shutdown() {
1077    shutdown_requests().send_replace(true);
1078}
1079
1080/// Resolves when SIGTERM is received (Unix) or [`request_shutdown`] is
1081/// called. Enables a single `select!` branch to handle both, beside Ctrl+C.
1082#[cfg(feature = "http2")]
1083async fn sigterm() {
1084    let requested = async {
1085        let mut requests = shutdown_requests().subscribe();
1086        let _ = requests.wait_for(|stop| *stop).await;
1087    };
1088    #[cfg(unix)]
1089    {
1090        if let Ok(mut s) = tokio::signal::unix::signal(
1091            tokio::signal::unix::SignalKind::terminate()
1092        ) {
1093            tokio::select! {
1094                _ = s.recv() => {}
1095                _ = requested => {}
1096            }
1097        } else {
1098            requested.await
1099        }
1100    }
1101    #[cfg(not(unix))]
1102    requested.await;
1103    #[cfg(unix)]
1104    crate::systemd::stopping();
1105}
1106
1107/// Returns a stream that fires on each SIGHUP on Unix; never fires elsewhere.
1108#[cfg(feature = "http2")]
1109async fn sighup() {
1110    #[cfg(unix)]
1111    {
1112        if let Ok(mut s) = tokio::signal::unix::signal(
1113            tokio::signal::unix::SignalKind::hangup()
1114        ) {
1115            s.recv().await;
1116        } else {
1117            std::future::pending::<()>().await
1118        }
1119    }
1120    #[cfg(not(unix))]
1121    std::future::pending::<()>().await
1122}
1123
1124/// Bind `port` for both IPv4 and IPv6 when `ip` is the wildcard `0.0.0.0`
1125/// (otherwise just `ip`). Let's Encrypt validates HTTP-01 over IPv6 when a
1126/// domain has an AAAA record, so a v4-only challenge/redirect listener fails
1127/// validation on dual-stack hosts. On Linux/macOS `[::]` already accepts
1128/// IPv4 too and the second bind reports "address in use", which is fine; on
1129/// Windows (`IPV6_V6ONLY` by default) both binds succeed.
1130#[cfg(feature = "http2")]
1131pub(crate) async fn bind_all_families(ip: &str, port: u16) -> Result<Vec<tokio::net::TcpListener>, String> {
1132    use tokio::net::TcpListener;
1133    #[cfg(unix)]
1134    {
1135        let wanted = if ip.contains(':') { format!("[{ip}]:{port}") } else { format!("{ip}:{port}") };
1136        if let Some(listener) = wanted.parse().ok().and_then(|addr| crate::systemd::tcp(addr, Some("redirect"))) {
1137            listener.set_nonblocking(true).map_err(|e| e.to_string())?;
1138            return TcpListener::from_std(listener).map(|l| vec![l]).map_err(|e| e.to_string());
1139        }
1140    }
1141    if ip != "0.0.0.0" {
1142        let addr = if ip.contains(':') { format!("[{ip}]:{port}") } else { format!("{ip}:{port}") };
1143        return TcpListener::bind(&addr).await.map(|l| vec![l]).map_err(|e| format!("{addr}: {e}"));
1144    }
1145    let mut listeners = Vec::new();
1146    let mut errors = Vec::new();
1147    for addr in [format!("[::]:{port}"), format!("0.0.0.0:{port}")] {
1148        match TcpListener::bind(&addr).await {
1149            Ok(l) => listeners.push(l),
1150            Err(e) => errors.push(format!("{addr}: {e}")),
1151        }
1152    }
1153    if listeners.is_empty() {
1154        return Err(errors.join("; "));
1155    }
1156    Ok(listeners)
1157}
1158
1159#[cfg(feature = "http2")]
1160impl Server {
1161    pub async fn run_tls(
1162        listener: TcpListener,
1163        pool: ThreadPool,
1164        app: impl Application + Send + 'static + Clone,
1165    ) {
1166        use crate::tls::create_tls_acceptor_from_vhosts;
1167
1168        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1169            .unwrap_or_default();
1170        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
1171            .unwrap_or_default();
1172
1173        if cert_path.is_empty() || key_path.is_empty() {
1174            println!("No TLS certificate configured — serving plain HTTP/1.1.");
1175            drop(pool);
1176            Server::run_plain(listener, app).await;
1177            return;
1178        }
1179
1180        let vhosts = crate::entry_point::get_virtual_hosts();
1181        let mut tls_acceptor = match create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1182            Ok(a) => a,
1183            Err(e) => {
1184                eprintln!("TLS setup failed: {}", e);
1185                return;
1186            }
1187        };
1188        // From now on this listener answers TLS-ALPN-01 challenges itself.
1189        #[cfg(feature = "acme")]
1190        crate::acme::tls_alpn::note_tls_listener();
1191
1192        #[cfg(unix)]
1193        if per_core::enabled() {
1194            println!("Listening for TLS connections (HTTP/1.1 + HTTP/2), per-core runtimes...");
1195            let (acceptor_tx, acceptor_rx) = tokio::sync::watch::channel(tls_acceptor);
1196            let accept_loop = move |listener: tokio::net::TcpListener, mut stop: tokio::sync::watch::Receiver<bool>| {
1197                let app = app.clone();
1198                let acceptor_rx = acceptor_rx.clone();
1199                async move {
1200                    loop {
1201                        tokio::select! {
1202                            result = listener.accept() => match result {
1203                                Ok((tcp_stream, peer_addr)) => {
1204                                    let acceptor = acceptor_rx.borrow().clone();
1205                                    tokio::spawn(serve_tls_connection(tcp_stream, peer_addr, acceptor, app.clone()));
1206                                }
1207                                Err(e) => accept_backoff(e).await,
1208                            },
1209                            _ = per_core::stopped(&mut stop) => break,
1210                        }
1211                    }
1212                }
1213            };
1214            Server::run_per_core(listener, accept_loop, move || {
1215                let vhosts = crate::entry_point::get_virtual_hosts();
1216                if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1217                    let _ = acceptor_tx.send(new_acceptor);
1218                    println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
1219                }
1220            })
1221            .await;
1222            return;
1223        }
1224
1225        listener
1226            .set_nonblocking(true)
1227            .expect("failed to set TCP listener to non-blocking");
1228        let tokio_listener = tokio::net::TcpListener::from_std(listener)
1229            .expect("failed to convert TCP listener to tokio");
1230
1231        println!("Listening for TLS connections (HTTP/1.1 + HTTP/2)...");
1232
1233        loop {
1234            tokio::select! {
1235                result = tokio_listener.accept() => {
1236                    match result {
1237                        Ok((tcp_stream, peer_addr)) => {
1238                            tokio::spawn(serve_tls_connection(tcp_stream, peer_addr, tls_acceptor.clone(), app.clone()));
1239                        }
1240                        Err(e) => eprintln!("TCP accept error: {}", e),
1241                    }
1242                }
1243                _ = tokio::signal::ctrl_c() => {
1244                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1245                    println!("\nShutting down gracefully (SIGINT).");
1246                    break;
1247                }
1248                _ = sigterm() => {
1249                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1250                    println!("\nShutting down gracefully (SIGTERM).");
1251                    break;
1252                }
1253                _ = sighup() => {
1254                    crate::config_reload::reload();
1255                    let vhosts = crate::entry_point::get_virtual_hosts();
1256                    if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1257                        tls_acceptor = new_acceptor;
1258                        println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
1259                    }
1260                }
1261            }
1262        }
1263    }
1264
1265    /// Plain-HTTP accept loop of the async builds (used by `run_tls` when no
1266    /// certificate is configured): one tokio task per connection via
1267    /// `http1_async::serve`, so idle or slow clients can't exhaust a thread
1268    /// pool. An accept error (e.g. out of file descriptors) backs off briefly
1269    /// and keeps serving instead of ending the loop.
1270    pub async fn run_plain(listener: TcpListener, app: impl Application + Send + 'static + Clone) {
1271        #[cfg(unix)]
1272        if per_core::enabled() {
1273            let accept_loop = move |listener: tokio::net::TcpListener, mut stop: tokio::sync::watch::Receiver<bool>| {
1274                let app = app.clone();
1275                async move {
1276                    loop {
1277                        tokio::select! {
1278                            result = listener.accept() => match result {
1279                                Ok((tcp_stream, peer_addr)) => {
1280                                    tokio::spawn(serve_plain_connection(tcp_stream, peer_addr, app.clone()));
1281                                }
1282                                Err(e) => accept_backoff(e).await,
1283                            },
1284                            _ = per_core::stopped(&mut stop) => break,
1285                        }
1286                    }
1287                }
1288            };
1289            Server::run_per_core(listener, accept_loop, || {}).await;
1290            return;
1291        }
1292
1293        listener
1294            .set_nonblocking(true)
1295            .expect("failed to set TCP listener to non-blocking");
1296        let tokio_listener = tokio::net::TcpListener::from_std(listener)
1297            .expect("failed to convert TCP listener to tokio");
1298
1299        loop {
1300            tokio::select! {
1301                result = tokio_listener.accept() => {
1302                    match result {
1303                        Ok((tcp_stream, peer_addr)) => {
1304                            tokio::spawn(serve_plain_connection(tcp_stream, peer_addr, app.clone()));
1305                        }
1306                        Err(e) => accept_backoff(e).await,
1307                    }
1308                }
1309                _ = tokio::signal::ctrl_c() => {
1310                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1311                    println!("\nShutting down gracefully (SIGINT).");
1312                    break;
1313                }
1314                _ = sigterm() => {
1315                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1316                    println!("\nShutting down gracefully (SIGTERM).");
1317                    break;
1318                }
1319                _ = sighup() => {
1320                    crate::config_reload::reload();
1321                }
1322            }
1323        }
1324    }
1325
1326    /// Per-core mode of `run_tls`/`run_plain` ([`per_core`]): rebinds
1327    /// `listener`'s address as one `SO_REUSEPORT` socket per runtime, runs
1328    /// `accept_loop` on each, and handles the signals here — SIGINT/SIGTERM
1329    /// stop every loop, SIGHUP reloads the config and calls `on_reload`.
1330    #[cfg(unix)]
1331    async fn run_per_core<F, Fut>(listener: TcpListener, accept_loop: F, on_reload: impl Fn())
1332    where
1333        F: Fn(tokio::net::TcpListener, tokio::sync::watch::Receiver<bool>) -> Fut + Send + Clone + 'static,
1334        Fut: std::future::Future<Output = ()>,
1335    {
1336        let addr = match listener.local_addr() {
1337            Ok(a) => a,
1338            Err(e) => return eprintln!("per-core runtimes: {}", e),
1339        };
1340        // The setup listener has no SO_REUSEPORT, so it can't share the port.
1341        drop(listener);
1342        let count = per_core::runtime_count();
1343        let (stop_tx, stop_rx) = tokio::sync::watch::channel(false);
1344        let handles = per_core::spawn(addr, count, stop_rx, accept_loop);
1345        println!("Started {} per-core runtimes on {}.", handles.len(), addr);
1346
1347        loop {
1348            tokio::select! {
1349                _ = tokio::signal::ctrl_c() => {
1350                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1351                    println!("\nShutting down gracefully (SIGINT).");
1352                    break;
1353                }
1354                _ = sigterm() => {
1355                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1356                    println!("\nShutting down gracefully (SIGTERM).");
1357                    break;
1358                }
1359                _ = sighup() => {
1360                    crate::config_reload::reload();
1361                    on_reload();
1362                }
1363            }
1364        }
1365        let _ = stop_tx.send(true);
1366        let _ = tokio::task::spawn_blocking(move || {
1367            for h in handles {
1368                let _ = h.join();
1369            }
1370        })
1371        .await;
1372    }
1373
1374    /// Binds a plain-HTTP listener on the port in `RWS_CONFIG_HTTP_REDIRECT_PORT` and sends
1375    /// `301 Moved Permanently` to the HTTPS equivalent of every incoming URL.
1376    /// Returns immediately if TLS is not configured or the redirect port is not set.
1377    pub async fn run_redirect() {
1378        use std::env;
1379
1380        let cert_path = env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1381            .unwrap_or_default();
1382        if cert_path.is_empty() {
1383            return;
1384        }
1385
1386        let redirect_port_str = env::var(crate::entry_point::Config::RWS_CONFIG_HTTP_REDIRECT_PORT)
1387            .unwrap_or_default();
1388        if redirect_port_str.is_empty() {
1389            return;
1390        }
1391
1392        let redirect_port: u16 = match redirect_port_str.parse() {
1393            Ok(p) => p,
1394            Err(_) => {
1395                eprintln!("Invalid RWS_CONFIG_HTTP_REDIRECT_PORT: {}", redirect_port_str);
1396                return;
1397            }
1398        };
1399
1400        let (server_ip, server_port, _) = get_ip_port_thread_count();
1401        let listeners = match bind_all_families(&server_ip, redirect_port).await {
1402            Ok(l) => l,
1403            Err(e) => {
1404                eprintln!("HTTP redirect listener error on port {}: {}", redirect_port, e);
1405                return;
1406            }
1407        };
1408
1409        println!("HTTP→HTTPS redirect listening on http://{}:{}", server_ip, redirect_port);
1410        #[cfg(feature = "acme")]
1411        crate::acme::note_redirect_listener(redirect_port);
1412
1413        for listener in listeners {
1414            tokio::spawn(async move {
1415                loop {
1416                    match listener.accept().await {
1417                        Ok((stream, _peer)) => {
1418                            tokio::spawn(Server::handle_redirect_connection(stream, server_port));
1419                        }
1420                        Err(e) => eprintln!("HTTP redirect accept error: {}", e),
1421                    }
1422                }
1423            });
1424        }
1425
1426        loop {
1427            tokio::select! {
1428                _ = tokio::signal::ctrl_c() => {
1429                    println!("\nShutting down HTTP redirect listener (SIGINT).");
1430                    break;
1431                }
1432                _ = sigterm() => {
1433                    println!("\nShutting down HTTP redirect listener (SIGTERM).");
1434                    break;
1435                }
1436                _ = sighup() => {
1437                    crate::config_reload::reload();
1438                }
1439            }
1440        }
1441    }
1442
1443    /// One redirect-listener connection: answer a pending ACME HTTP-01
1444    /// challenge, or `301` to the HTTPS equivalent of the requested URL.
1445    pub(crate) async fn handle_redirect_connection(mut stream: tokio::net::TcpStream, https_port: i32) {
1446        use tokio::io::{AsyncReadExt, AsyncWriteExt};
1447        let mut buf = vec![0u8; 4096];
1448        let n = match stream.read(&mut buf).await {
1449            Ok(n) => n,
1450            Err(_) => return,
1451        };
1452        let text = String::from_utf8_lossy(&buf[..n]);
1453
1454        let uri = text.lines()
1455            .next()
1456            .and_then(|line| line.split_whitespace().nth(1))
1457            .unwrap_or("/")
1458            .to_string();
1459
1460        // ACME HTTP-01 challenges must be answered over
1461        // plain HTTP, not redirected.
1462        #[cfg(feature = "acme")]
1463        if let Some(challenge) = crate::acme::challenge_http_response_shared(&uri).await {
1464            let _ = stream.write_all(challenge.as_bytes()).await;
1465            return;
1466        }
1467
1468        let host_header = text.lines()
1469            .find(|l| l.to_lowercase().starts_with("host:"))
1470            .map(|l| l[5..].trim().to_string());
1471
1472        let location = match host_header {
1473            Some(h) => {
1474                // strip existing port from Host header
1475                let h_no_port = if h.starts_with('[') {
1476                    // IPv6: [::1] or [::1]:port
1477                    h.find(']')
1478                        .map(|i| h[..=i].to_string())
1479                        .unwrap_or(h.clone())
1480                } else {
1481                    h.rfind(':')
1482                        .map(|i| h[..i].to_string())
1483                        .unwrap_or(h.clone())
1484                };
1485                if https_port == 443 {
1486                    format!("https://{}{}", h_no_port, uri)
1487                } else {
1488                    format!("https://{}:{}{}", h_no_port, https_port, uri)
1489                }
1490            }
1491            None => format!("https://localhost:{}{}", https_port, uri),
1492        };
1493
1494        let response = format!(
1495            "HTTP/1.1 301 Moved Permanently\r\nLocation: {}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
1496            location
1497        );
1498        let _ = stream.write_all(response.as_bytes()).await;
1499    }
1500
1501}
1502
1503#[cfg(feature = "http3")]
1504impl Server {
1505    pub async fn run_quic(
1506        app: impl Application + Send + 'static + Clone,
1507    ) {
1508        use crate::tls::create_quinn_server_config_from_vhosts;
1509        use crate::h3_handler;
1510
1511        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1512            .unwrap_or_default();
1513        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
1514            .unwrap_or_default();
1515
1516        if cert_path.is_empty() || key_path.is_empty() {
1517            return;
1518        }
1519
1520        let vhosts = crate::entry_point::get_virtual_hosts();
1521        let server_config = match create_quinn_server_config_from_vhosts(&vhosts, &cert_path, &key_path) {
1522            Ok(c) => c,
1523            Err(e) => {
1524                eprintln!("QUIC TLS setup failed: {}", e);
1525                return;
1526            }
1527        };
1528
1529        let (server_ip, server_port, _) = get_ip_port_thread_count();
1530        let bind_addr = format!("{}:{}", server_ip, server_port);
1531        let addr: std::net::SocketAddr = match bind_addr.parse() {
1532            Ok(a) => a,
1533            Err(e) => {
1534                eprintln!("Invalid QUIC bind address '{}': {}", bind_addr, e);
1535                return;
1536            }
1537        };
1538
1539        // A UDP socket systemd passed, else bind one.
1540        #[cfg(unix)]
1541        let inherited = crate::systemd::udp(addr, Some("quic"));
1542        #[cfg(not(unix))]
1543        let inherited: Option<std::net::UdpSocket> = None;
1544        let endpoint = match inherited {
1545            Some(socket) => quinn::Endpoint::new(quinn::EndpointConfig::default(), Some(server_config), socket, std::sync::Arc::new(quinn::TokioRuntime)),
1546            None => quinn::Endpoint::server(server_config, addr),
1547        };
1548        let endpoint = match endpoint {
1549            Ok(e) => e,
1550            Err(e) => {
1551                eprintln!("QUIC endpoint error: {}", e);
1552                return;
1553            }
1554        };
1555
1556        println!("Listening for QUIC/HTTP3 on UDP {}:{}", server_ip, server_port);
1557
1558        loop {
1559            tokio::select! {
1560                maybe = endpoint.accept() => {
1561                    match maybe {
1562                        Some(incoming) => {
1563                            let app = app.clone();
1564                            tokio::spawn(async move {
1565                                match incoming.await {
1566                                    Ok(conn) => {
1567                                        let peer_addr = conn.remote_address();
1568                                        if let Err(e) = h3_handler::handle_connection(conn, peer_addr, app).await {
1569                                            eprintln!("H3 connection error: {}", e);
1570                                        }
1571                                    }
1572                                    Err(e) => eprintln!("QUIC connection error: {}", e),
1573                                }
1574                            });
1575                        }
1576                        None => break,
1577                    }
1578                }
1579                _ = tokio::signal::ctrl_c() => {
1580                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1581                    println!("\nShutting down QUIC (SIGINT).");
1582                    endpoint.close(0u32.into(), b"shutdown");
1583                    break;
1584                }
1585                _ = sigterm() => {
1586                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1587                    println!("\nShutting down QUIC (SIGTERM).");
1588                    endpoint.close(0u32.into(), b"shutdown");
1589                    break;
1590                }
1591                _ = sighup() => {
1592                    crate::config_reload::reload();
1593                }
1594            }
1595        }
1596    }
1597}
1598
1599