reinhardt_dispatch/
handler.rs1use hyper::StatusCode;
7use reinhardt_core::signals::{
8 RequestFinishedEvent, RequestStartedEvent, request_finished, request_started,
9};
10use reinhardt_http::Handler;
11use reinhardt_http::{Request, Response};
12use reinhardt_urls::routers::DefaultRouter;
13use std::sync::Arc;
14use tracing::{debug, error, trace, warn};
15
16use crate::DispatchError;
17
18pub struct BaseHandler {
23 #[allow(dead_code)]
31 is_async: bool,
32 router: Option<Arc<DefaultRouter>>,
33}
34
35impl BaseHandler {
36 pub fn new() -> Self {
38 Self {
39 is_async: true,
40 router: None,
41 }
42 }
43
44 pub fn with_router(router: Arc<DefaultRouter>) -> Self {
58 Self {
59 is_async: true,
60 router: Some(router),
61 }
62 }
63
64 pub async fn handle_request(
71 &self,
72 request: Request,
73 ) -> std::result::Result<Response, DispatchError> {
74 trace!("Handling request: {:?}", request.uri);
75
76 let event = RequestStartedEvent::new();
78 if let Err(e) = request_started().send(event).await {
79 warn!("Failed to send request_started signal: {}", e);
80 }
81
82 let response = Self::get_response_async(request, self.router.as_ref()).await;
84
85 let event = RequestFinishedEvent::new();
87 if let Err(e) = request_finished().send(event).await {
88 warn!("Failed to send request_finished signal: {}", e);
89 }
90
91 response
92 }
93
94 async fn get_response_async(
102 request: Request,
103 router: Option<&Arc<DefaultRouter>>,
104 ) -> std::result::Result<Response, DispatchError> {
105 debug!("Getting response for: {}", request.uri.path());
106
107 if let Some(router) = router {
109 trace!("Attempting to route request through router");
110
111 match router.handle(request).await {
113 Ok(response) => {
114 trace!("Route handled successfully");
115 return Ok(response);
116 }
117 Err(reinhardt_core::exception::Error::NotFound(msg)) => {
118 debug!("No route matched: {}", msg);
119 return Ok(Response::new(StatusCode::NOT_FOUND));
120 }
121 Err(e) => {
122 error!("Handler error: {}", e);
123 return Err(DispatchError::View(e.to_string()));
125 }
126 }
127 }
128
129 debug!("No router configured, returning 404 Not Found");
131 Ok(Response::new(StatusCode::NOT_FOUND))
132 }
133
134 pub async fn handle_exception(&self, _request: &Request, error: DispatchError) -> Response {
139 error!("Handling exception: {}", error);
140
141 crate::build_error_response(StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
142 }
143
144 pub fn is_async(&self) -> bool {
146 self.is_async
147 }
148
149 pub fn set_async(&mut self, is_async: bool) {
151 self.is_async = is_async;
152 }
153}
154
155impl Default for BaseHandler {
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161#[async_trait::async_trait]
162impl Handler for BaseHandler {
163 async fn handle(&self, request: Request) -> reinhardt_core::exception::Result<Response> {
164 match self.handle_request(request).await {
165 Ok(response) => Ok(response),
166 Err(e) => {
167 error!("Handler error in BaseHandler::handle: {}", e);
169 Ok(crate::build_error_response(
170 StatusCode::INTERNAL_SERVER_ERROR,
171 "Internal Server Error",
172 ))
173 }
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use async_trait::async_trait;
182 use bytes::Bytes;
183 use hyper::{HeaderMap, Method, Version};
184 use reinhardt_urls::routers::{DefaultRouter, Router, path};
185
186 struct TestHandler {
188 response_body: String,
189 }
190
191 #[async_trait]
192 impl Handler for TestHandler {
193 async fn handle(&self, _req: Request) -> reinhardt_core::exception::Result<Response> {
194 Ok(Response::ok().with_body(self.response_body.clone()))
195 }
196 }
197
198 #[tokio::test]
199 async fn test_base_handler_new() {
200 let handler = BaseHandler::new();
201 assert!(handler.is_async());
202 }
203
204 #[tokio::test]
205 async fn test_base_handler_handle_request() {
206 let handler = BaseHandler::new();
207 let request = Request::builder()
208 .method(Method::GET)
209 .uri("/")
210 .version(Version::HTTP_11)
211 .headers(HeaderMap::new())
212 .body(Bytes::new())
213 .build()
214 .unwrap();
215
216 let response = handler.handle_request(request).await;
217 let resp = response.unwrap();
218 assert_eq!(resp.status, StatusCode::NOT_FOUND);
220 }
221
222 #[tokio::test]
223 async fn test_base_handler_handle_exception() {
224 let handler = BaseHandler::new();
225 let request = Request::builder()
226 .method(Method::GET)
227 .uri("/")
228 .version(Version::HTTP_11)
229 .headers(HeaderMap::new())
230 .body(Bytes::new())
231 .build()
232 .unwrap();
233 let error = DispatchError::View("Test error".to_string());
234
235 let response = handler.handle_exception(&request, error).await;
236 assert_eq!(response.status, StatusCode::INTERNAL_SERVER_ERROR);
237 }
238
239 #[tokio::test]
244 async fn test_handle_exception_does_not_expose_internal_details() {
245 let handler = BaseHandler::new();
247 let request = Request::builder()
248 .method(Method::GET)
249 .uri("/")
250 .version(Version::HTTP_11)
251 .headers(HeaderMap::new())
252 .body(Bytes::new())
253 .build()
254 .unwrap();
255 let sensitive_detail = "database connection refused at postgres://admin:secret@db:5432";
256 let error = DispatchError::Internal(sensitive_detail.to_string());
257
258 let response = handler.handle_exception(&request, error).await;
260
261 let body = String::from_utf8(response.body.to_vec()).unwrap();
263 assert_eq!(response.status, StatusCode::INTERNAL_SERVER_ERROR);
264 assert!(!body.contains("database"));
265 assert!(!body.contains("postgres"));
266 assert!(!body.contains("secret"));
267 assert_eq!(body, "Internal Server Error");
268 }
269
270 #[tokio::test]
271 async fn test_handler_impl_does_not_expose_error_in_body() {
272 struct FailingHandler;
274
275 #[async_trait]
276 impl Handler for FailingHandler {
277 async fn handle(&self, _req: Request) -> reinhardt_core::exception::Result<Response> {
278 Err(reinhardt_core::exception::Error::Internal(
279 "module::secret_handler panicked at /src/app/handlers.rs:42".to_string(),
280 ))
281 }
282 }
283
284 let mut router = DefaultRouter::new();
285 let failing = Arc::new(FailingHandler);
286 let mut route = path("/fail", failing);
287 route.name = Some("fail".to_string());
288 router.add_route(route);
289 let handler = BaseHandler::with_router(Arc::new(router));
290
291 let request = Request::builder()
292 .method(Method::GET)
293 .uri("/fail")
294 .version(Version::HTTP_11)
295 .headers(HeaderMap::new())
296 .body(Bytes::new())
297 .build()
298 .unwrap();
299
300 let response = handler.handle(request).await.unwrap();
302
303 let body = String::from_utf8(response.body.to_vec()).unwrap();
305 assert_eq!(response.status, StatusCode::INTERNAL_SERVER_ERROR);
306 assert!(!body.contains("panicked"));
307 assert!(!body.contains("handlers.rs"));
308 assert!(!body.contains("secret_handler"));
309 assert_eq!(body, "Internal Server Error");
310 }
311
312 #[test]
313 fn test_base_handler_async_mode() {
314 let mut handler = BaseHandler::new();
315 assert!(handler.is_async());
316
317 handler.set_async(false);
318 assert!(!handler.is_async());
319 }
320
321 #[tokio::test]
322 async fn test_base_handler_different_methods() {
323 let handler = BaseHandler::new();
324
325 for method in [Method::GET, Method::POST, Method::PUT, Method::DELETE] {
326 let request = Request::builder()
327 .method(method)
328 .uri("/")
329 .version(Version::HTTP_11)
330 .headers(HeaderMap::new())
331 .body(Bytes::new())
332 .build()
333 .unwrap();
334
335 let response = handler.handle_request(request).await;
336 assert!(response.is_ok());
337 }
338 }
339
340 #[tokio::test]
341 async fn test_base_handler_different_uris() {
342 let handler = BaseHandler::new();
343
344 for path in ["/", "/test", "/api/v1/users", "/admin/login"] {
345 let request = Request::builder()
346 .method(Method::GET)
347 .uri(path)
348 .version(Version::HTTP_11)
349 .headers(HeaderMap::new())
350 .body(Bytes::new())
351 .build()
352 .unwrap();
353
354 let response = handler.handle_request(request).await;
355 assert!(response.is_ok());
356 }
357 }
358
359 #[tokio::test]
360 async fn test_handler_with_router() {
361 let mut router = DefaultRouter::new();
363 let test_handler = Arc::new(TestHandler {
364 response_body: "Test response".to_string(),
365 });
366 let mut route = path("/test", test_handler);
367 route.name = Some("test".to_string());
368 router.add_route(route);
369
370 let handler = BaseHandler::with_router(Arc::new(router));
372
373 let request = Request::builder()
375 .method(Method::GET)
376 .uri("/test")
377 .version(Version::HTTP_11)
378 .headers(HeaderMap::new())
379 .body(Bytes::new())
380 .build()
381 .unwrap();
382
383 let response = handler.handle_request(request).await;
384 let resp = response.unwrap();
385 assert_eq!(resp.status, StatusCode::OK);
386
387 let body = String::from_utf8(resp.body.to_vec()).unwrap();
388 assert_eq!(body, "Test response");
389 }
390
391 #[tokio::test]
392 async fn test_handler_404_not_found() {
393 let router = DefaultRouter::new();
395
396 let handler = BaseHandler::with_router(Arc::new(router));
398
399 let request = Request::builder()
401 .method(Method::GET)
402 .uri("/nonexistent")
403 .version(Version::HTTP_11)
404 .headers(HeaderMap::new())
405 .body(Bytes::new())
406 .build()
407 .unwrap();
408
409 let response = handler.handle_request(request).await;
410 let resp = response.unwrap();
411 assert_eq!(resp.status, StatusCode::NOT_FOUND);
412 }
413
414 #[tokio::test]
415 async fn test_handler_multiple_routes() {
416 let mut router = DefaultRouter::new();
418
419 let hello_handler = Arc::new(TestHandler {
420 response_body: "Hello".to_string(),
421 });
422 let mut hello_route = path("/hello", hello_handler);
423 hello_route.name = Some("hello".to_string());
424 router.add_route(hello_route);
425
426 let world_handler = Arc::new(TestHandler {
427 response_body: "World".to_string(),
428 });
429 let mut world_route = path("/world", world_handler);
430 world_route.name = Some("world".to_string());
431 router.add_route(world_route);
432
433 let handler = BaseHandler::with_router(Arc::new(router));
434
435 let request = Request::builder()
437 .method(Method::GET)
438 .uri("/hello")
439 .version(Version::HTTP_11)
440 .headers(HeaderMap::new())
441 .body(Bytes::new())
442 .build()
443 .unwrap();
444 let response = handler.handle_request(request).await.unwrap();
445 assert_eq!(response.status, StatusCode::OK);
446 assert_eq!(String::from_utf8(response.body.to_vec()).unwrap(), "Hello");
447
448 let request = Request::builder()
450 .method(Method::GET)
451 .uri("/world")
452 .version(Version::HTTP_11)
453 .headers(HeaderMap::new())
454 .body(Bytes::new())
455 .build()
456 .unwrap();
457 let response = handler.handle_request(request).await.unwrap();
458 assert_eq!(response.status, StatusCode::OK);
459 assert_eq!(String::from_utf8(response.body.to_vec()).unwrap(), "World");
460 }
461}