Skip to main content

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