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;
14use hyper::service::service_fn;
15use hyper_util::rt::{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 body_limits: Vec<(String, Option<usize>)>,
34 header_read_timeout: Option<Duration>,
35 max_connections: Option<usize>,
36 max_connections_per_ip: Option<usize>,
37 #[cfg(feature = "tls")]
38 tls: Option<crate::tls::TlsConfig>,
39 #[cfg(feature = "tls")]
40 tls_reload: Option<Duration>,
41}
42
43struct ConnInfo {
45 peer: SocketAddr,
46 secure: bool,
47 client_cert: Option<Vec<u8>>,
48}
49
50type BackgroundTask = Box<dyn FnOnce(Context) -> BoxFuture<'static, ()> + Send>;
51
52struct Shared {
54 router: Router,
55 middlewares: Vec<Arc<dyn Middleware>>,
56 max_body_size: Option<usize>,
57 body_limits: Vec<(String, Option<usize>)>,
58 state: Arc<StateMap>,
59 shutdown: Shutdown,
60 header_read_timeout: Option<Duration>,
61}
62
63pub struct RouteGroup {
65 prefix: String,
66 routes: Vec<(String, String, DynHandler)>, middlewares: Vec<Arc<dyn Middleware>>,
68 docs: Vec<(String, String, Operation)>, body_limit: Option<Option<usize>>,
70 ws_paths: Vec<String>,
72}
73
74impl App {
75 pub fn new() -> Self {
76 Self {
77 router: Router::new(),
78 middlewares: Vec::new(),
79 max_body_size: Some(10 * 1024 * 1024), docs: HashMap::new(),
81 openapi: None,
82 state: StateMap::default(),
83 background: Vec::new(),
84 shutdown_grace: Duration::from_secs(10),
85 body_limits: Vec::new(),
86 header_read_timeout: Some(Duration::from_secs(30)),
87 max_connections: None,
88 max_connections_per_ip: None,
89 #[cfg(feature = "tls")]
90 tls: None,
91 #[cfg(feature = "tls")]
92 tls_reload: None,
93 }
94 }
95
96 pub fn max_body_size(mut self, size: Option<usize>) -> Self {
98 self.max_body_size = size;
99 self
100 }
101
102 pub fn body_limit(mut self, prefix: &str, limit: Option<usize>) -> Self {
109 self.body_limits
110 .push((prefix.trim_end_matches('/').to_string(), limit));
111 self
112 }
113
114 pub fn state<T: Send + Sync + 'static>(mut self, value: T) -> Self {
136 self.state.insert(value);
137 self
138 }
139
140 pub fn background<F, Fut>(mut self, task: F) -> Self
161 where
162 F: FnOnce(Context) -> Fut + Send + 'static,
163 Fut: std::future::Future<Output = ()> + Send + 'static,
164 {
165 self.background
166 .push(Box::new(move |ctx| Box::pin(task(ctx))));
167 self
168 }
169
170 #[cfg(feature = "tls")]
172 pub fn tls(mut self, config: crate::tls::TlsConfig) -> Self {
173 self.tls = Some(config);
174 self
175 }
176
177 #[cfg(feature = "tls")]
182 pub fn tls_reload_every(mut self, interval: Duration) -> Self {
183 self.tls_reload = Some(interval);
184 self
185 }
186
187 pub fn header_read_timeout(mut self, timeout: impl Into<Option<Duration>>) -> Self {
192 self.header_read_timeout = timeout.into();
193 self
194 }
195
196 pub fn max_connections(mut self, max: usize) -> Self {
200 self.max_connections = Some(max.max(1));
201 self
202 }
203
204 pub fn max_connections_per_ip(mut self, max: usize) -> Self {
208 self.max_connections_per_ip = Some(max.max(1));
209 self
210 }
211
212 pub fn shutdown_grace(mut self, grace: Duration) -> Self {
215 self.shutdown_grace = grace;
216 self
217 }
218
219 pub fn group(mut self, prefix: &str, configure: impl FnOnce(RouteGroup) -> RouteGroup) -> Self {
221 let group = RouteGroup::new(prefix);
222 let group = configure(group);
223
224 if let Some(limit) = group.body_limit {
225 self.body_limits.push((group.prefix.clone(), limit));
226 }
227 for (method, path, op) in group.docs {
228 let full_path = format!("{}{}", group.prefix, path);
229 self.docs.insert((method, full_path), op);
230 }
231
232 let middlewares = group.middlewares;
234 for (method, path, handler) in group.routes {
235 let full_path = format!("{}{}", group.prefix, path);
236 let handler: DynHandler = if middlewares.is_empty() {
237 handler
238 } else {
239 Arc::new(Layered::new(middlewares.clone(), handler))
240 };
241 let kind = if method == "GET" && group.ws_paths.contains(&path) {
242 RouteKind::WebSocket
243 } else {
244 RouteKind::Http
245 };
246 if let Err(e) = self.router.insert_as(kind, &method, &full_path, handler) {
247 panic!("Failed to register {} route {}: {}", method, full_path, e);
248 }
249 }
250
251 self
252 }
253
254 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
258 self.docs
259 .insert((method.to_ascii_uppercase(), path.to_string()), operation);
260 self
261 }
262
263 pub fn openapi(mut self, info: OpenApiInfo) -> Self {
267 self.openapi = Some(info);
268 self
269 }
270
271 pub fn get<H>(mut self, path: &str, handler: H) -> Self
273 where
274 H: Handler,
275 {
276 if let Err(e) = self
277 .router
278 .insert("GET", path, Arc::new(handler) as DynHandler)
279 {
280 panic!("Failed to register GET route {}: {}", path, e);
281 }
282 self
283 }
284
285 pub fn get_with_params<F, Fut>(mut self, path: &str, handler: F) -> Self
287 where
288 F: Fn(Params) -> Fut + Send + Sync + 'static,
289 Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
290 {
291 if let Err(e) = self.router.insert(
292 "GET",
293 path,
294 Arc::new(HandlerWithParams::new(handler)) as DynHandler,
295 ) {
296 panic!("Failed to register GET route {}: {}", path, e);
297 }
298 self
299 }
300
301 pub fn post<H>(mut self, path: &str, handler: H) -> Self
303 where
304 H: Handler,
305 {
306 if let Err(e) = self
307 .router
308 .insert("POST", path, Arc::new(handler) as DynHandler)
309 {
310 panic!("Failed to register POST route {}: {}", path, e);
311 }
312 self
313 }
314
315 pub fn put<H>(mut self, path: &str, handler: H) -> Self
317 where
318 H: Handler,
319 {
320 if let Err(e) = self
321 .router
322 .insert("PUT", path, Arc::new(handler) as DynHandler)
323 {
324 panic!("Failed to register PUT route {}: {}", path, e);
325 }
326 self
327 }
328
329 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
331 where
332 H: Handler,
333 {
334 if let Err(e) = self
335 .router
336 .insert("DELETE", path, Arc::new(handler) as DynHandler)
337 {
338 panic!("Failed to register DELETE route {}: {}", path, e);
339 }
340 self
341 }
342
343 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
345 where
346 H: Handler,
347 {
348 if let Err(e) = self
349 .router
350 .insert("PATCH", path, Arc::new(handler) as DynHandler)
351 {
352 panic!("Failed to register PATCH route {}: {}", path, e);
353 }
354 self
355 }
356
357 #[cfg(feature = "websocket")]
363 pub fn ws<F, Fut>(self, path: &str, handler: F) -> Self
364 where
365 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
366 Fut: std::future::Future<Output = ()> + Send + 'static,
367 {
368 self.ws_with(path, crate::websocket::WsOptions::default(), handler)
369 }
370
371 #[cfg(feature = "websocket")]
373 pub fn ws_with<F, Fut>(
374 mut self,
375 path: &str,
376 options: crate::websocket::WsOptions,
377 handler: F,
378 ) -> Self
379 where
380 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
381 Fut: std::future::Future<Output = ()> + Send + 'static,
382 {
383 let route = crate::websocket::WsRoute::new(handler, options);
384 if let Err(e) = self.router.insert_as(
385 RouteKind::WebSocket,
386 "GET",
387 path,
388 Arc::new(route) as DynHandler,
389 ) {
390 panic!("Failed to register WebSocket route {}: {}", path, e);
391 }
392 self
393 }
394
395 pub fn middleware<M>(mut self, middleware: M) -> Self
397 where
398 M: Middleware,
399 {
400 self.middlewares.push(Arc::new(middleware));
401 self
402 }
403
404 pub fn serve_static(mut self, route_prefix: &str, dir_path: &str) -> Self {
406 use crate::static_files::StaticFileHandler;
407 let handler = StaticFileHandler::new(dir_path);
408 let prefix = route_prefix.trim_end_matches('/');
410 let handler: DynHandler = Arc::new(handler);
411 let route = format!("{}/{{*filepath}}", prefix);
412 if let Err(e) = self
413 .router
414 .insert_as(RouteKind::Hidden, "GET", &route, handler.clone())
415 {
416 panic!("Failed to register static file route {}: {}", route, e);
417 }
418 let root = if prefix.is_empty() { "/" } else { prefix };
421 let _ = self
422 .router
423 .insert_as(RouteKind::Hidden, "GET", root, handler.clone());
424 if !prefix.is_empty() {
425 let _ =
426 self.router
427 .insert_as(RouteKind::Hidden, "GET", &format!("{}/", prefix), handler);
428 }
429 self
430 }
431
432 pub async fn run(self, addr: &str) -> Result<()> {
437 let addr: SocketAddr = addr
438 .parse()
439 .map_err(|e| Error::internal(format!("Invalid address: {}", e)))?;
440
441 let listener = TcpListener::bind(addr)
442 .await
443 .map_err(|e| Error::internal(format!("Failed to bind: {}", e)))?;
444
445 #[cfg(feature = "tls")]
446 let scheme = if self.tls.is_some() { "https" } else { "http" };
447 #[cfg(not(feature = "tls"))]
448 let scheme = "http";
449 println!("š ullun-api listening on {}://{}", scheme, addr);
450
451 let result = self
452 .serve_with_shutdown(listener, async {
453 termination_signal().await;
454 println!("\nš Shutting down gracefully...");
455 })
456 .await;
457 println!("ā
Server stopped");
458 result
459 }
460
461 pub async fn serve(self, listener: TcpListener) -> Result<()> {
468 self.serve_with_shutdown(listener, std::future::pending())
469 .await
470 }
471
472 pub async fn serve_with_shutdown(
479 mut self,
480 listener: TcpListener,
481 signal: impl std::future::Future<Output = ()>,
482 ) -> Result<()> {
483 self = self.finalize();
484 let grace = self.shutdown_grace;
485 let background = std::mem::take(&mut self.background);
486 #[cfg(feature = "tls")]
487 let tls = self.tls.take();
488 #[cfg(feature = "tls")]
489 let tls_reload = self.tls_reload;
490 let conn_limits = ConnLimits::new(self.max_connections, self.max_connections_per_ip);
491 let (trigger, rx) = tokio::sync::watch::channel(false);
492 let shutdown = Shutdown::new(rx);
493 let shared = Arc::new(self.into_shared(shutdown.clone()));
494
495 #[allow(unused_mut)]
496 let mut tasks: Vec<_> = background
497 .into_iter()
498 .map(|task| {
499 let ctx = Context::new(shared.state.clone(), shutdown.clone());
500 tokio::spawn(task(ctx))
501 })
502 .collect();
503
504 #[cfg(feature = "tls")]
505 if let (Some(config), Some(every)) = (tls.clone(), tls_reload) {
506 let shutdown = shutdown.clone();
507 tasks.push(tokio::spawn(async move {
508 while shutdown.sleep(every).await {
509 match config.reload() {
510 Ok(true) => println!("š TLS certificate reloaded"),
511 Ok(false) => {}
512 Err(e) => eprintln!(
513 "TLS certificate reload failed, keeping the previous one: {}",
514 e.message()
515 ),
516 }
517 }
518 }));
519 }
520
521 let (done_tx, mut done_rx) = tokio::sync::mpsc::channel::<()>(1);
523 tokio::pin!(signal);
524 loop {
525 tokio::select! {
526 _ = &mut signal => break,
527 accepted = listener.accept() => match accepted {
528 Ok((stream, peer)) => {
529 let Some(guard) = conn_limits.admit(peer.ip()) else {
530 tokio::spawn(limits::refuse(stream));
531 continue;
532 };
533 #[cfg(feature = "tls")]
534 if let Some(config) = tls.clone() {
535 let (shared, shutdown, done) = (shared.clone(), shutdown.clone(), done_tx.clone());
536 tokio::spawn(async move {
537 let _guard = guard;
538 if let Ok((tls_stream, client_cert)) = config.accept(stream).await {
542 let info = ConnInfo { peer, secure: true, client_cert };
543 serve_connection(tls_stream, info, shared, shutdown, done, _guard).await;
544 }
545 });
546 continue;
547 }
548 let info = ConnInfo { peer, secure: false, client_cert: None };
549 tokio::spawn(serve_connection(
550 stream,
551 info,
552 shared.clone(),
553 shutdown.clone(),
554 done_tx.clone(),
555 guard,
556 ));
557 }
558 Err(e) => {
559 eprintln!("Failed to accept connection: {}", e);
561 tokio::time::sleep(Duration::from_millis(100)).await;
562 }
563 },
564 }
565 }
566
567 let _ = trigger.send(true);
568 drop(done_tx);
569 drop(listener);
570 let drain = async {
571 let _ = done_rx.recv().await;
572 for task in tasks {
573 let _ = task.await;
574 }
575 };
576 if tokio::time::timeout(grace, drain).await.is_err() {
577 eprintln!(
578 "Shutdown grace period of {:?} elapsed, stopping anyway",
579 grace
580 );
581 }
582 Ok(())
583 }
584
585 fn into_shared(self, shutdown: Shutdown) -> Shared {
586 Shared {
587 router: self.router,
588 middlewares: self.middlewares,
589 max_body_size: self.max_body_size,
590 body_limits: self.body_limits,
591 state: Arc::new(self.state),
592 shutdown,
593 header_read_timeout: self.header_read_timeout,
594 }
595 }
596
597 fn finalize(mut self) -> Self {
600 let Some(info) = self.openapi.take() else {
601 return self;
602 };
603 let spec = openapi::build(&info, self.router.registered(), &self.docs);
604 let spec = bytes::Bytes::from(serde_json::to_vec(&spec).unwrap_or_default());
605
606 let spec_handler = {
607 let spec = spec.clone();
608 move |_req: Request| {
609 let spec = spec.clone();
610 async move {
611 Ok(Response::ok()
612 .with_header("content-type", "application/json")
613 .with_body(spec))
614 }
615 }
616 };
617 self.insert_hidden("GET", &info.spec_path, Arc::new(spec_handler));
618
619 if let Some(docs_path) = &info.docs_path {
620 let page = openapi::swagger_ui_html(&info.title, &info.spec_path);
621 let page_handler = move |_req: Request| {
622 let page = page.clone();
623 async move { Ok(Response::html(page)) }
624 };
625 self.insert_hidden("GET", docs_path, Arc::new(page_handler));
626 }
627 self
628 }
629
630 fn insert_hidden(&mut self, method: &str, path: &str, handler: DynHandler) {
631 if let Err(e) = self
632 .router
633 .insert_as(RouteKind::Hidden, method, path, handler)
634 {
635 panic!("Failed to register {} route {}: {}", method, path, e);
636 }
637 }
638}
639
640async fn serve_connection<S>(
642 stream: S,
643 info: ConnInfo,
644 shared: Arc<Shared>,
645 shutdown: Shutdown,
646 _done: tokio::sync::mpsc::Sender<()>,
647 _guard: ConnGuard,
648) where
649 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
650{
651 let io = TokioIo::new(stream);
652 let info = Arc::new(info);
653 let service = service_fn(|req| {
654 let (shared, info) = (shared.clone(), info.clone());
655 async move { Ok::<_, Infallible>(handle_request(req, &info, shared).await) }
656 });
657 let mut builder = http1::Builder::new();
658 if let Some(timeout) = shared.header_read_timeout {
659 builder
660 .timer(TokioTimer::new())
661 .header_read_timeout(timeout);
662 }
663 let conn = builder.serve_connection(io, service).with_upgrades();
664 tokio::pin!(conn);
665
666 let mut draining = false;
667 loop {
668 tokio::select! {
669 result = conn.as_mut() => {
670 if let Err(err) = &result {
672 if !err.is_timeout() {
673 eprintln!("Error serving connection: {:?}", err);
674 }
675 }
676 return;
677 }
678 _ = shutdown.wait(), if !draining => {
679 conn.as_mut().graceful_shutdown();
681 draining = true;
682 }
683 }
684 }
685}
686
687async fn termination_signal() {
689 #[cfg(unix)]
690 {
691 use tokio::signal::unix::{signal, SignalKind};
692 match signal(SignalKind::terminate()) {
693 Ok(mut term) => {
694 tokio::select! {
695 _ = tokio::signal::ctrl_c() => {}
696 _ = term.recv() => {}
697 }
698 return;
699 }
700 Err(e) => eprintln!("Cannot listen for SIGTERM: {}", e),
701 }
702 }
703 let _ = tokio::signal::ctrl_c().await;
704}
705
706impl Default for App {
707 fn default() -> Self {
708 Self::new()
709 }
710}
711
712impl RouteGroup {
713 fn new(prefix: &str) -> Self {
714 let prefix = prefix.trim_end_matches('/');
715 Self {
716 prefix: prefix.to_string(),
717 routes: Vec::new(),
718 middlewares: Vec::new(),
719 docs: Vec::new(),
720 body_limit: None,
721 ws_paths: Vec::new(),
722 }
723 }
724
725 #[cfg(feature = "websocket")]
729 pub fn ws_with<F, Fut>(
730 mut self,
731 path: &str,
732 options: crate::websocket::WsOptions,
733 handler: F,
734 ) -> Self
735 where
736 F: Fn(Request, crate::websocket::WebSocket) -> Fut + Send + Sync + 'static,
737 Fut: std::future::Future<Output = ()> + Send + 'static,
738 {
739 let route = crate::websocket::WsRoute::new(handler, options);
740 self.routes.push((
741 "GET".to_string(),
742 path.to_string(),
743 Arc::new(route) as DynHandler,
744 ));
745 self.ws_paths.push(path.to_string());
746 self
747 }
748
749 pub fn max_body_size(mut self, limit: Option<usize>) -> Self {
752 self.body_limit = Some(limit);
753 self
754 }
755
756 pub fn doc(mut self, method: &str, path: &str, operation: Operation) -> Self {
759 self.docs
760 .push((method.to_ascii_uppercase(), path.to_string(), operation));
761 self
762 }
763
764 pub fn get<H>(mut self, path: &str, handler: H) -> Self
765 where
766 H: Handler,
767 {
768 self.routes.push((
769 "GET".to_string(),
770 path.to_string(),
771 Arc::new(handler) as DynHandler,
772 ));
773 self
774 }
775
776 pub fn post<H>(mut self, path: &str, handler: H) -> Self
777 where
778 H: Handler,
779 {
780 self.routes.push((
781 "POST".to_string(),
782 path.to_string(),
783 Arc::new(handler) as DynHandler,
784 ));
785 self
786 }
787
788 pub fn put<H>(mut self, path: &str, handler: H) -> Self
789 where
790 H: Handler,
791 {
792 self.routes.push((
793 "PUT".to_string(),
794 path.to_string(),
795 Arc::new(handler) as DynHandler,
796 ));
797 self
798 }
799
800 pub fn delete<H>(mut self, path: &str, handler: H) -> Self
801 where
802 H: Handler,
803 {
804 self.routes.push((
805 "DELETE".to_string(),
806 path.to_string(),
807 Arc::new(handler) as DynHandler,
808 ));
809 self
810 }
811
812 pub fn patch<H>(mut self, path: &str, handler: H) -> Self
813 where
814 H: Handler,
815 {
816 self.routes.push((
817 "PATCH".to_string(),
818 path.to_string(),
819 Arc::new(handler) as DynHandler,
820 ));
821 self
822 }
823
824 pub fn middleware<M>(mut self, middleware: M) -> Self
829 where
830 M: Middleware,
831 {
832 self.middlewares.push(Arc::new(middleware));
833 self
834 }
835}
836
837async fn handle_request(
838 req: hyper::Request<hyper::body::Incoming>,
839 conn: &ConnInfo,
840 shared: Arc<Shared>,
841) -> hyper::Response<crate::response::HyperBody> {
842 let Shared {
843 router,
844 middlewares,
845 max_body_size,
846 body_limits,
847 state,
848 shutdown,
849 ..
850 } = &*shared;
851 let method = req.method().to_string();
852 let is_head = req.method() == http::Method::HEAD;
853 let path = req.uri().path().to_string();
854 let max_body_size = body_limit_for(body_limits, &path, *max_body_size);
855
856 let (parts, body) = req.into_parts();
858
859 let body_bytes = match max_body_size {
862 Some(max_size) => match read_limited(body, max_size).await {
863 Ok(bytes) => bytes,
864 Err(too_large) => return too_large.into_hyper(max_size),
865 },
866 None => match body.collect().await {
867 Ok(collected) => collected.to_bytes(),
868 Err(_) => bytes::Bytes::new(),
869 },
870 };
871
872 let mut request = Request::new(parts.method, parts.uri, parts.headers, body_bytes);
873 request.extensions = parts.extensions;
874 request.remote_addr = Some(conn.peer);
875 request.secure = conn.secure;
876 if let Some(cert) = &conn.client_cert {
877 request
878 .extensions
879 .insert(crate::request::ClientCertificate(cert.clone()));
880 }
881 request.state = Some(state.clone());
882 request.shutdown = Some(shutdown.clone());
883
884 let route = match router.match_route_with_pattern(&method, &path) {
887 Ok((handler, params, pattern)) => {
888 request.params = params;
889 request.matched_path = Some(pattern);
890 Route::Found(handler)
891 }
892 Err(_) => Route::Miss {
893 allow: router.allowed_methods(&path),
894 },
895 };
896
897 let result = if middlewares.is_empty() {
898 dispatch(route, request).await
899 } else {
900 let mut chain = middlewares.to_vec();
902 let final_handler = Arc::new(move |req: Request, _next: Next| {
903 let route = route.clone();
904 async move { dispatch(route, req).await }
905 });
906 chain.push(final_handler as Arc<dyn Middleware>);
907
908 Next::new(Arc::new(chain)).run(request).await
909 };
910
911 let response = match result {
913 Ok(resp) => resp,
914 Err(err) => Response::from_error(err),
915 };
916
917 let response = if is_head {
919 response.into_head()
920 } else {
921 response
922 };
923
924 response.into_hyper()
925}
926
927const DRAIN_CAP: u64 = 8 * 1024 * 1024;
931const DRAIN_TIME: Duration = Duration::from_secs(3);
932
933struct BodyTooLarge;
934
935impl BodyTooLarge {
936 fn into_hyper(self, max_size: usize) -> hyper::Response<crate::response::HyperBody> {
937 Response::from_error(Error::custom(
938 413,
939 format!("Request body too large (max {} bytes)", max_size),
940 ))
941 .with_header("connection", "close")
943 .into_hyper()
944 }
945}
946
947async fn read_limited(
949 mut body: hyper::body::Incoming,
950 max: usize,
951) -> std::result::Result<bytes::Bytes, BodyTooLarge> {
952 use bytes::BufMut;
953 use hyper::body::Body;
954
955 if body.size_hint().lower() > max as u64 {
957 drain(&mut body, 0).await;
958 return Err(BodyTooLarge);
959 }
960
961 let mut buf = bytes::BytesMut::new();
962 while let Some(frame) = body.frame().await {
963 let Ok(frame) = frame else {
964 return Ok(bytes::Bytes::new());
965 };
966 if let Ok(data) = frame.into_data() {
967 if buf.len() + data.len() > max {
968 drain(&mut body, (buf.len() + data.len()) as u64).await;
969 return Err(BodyTooLarge);
970 }
971 buf.put(data);
972 }
973 }
974 Ok(buf.freeze())
975}
976
977async fn drain(body: &mut hyper::body::Incoming, already: u64) {
979 let _ = tokio::time::timeout(DRAIN_TIME, async {
980 let mut seen = already;
981 while seen < DRAIN_CAP {
982 match body.frame().await {
983 Some(Ok(frame)) => {
984 if let Ok(data) = frame.into_data() {
985 seen += data.len() as u64;
986 }
987 }
988 _ => return,
989 }
990 }
991 })
992 .await;
993}
994
995fn body_limit_for(
997 rules: &[(String, Option<usize>)],
998 path: &str,
999 default: Option<usize>,
1000) -> Option<usize> {
1001 rules
1002 .iter()
1003 .filter(|(prefix, _)| {
1004 prefix.is_empty()
1005 || path == prefix
1006 || path
1007 .strip_prefix(prefix.as_str())
1008 .is_some_and(|rest| rest.starts_with('/'))
1009 })
1010 .max_by_key(|(prefix, _)| prefix.len())
1011 .map(|(_, limit)| *limit)
1012 .unwrap_or(default)
1013}
1014
1015#[derive(Clone)]
1017enum Route {
1018 Found(DynHandler),
1019 Miss {
1021 allow: Vec<&'static str>,
1022 },
1023}
1024
1025async fn dispatch(route: Route, req: Request) -> Result<Response> {
1026 match route {
1027 Route::Found(handler) => handler.call(req).await,
1028 Route::Miss { allow } if allow.is_empty() => Err(Error::not_found("Route not found")),
1029 Route::Miss { allow } => {
1030 let allow = allow.join(", ");
1031 if req.method == http::Method::OPTIONS {
1032 Ok(Response::new(http::StatusCode::NO_CONTENT).with_header("allow", allow))
1035 } else {
1036 Ok(
1037 Response::from_error(Error::custom(405, "Method not allowed"))
1038 .with_header("allow", allow),
1039 )
1040 }
1041 }
1042 }
1043}