1#[cfg(test)]
2pub mod tests;
3#[cfg(test)]
4mod example;
5
6use std::io::prelude::*;
7use std::borrow::Borrow;
8use std::net::{IpAddr, SocketAddr, TcpListener};
9use std::str::FromStr;
10use std::time::Duration;
11
12use crate::request::{METHOD, Request};
13use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
14use crate::app::App;
15use crate::application::Application;
16use crate::entry_point::{bootstrap, get_ip_port_thread_count, get_request_allocation_size, set_default_values};
17use crate::header::Header;
18use crate::log::Log;
19use crate::mime_type::MimeType;
20use crate::range::{ContentRange, Range};
21use crate::symbol::SYMBOL;
22use crate::thread_pool::ThreadPool;
23
24pub struct Server {}
25impl Server {
26 pub fn process_request(mut stream: impl Read + Write + Unpin, peer_addr: SocketAddr) -> Vec<u8> {
27 let request_allocation_size = get_request_allocation_size();
28 let mut buffer = vec![0; request_allocation_size as usize];
29 let boxed_read = stream.read(&mut buffer);
30 if boxed_read.is_err() {
31 let message = boxed_read.err().unwrap().to_string();
32 eprintln!("unable to read TCP stream {}", &message);
33
34 let raw_response = Server::bad_request_response(message);
35 let boxed_stream = stream.write(raw_response.borrow());
36 if boxed_stream.is_ok() {
37 stream.flush().unwrap();
38 };
39 return raw_response;
40 }
41
42 boxed_read.unwrap();
43 let request : &[u8] = &buffer;
44
45 let boxed_request = Request::parse_request(request);
50 if boxed_request.is_err() {
51 let message = boxed_request.err().unwrap();
52 eprintln!("unable to parse request: {}", &message);
53
54 let raw_response = Server::bad_request_response(message);
55 let boxed_stream = stream.write(raw_response.borrow());
56 if boxed_stream.is_ok() {
57 stream.flush().unwrap();
58 };
59 return raw_response;
60 }
61
62
63 let request: Request = boxed_request.unwrap();
64 let (response, request) = App::handle_request(request);
65
66
67 let log_request_response = Log::combined(&request, &response, &peer_addr);
68 println!("{}", log_request_response);
69 let raw_response = Response::generate_response(response, request);
70
71 let boxed_stream = stream.write(raw_response.borrow());
72 if boxed_stream.is_ok() {
73 stream.flush().unwrap();
74 };
75
76 raw_response
77 }
78
79 pub fn bad_request_response(message: String) -> Vec<u8> {
80 let error_request = Request {
81 method: METHOD.get.to_string(),
82 request_uri: "".to_string(),
83 http_version: "".to_string(),
84 headers: vec![],
85 body: vec![],
86 };
87
88 let size = message.chars().count() as u64;
89 let content_range = ContentRange {
90 unit: Range::BYTES.to_string(),
91 range: Range { start: 0, end: size },
92 size: size.to_string(),
93 body: Vec::from(message.as_bytes()),
94 content_type: MimeType::TEXT_PLAIN.to_string(),
95 };
96
97 let header_list = Header::get_header_list(&error_request);
98 let error_response: Response = Response::get_response(
99 STATUS_CODE_REASON_PHRASE.n400_bad_request,
100 Some(header_list),
101 Some(vec![content_range])
102 );
103
104 let response = Response::generate_response(error_response, error_request);
105 return response;
106 }
107
108 pub fn process(mut stream: impl Read + Write + Unpin,
109 connection: ConnectionInfo,
110 app: impl Application) -> Result<(), String> {
111 use crate::http::VERSION;
112
113 let request_allocation_size = connection.request_size;
114 let client = connection.client.clone();
115 let client_addr = SocketAddr::new(IpAddr::from_str(client.ip.as_str()).unwrap(), client.port as u16);
116
117 loop {
118 let mut buffer = vec![0; request_allocation_size as usize];
119 let boxed_read = stream.read(&mut buffer);
120 if boxed_read.is_err() {
121 break;
123 }
124 if boxed_read.unwrap() == 0 {
125 break;
126 }
127
128 let request = match Request::parse(&buffer) {
129 Ok(r) => r,
130 Err(message) => {
131 let raw_response = Server::bad_request_response(message.clone());
132 let boxed_stream = stream.write(raw_response.borrow());
133 if boxed_stream.is_ok() { stream.flush().unwrap(); }
134 return Err(message);
135 }
136 };
137
138 let keep_alive = {
139 let conn_hdr = request.get_header(Header::_CONNECTION.to_string());
140 match conn_hdr {
141 Some(h) => h.value.to_lowercase() != "close",
142 None => request.http_version == VERSION.http_1_1,
143 }
144 };
145
146 let mut response = match app.execute(&request, &connection) {
147 Ok(r) => r,
148 Err(message) => {
149 let raw_response = Server::bad_request_response(message.clone());
150 let boxed_stream = stream.write(raw_response.borrow());
151 if boxed_stream.is_ok() { stream.flush().unwrap(); }
152 return Err(message);
153 }
154 };
155
156 crate::metrics::record_request();
157 crate::compression::apply_gzip(&request, &mut response);
158
159 response.headers.push(Header {
160 name: Header::_CONNECTION.to_string(),
161 value: if keep_alive { "keep-alive".to_string() } else { "close".to_string() },
162 });
163
164 Log::log_access(&request, &response, &client_addr);
165
166 if let Some(ref filepath) = response.stream_file.clone() {
167 if let Err(e) = Server::write_chunked_file(&mut stream, response, request, filepath) {
168 return Err(e);
169 }
170 } else {
171 let raw_response = Response::generate_response(response, request);
172 if let Err(e) = stream.write(raw_response.borrow()) {
173 return Err(e.to_string());
174 }
175 stream.flush().unwrap();
176 }
177
178 if !keep_alive { break; }
179 }
180
181 Ok(())
182 }
183
184 pub(crate) fn write_chunked_file(
187 stream: &mut impl Write,
188 mut response: Response,
189 request: Request,
190 filepath: &str,
191 ) -> Result<(), String> {
192 use std::fs::File;
193 use std::io::Read as _;
194
195 response.headers.push(Header {
196 name: Header::_TRANSFER_ENCODING.to_string(),
197 value: "chunked".to_string(),
198 });
199
200 let status = [
202 response.http_version.clone(),
203 response.status_code.to_string(),
204 response.reason_phrase.clone(),
205 ].join(SYMBOL.whitespace);
206
207 let mut headers_str = SYMBOL.new_line_carriage_return.to_string();
208 for header in &response.headers {
209 headers_str.push_str(&header.name);
210 headers_str.push_str(Header::NAME_VALUE_SEPARATOR);
211 headers_str.push_str(&header.value);
212 headers_str.push_str(SYMBOL.new_line_carriage_return);
213 }
214 let head = format!("{}{}{}", status, headers_str, SYMBOL.new_line_carriage_return);
215
216 stream.write_all(head.as_bytes()).map_err(|e| e.to_string())?;
217
218 if request.method != METHOD.head && request.method != METHOD.options {
219 let mut file = File::open(filepath).map_err(|e| e.to_string())?;
220 let mut buf = vec![0u8; 65536];
221 loop {
222 let n = file.read(&mut buf).map_err(|e| e.to_string())?;
223 if n == 0 { break; }
224 stream.write_all(format!("{:x}\r\n", n).as_bytes()).map_err(|e| e.to_string())?;
226 stream.write_all(&buf[..n]).map_err(|e| e.to_string())?;
227 stream.write_all(b"\r\n").map_err(|e| e.to_string())?;
228 }
229 stream.write_all(b"0\r\n\r\n").map_err(|e| e.to_string())?;
231 }
232
233 stream.flush().map_err(|e| e.to_string())
234 }
235
236 pub fn setup() -> Result<(TcpListener, ThreadPool), String> {
239 let info = Log::info("Rust Web Server");
240 println!("{}", info);
241
242 let usage_info = Log::usage_information();
243 println!("{}", usage_info);
244
245
246 println!("RWS Configuration Start: \n");
247
248 set_default_values();
249 bootstrap();
250
251 println!("\nRWS Configuration End\n\n");
252
253
254 let (ip, port, thread_count) = get_ip_port_thread_count();
255
256
257 let mut ip_readable = ip.to_string();
258
259 if ip.contains(":") {
260 ip_readable = [SYMBOL.opening_square_bracket, &ip, SYMBOL.closing_square_bracket].join("");
261 }
262
263 let bind_addr = [ip_readable, SYMBOL.colon.to_string(), port.to_string()].join(SYMBOL.empty_string);
264
265 #[cfg(feature = "http2")]
266 let protocol = {
267 let cert = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE).unwrap_or_default();
268 if cert.is_empty() { "http" } else { "https" }
269 };
270 #[cfg(not(feature = "http2"))]
271 let protocol = "http";
272
273 println!("Setting up {}://{}...", protocol, &bind_addr);
274
275 let boxed_listener = TcpListener::bind(&bind_addr);
276 if boxed_listener.is_err() {
277 let message = format!("unable to set up TCP listener: {}", boxed_listener.err().unwrap());
278 return Err(message);
279 }
280
281 let listener = boxed_listener.unwrap();
282 let pool = ThreadPool::new(thread_count as usize);
283
284
285 let server_url_thread_count = Log::server_url_thread_count(protocol, &bind_addr, thread_count);
286 println!("{}", server_url_thread_count);
287
288 Ok((listener, pool))
289 }
290
291 pub fn run(listener: TcpListener,
299 pool: ThreadPool,
300 app: impl Application + Send + 'static + Clone) {
301 #[cfg(feature = "http1")]
302 {
303 use std::sync::Arc;
304 use std::sync::atomic::{AtomicBool, Ordering};
305
306 let shutdown = Arc::new(AtomicBool::new(false));
307 let s = shutdown.clone();
308 if let Err(e) = ctrlc::set_handler(move || {
309 s.store(true, Ordering::SeqCst);
310 }) {
311 eprintln!("unable to install signal handler: {}", e);
312 }
313 crate::config_reload::install_sighup_handler();
314 if let Err(e) = listener.set_nonblocking(true) {
315 eprintln!("unable to set non-blocking listener: {}", e);
316 }
317
318 loop {
319 if shutdown.load(Ordering::SeqCst) {
320 break;
321 }
322 if crate::config_reload::RELOAD_REQUESTED
323 .compare_exchange(true, false, Ordering::SeqCst, Ordering::Relaxed)
324 .is_ok()
325 {
326 crate::config_reload::reload();
327 }
328 match listener.accept() {
329 Ok((stream, peer_addr)) => {
330 Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
331 }
332 Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
333 std::thread::sleep(Duration::from_millis(10));
334 }
335 Err(e) => {
336 eprintln!("accept error: {}", e);
337 break;
338 }
339 }
340 }
341
342 crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
343 println!("Shutting down — waiting for in-flight connections to finish");
344 pool.join();
345 println!("Server stopped");
346 }
347
348 #[cfg(not(feature = "http1"))]
349 {
350 for boxed_stream in listener.incoming() {
351 match boxed_stream {
352 Err(e) => {
353 eprintln!("unable to get TCP stream: {}", e);
354 return;
355 }
356 Ok(stream) => {
357 let peer_addr = match stream.peer_addr() {
358 Ok(a) => a,
359 Err(e) => {
360 eprintln!("unable to read peer addr: {}", e);
361 return;
362 }
363 };
364 Server::dispatch_connection(stream, peer_addr, &pool, app.clone());
365 }
366 }
367 }
368 }
369 }
370
371 fn dispatch_connection(
372 stream: std::net::TcpStream,
373 peer_addr: std::net::SocketAddr,
374 pool: &ThreadPool,
375 app: impl Application + Send + 'static + Clone,
376 ) {
377 print!("Connection established, ");
378 if let Ok(local) = stream.local_addr() {
379 print!("local addr: {}", local);
380 }
381 println!(", peer addr: {}", peer_addr);
382
383 let (server_ip, server_port, _thread_count) = get_ip_port_thread_count();
384 let connection = ConnectionInfo {
385 client: Address {
386 ip: peer_addr.ip().to_string(),
387 port: peer_addr.port() as i32,
388 },
389 server: Address {
390 ip: server_ip,
391 port: server_port,
392 },
393 request_size: get_request_allocation_size(),
394 sni_hostname: None,
395 };
396
397 if let Err(e) = stream.set_read_timeout(Some(Duration::from_secs(30))) {
398 eprintln!("failed to set read timeout: {}", e);
399 }
400
401 pool.execute(move || {
402 crate::metrics::connection_open();
403 let result = Server::process(stream, connection, app);
404 crate::metrics::connection_close();
405 if let Err(msg) = result {
406 crate::metrics::record_error();
407 eprintln!("{}", msg);
408 }
409 });
410 }
411
412}
413
414#[derive(Clone)]
416pub struct ConnectionInfo {
417 pub client: Address,
419 pub server: Address,
421 pub request_size: i64,
423 pub sni_hostname: Option<String>,
426}
427
428#[derive(Clone)]
430pub struct Address {
431 pub ip: String,
432 pub port: i32
433}
434
435impl ConnectionInfo {
436 pub fn peer_addr(&self) -> Option<std::net::SocketAddr> {
439 self.client.to_socket_addr()
440 }
441}
442
443impl Address {
444 pub fn to_socket_addr(&self) -> Option<std::net::SocketAddr> {
447 let ip: std::net::IpAddr = self.ip.parse().ok()?;
448 let port = u16::try_from(self.port).ok()?;
449 Some(std::net::SocketAddr::new(ip, port))
450 }
451}
452
453#[cfg(feature = "http2")]
456async fn sigterm() {
457 #[cfg(unix)]
458 {
459 if let Ok(mut s) = tokio::signal::unix::signal(
460 tokio::signal::unix::SignalKind::terminate()
461 ) {
462 s.recv().await;
463 } else {
464 std::future::pending::<()>().await
465 }
466 }
467 #[cfg(not(unix))]
468 std::future::pending::<()>().await
469}
470
471#[cfg(feature = "http2")]
473async fn sighup() {
474 #[cfg(unix)]
475 {
476 if let Ok(mut s) = tokio::signal::unix::signal(
477 tokio::signal::unix::SignalKind::hangup()
478 ) {
479 s.recv().await;
480 } else {
481 std::future::pending::<()>().await
482 }
483 }
484 #[cfg(not(unix))]
485 std::future::pending::<()>().await
486}
487
488#[cfg(feature = "http2")]
489impl Server {
490 pub async fn run_tls(
491 listener: TcpListener,
492 pool: ThreadPool,
493 app: impl Application + Send + 'static + Clone,
494 ) {
495 use crate::tls::create_tls_acceptor_from_vhosts;
496 use crate::h2_handler;
497
498 let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
499 .unwrap_or_default();
500 let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
501 .unwrap_or_default();
502
503 if cert_path.is_empty() || key_path.is_empty() {
504 println!("No TLS certificate configured — serving plain HTTP/1.1.");
505 tokio::task::block_in_place(|| Server::run(listener, pool, app));
506 return;
507 }
508
509 let vhosts = crate::entry_point::get_virtual_hosts();
510 let mut tls_acceptor = match create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
511 Ok(a) => a,
512 Err(e) => {
513 eprintln!("TLS setup failed: {}", e);
514 return;
515 }
516 };
517
518 listener
519 .set_nonblocking(true)
520 .expect("failed to set TCP listener to non-blocking");
521 let tokio_listener = tokio::net::TcpListener::from_std(listener)
522 .expect("failed to convert TCP listener to tokio");
523
524 println!("Listening for TLS connections (HTTP/1.1 + HTTP/2)...");
525
526 loop {
527 tokio::select! {
528 result = tokio_listener.accept() => {
529 match result {
530 Ok((tcp_stream, peer_addr)) => {
531 let acceptor = tls_acceptor.clone();
532 let app = app.clone();
533 tokio::spawn(async move {
534 match acceptor.accept(tcp_stream).await {
535 Ok(tls_stream) => {
536 let server_conn = tls_stream.get_ref().1;
537 let sni = server_conn.server_name().map(|s| s.to_string());
538 let protocol = server_conn
539 .alpn_protocol()
540 .map(|p| p.to_vec());
541
542 match protocol.as_deref() {
543 Some(b"h2") => {
544 if let Err(e) =
545 h2_handler::handle_connection(tls_stream, peer_addr, sni, app)
546 .await
547 {
548 eprintln!("H2 connection error: {}", e);
549 }
550 }
551 _ => {
552 if let Err(e) =
553 Server::process_h1_tls(tls_stream, peer_addr, sni, app).await
554 {
555 eprintln!("H1 TLS error: {}", e);
556 }
557 }
558 }
559 }
560 Err(e) => eprintln!("TLS handshake failed: {}", e),
561 }
562 });
563 }
564 Err(e) => eprintln!("TCP accept error: {}", e),
565 }
566 }
567 _ = tokio::signal::ctrl_c() => {
568 crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
569 println!("\nShutting down gracefully (SIGINT).");
570 break;
571 }
572 _ = sigterm() => {
573 crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
574 println!("\nShutting down gracefully (SIGTERM).");
575 break;
576 }
577 _ = sighup() => {
578 crate::config_reload::reload();
579 let vhosts = crate::entry_point::get_virtual_hosts();
580 if let Ok(new_acceptor) = create_tls_acceptor_from_vhosts(&vhosts, &cert_path, &key_path) {
581 tls_acceptor = new_acceptor;
582 println!("[TLS] Certificates reloaded ({} virtual hosts).", vhosts.len());
583 }
584 }
585 }
586 }
587 }
588
589 pub async fn run_redirect() {
593 use std::env;
594 use tokio::io::{AsyncReadExt, AsyncWriteExt};
595 use tokio::net::TcpListener as TokioListener;
596
597 let cert_path = env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
598 .unwrap_or_default();
599 if cert_path.is_empty() {
600 return;
601 }
602
603 let redirect_port_str = env::var(crate::entry_point::Config::RWS_CONFIG_HTTP_REDIRECT_PORT)
604 .unwrap_or_default();
605 if redirect_port_str.is_empty() {
606 return;
607 }
608
609 let redirect_port: u16 = match redirect_port_str.parse() {
610 Ok(p) => p,
611 Err(_) => {
612 eprintln!("Invalid RWS_CONFIG_HTTP_REDIRECT_PORT: {}", redirect_port_str);
613 return;
614 }
615 };
616
617 let (server_ip, server_port, _) = get_ip_port_thread_count();
618 let bind_addr = format!("{}:{}", server_ip, redirect_port);
619
620 let listener = match TokioListener::bind(&bind_addr).await {
621 Ok(l) => l,
622 Err(e) => {
623 eprintln!("HTTP redirect listener error on {}: {}", bind_addr, e);
624 return;
625 }
626 };
627
628 println!("HTTP→HTTPS redirect listening on http://{}:{}", server_ip, redirect_port);
629
630 loop {
631 tokio::select! {
632 result = listener.accept() => {
633 match result {
634 Ok((mut stream, _peer)) => {
635 let https_port = server_port;
636 tokio::spawn(async move {
637 let mut buf = vec![0u8; 4096];
638 let n = match stream.read(&mut buf).await {
639 Ok(n) => n,
640 Err(_) => return,
641 };
642 let text = String::from_utf8_lossy(&buf[..n]);
643
644 let uri = text.lines()
645 .next()
646 .and_then(|line| line.split_whitespace().nth(1))
647 .unwrap_or("/")
648 .to_string();
649
650 let host_header = text.lines()
651 .find(|l| l.to_lowercase().starts_with("host:"))
652 .map(|l| l[5..].trim().to_string());
653
654 let location = match host_header {
655 Some(h) => {
656 let h_no_port = if h.starts_with('[') {
658 h.find(']')
660 .map(|i| h[..=i].to_string())
661 .unwrap_or(h.clone())
662 } else {
663 h.rfind(':')
664 .map(|i| h[..i].to_string())
665 .unwrap_or(h.clone())
666 };
667 if https_port == 443 {
668 format!("https://{}{}", h_no_port, uri)
669 } else {
670 format!("https://{}:{}{}", h_no_port, https_port, uri)
671 }
672 }
673 None => format!("https://localhost:{}{}", https_port, uri),
674 };
675
676 let response = format!(
677 "HTTP/1.1 301 Moved Permanently\r\nLocation: {}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
678 location
679 );
680 let _ = stream.write_all(response.as_bytes()).await;
681 });
682 }
683 Err(e) => eprintln!("HTTP redirect accept error: {}", e),
684 }
685 }
686 _ = tokio::signal::ctrl_c() => {
687 println!("\nShutting down HTTP redirect listener (SIGINT).");
688 break;
689 }
690 _ = sigterm() => {
691 println!("\nShutting down HTTP redirect listener (SIGTERM).");
692 break;
693 }
694 _ = sighup() => {
695 crate::config_reload::reload();
696 }
697 }
698 }
699 }
700
701 async fn process_h1_tls(
702 mut stream: tokio_rustls::server::TlsStream<tokio::net::TcpStream>,
703 peer_addr: std::net::SocketAddr,
704 sni_hostname: Option<String>,
705 app: impl Application,
706 ) -> Result<(), String> {
707 use tokio::io::{AsyncReadExt, AsyncWriteExt};
708
709 let (server_ip, server_port, _) = get_ip_port_thread_count();
710 let request_allocation_size = get_request_allocation_size();
711
712 let mut buffer = vec![0u8; request_allocation_size as usize];
713 if let Err(e) = stream.read(&mut buffer).await {
714 let raw = Server::bad_request_response(e.to_string());
715 let _ = stream.write_all(&raw).await;
716 return Ok(());
717 }
718
719 let request = match Request::parse(&buffer) {
720 Ok(r) => r,
721 Err(message) => {
722 let raw = Server::bad_request_response(message);
723 let _ = stream.write_all(&raw).await;
724 return Ok(());
725 }
726 };
727
728 let connection = ConnectionInfo {
729 client: Address {
730 ip: peer_addr.ip().to_string(),
731 port: peer_addr.port() as i32,
732 },
733 server: Address {
734 ip: server_ip,
735 port: server_port,
736 },
737 request_size: request_allocation_size,
738 sni_hostname,
739 };
740
741 let mut response = match app.execute(&request, &connection) {
742 Ok(r) => r,
743 Err(message) => {
744 let raw = Server::bad_request_response(message);
745 let _ = stream.write_all(&raw).await;
746 return Ok(());
747 }
748 };
749
750 crate::metrics::record_request();
751 crate::compression::apply_gzip(&request, &mut response);
752 response.headers.push(Header::get_hsts_header());
753
754 #[cfg(feature = "http3")]
755 response.headers.push(Header {
756 name: Header::_ALT_SVC.to_string(),
757 value: format!("h3=\":{}\"", server_port),
758 });
759 #[cfg(not(feature = "http3"))]
760 response.headers.push(Header {
761 name: Header::_ALT_SVC.to_string(),
762 value: format!("h2=\":{}\"", server_port),
763 });
764
765 Log::log_access(&request, &response, &peer_addr);
766
767 let raw = Response::generate_response(response, request);
768 stream
769 .write_all(&raw)
770 .await
771 .map_err(|e| e.to_string())?;
772 stream.flush().await.map_err(|e| e.to_string())?;
773
774 Ok(())
775 }
776}
777
778#[cfg(feature = "http3")]
779impl Server {
780 pub async fn run_quic(
781 app: impl Application + Send + 'static + Clone,
782 ) {
783 use crate::tls::create_quinn_server_config_from_vhosts;
784 use crate::h3_handler;
785
786 let cert_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_CERT_FILE)
787 .unwrap_or_default();
788 let key_path = std::env::var(crate::entry_point::Config::RWS_CONFIG_TLS_KEY_FILE)
789 .unwrap_or_default();
790
791 if cert_path.is_empty() || key_path.is_empty() {
792 return;
793 }
794
795 let vhosts = crate::entry_point::get_virtual_hosts();
796 let server_config = match create_quinn_server_config_from_vhosts(&vhosts, &cert_path, &key_path) {
797 Ok(c) => c,
798 Err(e) => {
799 eprintln!("QUIC TLS setup failed: {}", e);
800 return;
801 }
802 };
803
804 let (server_ip, server_port, _) = get_ip_port_thread_count();
805 let bind_addr = format!("{}:{}", server_ip, server_port);
806 let addr: std::net::SocketAddr = match bind_addr.parse() {
807 Ok(a) => a,
808 Err(e) => {
809 eprintln!("Invalid QUIC bind address '{}': {}", bind_addr, e);
810 return;
811 }
812 };
813
814 let endpoint = match quinn::Endpoint::server(server_config, addr) {
815 Ok(e) => e,
816 Err(e) => {
817 eprintln!("QUIC endpoint error: {}", e);
818 return;
819 }
820 };
821
822 println!("Listening for QUIC/HTTP3 on UDP {}:{}", server_ip, server_port);
823
824 loop {
825 tokio::select! {
826 maybe = endpoint.accept() => {
827 match maybe {
828 Some(incoming) => {
829 let app = app.clone();
830 tokio::spawn(async move {
831 match incoming.await {
832 Ok(conn) => {
833 let peer_addr = conn.remote_address();
834 if let Err(e) = h3_handler::handle_connection(conn, peer_addr, app).await {
835 eprintln!("H3 connection error: {}", e);
836 }
837 }
838 Err(e) => eprintln!("QUIC connection error: {}", e),
839 }
840 });
841 }
842 None => break,
843 }
844 }
845 _ = tokio::signal::ctrl_c() => {
846 crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
847 println!("\nShutting down QUIC (SIGINT).");
848 endpoint.close(0u32.into(), b"shutdown");
849 break;
850 }
851 _ = sigterm() => {
852 crate::metrics::SERVER_READY.store(false, std::sync::atomic::Ordering::SeqCst);
853 println!("\nShutting down QUIC (SIGTERM).");
854 endpoint.close(0u32.into(), b"shutdown");
855 break;
856 }
857 _ = sighup() => {
858 crate::config_reload::reload();
859 }
860 }
861 }
862 }
863}
864
865