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///
1123/// After a SIGTERM (since 18.27.0) `/readyz` answers `503` at once, but this
1124/// resolves only `shutdown_delay_secs` later: the accept loops keep serving
1125/// while the load balancer notices and takes the pod out, then drain. The
1126/// deadline is shared, so a loop's `select!` dropping and re-creating this
1127/// future (on every accepted connection) keeps the same one.
1128#[cfg(feature = "http2")]
1129async fn sigterm() {
1130    static DEADLINE: std::sync::OnceLock<tokio::time::Instant> = std::sync::OnceLock::new();
1131    if let Some(deadline) = DEADLINE.get() {
1132        return tokio::time::sleep_until(*deadline).await;
1133    }
1134    if terminate_or_requested().await {
1135        let delay = std::time::Duration::from_secs(crate::server_config::ServerConfig::current().shutdown_delay_secs);
1136        let mut first = false;
1137        let deadline = *DEADLINE.get_or_init(|| {
1138            first = true;
1139            tokio::time::Instant::now() + delay
1140        });
1141        crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1142        #[cfg(unix)]
1143        crate::systemd::stopping();
1144        if first && !delay.is_zero() {
1145            println!("SIGTERM: not ready; draining in {} s (shutdown_delay_secs)", delay.as_secs());
1146        }
1147        tokio::time::sleep_until(deadline).await;
1148    } else {
1149        #[cfg(unix)]
1150        crate::systemd::stopping();
1151    }
1152}
1153
1154/// `true` for a SIGTERM, `false` for [`request_shutdown`] (no delay: no load
1155/// balancer is waiting on that path).
1156#[cfg(feature = "http2")]
1157async fn terminate_or_requested() -> bool {
1158    let requested = async {
1159        let mut requests = shutdown_requests().subscribe();
1160        let _ = requests.wait_for(|stop| *stop).await;
1161    };
1162    #[cfg(unix)]
1163    {
1164        if let Ok(mut s) = tokio::signal::unix::signal(
1165            tokio::signal::unix::SignalKind::terminate()
1166        ) {
1167            tokio::select! {
1168                _ = s.recv() => true,
1169                _ = requested => false,
1170            }
1171        } else {
1172            requested.await;
1173            false
1174        }
1175    }
1176    #[cfg(not(unix))]
1177    {
1178        requested.await;
1179        false
1180    }
1181}
1182
1183/// Returns a stream that fires on each SIGHUP on Unix; never fires elsewhere.
1184#[cfg(feature = "http2")]
1185async fn sighup() {
1186    #[cfg(unix)]
1187    {
1188        if let Ok(mut s) = tokio::signal::unix::signal(
1189            tokio::signal::unix::SignalKind::hangup()
1190        ) {
1191            s.recv().await;
1192        } else {
1193            std::future::pending::<()>().await
1194        }
1195    }
1196    #[cfg(not(unix))]
1197    std::future::pending::<()>().await
1198}
1199
1200/// Bind `port` for both IPv4 and IPv6 when `ip` is the wildcard `0.0.0.0`
1201/// (otherwise just `ip`). Let's Encrypt validates HTTP-01 over IPv6 when a
1202/// domain has an AAAA record, so a v4-only challenge/redirect listener fails
1203/// validation on dual-stack hosts. On Linux/macOS `[::]` already accepts
1204/// IPv4 too and the second bind reports "address in use", which is fine; on
1205/// Windows (`IPV6_V6ONLY` by default) both binds succeed.
1206#[cfg(feature = "http2")]
1207#[doc(hidden)]
1208pub async fn bind_all_families(ip: &str, port: u16) -> Result<Vec<tokio::net::TcpListener>, String> {
1209    use tokio::net::TcpListener;
1210    #[cfg(unix)]
1211    {
1212        let wanted = if ip.contains(':') { format!("[{ip}]:{port}") } else { format!("{ip}:{port}") };
1213        if let Some(listener) = wanted.parse().ok().and_then(|addr| crate::systemd::tcp(addr, Some("redirect"))) {
1214            listener.set_nonblocking(true).map_err(|e| e.to_string())?;
1215            return TcpListener::from_std(listener).map(|l| vec![l]).map_err(|e| e.to_string());
1216        }
1217    }
1218    if ip != "0.0.0.0" {
1219        let addr = if ip.contains(':') { format!("[{ip}]:{port}") } else { format!("{ip}:{port}") };
1220        return TcpListener::bind(&addr).await.map(|l| vec![l]).map_err(|e| format!("{addr}: {e}"));
1221    }
1222    let mut listeners = Vec::new();
1223    let mut errors = Vec::new();
1224    for addr in [format!("[::]:{port}"), format!("0.0.0.0:{port}")] {
1225        match TcpListener::bind(&addr).await {
1226            Ok(l) => listeners.push(l),
1227            Err(e) => errors.push(format!("{addr}: {e}")),
1228        }
1229    }
1230    if listeners.is_empty() {
1231        return Err(errors.join("; "));
1232    }
1233    Ok(listeners)
1234}
1235
1236#[cfg(feature = "http2")]
1237impl Server {
1238    pub async fn run_tls(
1239        listener: TcpListener,
1240        pool: ThreadPool,
1241        app: impl Application + Send + 'static + Clone,
1242    ) {
1243        use crate::tls::create_tls_acceptor_from_vhosts;
1244
1245        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1246            .unwrap_or_default();
1247        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
1248            .unwrap_or_default();
1249
1250        if cert_path.is_empty() || key_path.is_empty() {
1251            println!("No TLS certificate configured — serving plain HTTP/1.1.");
1252            drop(pool);
1253            Server::run_plain(listener, app).await;
1254            return;
1255        }
1256
1257        let vhosts = crate::entry_point::get_virtual_hosts();
1258        let mut tls_acceptor = match create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1259            Ok(a) => a,
1260            Err(e) => {
1261                eprintln!("TLS setup failed: {}", e);
1262                return;
1263            }
1264        };
1265        // From now on this listener answers TLS-ALPN-01 challenges itself.
1266        if let Some(acme) = crate::tls::acme_hooks() {
1267            (acme.note_tls_listener)();
1268        }
1269
1270        #[cfg(unix)]
1271        if per_core::enabled() {
1272            println!("Listening for TLS connections (HTTP/1.1 + HTTP/2), per-core runtimes...");
1273            let (acceptor_tx, acceptor_rx) = tokio::sync::watch::channel(tls_acceptor);
1274            let accept_loop = move |listener: tokio::net::TcpListener, mut stop: tokio::sync::watch::Receiver<bool>| {
1275                let app = app.clone();
1276                let acceptor_rx = acceptor_rx.clone();
1277                async move {
1278                    loop {
1279                        tokio::select! {
1280                            result = listener.accept() => match result {
1281                                Ok((tcp_stream, peer_addr)) => {
1282                                    let acceptor = acceptor_rx.borrow().clone();
1283                                    tokio::spawn(serve_tls_connection(tcp_stream, peer_addr, acceptor, app.clone()));
1284                                }
1285                                Err(e) => accept_backoff(e).await,
1286                            },
1287                            _ = per_core::stopped(&mut stop) => break,
1288                        }
1289                    }
1290                }
1291            };
1292            Server::run_per_core(listener, accept_loop, move || {
1293                let vhosts = crate::entry_point::get_virtual_hosts();
1294                if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1295                    let _ = acceptor_tx.send(new_acceptor);
1296                    println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
1297                }
1298            })
1299            .await;
1300            return;
1301        }
1302
1303        listener
1304            .set_nonblocking(true)
1305            .expect("failed to set TCP listener to non-blocking");
1306        let tokio_listener = tokio::net::TcpListener::from_std(listener)
1307            .expect("failed to convert TCP listener to tokio");
1308
1309        println!("Listening for TLS connections (HTTP/1.1 + HTTP/2)...");
1310
1311        loop {
1312            tokio::select! {
1313                result = tokio_listener.accept() => {
1314                    match result {
1315                        Ok((tcp_stream, peer_addr)) => {
1316                            tokio::spawn(serve_tls_connection(tcp_stream, peer_addr, tls_acceptor.clone(), app.clone()));
1317                        }
1318                        Err(e) => eprintln!("TCP accept error: {}", e),
1319                    }
1320                }
1321                _ = tokio::signal::ctrl_c() => {
1322                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1323                    println!("\nShutting down gracefully (SIGINT).");
1324                    break;
1325                }
1326                _ = sigterm() => {
1327                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1328                    println!("\nShutting down gracefully (SIGTERM).");
1329                    break;
1330                }
1331                _ = sighup() => {
1332                    crate::config_reload::reload();
1333                    let vhosts = crate::entry_point::get_virtual_hosts();
1334                    if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
1335                        tls_acceptor = new_acceptor;
1336                        println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
1337                    }
1338                }
1339            }
1340        }
1341    }
1342
1343    /// Plain-HTTP accept loop of the async builds (used by `run_tls` when no
1344    /// certificate is configured): one tokio task per connection via
1345    /// `http1_async::serve`, so idle or slow clients can't exhaust a thread
1346    /// pool. An accept error (e.g. out of file descriptors) backs off briefly
1347    /// and keeps serving instead of ending the loop.
1348    pub async fn run_plain(listener: TcpListener, app: impl Application + Send + 'static + Clone) {
1349        #[cfg(unix)]
1350        if per_core::enabled() {
1351            let accept_loop = move |listener: tokio::net::TcpListener, mut stop: tokio::sync::watch::Receiver<bool>| {
1352                let app = app.clone();
1353                async move {
1354                    loop {
1355                        tokio::select! {
1356                            result = listener.accept() => match result {
1357                                Ok((tcp_stream, peer_addr)) => {
1358                                    tokio::spawn(serve_plain_connection(tcp_stream, peer_addr, app.clone()));
1359                                }
1360                                Err(e) => accept_backoff(e).await,
1361                            },
1362                            _ = per_core::stopped(&mut stop) => break,
1363                        }
1364                    }
1365                }
1366            };
1367            Server::run_per_core(listener, accept_loop, || {}).await;
1368            return;
1369        }
1370
1371        listener
1372            .set_nonblocking(true)
1373            .expect("failed to set TCP listener to non-blocking");
1374        let tokio_listener = tokio::net::TcpListener::from_std(listener)
1375            .expect("failed to convert TCP listener to tokio");
1376
1377        loop {
1378            tokio::select! {
1379                result = tokio_listener.accept() => {
1380                    match result {
1381                        Ok((tcp_stream, peer_addr)) => {
1382                            tokio::spawn(serve_plain_connection(tcp_stream, peer_addr, app.clone()));
1383                        }
1384                        Err(e) => accept_backoff(e).await,
1385                    }
1386                }
1387                _ = tokio::signal::ctrl_c() => {
1388                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1389                    println!("\nShutting down gracefully (SIGINT).");
1390                    break;
1391                }
1392                _ = sigterm() => {
1393                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1394                    println!("\nShutting down gracefully (SIGTERM).");
1395                    break;
1396                }
1397                _ = sighup() => {
1398                    crate::config_reload::reload();
1399                }
1400            }
1401        }
1402    }
1403
1404    /// Per-core mode of `run_tls`/`run_plain` ([`per_core`]): rebinds
1405    /// `listener`'s address as one `SO_REUSEPORT` socket per runtime, runs
1406    /// `accept_loop` on each, and handles the signals here — SIGINT/SIGTERM
1407    /// stop every loop, SIGHUP reloads the config and calls `on_reload`.
1408    #[cfg(unix)]
1409    async fn run_per_core<F, Fut>(listener: TcpListener, accept_loop: F, on_reload: impl Fn())
1410    where
1411        F: Fn(tokio::net::TcpListener, tokio::sync::watch::Receiver<bool>) -> Fut + Send + Clone + 'static,
1412        Fut: std::future::Future<Output = ()>,
1413    {
1414        let addr = match listener.local_addr() {
1415            Ok(a) => a,
1416            Err(e) => return eprintln!("per-core runtimes: {}", e),
1417        };
1418        // The setup listener has no SO_REUSEPORT, so it can't share the port.
1419        drop(listener);
1420        let count = per_core::runtime_count();
1421        let (stop_tx, stop_rx) = tokio::sync::watch::channel(false);
1422        let handles = per_core::spawn(addr, count, stop_rx, accept_loop);
1423        println!("Started {} per-core runtimes on {}.", handles.len(), addr);
1424
1425        loop {
1426            tokio::select! {
1427                _ = tokio::signal::ctrl_c() => {
1428                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1429                    println!("\nShutting down gracefully (SIGINT).");
1430                    break;
1431                }
1432                _ = sigterm() => {
1433                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1434                    println!("\nShutting down gracefully (SIGTERM).");
1435                    break;
1436                }
1437                _ = sighup() => {
1438                    crate::config_reload::reload();
1439                    on_reload();
1440                }
1441            }
1442        }
1443        let _ = stop_tx.send(true);
1444        let _ = tokio::task::spawn_blocking(move || {
1445            for h in handles {
1446                let _ = h.join();
1447            }
1448        })
1449        .await;
1450    }
1451
1452    /// Binds a plain-HTTP listener on the port in `RWS_CONFIG_HTTP_REDIRECT_PORT` and sends
1453    /// `301 Moved Permanently` to the HTTPS equivalent of every incoming URL.
1454    /// Returns immediately if TLS is not configured or the redirect port is not set.
1455    pub async fn run_redirect() {
1456        use std::env;
1457
1458        let cert_path = env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1459            .unwrap_or_default();
1460        if cert_path.is_empty() {
1461            return;
1462        }
1463
1464        let redirect_port_str = env::var(crate::entry_point::Config::RWS_CONFIG_HTTP_REDIRECT_PORT)
1465            .unwrap_or_default();
1466        if redirect_port_str.is_empty() {
1467            return;
1468        }
1469
1470        let redirect_port: u16 = match redirect_port_str.parse() {
1471            Ok(p) => p,
1472            Err(_) => {
1473                eprintln!("Invalid RWS_CONFIG_HTTP_REDIRECT_PORT: {}", redirect_port_str);
1474                return;
1475            }
1476        };
1477
1478        let (server_ip, server_port, _) = get_ip_port_thread_count();
1479        let listeners = match bind_all_families(&server_ip, redirect_port).await {
1480            Ok(l) => l,
1481            Err(e) => {
1482                eprintln!("HTTP redirect listener error on port {}: {}", redirect_port, e);
1483                return;
1484            }
1485        };
1486
1487        println!("HTTP→HTTPS redirect listening on http://{}:{}", server_ip, redirect_port);
1488        if let Some(acme) = crate::tls::acme_hooks() {
1489            (acme.note_redirect_listener)(redirect_port);
1490        }
1491
1492        for listener in listeners {
1493            tokio::spawn(async move {
1494                loop {
1495                    match listener.accept().await {
1496                        Ok((stream, _peer)) => {
1497                            tokio::spawn(Server::handle_redirect_connection(stream, server_port));
1498                        }
1499                        Err(e) => eprintln!("HTTP redirect accept error: {}", e),
1500                    }
1501                }
1502            });
1503        }
1504
1505        loop {
1506            tokio::select! {
1507                _ = tokio::signal::ctrl_c() => {
1508                    println!("\nShutting down HTTP redirect listener (SIGINT).");
1509                    break;
1510                }
1511                _ = sigterm() => {
1512                    println!("\nShutting down HTTP redirect listener (SIGTERM).");
1513                    break;
1514                }
1515                _ = sighup() => {
1516                    crate::config_reload::reload();
1517                }
1518            }
1519        }
1520    }
1521
1522    /// One redirect-listener connection: answer a pending ACME HTTP-01
1523    /// challenge, or `301` to the HTTPS equivalent of the requested URL.
1524    #[doc(hidden)]
1525    pub async fn handle_redirect_connection(mut stream: tokio::net::TcpStream, https_port: i32) {
1526        use tokio::io::{AsyncReadExt, AsyncWriteExt};
1527        let mut buf = vec![0u8; 4096];
1528        let n = match stream.read(&mut buf).await {
1529            Ok(n) => n,
1530            Err(_) => return,
1531        };
1532        let text = String::from_utf8_lossy(&buf[..n]);
1533
1534        let uri = text.lines()
1535            .next()
1536            .and_then(|line| line.split_whitespace().nth(1))
1537            .unwrap_or("/")
1538            .to_string();
1539
1540        // ACME HTTP-01 challenges must be answered over
1541        // plain HTTP, not redirected.
1542        let challenge = match crate::tls::acme_hooks() {
1543            Some(acme) => (acme.http_challenge)(&uri).await,
1544            None => None,
1545        };
1546        if let Some(challenge) = challenge {
1547            let _ = stream.write_all(challenge.as_bytes()).await;
1548            return;
1549        }
1550
1551        let host_header = text.lines()
1552            .find(|l| l.to_lowercase().starts_with("host:"))
1553            .map(|l| l[5..].trim().to_string());
1554
1555        let location = match host_header {
1556            Some(h) => {
1557                // strip existing port from Host header
1558                let h_no_port = if h.starts_with('[') {
1559                    // IPv6: [::1] or [::1]:port
1560                    h.find(']')
1561                        .map(|i| h[..=i].to_string())
1562                        .unwrap_or(h.clone())
1563                } else {
1564                    h.rfind(':')
1565                        .map(|i| h[..i].to_string())
1566                        .unwrap_or(h.clone())
1567                };
1568                if https_port == 443 {
1569                    format!("https://{}{}", h_no_port, uri)
1570                } else {
1571                    format!("https://{}:{}{}", h_no_port, https_port, uri)
1572                }
1573            }
1574            None => format!("https://localhost:{}{}", https_port, uri),
1575        };
1576
1577        let response = format!(
1578            "HTTP/1.1 301 Moved Permanently\r\nLocation: {}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
1579            location
1580        );
1581        let _ = stream.write_all(response.as_bytes()).await;
1582    }
1583
1584}
1585
1586#[cfg(feature = "http3")]
1587impl Server {
1588    pub async fn run_quic(
1589        app: impl Application + Send + 'static + Clone,
1590    ) {
1591        use crate::tls::create_quinn_server_config_from_vhosts;
1592        use crate::h3_handler;
1593
1594        let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
1595            .unwrap_or_default();
1596        let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
1597            .unwrap_or_default();
1598
1599        if cert_path.is_empty() || key_path.is_empty() {
1600            return;
1601        }
1602
1603        let vhosts = crate::entry_point::get_virtual_hosts();
1604        let server_config = match create_quinn_server_config_from_vhosts(&vhosts, &cert_path, &key_path) {
1605            Ok(c) => c,
1606            Err(e) => {
1607                eprintln!("QUIC TLS setup failed: {}", e);
1608                return;
1609            }
1610        };
1611
1612        let (server_ip, server_port, _) = get_ip_port_thread_count();
1613        let bind_addr = format!("{}:{}", server_ip, server_port);
1614        let addr: std::net::SocketAddr = match bind_addr.parse() {
1615            Ok(a) => a,
1616            Err(e) => {
1617                eprintln!("Invalid QUIC bind address '{}': {}", bind_addr, e);
1618                return;
1619            }
1620        };
1621
1622        // A UDP socket systemd passed, else bind one.
1623        #[cfg(unix)]
1624        let inherited = crate::systemd::udp(addr, Some("quic"));
1625        #[cfg(not(unix))]
1626        let inherited: Option<std::net::UdpSocket> = None;
1627        let endpoint = match inherited {
1628            Some(socket) => quinn::Endpoint::new(quinn::EndpointConfig::default(), Some(server_config), socket, std::sync::Arc::new(quinn::TokioRuntime)),
1629            None => quinn::Endpoint::server(server_config, addr),
1630        };
1631        let endpoint = match endpoint {
1632            Ok(e) => e,
1633            Err(e) => {
1634                eprintln!("QUIC endpoint error: {}", e);
1635                return;
1636            }
1637        };
1638
1639        println!("Listening for QUIC/HTTP3 on UDP {}:{}", server_ip, server_port);
1640
1641        loop {
1642            tokio::select! {
1643                maybe = endpoint.accept() => {
1644                    match maybe {
1645                        Some(incoming) => {
1646                            let app = app.clone();
1647                            tokio::spawn(async move {
1648                                match incoming.await {
1649                                    Ok(conn) => {
1650                                        let peer_addr = conn.remote_address();
1651                                        if let Err(e) = h3_handler::handle_connection(conn, peer_addr, app).await {
1652                                            eprintln!("H3 connection error: {}", e);
1653                                        }
1654                                    }
1655                                    Err(e) => eprintln!("QUIC connection error: {}", e),
1656                                }
1657                            });
1658                        }
1659                        None => break,
1660                    }
1661                }
1662                _ = tokio::signal::ctrl_c() => {
1663                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1664                    println!("\nShutting down QUIC (SIGINT).");
1665                    endpoint.close(0u32.into(), b"shutdown");
1666                    break;
1667                }
1668                _ = sigterm() => {
1669                    crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
1670                    println!("\nShutting down QUIC (SIGTERM).");
1671                    endpoint.close(0u32.into(), b"shutdown");
1672                    break;
1673                }
1674                _ = sighup() => {
1675                    crate::config_reload::reload();
1676                }
1677            }
1678        }
1679    }
1680}
1681
1682