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 route = path("/fail", failing).with_name("fail");
287 router.add_route(route);
288 let handler = BaseHandler::with_router(Arc::new(router));
289
290 let request = Request::builder()
291 .method(Method::GET)
292 .uri("/fail")
293 .version(Version::HTTP_11)
294 .headers(HeaderMap::new())
295 .body(Bytes::new())
296 .build()
297 .unwrap();
298
299 let response = handler.handle(request).await.unwrap();
301
302 let body = String::from_utf8(response.body.to_vec()).unwrap();
304 assert_eq!(response.status, StatusCode::INTERNAL_SERVER_ERROR);
305 assert!(!body.contains("panicked"));
306 assert!(!body.contains("handlers.rs"));
307 assert!(!body.contains("secret_handler"));
308 assert_eq!(body, "Internal Server Error");
309 }
310
311 #[test]
312 fn test_base_handler_async_mode() {
313 let mut handler = BaseHandler::new();
314 assert!(handler.is_async());
315
316 handler.set_async(false);
317 assert!(!handler.is_async());
318 }
319
320 #[tokio::test]
321 async fn test_base_handler_different_methods() {
322 let handler = BaseHandler::new();
323
324 for method in [Method::GET, Method::POST, Method::PUT, Method::DELETE] {
325 let request = Request::builder()
326 .method(method)
327 .uri("/")
328 .version(Version::HTTP_11)
329 .headers(HeaderMap::new())
330 .body(Bytes::new())
331 .build()
332 .unwrap();
333
334 let response = handler.handle_request(request).await;
335 assert!(response.is_ok());
336 }
337 }
338
339 #[tokio::test]
340 async fn test_base_handler_different_uris() {
341 let handler = BaseHandler::new();
342
343 for path in ["/", "/test", "/api/v1/users", "/admin/login"] {
344 let request = Request::builder()
345 .method(Method::GET)
346 .uri(path)
347 .version(Version::HTTP_11)
348 .headers(HeaderMap::new())
349 .body(Bytes::new())
350 .build()
351 .unwrap();
352
353 let response = handler.handle_request(request).await;
354 assert!(response.is_ok());
355 }
356 }
357
358 #[tokio::test]
359 async fn test_handler_with_router() {
360 let mut router = DefaultRouter::new();
362 let test_handler = Arc::new(TestHandler {
363 response_body: "Test response".to_string(),
364 });
365 let route = path("/test", test_handler).with_name("test");
366 router.add_route(route);
367
368 let handler = BaseHandler::with_router(Arc::new(router));
370
371 let request = Request::builder()
373 .method(Method::GET)
374 .uri("/test")
375 .version(Version::HTTP_11)
376 .headers(HeaderMap::new())
377 .body(Bytes::new())
378 .build()
379 .unwrap();
380
381 let response = handler.handle_request(request).await;
382 let resp = response.unwrap();
383 assert_eq!(resp.status, StatusCode::OK);
384
385 let body = String::from_utf8(resp.body.to_vec()).unwrap();
386 assert_eq!(body, "Test response");
387 }
388
389 #[tokio::test]
390 async fn test_handler_404_not_found() {
391 let router = DefaultRouter::new();
393
394 let handler = BaseHandler::with_router(Arc::new(router));
396
397 let request = Request::builder()
399 .method(Method::GET)
400 .uri("/nonexistent")
401 .version(Version::HTTP_11)
402 .headers(HeaderMap::new())
403 .body(Bytes::new())
404 .build()
405 .unwrap();
406
407 let response = handler.handle_request(request).await;
408 let resp = response.unwrap();
409 assert_eq!(resp.status, StatusCode::NOT_FOUND);
410 }
411
412 #[tokio::test]
413 async fn test_handler_multiple_routes() {
414 let mut router = DefaultRouter::new();
416
417 let hello_handler = Arc::new(TestHandler {
418 response_body: "Hello".to_string(),
419 });
420 let hello_route = path("/hello", hello_handler).with_name("hello");
421 router.add_route(hello_route);
422
423 let world_handler = Arc::new(TestHandler {
424 response_body: "World".to_string(),
425 });
426 let world_route = path("/world", world_handler).with_name("world");
427 router.add_route(world_route);
428
429 let handler = BaseHandler::with_router(Arc::new(router));
430
431 let request = Request::builder()
433 .method(Method::GET)
434 .uri("/hello")
435 .version(Version::HTTP_11)
436 .headers(HeaderMap::new())
437 .body(Bytes::new())
438 .build()
439 .unwrap();
440 let response = handler.handle_request(request).await.unwrap();
441 assert_eq!(response.status, StatusCode::OK);
442 assert_eq!(String::from_utf8(response.body.to_vec()).unwrap(), "Hello");
443
444 let request = Request::builder()
446 .method(Method::GET)
447 .uri("/world")
448 .version(Version::HTTP_11)
449 .headers(HeaderMap::new())
450 .body(Bytes::new())
451 .build()
452 .unwrap();
453 let response = handler.handle_request(request).await.unwrap();
454 assert_eq!(response.status, StatusCode::OK);
455 assert_eq!(String::from_utf8(response.body.to_vec()).unwrap(), "World");
456 }
457}