1use crate::error::{Error, Result};
4use crate::handler::{BoxFuture, DynHandler, Handler, HandlerWithParams};
5use crate::limits::{self, ConnGuard, ConnLimits};
6use crate::middleware::{Layered, Middleware, Next};
7use crate::openapi::{self, OpenApiInfo, Operation, RouteKind};
8use crate::request::{Params, Request, StateMap};
9use crate::response::Response;
10use crate::router::Router;
11use crate::shutdown::{Context, Shutdown};
12use http_body_util::BodyExt;
13use hyper::server::conn::{http1, http2};
14use hyper::service::service_fn;
15use hyper_util::rt::{TokioExecutor, TokioIo, TokioTimer};
16use std::collections::HashMap;
17use std::convert::Infallible;
18use std::net::SocketAddr;
19use std::sync::Arc;
20use std::time::Duration;
21use tokio::net::TcpListener;
22
23pub struct App {
25 router: Router,
26 middlewares: Vec<Arc<dyn Middleware>>,
27 max_body_size: Option<usize>, docs: HashMap<(String, String), Operation>,
29 openapi: Option<OpenApiInfo>,
30 state: StateMap,
31 background: Vec<BackgroundTask>,
32 shutdown_grace: Duration,
33 shutdown_delay: Duration,
34 body_limits: Vec<(String, Option<usize>)>,
35 stream_bodies: Vec<(String, Option<u64>)>,
36 header_read_timeout: Option<Duration>,
37 max_connections: Option<usize>,
38 max_connections_per_ip: Option<usize>,
39 h2c: bool,
40 trusted_proxies: Option<Arc<crate::proxy::TrustedProxies>>,
41 fallback: Option<DynHandler>,
42 catch_panics: bool,
43 #[cfg(feature = "tls")]
44 tls: Option<crate::tls::TlsConfig>,
45 #[cfg(feature = "tls")]
46 tls_reload: Option<Duration>,
47}
48
49struct ConnInfo {
51 peer: SocketAddr,
52 secure: bool,
53 client_cert: Option<Vec<u8>>,
54}
55
56type BackgroundTask = Box<dyn FnOnce(Context) -> BoxFuture<'static, ()> + Send>;
57
58struct Shared {
60 router: Router,
61 middlewares: Vec<Arc<dyn Middleware>>,
62 max_body_size: Option<usize>,
63 body_limits: Vec<(String, Option<usize>)>,
64 stream_bodies: Vec<(String, Option<u64>)>,
65 trusted_proxies: Option<Arc<crate::proxy::TrustedProxies>>,
66 fallback: Option<DynHandler>,
67 catch_panics: bool,
68 state: Arc<StateMap>,
69 shutdown: Shutdown,
70 header_read_timeout: Option<Duration>,
71}
72
73pub struct RouteGroup {
75 prefix: String,
76 routes: Vec<(String, String, DynHandler)>, middlewares: Vec<Arc<dyn Middleware>>,
78 docs: Vec<(String, String, Operation)>, body_limit: Option<Option<usize>>,
80 ws_paths: Vec<String>,
82}
83
84impl App {
85 pub fn new() -> Self {
86 Self {
87 router: Router::new(),
88 middlewares: Vec::new(),
89 max_body_size: Some(10 * 1024 * 1024), docs: HashMap::new(),
91 openapi: None,
92 state: StateMap::default(),
93 background: Vec::new(),
94 shutdown_grace: Duration::from_secs(10),
95 shutdown_delay: Duration::ZERO,
96 body_limits: Vec::new(),
97 stream_bodies: Vec::new(),
98 header_read_timeout: Some(Duration::from_secs(30)),
99 max_connections: None,
100 max_connections_per_ip: None,
101 h2c: false,
102 trusted_proxies: None,
103 fallback: None,
104 catch_panics: true,
105 #[cfg(feature = "tls")]
106 tls: None,
107 #[cfg(feature = "tls")]
108 tls_reload: None,
109 }
110 }
111
112 pub fn max_body_size(mut self, size: Option<usize>) -> Self {
114 self.max_body_size = size;
115 self
116 }
117
118 pub fn body_limit(mut self, prefix: &str, limit: Option<usize>) -> Self {
125 self.body_limits
126 .push((prefix.trim_end_matches('/').to_string(), limit));
127 self
128 }
129
130 pub fn state<T: Send + Sync + 'static>(mut self, value: T) -> Self {
152 self.state.insert(value);
153 self
154 }
155
156 pub fn background<F, Fut>(mut self, task: F) -> Self
177 where
178 F: FnOnce(Context) -> Fut + Send + 'static,
179 Fut: std::future::Future<Output = ()> + Send + 'static,
180 {
181 self.background
182 .push(Box::new(move |ctx| Box::pin(task(ctx))));
183 self
184 }
185
186 #[cfg(feature = "tls")]
188 pub fn tls(mut self, config: crate::tls::TlsConfig) -> Self {
189 self.tls = Some(config);
190 self
191 }
192
193 #[cfg(feature = "tls")]
198 pub fn tls_reload_every(mut self, interval: Duration) -> Self {
199 self.tls_reload = Some(interval);
200 self
201 }
202
203 pub fn header_read_timeout(mut self, timeout: impl Into<Option<Duration>>) -> Self {
208 self.header_read_timeout = timeout.into();
209 self
210 }
211
212 pub fn h2c(mut self, enabled: bool) -> Self {
219 self.h2c = enabled;
220 self
221 }
222
223 pub fn max_connections(mut self, max: usize) -> Self {
227 self.max_connections = Some(max.max(1));
228 self
229 }
230
231 pub fn max_connections_per_ip(mut self, max: usize) -> Self {
235 self.max_connections_per_ip = Some(max.max(1));
236 self
237 }
238
239 pub fn shutdown_grace(mut self, grace: Duration) -> Self {
242 self.shutdown_grace = grace;
243 self
244 }
245
246 pub fn trusted_proxies(mut self, proxies: crate::proxy::TrustedProxies) -> Self {
250 self.trusted_proxies = Some(Arc::new(proxies));
251 self
252 }
253
254 pub fn fallback<H>(mut self, handler: H) -> Self
269 where
270 H: Handler,
271 {
272 self.fallback = Some(Arc::new(handler) as DynHandler);
273 self
274 }
275
276 pub fn catch_panics(mut self, enabled: bool) -> Self {
280 self.catch_panics = enabled;
281 self
282 }
283
284 pub fn stream_body(mut self, prefix: &str, max_bytes: Option<u64>) -> Self {
289 self.stream_bodies.push((prefix.to_string(), max_bytes));
290 self
291 }
292
293 pub fn shutdown_delay(mut self, delay: Duration) -> Self {
300 self.shutdown_delay = delay;
301 self
302 }
303
304 pub fn group(mut self, prefix: &str, configure: impl FnOnce(RouteGroup) -> RouteGroup) -> Self {
306 let group = RouteGroup::new(prefix);
307 let group = configure(group);
308
309 if let Some(limit) = group.body_limit {
310 self.body_limits.push((group.prefix.clone(), limit));
311 }
312 for (method, path, op) in group.docs {
313 let full_path = format!("{}{}", group.prefix, path);
314 self.docs.insert((method, full_path), op);
315 }
316
317 let middlewares = group.middlewares;
319 for (method, path, handler) in group.routes {
320 let full_path = format!("{}{}", group.prefix, path);
321 let handler: DynHandler = if middlewares.is_empty() {
322 handler
323 } else {
324 Arc::new(Layered::new(middlewares.clone(), handler))
325 };
326 let kind = if method == "GET" && group.ws_paths.contains(&path) {
327 RouteKind::WebSocket
328 } else {
329 RouteKind::Http
330 };
331 if let Err(e) = self.router.insert_as(kind, &method, &full_path, handler) {
332 panic!("Failed to register {} route {}: {}", method, full_path, e);
333 }
334 }
335
336 self
337 }
338
339 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
343 self.docs
344 .insert((method.to_ascii_uppercase(), path.to_string()), operation);
345 self
346 }
347
348 pub fn openapi(mut self, info: OpenApiInfo) -> Self {
352 self.openapi = Some(info);
353 self
354 }
355
356 pub fn get<H>(mut self, path: &str, handler: H) -> Self
358 where
359 H: Handler,
360 {
361 if let Err(e) = self
362 .router
363 .insert("GET", path, Arc::new(handler) as DynHandler)
364 {
365 panic!("Failed to register GET route {}: {}", path, e);
366 }
367 self
368 }
369
370 pub fn get_with_params<F, Fut>(mut self, path: &str, handler: F) -> Self
372 where
373 F: Fn(Params) -> Fut + Send + Sync + 'static,
374 Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
375 {
376 if let Err(e) = self.router.insert(
377 "GET",
378 path,
379 Arc::new(HandlerWithParams::new(handler)) as DynHandler,
380 ) {
381 panic!("Failed to register GET route {}: {}", path, e);
382 }
383 self
384 }
385
386 pub fn post<H>(mut self, path: &str, handler: H) -> Self
388 where
389 H: Handler,
390 {
391 if let Err(e) = self
392 .router
393 .insert("POST", path, Arc::new(handler) as DynHandler)
394 {
395 panic!("Failed to register POST route {}: {}", path, e);
396 }
397 self
398 }
399
400 pub fn put<H>(mut self, path: &str, handler: H) -> Self
402 where
403 H: Handler,
404 {
405 if let Err(e) = self
406 .router
407 .insert("PUT", path, Arc::new(handler) as DynHandler)
408 {
409 panic!("Failed to register PUT route {}: {}", path, e);
410 }
411 self
412 }
413
414 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
416 where
417 H: Handler,
418 {
419 if let Err(e) = self
420 .router
421 .insert("DELETE", path, Arc::new(handler) as DynHandler)
422 {
423 panic!("Failed to register DELETE route {}: {}", path, e);
424 }
425 self
426 }
427
428 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
430 where
431 H: Handler,
432 {
433 if let Err(e) = self
434 .router
435 .insert("PATCH", path, Arc::new(handler) as DynHandler)
436 {
437 panic!("Failed to register PATCH route {}: {}", path, e);
438 }
439 self
440 }
441
442 #[cfg(feature = "websocket")]
448 pub fn ws<F, Fut>(self, path: &str, handler: F) -> Self
449 where
450 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
451 Fut: std::future::Future<Output = ()> + Send + 'static,
452 {
453 self.ws_with(path, crate::websocket::WsOptions::default(), handler)
454 }
455
456 #[cfg(feature = "websocket")]
458 pub fn ws_with<F, Fut>(
459 mut self,
460 path: &str,
461 options: crate::websocket::WsOptions,
462 handler: F,
463 ) -> Self
464 where
465 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
466 Fut: std::future::Future<Output = ()> + Send + 'static,
467 {
468 let route = crate::websocket::WsRoute::new(handler, options);
469 if let Err(e) = self.router.insert_as(
470 RouteKind::WebSocket,
471 "GET",
472 path,
473 Arc::new(route) as DynHandler,
474 ) {
475 panic!("Failed to register WebSocket route {}: {}", path, e);
476 }
477 self
478 }
479
480 pub fn middleware<M>(mut self, middleware: M) -> Self
482 where
483 M: Middleware,
484 {
485 self.middlewares.push(Arc::new(middleware));
486 self
487 }
488
489 pub fn serve_static(self, route_prefix: &str, dir_path: &str) -> Self {
491 self.serve_static_with(
492 route_prefix,
493 dir_path,
494 crate::static_files::StaticOptions::new(),
495 )
496 }
497
498 pub fn serve_static_with(
501 mut self,
502 route_prefix: &str,
503 dir_path: &str,
504 options: crate::static_files::StaticOptions,
505 ) -> Self {
506 use crate::static_files::StaticFileHandler;
507 let handler = StaticFileHandler::with_options(dir_path, options);
508 let prefix = route_prefix.trim_end_matches('/');
510 let handler: DynHandler = Arc::new(handler);
511 let route = format!("{}/{{*filepath}}", prefix);
512 if let Err(e) = self
513 .router
514 .insert_as(RouteKind::Hidden, "GET", &route, handler.clone())
515 {
516 panic!("Failed to register static file route {}: {}", route, e);
517 }
518 let root = if prefix.is_empty() { "/" } else { prefix };
521 let _ = self
522 .router
523 .insert_as(RouteKind::Hidden, "GET", root, handler.clone());
524 if !prefix.is_empty() {
525 let _ =
526 self.router
527 .insert_as(RouteKind::Hidden, "GET", &format!("{}/", prefix), handler);
528 }
529 self
530 }
531
532 pub async fn run(self, addr: &str) -> Result<()> {
537 let addr: SocketAddr = addr
538 .parse()
539 .map_err(|e| Error::internal(format!("Invalid address: {}", e)))?;
540
541 let listener = TcpListener::bind(addr)
542 .await
543 .map_err(|e| Error::internal(format!("Failed to bind: {}", e)))?;
544
545 #[cfg(feature = "tls")]
546 let scheme = if self.tls.is_some() { "https" } else { "http" };
547 #[cfg(not(feature = "tls"))]
548 let scheme = "http";
549 println!("🚀 ullun-api listening on {}://{}", scheme, addr);
550
551 let result = self
552 .serve_with_shutdown(listener, async {
553 termination_signal().await;
554 println!("\n🛑 Shutting down gracefully...");
555 })
556 .await;
557 println!("✅ Server stopped");
558 result
559 }
560
561 pub async fn serve(self, listener: TcpListener) -> Result<()> {
568 self.serve_with_shutdown(listener, std::future::pending())
569 .await
570 }
571
572 pub async fn serve_with_shutdown(
579 mut self,
580 listener: TcpListener,
581 signal: impl std::future::Future<Output = ()>,
582 ) -> Result<()> {
583 self = self.finalize();
584 let grace = self.shutdown_grace;
585 let delay = self.shutdown_delay;
586 let background = std::mem::take(&mut self.background);
587 #[cfg(feature = "tls")]
588 let tls = self.tls.take();
589 #[cfg(feature = "tls")]
590 let tls_reload = self.tls_reload;
591 let h2c = self.h2c;
592 let conn_limits = ConnLimits::new(self.max_connections, self.max_connections_per_ip);
593 let (trigger, rx) = tokio::sync::watch::channel(false);
594 let (drain_tx, drain_rx) = tokio::sync::watch::channel(false);
595 let shutdown = Shutdown::with_drain(rx, drain_rx);
596 let shared = Arc::new(self.into_shared(shutdown.clone()));
597
598 #[allow(unused_mut)]
599 let mut tasks: Vec<_> = background
600 .into_iter()
601 .map(|task| {
602 let ctx = Context::new(shared.state.clone(), shutdown.clone());
603 tokio::spawn(task(ctx))
604 })
605 .collect();
606
607 #[cfg(feature = "tls")]
608 if let (Some(config), Some(every)) = (tls.clone(), tls_reload) {
609 let shutdown = shutdown.clone();
610 tasks.push(tokio::spawn(async move {
611 while shutdown.sleep(every).await {
612 match config.reload() {
613 Ok(true) => println!("🔐 TLS certificate reloaded"),
614 Ok(false) => {}
615 Err(e) => eprintln!(
616 "TLS certificate reload failed, keeping the previous one: {}",
617 e.message()
618 ),
619 }
620 }
621 }));
622 }
623
624 let (done_tx, mut done_rx) = tokio::sync::mpsc::channel::<()>(1);
626 tokio::pin!(signal);
627 let mut stop_at: Option<tokio::time::Instant> = None;
628 loop {
629 tokio::select! {
630 _ = &mut signal, if stop_at.is_none() => {
631 let _ = drain_tx.send(true);
632 if delay.is_zero() {
633 break;
634 }
635 stop_at = Some(tokio::time::Instant::now() + delay);
636 }
637 _ = tokio::time::sleep_until(stop_at.unwrap_or_else(tokio::time::Instant::now)), if stop_at.is_some() => break,
638 accepted = listener.accept() => match accepted {
639 Ok((stream, peer)) => {
640 let Some(guard) = conn_limits.admit(peer.ip()) else {
641 tokio::spawn(limits::refuse(stream));
642 continue;
643 };
644 #[cfg(feature = "tls")]
645 if let Some(config) = tls.clone() {
646 let (shared, shutdown, done) = (shared.clone(), shutdown.clone(), done_tx.clone());
647 tokio::spawn(async move {
648 let _guard = guard;
649 if let Ok((tls_stream, client_cert, h2)) = config.accept(stream).await {
653 let info = ConnInfo { peer, secure: true, client_cert };
654 serve_connection(tls_stream, info, shared, shutdown, done, _guard, h2).await;
655 }
656 });
657 continue;
658 }
659 let info = ConnInfo { peer, secure: false, client_cert: None };
660 let (shared, shutdown, done) = (shared.clone(), shutdown.clone(), done_tx.clone());
661 tokio::spawn(async move {
662 let h2 = h2c && is_h2c(&stream).await;
663 serve_connection(stream, info, shared, shutdown, done, guard, h2).await;
664 });
665 }
666 Err(e) => {
667 eprintln!("Failed to accept connection: {}", e);
669 tokio::time::sleep(Duration::from_millis(100)).await;
670 }
671 },
672 }
673 }
674
675 let _ = trigger.send(true);
676 drop(done_tx);
677 drop(listener);
678 let drain = async {
679 let _ = done_rx.recv().await;
680 for task in tasks {
681 let _ = task.await;
682 }
683 };
684 if tokio::time::timeout(grace, drain).await.is_err() {
685 eprintln!(
686 "Shutdown grace period of {:?} elapsed, stopping anyway",
687 grace
688 );
689 }
690 Ok(())
691 }
692
693 pub(crate) fn into_in_process(self) -> InProcess {
696 let app = self.finalize();
697 InProcess {
698 shared: Arc::new(app.into_shared(Shutdown::never())),
699 }
700 }
701
702 fn into_shared(self, shutdown: Shutdown) -> Shared {
703 Shared {
704 router: self.router,
705 middlewares: self.middlewares,
706 max_body_size: self.max_body_size,
707 body_limits: self.body_limits,
708 stream_bodies: self.stream_bodies,
709 trusted_proxies: self.trusted_proxies,
710 fallback: self.fallback,
711 catch_panics: self.catch_panics,
712 state: Arc::new(self.state),
713 shutdown,
714 header_read_timeout: self.header_read_timeout,
715 }
716 }
717
718 fn finalize(mut self) -> Self {
721 let Some(info) = self.openapi.take() else {
722 return self;
723 };
724 let spec = openapi::build(&info, self.router.registered(), &self.docs);
725 let spec = bytes::Bytes::from(serde_json::to_vec(&spec).unwrap_or_default());
726
727 let spec_handler = {
728 let spec = spec.clone();
729 move |_req: Request| {
730 let spec = spec.clone();
731 async move {
732 Ok(Response::ok()
733 .with_header("content-type", "application/json")
734 .with_body(spec))
735 }
736 }
737 };
738 self.insert_hidden("GET", &info.spec_path, Arc::new(spec_handler));
739
740 if let Some(docs_path) = &info.docs_path {
741 let page = openapi::swagger_ui_html(&info.title, &info.spec_path);
742 let page_handler = move |_req: Request| {
743 let page = page.clone();
744 async move { Ok(Response::html(page)) }
745 };
746 self.insert_hidden("GET", docs_path, Arc::new(page_handler));
747 }
748 self
749 }
750
751 fn insert_hidden(&mut self, method: &str, path: &str, handler: DynHandler) {
752 if let Err(e) = self
753 .router
754 .insert_as(RouteKind::Hidden, method, path, handler)
755 {
756 panic!("Failed to register {} route {}: {}", method, path, e);
757 }
758 }
759}
760
761const H2_PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
762
763async fn is_h2c(stream: &tokio::net::TcpStream) -> bool {
767 let sniff = async {
768 let mut buf = [0u8; 24];
769 loop {
770 match stream.peek(&mut buf).await {
771 Ok(0) | Err(_) => return false,
772 Ok(n) if buf[..n] != H2_PREFACE[..n] => return false,
773 Ok(24) => return true,
774 Ok(_) => tokio::time::sleep(Duration::from_millis(5)).await,
776 }
777 }
778 };
779 tokio::time::timeout(Duration::from_secs(10), sniff)
780 .await
781 .unwrap_or(false)
782}
783
784async fn serve_connection<S>(
786 stream: S,
787 info: ConnInfo,
788 shared: Arc<Shared>,
789 shutdown: Shutdown,
790 _done: tokio::sync::mpsc::Sender<()>,
791 _guard: ConnGuard,
792 h2: bool,
793) where
794 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
795{
796 let io = TokioIo::new(stream);
797 let info = Arc::new(info);
798 let service = service_fn(|req| {
799 let (shared, info) = (shared.clone(), info.clone());
800 async move { Ok::<_, Infallible>(handle_request(req, &info, shared).await) }
801 });
802
803 if h2 {
804 let conn = http2::Builder::new(TokioExecutor::new())
806 .timer(TokioTimer::new())
807 .max_concurrent_streams(128)
808 .keep_alive_interval(Duration::from_secs(30))
810 .keep_alive_timeout(Duration::from_secs(20))
811 .serve_connection(io, service);
812 drive(conn, &shutdown, |c| c.graceful_shutdown()).await;
813 } else {
814 let mut builder = http1::Builder::new();
815 if let Some(timeout) = shared.header_read_timeout {
816 builder
817 .timer(TokioTimer::new())
818 .header_read_timeout(timeout);
819 }
820 let conn = builder.serve_connection(io, service).with_upgrades();
821 drive(conn, &shutdown, |c| c.graceful_shutdown()).await;
822 }
823}
824
825async fn drive<C>(conn: C, shutdown: &Shutdown, graceful: impl Fn(std::pin::Pin<&mut C>))
828where
829 C: std::future::Future<Output = std::result::Result<(), hyper::Error>>,
830{
831 tokio::pin!(conn);
832 let mut draining = false;
833 loop {
834 tokio::select! {
835 result = conn.as_mut() => {
836 if let Err(err) = &result {
838 if !err.is_timeout() {
839 eprintln!("Error serving connection: {:?}", err);
840 }
841 }
842 return;
843 }
844 _ = shutdown.wait(), if !draining => {
845 graceful(conn.as_mut());
846 draining = true;
847 }
848 }
849 }
850}
851
852async fn termination_signal() {
854 #[cfg(unix)]
855 {
856 use tokio::signal::unix::{signal, SignalKind};
857 match signal(SignalKind::terminate()) {
858 Ok(mut term) => {
859 tokio::select! {
860 _ = tokio::signal::ctrl_c() => {}
861 _ = term.recv() => {}
862 }
863 return;
864 }
865 Err(e) => eprintln!("Cannot listen for SIGTERM: {}", e),
866 }
867 }
868 let _ = tokio::signal::ctrl_c().await;
869}
870
871impl Default for App {
872 fn default() -> Self {
873 Self::new()
874 }
875}
876
877impl RouteGroup {
878 fn new(prefix: &str) -> Self {
879 let prefix = prefix.trim_end_matches('/');
880 Self {
881 prefix: prefix.to_string(),
882 routes: Vec::new(),
883 middlewares: Vec::new(),
884 docs: Vec::new(),
885 body_limit: None,
886 ws_paths: Vec::new(),
887 }
888 }
889
890 #[cfg(feature = "websocket")]
894 pub fn ws_with<F, Fut>(
895 mut self,
896 path: &str,
897 options: crate::websocket::WsOptions,
898 handler: F,
899 ) -> Self
900 where
901 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
902 Fut: std::future::Future<Output = ()> + Send + 'static,
903 {
904 let route = crate::websocket::WsRoute::new(handler, options);
905 self.routes.push((
906 "GET".to_string(),
907 path.to_string(),
908 Arc::new(route) as DynHandler,
909 ));
910 self.ws_paths.push(path.to_string());
911 self
912 }
913
914 pub fn max_body_size(mut self, limit: Option<usize>) -> Self {
917 self.body_limit = Some(limit);
918 self
919 }
920
921 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
924 self.docs
925 .push((method.to_ascii_uppercase(), path.to_string(), operation));
926 self
927 }
928
929 pub fn get<H>(mut self, path: &str, handler: H) -> Self
930 where
931 H: Handler,
932 {
933 self.routes.push((
934 "GET".to_string(),
935 path.to_string(),
936 Arc::new(handler) as DynHandler,
937 ));
938 self
939 }
940
941 pub fn post<H>(mut self, path: &str, handler: H) -> Self
942 where
943 H: Handler,
944 {
945 self.routes.push((
946 "POST".to_string(),
947 path.to_string(),
948 Arc::new(handler) as DynHandler,
949 ));
950 self
951 }
952
953 pub fn put<H>(mut self, path: &str, handler: H) -> Self
954 where
955 H: Handler,
956 {
957 self.routes.push((
958 "PUT".to_string(),
959 path.to_string(),
960 Arc::new(handler) as DynHandler,
961 ));
962 self
963 }
964
965 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
966 where
967 H: Handler,
968 {
969 self.routes.push((
970 "DELETE".to_string(),
971 path.to_string(),
972 Arc::new(handler) as DynHandler,
973 ));
974 self
975 }
976
977 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
978 where
979 H: Handler,
980 {
981 self.routes.push((
982 "PATCH".to_string(),
983 path.to_string(),
984 Arc::new(handler) as DynHandler,
985 ));
986 self
987 }
988
989 pub fn middleware<M>(mut self, middleware: M) -> Self
994 where
995 M: Middleware,
996 {
997 self.middlewares.push(Arc::new(middleware));
998 self
999 }
1000}
1001
1002async fn handle_request(
1003 req: hyper::Request<hyper::body::Incoming>,
1004 conn: &ConnInfo,
1005 shared: Arc<Shared>,
1006) -> hyper::Response<crate::response::HyperBody> {
1007 let path = req.uri().path().to_string();
1008 let max_body_size = body_limit_for(&shared.body_limits, &path, shared.max_body_size);
1009 let streaming = stream_limit_for(&shared.stream_bodies, &path);
1010
1011 let (parts, body) = req.into_parts();
1013
1014 let (body, stream) = match streaming {
1016 Some(limit) => (
1017 None,
1018 Some(crate::upload::BodyStream::from_incoming(body, limit)),
1019 ),
1020 None => (Some(body), None),
1021 };
1022 let body_bytes = match body {
1025 None => bytes::Bytes::new(),
1026 Some(body) => match max_body_size {
1027 Some(max_size) => match read_limited(body, max_size).await {
1028 Ok(bytes) => bytes,
1029 Err(too_large) => return too_large.into_hyper(max_size),
1030 },
1031 None => match body.collect().await {
1032 Ok(collected) => collected.to_bytes(),
1033 Err(_) => bytes::Bytes::new(),
1034 },
1035 },
1036 };
1037
1038 let mut headers = parts.headers;
1039 if !headers.contains_key(http::header::HOST) {
1041 if let Some(authority) = parts.uri.authority() {
1042 if let Ok(v) = http::HeaderValue::from_str(authority.as_str()) {
1043 headers.insert(http::header::HOST, v);
1044 }
1045 }
1046 }
1047 let mut request = Request::new(parts.method, parts.uri, headers, body_bytes);
1048 request.extensions = parts.extensions;
1049 request.stream = stream;
1050 run_pipeline(request, conn, &shared).await.into_hyper()
1051}
1052
1053pub(crate) struct InProcess {
1055 shared: Arc<Shared>,
1056}
1057
1058impl InProcess {
1059 pub(crate) async fn call(
1060 &self,
1061 request: Request,
1062 peer: SocketAddr,
1063 secure: bool,
1064 ) -> hyper::Response<crate::response::HyperBody> {
1065 let mut request = request;
1066 if let Some(limit) = stream_limit_for(&self.shared.stream_bodies, request.uri.path()) {
1067 let body = std::mem::take(&mut request.body);
1068 request.stream = Some(crate::upload::BodyStream::from_bytes(body, limit));
1069 } else {
1070 let max = body_limit_for(
1071 &self.shared.body_limits,
1072 request.uri.path(),
1073 self.shared.max_body_size,
1074 );
1075 if let Some(max) = max.filter(|max| request.body.len() > *max) {
1076 return BodyTooLarge.into_hyper(max);
1077 }
1078 }
1079 let conn = ConnInfo {
1080 peer,
1081 secure,
1082 client_cert: None,
1083 };
1084 run_pipeline(request, &conn, &self.shared)
1085 .await
1086 .into_hyper()
1087 }
1088}
1089
1090async fn run_pipeline(mut request: Request, conn: &ConnInfo, shared: &Shared) -> Response {
1092 let Shared {
1093 router,
1094 middlewares,
1095 state,
1096 shutdown,
1097 ..
1098 } = shared;
1099 let method = request.method.to_string();
1100 let is_head = request.method == http::Method::HEAD;
1101 let path = request.uri.path().to_string();
1102 request.remote_addr = Some(conn.peer);
1103 request.secure = conn.secure;
1104 if let Some(cert) = &conn.client_cert {
1105 request
1106 .extensions
1107 .insert(crate::request::ClientCertificate(cert.clone()));
1108 }
1109 request.state = Some(state.clone());
1110 request.trusted_proxies = shared.trusted_proxies.clone();
1111 request.shutdown = Some(shutdown.clone());
1112
1113 let route = match router.match_route_with_pattern(&method, &path) {
1116 Ok((handler, params, pattern)) => {
1117 request.params = params;
1118 request.matched_path = Some(pattern);
1119 Route::Found(handler)
1120 }
1121 Err(_) => {
1122 let allow = router.allowed_methods(&path);
1123 match (&shared.fallback, allow.is_empty()) {
1124 (Some(handler), true) => Route::Found(handler.clone()),
1125 _ => Route::Miss { allow },
1126 }
1127 }
1128 };
1129 let catch = shared.catch_panics;
1130
1131 let result = if middlewares.is_empty() {
1132 dispatch(route, request, catch).await
1133 } else {
1134 let mut chain = middlewares.to_vec();
1136 let final_handler = Arc::new(move |req: Request, _next: Next| {
1137 let route = route.clone();
1138 async move { dispatch(route, req, catch).await }
1139 });
1140 chain.push(final_handler as Arc<dyn Middleware>);
1141
1142 Next::new(Arc::new(chain)).run(request).await
1143 };
1144
1145 let response = match result {
1147 Ok(resp) => resp,
1148 Err(err) => Response::from_error(err),
1149 };
1150
1151 if is_head {
1153 response.into_head()
1154 } else {
1155 response
1156 }
1157}
1158
1159const DRAIN_CAP: u64 = 8 * 1024 * 1024;
1163const DRAIN_TIME: Duration = Duration::from_secs(3);
1164
1165struct BodyTooLarge;
1166
1167impl BodyTooLarge {
1168 fn into_hyper(self, max_size: usize) -> hyper::Response<crate::response::HyperBody> {
1169 Response::from_error(Error::custom(
1170 413,
1171 format!("Request body too large (max {} bytes)", max_size),
1172 ))
1173 .with_header("connection", "close")
1175 .into_hyper()
1176 }
1177}
1178
1179async fn read_limited(
1181 mut body: hyper::body::Incoming,
1182 max: usize,
1183) -> std::result::Result<bytes::Bytes, BodyTooLarge> {
1184 use bytes::BufMut;
1185 use hyper::body::Body;
1186
1187 if body.size_hint().lower() > max as u64 {
1189 drain(&mut body, 0).await;
1190 return Err(BodyTooLarge);
1191 }
1192
1193 let mut buf = bytes::BytesMut::new();
1194 while let Some(frame) = body.frame().await {
1195 let Ok(frame) = frame else {
1196 return Ok(bytes::Bytes::new());
1197 };
1198 if let Ok(data) = frame.into_data() {
1199 if buf.len() + data.len() > max {
1200 drain(&mut body, (buf.len() + data.len()) as u64).await;
1201 return Err(BodyTooLarge);
1202 }
1203 buf.put(data);
1204 }
1205 }
1206 Ok(buf.freeze())
1207}
1208
1209pub(crate) async fn drain(body: &mut hyper::body::Incoming, already: u64) {
1211 let _ = tokio::time::timeout(DRAIN_TIME, async {
1212 let mut seen = already;
1213 while seen < DRAIN_CAP {
1214 match body.frame().await {
1215 Some(Ok(frame)) => {
1216 if let Ok(data) = frame.into_data() {
1217 seen += data.len() as u64;
1218 }
1219 }
1220 _ => return,
1221 }
1222 }
1223 })
1224 .await;
1225}
1226
1227fn stream_limit_for(rules: &[(String, Option<u64>)], path: &str) -> Option<Option<u64>> {
1231 rules
1232 .iter()
1233 .filter(|(prefix, _)| {
1234 prefix.is_empty()
1235 || path == prefix
1236 || path
1237 .strip_prefix(prefix.as_str())
1238 .is_some_and(|rest| rest.starts_with('/'))
1239 })
1240 .max_by_key(|(prefix, _)| prefix.len())
1241 .map(|(_, limit)| *limit)
1242}
1243
1244fn body_limit_for(
1245 rules: &[(String, Option<usize>)],
1246 path: &str,
1247 default: Option<usize>,
1248) -> Option<usize> {
1249 rules
1250 .iter()
1251 .filter(|(prefix, _)| {
1252 prefix.is_empty()
1253 || path == prefix
1254 || path
1255 .strip_prefix(prefix.as_str())
1256 .is_some_and(|rest| rest.starts_with('/'))
1257 })
1258 .max_by_key(|(prefix, _)| prefix.len())
1259 .map(|(_, limit)| *limit)
1260 .unwrap_or(default)
1261}
1262
1263#[derive(Clone)]
1265enum Route {
1266 Found(DynHandler),
1267 Miss {
1269 allow: Vec<&'static str>,
1270 },
1271}
1272
1273async fn dispatch(route: Route, req: Request, catch: bool) -> Result<Response> {
1274 match route {
1275 Route::Found(handler) if catch => CatchPanic(handler.call(req)).await,
1276 Route::Found(handler) => handler.call(req).await,
1277 Route::Miss { allow } if allow.is_empty() => Err(Error::not_found("Route not found")),
1278 Route::Miss { allow } => {
1279 let allow = allow.join(", ");
1280 if req.method == http::Method::OPTIONS {
1281 Ok(Response::new(http::StatusCode::NO_CONTENT).with_header("allow", allow))
1284 } else {
1285 Ok(
1286 Response::from_error(Error::custom(405, "Method not allowed"))
1287 .with_header("allow", allow),
1288 )
1289 }
1290 }
1291 }
1292}
1293
1294struct CatchPanic<F>(F);
1297
1298impl<F> std::future::Future for CatchPanic<F>
1299where
1300 F: std::future::Future<Output = Result<Response>> + Unpin,
1301{
1302 type Output = Result<Response>;
1303
1304 fn poll(
1305 mut self: std::pin::Pin<&mut Self>,
1306 cx: &mut std::task::Context<'_>,
1307 ) -> std::task::Poll<Self::Output> {
1308 let inner = &mut self.0;
1309 match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1310 std::pin::Pin::new(inner).poll(cx)
1311 })) {
1312 Ok(poll) => poll,
1313 Err(payload) => {
1314 let what = payload
1315 .downcast_ref::<&str>()
1316 .map(|s| s.to_string())
1317 .or_else(|| payload.downcast_ref::<String>().cloned())
1318 .unwrap_or_else(|| "unknown panic".into());
1319 eprintln!("Handler panicked: {what}");
1320 std::task::Poll::Ready(Err(Error::internal("Internal server error")))
1322 }
1323 }
1324 }
1325}