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