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