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 #[cfg(feature = "tls")]
40 tls: Option<crate::tls::TlsConfig>,
41 #[cfg(feature = "tls")]
42 tls_reload: Option<Duration>,
43}
44
45struct ConnInfo {
47 peer: SocketAddr,
48 secure: bool,
49 client_cert: Option<Vec<u8>>,
50}
51
52type BackgroundTask = Box<dyn FnOnce(Context) -> BoxFuture<'static, ()> + Send>;
53
54struct Shared {
56 router: Router,
57 middlewares: Vec<Arc<dyn Middleware>>,
58 max_body_size: Option<usize>,
59 body_limits: Vec<(String, Option<usize>)>,
60 stream_bodies: Vec<(String, Option<u64>)>,
61 state: Arc<StateMap>,
62 shutdown: Shutdown,
63 header_read_timeout: Option<Duration>,
64}
65
66pub struct RouteGroup {
68 prefix: String,
69 routes: Vec<(String, String, DynHandler)>, middlewares: Vec<Arc<dyn Middleware>>,
71 docs: Vec<(String, String, Operation)>, body_limit: Option<Option<usize>>,
73 ws_paths: Vec<String>,
75}
76
77impl App {
78 pub fn new() -> Self {
79 Self {
80 router: Router::new(),
81 middlewares: Vec::new(),
82 max_body_size: Some(10 * 1024 * 1024), docs: HashMap::new(),
84 openapi: None,
85 state: StateMap::default(),
86 background: Vec::new(),
87 shutdown_grace: Duration::from_secs(10),
88 shutdown_delay: Duration::ZERO,
89 body_limits: Vec::new(),
90 stream_bodies: Vec::new(),
91 header_read_timeout: Some(Duration::from_secs(30)),
92 max_connections: None,
93 max_connections_per_ip: None,
94 #[cfg(feature = "tls")]
95 tls: None,
96 #[cfg(feature = "tls")]
97 tls_reload: None,
98 }
99 }
100
101 pub fn max_body_size(mut self, size: Option<usize>) -> Self {
103 self.max_body_size = size;
104 self
105 }
106
107 pub fn body_limit(mut self, prefix: &str, limit: Option<usize>) -> Self {
114 self.body_limits
115 .push((prefix.trim_end_matches('/').to_string(), limit));
116 self
117 }
118
119 pub fn state<T: Send + Sync + 'static>(mut self, value: T) -> Self {
141 self.state.insert(value);
142 self
143 }
144
145 pub fn background<F, Fut>(mut self, task: F) -> Self
166 where
167 F: FnOnce(Context) -> Fut + Send + 'static,
168 Fut: std::future::Future<Output = ()> + Send + 'static,
169 {
170 self.background
171 .push(Box::new(move |ctx| Box::pin(task(ctx))));
172 self
173 }
174
175 #[cfg(feature = "tls")]
177 pub fn tls(mut self, config: crate::tls::TlsConfig) -> Self {
178 self.tls = Some(config);
179 self
180 }
181
182 #[cfg(feature = "tls")]
187 pub fn tls_reload_every(mut self, interval: Duration) -> Self {
188 self.tls_reload = Some(interval);
189 self
190 }
191
192 pub fn header_read_timeout(mut self, timeout: impl Into<Option<Duration>>) -> Self {
197 self.header_read_timeout = timeout.into();
198 self
199 }
200
201 pub fn max_connections(mut self, max: usize) -> Self {
205 self.max_connections = Some(max.max(1));
206 self
207 }
208
209 pub fn max_connections_per_ip(mut self, max: usize) -> Self {
213 self.max_connections_per_ip = Some(max.max(1));
214 self
215 }
216
217 pub fn shutdown_grace(mut self, grace: Duration) -> Self {
220 self.shutdown_grace = grace;
221 self
222 }
223
224 pub fn stream_body(mut self, prefix: &str, max_bytes: Option<u64>) -> Self {
229 self.stream_bodies.push((prefix.to_string(), max_bytes));
230 self
231 }
232
233 pub fn shutdown_delay(mut self, delay: Duration) -> Self {
240 self.shutdown_delay = delay;
241 self
242 }
243
244 pub fn group(mut self, prefix: &str, configure: impl FnOnce(RouteGroup) -> RouteGroup) -> Self {
246 let group = RouteGroup::new(prefix);
247 let group = configure(group);
248
249 if let Some(limit) = group.body_limit {
250 self.body_limits.push((group.prefix.clone(), limit));
251 }
252 for (method, path, op) in group.docs {
253 let full_path = format!("{}{}", group.prefix, path);
254 self.docs.insert((method, full_path), op);
255 }
256
257 let middlewares = group.middlewares;
259 for (method, path, handler) in group.routes {
260 let full_path = format!("{}{}", group.prefix, path);
261 let handler: DynHandler = if middlewares.is_empty() {
262 handler
263 } else {
264 Arc::new(Layered::new(middlewares.clone(), handler))
265 };
266 let kind = if method == "GET" && group.ws_paths.contains(&path) {
267 RouteKind::WebSocket
268 } else {
269 RouteKind::Http
270 };
271 if let Err(e) = self.router.insert_as(kind, &method, &full_path, handler) {
272 panic!("Failed to register {} route {}: {}", method, full_path, e);
273 }
274 }
275
276 self
277 }
278
279 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
283 self.docs
284 .insert((method.to_ascii_uppercase(), path.to_string()), operation);
285 self
286 }
287
288 pub fn openapi(mut self, info: OpenApiInfo) -> Self {
292 self.openapi = Some(info);
293 self
294 }
295
296 pub fn get<H>(mut self, path: &str, handler: H) -> Self
298 where
299 H: Handler,
300 {
301 if let Err(e) = self
302 .router
303 .insert("GET", path, Arc::new(handler) as DynHandler)
304 {
305 panic!("Failed to register GET route {}: {}", path, e);
306 }
307 self
308 }
309
310 pub fn get_with_params<F, Fut>(mut self, path: &str, handler: F) -> Self
312 where
313 F: Fn(Params) -> Fut + Send + Sync + 'static,
314 Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
315 {
316 if let Err(e) = self.router.insert(
317 "GET",
318 path,
319 Arc::new(HandlerWithParams::new(handler)) as DynHandler,
320 ) {
321 panic!("Failed to register GET route {}: {}", path, e);
322 }
323 self
324 }
325
326 pub fn post<H>(mut self, path: &str, handler: H) -> Self
328 where
329 H: Handler,
330 {
331 if let Err(e) = self
332 .router
333 .insert("POST", path, Arc::new(handler) as DynHandler)
334 {
335 panic!("Failed to register POST route {}: {}", path, e);
336 }
337 self
338 }
339
340 pub fn put<H>(mut self, path: &str, handler: H) -> Self
342 where
343 H: Handler,
344 {
345 if let Err(e) = self
346 .router
347 .insert("PUT", path, Arc::new(handler) as DynHandler)
348 {
349 panic!("Failed to register PUT route {}: {}", path, e);
350 }
351 self
352 }
353
354 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
356 where
357 H: Handler,
358 {
359 if let Err(e) = self
360 .router
361 .insert("DELETE", path, Arc::new(handler) as DynHandler)
362 {
363 panic!("Failed to register DELETE route {}: {}", path, e);
364 }
365 self
366 }
367
368 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
370 where
371 H: Handler,
372 {
373 if let Err(e) = self
374 .router
375 .insert("PATCH", path, Arc::new(handler) as DynHandler)
376 {
377 panic!("Failed to register PATCH route {}: {}", path, e);
378 }
379 self
380 }
381
382 #[cfg(feature = "websocket")]
388 pub fn ws<F, Fut>(self, path: &str, handler: F) -> Self
389 where
390 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
391 Fut: std::future::Future<Output = ()> + Send + 'static,
392 {
393 self.ws_with(path, crate::websocket::WsOptions::default(), handler)
394 }
395
396 #[cfg(feature = "websocket")]
398 pub fn ws_with<F, Fut>(
399 mut self,
400 path: &str,
401 options: crate::websocket::WsOptions,
402 handler: F,
403 ) -> Self
404 where
405 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
406 Fut: std::future::Future<Output = ()> + Send + 'static,
407 {
408 let route = crate::websocket::WsRoute::new(handler, options);
409 if let Err(e) = self.router.insert_as(
410 RouteKind::WebSocket,
411 "GET",
412 path,
413 Arc::new(route) as DynHandler,
414 ) {
415 panic!("Failed to register WebSocket route {}: {}", path, e);
416 }
417 self
418 }
419
420 pub fn middleware<M>(mut self, middleware: M) -> Self
422 where
423 M: Middleware,
424 {
425 self.middlewares.push(Arc::new(middleware));
426 self
427 }
428
429 pub fn serve_static(mut self, route_prefix: &str, dir_path: &str) -> Self {
431 use crate::static_files::StaticFileHandler;
432 let handler = StaticFileHandler::new(dir_path);
433 let prefix = route_prefix.trim_end_matches('/');
435 let handler: DynHandler = Arc::new(handler);
436 let route = format!("{}/{{*filepath}}", prefix);
437 if let Err(e) = self
438 .router
439 .insert_as(RouteKind::Hidden, "GET", &route, handler.clone())
440 {
441 panic!("Failed to register static file route {}: {}", route, e);
442 }
443 let root = if prefix.is_empty() { "/" } else { prefix };
446 let _ = self
447 .router
448 .insert_as(RouteKind::Hidden, "GET", root, handler.clone());
449 if !prefix.is_empty() {
450 let _ =
451 self.router
452 .insert_as(RouteKind::Hidden, "GET", &format!("{}/", prefix), handler);
453 }
454 self
455 }
456
457 pub async fn run(self, addr: &str) -> Result<()> {
462 let addr: SocketAddr = addr
463 .parse()
464 .map_err(|e| Error::internal(format!("Invalid address: {}", e)))?;
465
466 let listener = TcpListener::bind(addr)
467 .await
468 .map_err(|e| Error::internal(format!("Failed to bind: {}", e)))?;
469
470 #[cfg(feature = "tls")]
471 let scheme = if self.tls.is_some() { "https" } else { "http" };
472 #[cfg(not(feature = "tls"))]
473 let scheme = "http";
474 println!("🚀 ullun-api listening on {}://{}", scheme, addr);
475
476 let result = self
477 .serve_with_shutdown(listener, async {
478 termination_signal().await;
479 println!("\n🛑 Shutting down gracefully...");
480 })
481 .await;
482 println!("✅ Server stopped");
483 result
484 }
485
486 pub async fn serve(self, listener: TcpListener) -> Result<()> {
493 self.serve_with_shutdown(listener, std::future::pending())
494 .await
495 }
496
497 pub async fn serve_with_shutdown(
504 mut self,
505 listener: TcpListener,
506 signal: impl std::future::Future<Output = ()>,
507 ) -> Result<()> {
508 self = self.finalize();
509 let grace = self.shutdown_grace;
510 let delay = self.shutdown_delay;
511 let background = std::mem::take(&mut self.background);
512 #[cfg(feature = "tls")]
513 let tls = self.tls.take();
514 #[cfg(feature = "tls")]
515 let tls_reload = self.tls_reload;
516 let conn_limits = ConnLimits::new(self.max_connections, self.max_connections_per_ip);
517 let (trigger, rx) = tokio::sync::watch::channel(false);
518 let (drain_tx, drain_rx) = tokio::sync::watch::channel(false);
519 let shutdown = Shutdown::with_drain(rx, drain_rx);
520 let shared = Arc::new(self.into_shared(shutdown.clone()));
521
522 #[allow(unused_mut)]
523 let mut tasks: Vec<_> = background
524 .into_iter()
525 .map(|task| {
526 let ctx = Context::new(shared.state.clone(), shutdown.clone());
527 tokio::spawn(task(ctx))
528 })
529 .collect();
530
531 #[cfg(feature = "tls")]
532 if let (Some(config), Some(every)) = (tls.clone(), tls_reload) {
533 let shutdown = shutdown.clone();
534 tasks.push(tokio::spawn(async move {
535 while shutdown.sleep(every).await {
536 match config.reload() {
537 Ok(true) => println!("🔐 TLS certificate reloaded"),
538 Ok(false) => {}
539 Err(e) => eprintln!(
540 "TLS certificate reload failed, keeping the previous one: {}",
541 e.message()
542 ),
543 }
544 }
545 }));
546 }
547
548 let (done_tx, mut done_rx) = tokio::sync::mpsc::channel::<()>(1);
550 tokio::pin!(signal);
551 let mut stop_at: Option<tokio::time::Instant> = None;
552 loop {
553 tokio::select! {
554 _ = &mut signal, if stop_at.is_none() => {
555 let _ = drain_tx.send(true);
556 if delay.is_zero() {
557 break;
558 }
559 stop_at = Some(tokio::time::Instant::now() + delay);
560 }
561 _ = tokio::time::sleep_until(stop_at.unwrap_or_else(tokio::time::Instant::now)), if stop_at.is_some() => break,
562 accepted = listener.accept() => match accepted {
563 Ok((stream, peer)) => {
564 let Some(guard) = conn_limits.admit(peer.ip()) else {
565 tokio::spawn(limits::refuse(stream));
566 continue;
567 };
568 #[cfg(feature = "tls")]
569 if let Some(config) = tls.clone() {
570 let (shared, shutdown, done) = (shared.clone(), shutdown.clone(), done_tx.clone());
571 tokio::spawn(async move {
572 let _guard = guard;
573 if let Ok((tls_stream, client_cert, h2)) = config.accept(stream).await {
577 let info = ConnInfo { peer, secure: true, client_cert };
578 serve_connection(tls_stream, info, shared, shutdown, done, _guard, h2).await;
579 }
580 });
581 continue;
582 }
583 let info = ConnInfo { peer, secure: false, client_cert: None };
584 tokio::spawn(serve_connection(
585 stream,
586 info,
587 shared.clone(),
588 shutdown.clone(),
589 done_tx.clone(),
590 guard,
591 false,
592 ));
593 }
594 Err(e) => {
595 eprintln!("Failed to accept connection: {}", e);
597 tokio::time::sleep(Duration::from_millis(100)).await;
598 }
599 },
600 }
601 }
602
603 let _ = trigger.send(true);
604 drop(done_tx);
605 drop(listener);
606 let drain = async {
607 let _ = done_rx.recv().await;
608 for task in tasks {
609 let _ = task.await;
610 }
611 };
612 if tokio::time::timeout(grace, drain).await.is_err() {
613 eprintln!(
614 "Shutdown grace period of {:?} elapsed, stopping anyway",
615 grace
616 );
617 }
618 Ok(())
619 }
620
621 pub(crate) fn into_in_process(self) -> InProcess {
624 let app = self.finalize();
625 InProcess {
626 shared: Arc::new(app.into_shared(Shutdown::never())),
627 }
628 }
629
630 fn into_shared(self, shutdown: Shutdown) -> Shared {
631 Shared {
632 router: self.router,
633 middlewares: self.middlewares,
634 max_body_size: self.max_body_size,
635 body_limits: self.body_limits,
636 stream_bodies: self.stream_bodies,
637 state: Arc::new(self.state),
638 shutdown,
639 header_read_timeout: self.header_read_timeout,
640 }
641 }
642
643 fn finalize(mut self) -> Self {
646 let Some(info) = self.openapi.take() else {
647 return self;
648 };
649 let spec = openapi::build(&info, self.router.registered(), &self.docs);
650 let spec = bytes::Bytes::from(serde_json::to_vec(&spec).unwrap_or_default());
651
652 let spec_handler = {
653 let spec = spec.clone();
654 move |_req: Request| {
655 let spec = spec.clone();
656 async move {
657 Ok(Response::ok()
658 .with_header("content-type", "application/json")
659 .with_body(spec))
660 }
661 }
662 };
663 self.insert_hidden("GET", &info.spec_path, Arc::new(spec_handler));
664
665 if let Some(docs_path) = &info.docs_path {
666 let page = openapi::swagger_ui_html(&info.title, &info.spec_path);
667 let page_handler = move |_req: Request| {
668 let page = page.clone();
669 async move { Ok(Response::html(page)) }
670 };
671 self.insert_hidden("GET", docs_path, Arc::new(page_handler));
672 }
673 self
674 }
675
676 fn insert_hidden(&mut self, method: &str, path: &str, handler: DynHandler) {
677 if let Err(e) = self
678 .router
679 .insert_as(RouteKind::Hidden, method, path, handler)
680 {
681 panic!("Failed to register {} route {}: {}", method, path, e);
682 }
683 }
684}
685
686async fn serve_connection<S>(
688 stream: S,
689 info: ConnInfo,
690 shared: Arc<Shared>,
691 shutdown: Shutdown,
692 _done: tokio::sync::mpsc::Sender<()>,
693 _guard: ConnGuard,
694 h2: bool,
695) where
696 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
697{
698 let io = TokioIo::new(stream);
699 let info = Arc::new(info);
700 let service = service_fn(|req| {
701 let (shared, info) = (shared.clone(), info.clone());
702 async move { Ok::<_, Infallible>(handle_request(req, &info, shared).await) }
703 });
704
705 if h2 {
706 let conn = http2::Builder::new(TokioExecutor::new())
708 .timer(TokioTimer::new())
709 .max_concurrent_streams(128)
710 .keep_alive_interval(Duration::from_secs(30))
712 .keep_alive_timeout(Duration::from_secs(20))
713 .serve_connection(io, service);
714 drive(conn, &shutdown, |c| c.graceful_shutdown()).await;
715 } else {
716 let mut builder = http1::Builder::new();
717 if let Some(timeout) = shared.header_read_timeout {
718 builder
719 .timer(TokioTimer::new())
720 .header_read_timeout(timeout);
721 }
722 let conn = builder.serve_connection(io, service).with_upgrades();
723 drive(conn, &shutdown, |c| c.graceful_shutdown()).await;
724 }
725}
726
727async fn drive<C>(conn: C, shutdown: &Shutdown, graceful: impl Fn(std::pin::Pin<&mut C>))
730where
731 C: std::future::Future<Output = std::result::Result<(), hyper::Error>>,
732{
733 tokio::pin!(conn);
734 let mut draining = false;
735 loop {
736 tokio::select! {
737 result = conn.as_mut() => {
738 if let Err(err) = &result {
740 if !err.is_timeout() {
741 eprintln!("Error serving connection: {:?}", err);
742 }
743 }
744 return;
745 }
746 _ = shutdown.wait(), if !draining => {
747 graceful(conn.as_mut());
748 draining = true;
749 }
750 }
751 }
752}
753
754async fn termination_signal() {
756 #[cfg(unix)]
757 {
758 use tokio::signal::unix::{signal, SignalKind};
759 match signal(SignalKind::terminate()) {
760 Ok(mut term) => {
761 tokio::select! {
762 _ = tokio::signal::ctrl_c() => {}
763 _ = term.recv() => {}
764 }
765 return;
766 }
767 Err(e) => eprintln!("Cannot listen for SIGTERM: {}", e),
768 }
769 }
770 let _ = tokio::signal::ctrl_c().await;
771}
772
773impl Default for App {
774 fn default() -> Self {
775 Self::new()
776 }
777}
778
779impl RouteGroup {
780 fn new(prefix: &str) -> Self {
781 let prefix = prefix.trim_end_matches('/');
782 Self {
783 prefix: prefix.to_string(),
784 routes: Vec::new(),
785 middlewares: Vec::new(),
786 docs: Vec::new(),
787 body_limit: None,
788 ws_paths: Vec::new(),
789 }
790 }
791
792 #[cfg(feature = "websocket")]
796 pub fn ws_with<F, Fut>(
797 mut self,
798 path: &str,
799 options: crate::websocket::WsOptions,
800 handler: F,
801 ) -> Self
802 where
803 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
804 Fut: std::future::Future<Output = ()> + Send + 'static,
805 {
806 let route = crate::websocket::WsRoute::new(handler, options);
807 self.routes.push((
808 "GET".to_string(),
809 path.to_string(),
810 Arc::new(route) as DynHandler,
811 ));
812 self.ws_paths.push(path.to_string());
813 self
814 }
815
816 pub fn max_body_size(mut self, limit: Option<usize>) -> Self {
819 self.body_limit = Some(limit);
820 self
821 }
822
823 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
826 self.docs
827 .push((method.to_ascii_uppercase(), path.to_string(), operation));
828 self
829 }
830
831 pub fn get<H>(mut self, path: &str, handler: H) -> Self
832 where
833 H: Handler,
834 {
835 self.routes.push((
836 "GET".to_string(),
837 path.to_string(),
838 Arc::new(handler) as DynHandler,
839 ));
840 self
841 }
842
843 pub fn post<H>(mut self, path: &str, handler: H) -> Self
844 where
845 H: Handler,
846 {
847 self.routes.push((
848 "POST".to_string(),
849 path.to_string(),
850 Arc::new(handler) as DynHandler,
851 ));
852 self
853 }
854
855 pub fn put<H>(mut self, path: &str, handler: H) -> Self
856 where
857 H: Handler,
858 {
859 self.routes.push((
860 "PUT".to_string(),
861 path.to_string(),
862 Arc::new(handler) as DynHandler,
863 ));
864 self
865 }
866
867 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
868 where
869 H: Handler,
870 {
871 self.routes.push((
872 "DELETE".to_string(),
873 path.to_string(),
874 Arc::new(handler) as DynHandler,
875 ));
876 self
877 }
878
879 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
880 where
881 H: Handler,
882 {
883 self.routes.push((
884 "PATCH".to_string(),
885 path.to_string(),
886 Arc::new(handler) as DynHandler,
887 ));
888 self
889 }
890
891 pub fn middleware<M>(mut self, middleware: M) -> Self
896 where
897 M: Middleware,
898 {
899 self.middlewares.push(Arc::new(middleware));
900 self
901 }
902}
903
904async fn handle_request(
905 req: hyper::Request<hyper::body::Incoming>,
906 conn: &ConnInfo,
907 shared: Arc<Shared>,
908) -> hyper::Response<crate::response::HyperBody> {
909 let path = req.uri().path().to_string();
910 let max_body_size = body_limit_for(&shared.body_limits, &path, shared.max_body_size);
911 let streaming = stream_limit_for(&shared.stream_bodies, &path);
912
913 let (parts, body) = req.into_parts();
915
916 let (body, stream) = match streaming {
918 Some(limit) => (
919 None,
920 Some(crate::upload::BodyStream::from_incoming(body, limit)),
921 ),
922 None => (Some(body), None),
923 };
924 let body_bytes = match body {
927 None => bytes::Bytes::new(),
928 Some(body) => match max_body_size {
929 Some(max_size) => match read_limited(body, max_size).await {
930 Ok(bytes) => bytes,
931 Err(too_large) => return too_large.into_hyper(max_size),
932 },
933 None => match body.collect().await {
934 Ok(collected) => collected.to_bytes(),
935 Err(_) => bytes::Bytes::new(),
936 },
937 },
938 };
939
940 let mut headers = parts.headers;
941 if !headers.contains_key(http::header::HOST) {
943 if let Some(authority) = parts.uri.authority() {
944 if let Ok(v) = http::HeaderValue::from_str(authority.as_str()) {
945 headers.insert(http::header::HOST, v);
946 }
947 }
948 }
949 let mut request = Request::new(parts.method, parts.uri, headers, body_bytes);
950 request.extensions = parts.extensions;
951 request.stream = stream;
952 run_pipeline(request, conn, &shared).await.into_hyper()
953}
954
955pub(crate) struct InProcess {
957 shared: Arc<Shared>,
958}
959
960impl InProcess {
961 pub(crate) async fn call(
962 &self,
963 request: Request,
964 peer: SocketAddr,
965 secure: bool,
966 ) -> hyper::Response<crate::response::HyperBody> {
967 let mut request = request;
968 if let Some(limit) = stream_limit_for(&self.shared.stream_bodies, request.uri.path()) {
969 let body = std::mem::take(&mut request.body);
970 request.stream = Some(crate::upload::BodyStream::from_bytes(body, limit));
971 } else {
972 let max = body_limit_for(
973 &self.shared.body_limits,
974 request.uri.path(),
975 self.shared.max_body_size,
976 );
977 if let Some(max) = max.filter(|max| request.body.len() > *max) {
978 return BodyTooLarge.into_hyper(max);
979 }
980 }
981 let conn = ConnInfo {
982 peer,
983 secure,
984 client_cert: None,
985 };
986 run_pipeline(request, &conn, &self.shared)
987 .await
988 .into_hyper()
989 }
990}
991
992async fn run_pipeline(mut request: Request, conn: &ConnInfo, shared: &Shared) -> Response {
994 let Shared {
995 router,
996 middlewares,
997 state,
998 shutdown,
999 ..
1000 } = shared;
1001 let method = request.method.to_string();
1002 let is_head = request.method == http::Method::HEAD;
1003 let path = request.uri.path().to_string();
1004 request.remote_addr = Some(conn.peer);
1005 request.secure = conn.secure;
1006 if let Some(cert) = &conn.client_cert {
1007 request
1008 .extensions
1009 .insert(crate::request::ClientCertificate(cert.clone()));
1010 }
1011 request.state = Some(state.clone());
1012 request.shutdown = Some(shutdown.clone());
1013
1014 let route = match router.match_route_with_pattern(&method, &path) {
1017 Ok((handler, params, pattern)) => {
1018 request.params = params;
1019 request.matched_path = Some(pattern);
1020 Route::Found(handler)
1021 }
1022 Err(_) => Route::Miss {
1023 allow: router.allowed_methods(&path),
1024 },
1025 };
1026
1027 let result = if middlewares.is_empty() {
1028 dispatch(route, request).await
1029 } else {
1030 let mut chain = middlewares.to_vec();
1032 let final_handler = Arc::new(move |req: Request, _next: Next| {
1033 let route = route.clone();
1034 async move { dispatch(route, req).await }
1035 });
1036 chain.push(final_handler as Arc<dyn Middleware>);
1037
1038 Next::new(Arc::new(chain)).run(request).await
1039 };
1040
1041 let response = match result {
1043 Ok(resp) => resp,
1044 Err(err) => Response::from_error(err),
1045 };
1046
1047 if is_head {
1049 response.into_head()
1050 } else {
1051 response
1052 }
1053}
1054
1055const DRAIN_CAP: u64 = 8 * 1024 * 1024;
1059const DRAIN_TIME: Duration = Duration::from_secs(3);
1060
1061struct BodyTooLarge;
1062
1063impl BodyTooLarge {
1064 fn into_hyper(self, max_size: usize) -> hyper::Response<crate::response::HyperBody> {
1065 Response::from_error(Error::custom(
1066 413,
1067 format!("Request body too large (max {} bytes)", max_size),
1068 ))
1069 .with_header("connection", "close")
1071 .into_hyper()
1072 }
1073}
1074
1075async fn read_limited(
1077 mut body: hyper::body::Incoming,
1078 max: usize,
1079) -> std::result::Result<bytes::Bytes, BodyTooLarge> {
1080 use bytes::BufMut;
1081 use hyper::body::Body;
1082
1083 if body.size_hint().lower() > max as u64 {
1085 drain(&mut body, 0).await;
1086 return Err(BodyTooLarge);
1087 }
1088
1089 let mut buf = bytes::BytesMut::new();
1090 while let Some(frame) = body.frame().await {
1091 let Ok(frame) = frame else {
1092 return Ok(bytes::Bytes::new());
1093 };
1094 if let Ok(data) = frame.into_data() {
1095 if buf.len() + data.len() > max {
1096 drain(&mut body, (buf.len() + data.len()) as u64).await;
1097 return Err(BodyTooLarge);
1098 }
1099 buf.put(data);
1100 }
1101 }
1102 Ok(buf.freeze())
1103}
1104
1105pub(crate) async fn drain(body: &mut hyper::body::Incoming, already: u64) {
1107 let _ = tokio::time::timeout(DRAIN_TIME, async {
1108 let mut seen = already;
1109 while seen < DRAIN_CAP {
1110 match body.frame().await {
1111 Some(Ok(frame)) => {
1112 if let Ok(data) = frame.into_data() {
1113 seen += data.len() as u64;
1114 }
1115 }
1116 _ => return,
1117 }
1118 }
1119 })
1120 .await;
1121}
1122
1123fn stream_limit_for(rules: &[(String, Option<u64>)], path: &str) -> Option<Option<u64>> {
1127 rules
1128 .iter()
1129 .filter(|(prefix, _)| {
1130 prefix.is_empty()
1131 || path == prefix
1132 || path
1133 .strip_prefix(prefix.as_str())
1134 .is_some_and(|rest| rest.starts_with('/'))
1135 })
1136 .max_by_key(|(prefix, _)| prefix.len())
1137 .map(|(_, limit)| *limit)
1138}
1139
1140fn body_limit_for(
1141 rules: &[(String, Option<usize>)],
1142 path: &str,
1143 default: Option<usize>,
1144) -> Option<usize> {
1145 rules
1146 .iter()
1147 .filter(|(prefix, _)| {
1148 prefix.is_empty()
1149 || path == prefix
1150 || path
1151 .strip_prefix(prefix.as_str())
1152 .is_some_and(|rest| rest.starts_with('/'))
1153 })
1154 .max_by_key(|(prefix, _)| prefix.len())
1155 .map(|(_, limit)| *limit)
1156 .unwrap_or(default)
1157}
1158
1159#[derive(Clone)]
1161enum Route {
1162 Found(DynHandler),
1163 Miss {
1165 allow: Vec<&'static str>,
1166 },
1167}
1168
1169async fn dispatch(route: Route, req: Request) -> Result<Response> {
1170 match route {
1171 Route::Found(handler) => handler.call(req).await,
1172 Route::Miss { allow } if allow.is_empty() => Err(Error::not_found("Route not found")),
1173 Route::Miss { allow } => {
1174 let allow = allow.join(", ");
1175 if req.method == http::Method::OPTIONS {
1176 Ok(Response::new(http::StatusCode::NO_CONTENT).with_header("allow", allow))
1179 } else {
1180 Ok(
1181 Response::from_error(Error::custom(405, "Method not allowed"))
1182 .with_header("allow", allow),
1183 )
1184 }
1185 }
1186 }
1187}