httpmcp_rust/
context.rs

1use actix_web::http::header::HeaderMap;
2use std::net::SocketAddr;
3use uuid::Uuid;
4
5/// Request context passed to all handler methods
6#[derive(Debug, Clone)]
7pub struct RequestContext {
8    /// HTTP headers from the request
9    pub headers: HeaderMap,
10
11    /// Request ID for tracing
12    pub request_id: String,
13
14    /// HTTP method (GET, POST)
15    pub method: String,
16
17    /// Request path
18    pub path: String,
19
20    /// Remote client address
21    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    /// Get a header value as string
41    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    /// Get authorization header
49    pub fn get_authorization(&self) -> Option<String> {
50        self.get_header("authorization")
51    }
52
53    /// Get bearer token from authorization header
54    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    /// Get custom header by name
60    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}