Skip to main content

reinhardt_urls/routers/server_router/
router_impls.rs

1//! Trait impls for [`ServerRouter`] that don't fit the builder / dispatch split.
2//!
3//! Includes `Debug`, `Default`, the `Handler` impl that turns the router
4//! into an HTTP entry point, and the `RegisterViewSet` adapter used by
5//! `ViewSetBuilder`.
6
7use super::ServerRouter;
8#[cfg(feature = "viewsets")]
9use super::types::ViewRoute;
10use async_trait::async_trait;
11use reinhardt_http::{Error, Handler, MiddlewareChain, Request, Response, Result};
12use std::sync::Arc;
13
14impl std::fmt::Debug for ServerRouter {
15	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16		let mut debug = f.debug_struct("ServerRouter");
17		debug
18			.field("prefix", &self.prefix)
19			.field("namespace", &self.namespace)
20			.field("routes", &self.routes.len());
21		#[cfg(feature = "viewsets")]
22		debug.field("viewsets", &self.viewsets.len());
23		debug
24			.field("functions", &self.functions.len())
25			.field("views", &self.views.len())
26			.field("children", &self.children.len())
27			.field("middleware", &self.middleware.len())
28			.finish_non_exhaustive()
29	}
30}
31
32impl Default for ServerRouter {
33	fn default() -> Self {
34		Self::new()
35	}
36}
37
38/// Handler that always returns a pre-built response.
39///
40/// Used internally to route framework-level error responses (404/405)
41/// through the middleware chain for post-processing. (#3234)
42struct FixedResponseHandler(Response);
43
44#[async_trait]
45impl Handler for FixedResponseHandler {
46	async fn handle(&self, _request: Request) -> Result<Response> {
47		Ok(self.0.clone())
48	}
49}
50
51/// Handler implementation for ServerRouter
52#[async_trait]
53impl Handler for ServerRouter {
54	async fn handle(&self, mut req: Request) -> Result<Response> {
55		let path = req.uri.path();
56		let method = &req.method;
57
58		// Resolve route with HTTP method for matchit routing
59		let route_match = match self.resolve(path, method) {
60			Some(m) => m,
61			None => {
62				// Route not found for this method
63				// Check if path exists for any other method to determine 404 vs 405
64				let error = if self.path_exists_for_any_method(path) {
65					Error::MethodNotAllowed(format!("Method {} not allowed for {}", method, path))
66				} else {
67					Error::NotFound(format!("No route for {} {}", method, path))
68				};
69
70				// If router has middleware, route the error response through the
71				// middleware chain so post-processing (e.g., security headers) is
72				// applied to framework-level 404/405 responses. (#3234)
73				let own_middleware = self.build_middleware_with_exclusions();
74				if own_middleware.is_empty() {
75					return Err(error);
76				}
77
78				let response = Response::from(error);
79				let handler: Arc<dyn Handler> = Arc::new(FixedResponseHandler(response));
80				let chain = own_middleware
81					.iter()
82					.fold(MiddlewareChain::new(handler), |chain, mw| {
83						chain.with_middleware(mw.clone())
84					});
85				return chain.handle(req).await;
86			}
87		};
88
89		// Set path parameters in request
90		for (key, value) in route_match.params {
91			req.set_path_param(key, value);
92		}
93
94		// Set DI context if available
95		if let Some(di_ctx) = &route_match.di_context {
96			req.set_di_context(di_ctx.clone());
97		}
98
99		// Apply middleware stack using MiddlewareChain
100		if route_match.middleware_stack.is_empty() {
101			// No middleware, execute handler directly
102			route_match.handler.handle(req).await
103		} else {
104			// Build middleware chain
105			let chain = route_match.middleware_stack.iter().fold(
106				MiddlewareChain::new(route_match.handler.clone()),
107				|chain, mw| chain.with_middleware(mw.clone()),
108			);
109
110			// Execute chain
111			chain.handle(req).await
112		}
113	}
114}
115
116/// Implement RegisterViewSet trait for ServerRouter
117///
118/// This allows ViewSetBuilder to directly register handlers to the router.
119#[cfg(feature = "viewsets")]
120impl reinhardt_views::viewsets::RegisterViewSet for ServerRouter {
121	fn register_handler(&mut self, path: &str, handler: Arc<dyn Handler>) {
122		self.views.push(ViewRoute {
123			path: path.to_string(),
124			handler,
125			name: None,
126			middleware: Vec::new(),
127		});
128	}
129}