1use actix_web::http::header::HeaderMap;
2use std::net::SocketAddr;
3use uuid::Uuid;
4
5#[derive(Debug, Clone)]
7pub struct RequestContext {
8 pub headers: HeaderMap,
10
11 pub request_id: String,
13
14 pub method: String,
16
17 pub path: String,
19
20 pub remote_addr: Option<SocketAddr>,
22}
23
24impl RequestContext {
25 pub fn new(
26 headers: HeaderMap,
27 method: String,
28 path: String,
29 remote_addr: Option<SocketAddr>,
30 ) -> Self {
31 Self {
32 headers,
33 request_id: Uuid::new_v4().to_string(),
34 method,
35 path,
36 remote_addr,
37 }
38 }
39
40 pub fn get_header(&self, name: &str) -> Option<String> {
42 self.headers
43 .get(name)
44 .and_then(|v| v.to_str().ok())
45 .map(|s| s.to_string())
46 }
47
48 pub fn get_authorization(&self) -> Option<String> {
50 self.get_header("authorization")
51 }
52
53 pub fn get_bearer_token(&self) -> Option<String> {
55 self.get_authorization()
56 .and_then(|auth| auth.strip_prefix("Bearer ").map(|s| s.to_string()))
57 }
58
59 pub fn get_custom_header(&self, name: &str) -> Option<String> {
61 self.get_header(name)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use actix_web::http::header::{HeaderMap, HeaderName, HeaderValue};
69
70 #[test]
71 fn test_get_bearer_token() {
72 let mut headers = HeaderMap::new();
73 headers.insert(
74 HeaderName::from_static("authorization"),
75 HeaderValue::from_static("Bearer test_token_123"),
76 );
77
78 let ctx = RequestContext::new(headers, "POST".to_string(), "/mcp".to_string(), None);
79
80 assert_eq!(ctx.get_bearer_token(), Some("test_token_123".to_string()));
81 }
82
83 #[test]
84 fn test_get_custom_header() {
85 let mut headers = HeaderMap::new();
86 headers.insert(
87 HeaderName::from_static("x-tenant-id"),
88 HeaderValue::from_static("tenant-123"),
89 );
90
91 let ctx = RequestContext::new(headers, "POST".to_string(), "/mcp".to_string(), None);
92
93 assert_eq!(
94 ctx.get_custom_header("x-tenant-id"),
95 Some("tenant-123".to_string())
96 );
97 }
98}