structured_proxy/transcode/
metadata.rs1use axum::http::HeaderMap;
7use tonic::metadata::MetadataMap;
8
9pub fn http_headers_to_grpc_metadata(
12 headers: &HeaderMap,
13 forwarded_headers: &[String],
14) -> MetadataMap {
15 let mut metadata = MetadataMap::new();
16
17 for header_name in forwarded_headers {
18 if let Some(value) = headers.get(header_name.as_str()) {
19 if let Ok(meta_value) = tonic::metadata::AsciiMetadataValue::try_from(value.as_bytes())
20 {
21 if let Ok(key) =
22 header_name.parse::<tonic::metadata::MetadataKey<tonic::metadata::Ascii>>()
23 {
24 metadata.insert(key, meta_value);
25 }
26 }
27 }
28 }
29
30 metadata
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use axum::http::HeaderValue;
37
38 fn default_headers() -> Vec<String> {
39 vec![
40 "authorization".into(),
41 "dpop".into(),
42 "x-request-id".into(),
43 "x-forwarded-for".into(),
44 "x-forwarded-proto".into(),
45 "x-real-ip".into(),
46 "accept-language".into(),
47 "user-agent".into(),
48 "idempotency-key".into(),
49 ]
50 }
51
52 #[test]
53 fn test_authorization_forwarded() {
54 let mut headers = HeaderMap::new();
55 headers.insert("authorization", HeaderValue::from_static("Bearer tok123"));
56 let meta = http_headers_to_grpc_metadata(&headers, &default_headers());
57 assert_eq!(
58 meta.get("authorization").unwrap().to_str().unwrap(),
59 "Bearer tok123"
60 );
61 }
62
63 #[test]
64 fn test_multiple_headers_forwarded() {
65 let mut headers = HeaderMap::new();
66 headers.insert("authorization", HeaderValue::from_static("Bearer tok"));
67 headers.insert("x-request-id", HeaderValue::from_static("req-42"));
68 headers.insert("accept-language", HeaderValue::from_static("en-US"));
69 let meta = http_headers_to_grpc_metadata(&headers, &default_headers());
70 assert_eq!(
71 meta.get("authorization").unwrap().to_str().unwrap(),
72 "Bearer tok"
73 );
74 assert_eq!(
75 meta.get("x-request-id").unwrap().to_str().unwrap(),
76 "req-42"
77 );
78 assert_eq!(
79 meta.get("accept-language").unwrap().to_str().unwrap(),
80 "en-US"
81 );
82 }
83
84 #[test]
85 fn test_unknown_headers_not_forwarded() {
86 let mut headers = HeaderMap::new();
87 headers.insert("x-custom-header", HeaderValue::from_static("value"));
88 let meta = http_headers_to_grpc_metadata(&headers, &default_headers());
89 assert!(meta.get("x-custom-header").is_none());
90 }
91
92 #[test]
93 fn test_custom_forwarded_headers() {
94 let mut headers = HeaderMap::new();
95 headers.insert("x-custom-header", HeaderValue::from_static("value"));
96 let forwarded = vec!["x-custom-header".to_string()];
97 let meta = http_headers_to_grpc_metadata(&headers, &forwarded);
98 assert_eq!(
99 meta.get("x-custom-header").unwrap().to_str().unwrap(),
100 "value"
101 );
102 }
103
104 #[test]
105 fn test_empty_headers() {
106 let headers = HeaderMap::new();
107 let meta = http_headers_to_grpc_metadata(&headers, &default_headers());
108 assert!(meta.is_empty());
109 }
110
111 #[test]
112 fn test_dpop_forwarded() {
113 let mut headers = HeaderMap::new();
114 headers.insert("dpop", HeaderValue::from_static("eyJ0eXAiOiJkcG9wK2p3dCJ9"));
115 let meta = http_headers_to_grpc_metadata(&headers, &default_headers());
116 assert!(meta.get("dpop").is_some());
117 }
118}