agentsight_capture/analyzers/common.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 eunomia-bpf org.
3
4/// Common utilities for data analysis and processing across analyzers
5use serde_json::Value;
6
7/// Detect if string data is binary or text based on control characters
8///
9/// This function determines data type by checking if the string contains
10/// control characters beyond the allowed ones (\n, \r, \t).
11///
12/// # Arguments
13/// * `data_str` - The string data to analyze
14///
15/// # Returns
16/// * `"text"` if the data contains only printable characters and allowed control chars
17/// * `"binary"` if the data contains other control characters (likely binary data)
18///
19/// # Examples
20/// ```
21/// use agentsight_capture::analyzers::common::detect_data_type;
22///
23/// assert_eq!(detect_data_type("Hello World"), "text");
24/// assert_eq!(detect_data_type("HTTP/1.1 200 OK\r\n"), "text");
25/// assert_eq!(detect_data_type("\x00\x01\x02binary"), "binary");
26/// ```
27pub fn detect_data_type(data_str: &str) -> &'static str {
28 if data_str
29 .chars()
30 .all(|c| !c.is_control() || c == '\n' || c == '\r' || c == '\t')
31 {
32 "text"
33 } else {
34 "binary"
35 }
36}
37
38/// Convert data to a human-readable string representation
39///
40/// This function handles both text and binary data by detecting the type
41/// and formatting appropriately. Binary data is converted to hex representation.
42///
43/// # Arguments
44/// * `data` - The JSON value containing the data to convert
45///
46/// # Returns
47/// * For text data: the original string
48/// * For binary data: hex-encoded string with "HEX:" prefix
49/// * For null data: "null" string
50/// * For other types: JSON string representation
51///
52/// # Examples
53/// ```
54/// use serde_json::json;
55/// use agentsight_capture::analyzers::common::data_to_string;
56///
57/// let text_data = json!("Hello World");
58/// assert_eq!(data_to_string(&text_data), "Hello World");
59///
60/// let binary_data = json!("\x00\x01\x02");
61/// assert!(data_to_string(&binary_data).starts_with("HEX:"));
62/// ```
63pub fn data_to_string(data: &Value) -> String {
64 match data {
65 Value::String(s) => {
66 // Check if string contains valid UTF-8 text or binary data
67 if detect_data_type(s) == "text" {
68 s.clone()
69 } else {
70 // Convert to hex if it contains control characters (likely binary)
71 format!("HEX:{}", hex::encode(s.as_bytes()))
72 }
73 }
74 Value::Null => "null".to_string(),
75 _ => data.to_string(),
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use serde_json::json;
83
84 #[test]
85 fn test_detect_data_type() {
86 // Test text data detection
87 assert_eq!(detect_data_type("Hello World"), "text");
88 assert_eq!(detect_data_type("HTTP/1.1 200 OK\r\n"), "text");
89 assert_eq!(detect_data_type("JSON: {\"key\": \"value\"}\n"), "text");
90 assert_eq!(detect_data_type("Line1\nLine2\tTabbed"), "text");
91
92 // Test binary data detection (contains control characters)
93 assert_eq!(detect_data_type("\x00\x01\x02binary"), "binary");
94 assert_eq!(detect_data_type("text\x00with\x01null"), "binary");
95 assert_eq!(detect_data_type("\x1b[31mANSI\x1b[0m"), "binary");
96
97 // Test edge cases
98 assert_eq!(detect_data_type(""), "text"); // Empty string is text
99 assert_eq!(detect_data_type("\r\n\t"), "text"); // Only allowed control chars
100 }
101
102 #[test]
103 fn test_data_to_string() {
104 // Test text data
105 let text_value = json!("Hello World");
106 assert_eq!(data_to_string(&text_value), "Hello World");
107
108 // Test binary data
109 let binary_value = json!("\x00\x01\x02binary");
110 let result = data_to_string(&binary_value);
111 assert!(result.starts_with("HEX:"));
112 assert!(result.contains("000102"));
113
114 // Test null value
115 let null_value = json!(null);
116 assert_eq!(data_to_string(&null_value), "null");
117
118 // Test other types
119 let number_value = json!(42);
120 assert_eq!(data_to_string(&number_value), "42");
121 }
122
123 #[test]
124 fn test_edge_cases() {
125 // Empty string
126 assert_eq!(detect_data_type(""), "text");
127 assert_eq!(data_to_string(&json!("")), "");
128
129 // Only control characters
130 assert_eq!(detect_data_type("\r\n\t"), "text");
131 assert_eq!(detect_data_type("\x00"), "binary");
132
133 // Mixed content
134 assert_eq!(detect_data_type("Hello\x00World"), "binary");
135 assert_eq!(detect_data_type("Hello\nWorld"), "text");
136 }
137}