1use crate::error::Result;
8use crate::server::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
9use serde_json::Value;
10use std::any::Any;
11use std::sync::Arc;
12
13#[derive(Debug, Clone, serde::Deserialize)]
19#[serde(rename_all = "camelCase")]
20#[non_exhaustive]
21pub struct SecurityDetails {
22 pub issuer: Option<String>,
24 pub protocol: Option<String>,
26 pub subject_name: Option<String>,
28 pub valid_from: Option<f64>,
30 pub valid_to: Option<f64>,
32}
33
34#[derive(Debug, Clone, serde::Deserialize)]
38#[serde(rename_all = "camelCase")]
39#[non_exhaustive]
40pub struct RemoteAddr {
41 pub ip_address: String,
43 pub port: u16,
45}
46
47#[derive(Debug, Clone)]
51#[non_exhaustive]
52pub struct RequestSizes {
53 pub request_body_size: i64,
55 pub request_headers_size: i64,
58 pub response_body_size: i64,
60 pub response_headers_size: i64,
63}
64
65#[derive(Debug, Clone)]
71#[non_exhaustive]
72pub struct HeaderEntry {
73 pub name: String,
75 pub value: String,
77}
78
79#[derive(Clone)]
86pub struct ResponseObject {
87 base: ChannelOwnerImpl,
88}
89
90impl ResponseObject {
91 pub fn new(
96 parent: Arc<dyn ChannelOwner>,
97 type_name: String,
98 guid: Arc<str>,
99 initializer: Value,
100 ) -> Result<Self> {
101 let base = ChannelOwnerImpl::new(
102 ParentOrConnection::Parent(parent),
103 type_name,
104 guid,
105 initializer,
106 );
107
108 Ok(Self { base })
109 }
110
111 pub fn status(&self) -> u16 {
115 self.initializer()
116 .get("status")
117 .and_then(|v| v.as_u64())
118 .unwrap_or(0) as u16
119 }
120
121 pub fn status_text(&self) -> &str {
125 self.initializer()
126 .get("statusText")
127 .and_then(|v| v.as_str())
128 .unwrap_or("")
129 }
130
131 pub fn url(&self) -> &str {
135 self.initializer()
136 .get("url")
137 .and_then(|v| v.as_str())
138 .unwrap_or("")
139 }
140
141 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid(), bytes_len = tracing::field::Empty))]
148 pub async fn body(&self) -> Result<Vec<u8>> {
149 use serde::Deserialize;
150
151 #[derive(Deserialize)]
152 struct BodyResponse {
153 binary: String,
154 }
155
156 let result: BodyResponse = self.channel().send("body", serde_json::json!({})).await?;
157
158 use base64::Engine;
159 let bytes = base64::engine::general_purpose::STANDARD
160 .decode(&result.binary)
161 .map_err(|e| {
162 crate::error::Error::ProtocolError(format!(
163 "Failed to decode response body from base64: {}",
164 e
165 ))
166 })?;
167 Ok(bytes)
168 }
169
170 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
174 pub async fn security_details(&self) -> Result<Option<SecurityDetails>> {
175 let result: serde_json::Value = self
176 .channel()
177 .send("securityDetails", serde_json::json!({}))
178 .await?;
179
180 let value = result.get("value");
181 match value {
182 Some(v) if v.as_object().is_some_and(|obj| !obj.is_empty()) => {
183 Ok(Some(SecurityDetails {
184 issuer: v.get("issuer").and_then(|v| v.as_str()).map(String::from),
185 protocol: v.get("protocol").and_then(|v| v.as_str()).map(String::from),
186 subject_name: v
187 .get("subjectName")
188 .and_then(|v| v.as_str())
189 .map(String::from),
190 valid_from: v.get("validFrom").and_then(|v| v.as_f64()),
191 valid_to: v.get("validTo").and_then(|v| v.as_f64()),
192 }))
193 }
194 _ => Ok(None),
195 }
196 }
197
198 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
202 pub async fn server_addr(&self) -> Result<Option<RemoteAddr>> {
203 let result: serde_json::Value = self
204 .channel()
205 .send("serverAddr", serde_json::json!({}))
206 .await?;
207
208 let value = result.get("value");
209 match value {
210 Some(v) if !v.is_null() => {
211 let ip_address = v
212 .get("ipAddress")
213 .and_then(|v| v.as_str())
214 .unwrap_or("")
215 .to_string();
216 let port = v.get("port").and_then(|v| v.as_u64()).unwrap_or(0) as u16;
217 Ok(Some(RemoteAddr { ip_address, port }))
218 }
219 _ => Ok(None),
220 }
221 }
222
223 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
227 pub async fn sizes(&self) -> Result<RequestSizes> {
228 use serde::Deserialize;
229
230 #[derive(Deserialize)]
231 #[serde(rename_all = "camelCase")]
232 struct SizesRaw {
233 request_body_size: i64,
234 request_headers_size: i64,
235 response_body_size: i64,
236 response_headers_size: i64,
237 }
238
239 #[derive(Deserialize)]
240 struct RpcResult {
241 sizes: SizesRaw,
242 }
243
244 let result: RpcResult = self.channel().send("sizes", serde_json::json!({})).await?;
245
246 Ok(RequestSizes {
247 request_body_size: result.sizes.request_body_size,
248 request_headers_size: result.sizes.request_headers_size,
249 response_body_size: result.sizes.response_body_size,
250 response_headers_size: result.sizes.response_headers_size,
251 })
252 }
253
254 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid(), version = tracing::field::Empty))]
260 pub async fn http_version(&self) -> Result<String> {
261 use serde::Deserialize;
262
263 #[derive(Deserialize)]
264 struct HttpVersionResponse {
265 value: String,
266 }
267
268 let result: HttpVersionResponse = self
269 .channel()
270 .send("httpVersion", serde_json::json!({}))
271 .await?;
272 Ok(result.value)
273 }
274
275 #[tracing::instrument(level = "debug", skip_all, fields(guid = %self.guid()))]
281 pub async fn raw_headers(&self) -> Result<Vec<HeaderEntry>> {
282 use serde::Deserialize;
283
284 #[derive(Deserialize)]
285 struct RawHeadersResponse {
286 headers: Vec<HeaderEntryRaw>,
287 }
288
289 #[derive(Deserialize)]
290 struct HeaderEntryRaw {
291 name: String,
292 value: String,
293 }
294
295 let result: RawHeadersResponse = self
296 .channel()
297 .send("rawResponseHeaders", serde_json::json!({}))
298 .await?;
299
300 Ok(result
301 .headers
302 .into_iter()
303 .map(|h| HeaderEntry {
304 name: h.name,
305 value: h.value,
306 })
307 .collect())
308 }
309}
310
311impl ChannelOwner for ResponseObject {
312 fn guid(&self) -> &str {
313 self.base.guid()
314 }
315
316 fn type_name(&self) -> &str {
317 self.base.type_name()
318 }
319
320 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
321 self.base.parent()
322 }
323
324 fn connection(&self) -> Arc<dyn crate::server::connection::ConnectionLike> {
325 self.base.connection()
326 }
327
328 fn initializer(&self) -> &Value {
329 self.base.initializer()
330 }
331
332 fn channel(&self) -> &crate::server::channel::Channel {
333 self.base.channel()
334 }
335
336 fn dispose(&self, reason: crate::server::channel_owner::DisposeReason) {
337 self.base.dispose(reason)
338 }
339
340 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
341 self.base.adopt(child)
342 }
343
344 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
345 self.base.add_child(guid, child)
346 }
347
348 fn remove_child(&self, guid: &str) {
349 self.base.remove_child(guid)
350 }
351
352 fn on_event(&self, _method: &str, _params: Value) {
353 }
355
356 fn was_collected(&self) -> bool {
357 self.base.was_collected()
358 }
359
360 fn as_any(&self) -> &dyn Any {
361 self
362 }
363}
364
365impl std::fmt::Debug for ResponseObject {
366 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
367 f.debug_struct("ResponseObject")
368 .field("guid", &self.guid())
369 .finish()
370 }
371}
372
373#[cfg(test)]
374mod security_remote_addr_tests {
375 use super::{RemoteAddr, SecurityDetails};
376
377 #[test]
378 fn security_details_deserializes_camelcase() {
379 let v = serde_json::json!({
380 "issuer": "Let's Encrypt",
381 "protocol": "TLS 1.3",
382 "subjectName": "example.com",
383 "validFrom": 1_700_000_000.0,
384 "validTo": 1_800_000_000.0
385 });
386 let sd: SecurityDetails = serde_json::from_value(v).unwrap();
387 assert_eq!(sd.issuer.as_deref(), Some("Let's Encrypt"));
388 assert_eq!(sd.subject_name.as_deref(), Some("example.com"));
389 assert_eq!(sd.protocol.as_deref(), Some("TLS 1.3"));
390 assert_eq!(sd.valid_from, Some(1_700_000_000.0));
391 assert_eq!(sd.valid_to, Some(1_800_000_000.0));
392 }
393
394 #[test]
395 fn security_details_allows_missing_fields() {
396 let sd: SecurityDetails = serde_json::from_value(serde_json::json!({})).unwrap();
397 assert!(sd.issuer.is_none() && sd.protocol.is_none() && sd.subject_name.is_none());
398 }
399
400 #[test]
401 fn remote_addr_deserializes_camelcase() {
402 let v = serde_json::json!({ "ipAddress": "127.0.0.1", "port": 8080 });
403 let addr: RemoteAddr = serde_json::from_value(v).unwrap();
404 assert_eq!(addr.ip_address, "127.0.0.1");
405 assert_eq!(addr.port, 8080);
406 }
407}