http_tunnel_common/protocol/
response.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct HttpResponse {
7 pub request_id: String,
9
10 pub status_code: u16,
12
13 pub headers: HashMap<String, Vec<String>>,
15
16 #[serde(default)]
18 pub body: String,
19
20 #[serde(default)]
22 pub processing_time_ms: u64,
23}
24
25impl HttpResponse {
26 pub fn new(request_id: String, status_code: u16) -> Self {
28 Self {
29 request_id,
30 status_code,
31 headers: HashMap::new(),
32 body: String::new(),
33 processing_time_ms: 0,
34 }
35 }
36
37 pub fn has_body(&self) -> bool {
39 !self.body.is_empty()
40 }
41
42 pub fn is_success(&self) -> bool {
44 (200..300).contains(&self.status_code)
45 }
46
47 pub fn is_client_error(&self) -> bool {
49 (400..500).contains(&self.status_code)
50 }
51
52 pub fn is_server_error(&self) -> bool {
54 (500..600).contains(&self.status_code)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn test_http_response_creation() {
64 let res = HttpResponse::new("req_123".to_string(), 200);
65
66 assert_eq!(res.request_id, "req_123");
67 assert_eq!(res.status_code, 200);
68 assert!(res.headers.is_empty());
69 assert!(!res.has_body());
70 assert_eq!(res.processing_time_ms, 0);
71 }
72
73 #[test]
74 fn test_http_response_status_checks() {
75 let success = HttpResponse::new("req_1".to_string(), 200);
76 assert!(success.is_success());
77 assert!(!success.is_client_error());
78 assert!(!success.is_server_error());
79
80 let client_error = HttpResponse::new("req_2".to_string(), 404);
81 assert!(!client_error.is_success());
82 assert!(client_error.is_client_error());
83 assert!(!client_error.is_server_error());
84
85 let server_error = HttpResponse::new("req_3".to_string(), 500);
86 assert!(!server_error.is_success());
87 assert!(!server_error.is_client_error());
88 assert!(server_error.is_server_error());
89 }
90
91 #[test]
92 fn test_http_response_with_headers() {
93 let mut headers = HashMap::new();
94 headers.insert(
95 "content-type".to_string(),
96 vec!["application/json".to_string()],
97 );
98 headers.insert("x-custom-header".to_string(), vec!["value".to_string()]);
99
100 let res = HttpResponse {
101 request_id: "req_123".to_string(),
102 status_code: 200,
103 headers,
104 body: "eyJ0ZXN0IjoidmFsdWUifQ==".to_string(),
105 processing_time_ms: 123,
106 };
107
108 assert_eq!(res.headers.len(), 2);
109 assert!(res.has_body());
110 assert_eq!(res.processing_time_ms, 123);
111 }
112
113 #[test]
114 fn test_http_response_serialization() {
115 let mut headers = HashMap::new();
116 headers.insert("content-type".to_string(), vec!["text/plain".to_string()]);
117
118 let res = HttpResponse {
119 request_id: "req_abc123".to_string(),
120 status_code: 201,
121 headers,
122 body: "dGVzdCBkYXRh".to_string(), processing_time_ms: 456,
124 };
125
126 let json = serde_json::to_string(&res).unwrap();
127 assert!(json.contains(r#""request_id":"req_abc123"#));
128 assert!(json.contains(r#""status_code":201"#));
129 assert!(json.contains(r#""processing_time_ms":456"#));
130
131 let parsed: HttpResponse = serde_json::from_str(&json).unwrap();
132 assert_eq!(parsed.request_id, res.request_id);
133 assert_eq!(parsed.status_code, res.status_code);
134 assert_eq!(parsed.body, res.body);
135 assert_eq!(parsed.processing_time_ms, res.processing_time_ms);
136 }
137
138 #[test]
139 fn test_http_response_multiple_header_values() {
140 let mut headers = HashMap::new();
141 headers.insert(
142 "set-cookie".to_string(),
143 vec!["session=abc".to_string(), "token=xyz".to_string()],
144 );
145
146 let res = HttpResponse {
147 request_id: "req_123".to_string(),
148 status_code: 200,
149 headers,
150 body: String::new(),
151 processing_time_ms: 0,
152 };
153
154 assert_eq!(res.headers.get("set-cookie").unwrap().len(), 2);
155
156 let json = serde_json::to_string(&res).unwrap();
157 let parsed: HttpResponse = serde_json::from_str(&json).unwrap();
158 assert_eq!(parsed.headers.get("set-cookie").unwrap().len(), 2);
159 }
160
161 #[test]
162 fn test_http_response_defaults() {
163 let json = r#"{
164 "request_id": "req_123",
165 "status_code": 200,
166 "headers": {}
167 }"#;
168
169 let parsed: HttpResponse = serde_json::from_str(json).unwrap();
170 assert_eq!(parsed.body, "");
171 assert_eq!(parsed.processing_time_ms, 0);
172 assert!(!parsed.has_body());
173 }
174
175 #[test]
176 fn test_status_code_ranges() {
177 let codes = vec![
178 (100, false, false, false),
179 (200, true, false, false),
180 (299, true, false, false),
181 (300, false, false, false),
182 (400, false, true, false),
183 (404, false, true, false),
184 (499, false, true, false),
185 (500, false, false, true),
186 (503, false, false, true),
187 (599, false, false, true),
188 ];
189
190 for (code, is_success, is_client_err, is_server_err) in codes {
191 let res = HttpResponse::new("req".to_string(), code);
192 assert_eq!(
193 res.is_success(),
194 is_success,
195 "Failed for status code {}",
196 code
197 );
198 assert_eq!(
199 res.is_client_error(),
200 is_client_err,
201 "Failed for status code {}",
202 code
203 );
204 assert_eq!(
205 res.is_server_error(),
206 is_server_err,
207 "Failed for status code {}",
208 code
209 );
210 }
211 }
212}