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