1#[cfg(all(test, not(target_arch = "wasm32")))]
12pub mod tests;
13#[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#[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"))]
101pub const REQUEST_HEAD_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
106
107#[doc(hidden)]
111pub const PIPE_CHUNK: usize = 64 * 1024;
112
113#[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 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 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 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 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 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 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 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 Self::process_upgradable(stream, connection, app, |_| None)
329 }
330
331 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 let mut pending: Vec<u8> = Vec::new();
350 let mut read_buffer = vec![0u8; request_allocation_size as usize];
351
352 'session: loop {
353 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 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 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 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, 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 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 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 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 #[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 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 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 #[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 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 #[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 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 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 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 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 pub fn setup() -> Result<(TcpListener, ThreadPool), String> {
740 let info = Log::info("Rust Web Server");
741 println!("{}", info);
742
743 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 #[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 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 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 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#[derive(Clone)]
953pub struct ConnectionInfo {
954 pub client: Address,
956 pub server: Address,
958 pub request_size: i64,
960 pub sni_hostname: Option<String>,
963 pub tls: bool,
966}
967
968impl Default for ConnectionInfo {
969 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#[derive(Clone)]
979pub struct Address {
980 pub ip: String,
981 pub port: i32
982}
983
984impl ConnectionInfo {
985 pub fn new(client: Address, server: Address) -> Self {
988 ConnectionInfo { client, server, request_size: 0, sni_hostname: None, tls: false }
989 }
990
991 pub fn peer_addr(&self) -> Option<std::net::SocketAddr> {
994 self.client.to_socket_addr()
995 }
996}
997
998impl Address {
999 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#[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 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 => {} 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 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#[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 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#[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#[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 tokio::time::sleep(std::time::Duration::from_millis(5)).await;
1140 }
1141}
1142
1143#[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#[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#[cfg(feature = "http2")]
1162pub fn request_shutdown() {
1163 shutdown_requests().send_replace(true);
1164}
1165
1166#[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#[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#[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#[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 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 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 #[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 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 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 #[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 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 let h_no_port = if h.starts_with('[') {
1605 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 #[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