Skip to main content

ocular_protocol/
handlers.rs

1use crate::handler::ProtocolHandler;
2use crate::ProxyEvent;
3
4// ─── Redis ──────────────────────────────────────────────────────────────────
5
6pub struct RedisHandler;
7
8impl ProtocolHandler for RedisHandler {
9    fn parse_request(&self, buf: &[u8]) -> Option<String> {
10        crate::parse_resp(buf).ok().flatten().map(|(val, _)| val.to_command_string())
11    }
12    fn parse_response(&self, buf: &[u8]) -> Option<String> {
13        crate::parse_resp(buf).ok().flatten().map(|(val, _)| val.to_command_string())
14    }
15}
16
17// ─── MySQL ──────────────────────────────────────────────────────────────────
18
19pub struct MysqlHandler;
20
21impl ProtocolHandler for MysqlHandler {
22    fn parse_request(&self, buf: &[u8]) -> Option<String> {
23        crate::parse_mysql_request(buf).map(|pkt| pkt.to_summary())
24    }
25    fn extract_full_command(&self, buf: &[u8]) -> Option<String> {
26        if buf.len() < 5 { return None; }
27        let payload_len = (buf[0] as usize) | (buf[1] as usize) << 8 | (buf[2] as usize) << 16;
28        if buf.len() < 4 + payload_len || payload_len <= 1 { return None; }
29        let cmd = buf[4];
30        if cmd == 0x03 || cmd == 0x16 {
31            let sql = String::from_utf8_lossy(&buf[5..4 + payload_len]);
32            Some(sql.replace(|c: char| c.is_control(), ""))
33        } else {
34            self.parse_request(buf)
35        }
36    }
37    fn parse_response(&self, buf: &[u8]) -> Option<String> {
38        crate::parse_mysql_response(buf).map(|r| r.to_summary())
39    }
40    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
41        crate::parse_mysql_response(buf).map(|r| r.to_display())
42    }
43    fn needs_response_buffering(&self) -> bool { true }
44    fn response_complete(&self, buf: &[u8]) -> bool {
45        crate::mysql::mysql_response_complete(buf)
46    }
47}
48
49// ─── PostgreSQL ─────────────────────────────────────────────────────────────
50
51pub struct PostgresHandler;
52
53impl ProtocolHandler for PostgresHandler {
54    fn parse_request(&self, buf: &[u8]) -> Option<String> {
55        crate::postgres::parse_postgres_request(buf)
56    }
57    fn extract_full_command(&self, buf: &[u8]) -> Option<String> {
58        crate::postgres::extract_postgres_full_command(buf)
59    }
60    fn parse_response(&self, buf: &[u8]) -> Option<String> {
61        crate::postgres::parse_postgres_response(buf)
62    }
63    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
64        crate::postgres::format_postgres_response_detail(buf)
65    }
66    fn needs_response_buffering(&self) -> bool { true }
67    fn response_complete(&self, buf: &[u8]) -> bool {
68        crate::postgres::postgres_response_complete(buf)
69    }
70}
71
72// ─── AMQP ───────────────────────────────────────────────────────────────────
73
74pub struct AmqpHandler;
75
76impl ProtocolHandler for AmqpHandler {
77    fn parse_request(&self, buf: &[u8]) -> Option<String> {
78        crate::amqp::parse_amqp_request(buf)
79    }
80    fn parse_response(&self, buf: &[u8]) -> Option<String> {
81        crate::amqp::parse_amqp_response(buf)
82    }
83    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
84        crate::amqp::format_amqp_response_detail(buf)
85    }
86    fn is_frame_based(&self) -> bool { true }
87}
88
89// ─── MongoDB ────────────────────────────────────────────────────────────────
90
91pub struct MongodbHandler;
92
93impl ProtocolHandler for MongodbHandler {
94    fn parse_request(&self, buf: &[u8]) -> Option<String> {
95        crate::mongodb::parse_mongo_request(buf)
96    }
97    fn extract_full_command(&self, buf: &[u8]) -> Option<String> {
98        crate::mongodb::extract_mongo_full_command(buf)
99    }
100    fn parse_response(&self, buf: &[u8]) -> Option<String> {
101        crate::mongodb::parse_mongo_response(buf)
102    }
103    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
104        crate::mongodb::format_mongo_response_detail(buf)
105    }
106}
107
108// ─── HTTP ───────────────────────────────────────────────────────────────────
109
110pub struct HttpHandler;
111
112
113impl ProtocolHandler for HttpHandler {
114    fn parse_request(&self, buf: &[u8]) -> Option<String> {
115        crate::http::parse_http_request(buf)
116    }
117    fn extract_full_command(&self, buf: &[u8]) -> Option<String> {
118        crate::http::extract_http_full_command(buf)
119    }
120    fn parse_response(&self, buf: &[u8]) -> Option<String> {
121        crate::http::parse_http_response(buf)
122    }
123    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
124        crate::http::format_http_response_detail(buf)
125    }
126    fn to_replay_command(&self, ev: &ProxyEvent) -> String {
127        let dest = ev.dest.as_deref().unwrap_or("localhost");
128        let lines: Vec<&str> = ev.full_command.lines().collect();
129        let first_line = lines.first().copied().unwrap_or("");
130        let mut parts = first_line.splitn(2, ' ');
131        let method = parts.next().unwrap_or("GET");
132        let path = parts.next().unwrap_or("/");
133        let url = format!("http://{}{}", dest, path);
134        let mut curl = format!("curl -X {} '{}'", method, url);
135
136        let mut in_headers = false;
137        let mut in_body = false;
138        let mut body = String::new();
139        for line in &lines[1..] {
140            if *line == "[Request Headers]" { in_headers = true; in_body = false; continue; }
141            if *line == "[Request Body]" { in_body = true; in_headers = false; continue; }
142            if line.starts_with('[') && line.ends_with(']') { in_headers = false; in_body = false; continue; }
143            if line.is_empty() { continue; }
144            if in_headers { curl.push_str(&format!(" \\\n  -H '{}'", line)); }
145            if in_body { body.push_str(line); }
146        }
147        if !body.is_empty() { curl.push_str(&format!(" \\\n  -d '{}'", body)); }
148        curl
149    }
150    fn needs_request_buffering(&self) -> bool { true }
151    fn needs_response_buffering(&self) -> bool { true }
152    fn request_complete(&self, buf: &[u8]) -> bool {
153        crate::http::http_request_complete(buf)
154    }
155    fn response_complete(&self, buf: &[u8]) -> bool {
156        crate::http::http_response_complete(buf)
157    }
158}
159
160// ─── Memcached ──────────────────────────────────────────────────────────────
161
162pub struct MemcachedHandler;
163
164impl ProtocolHandler for MemcachedHandler {
165    fn parse_request(&self, buf: &[u8]) -> Option<String> {
166        crate::memcached::parse_memcached_request(buf)
167    }
168    fn parse_response(&self, buf: &[u8]) -> Option<String> {
169        crate::memcached::parse_memcached_response(buf)
170    }
171    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
172        crate::memcached::format_memcached_response_detail(buf)
173    }
174    fn needs_request_buffering(&self) -> bool { true }
175    fn needs_response_buffering(&self) -> bool { true }
176    fn request_complete(&self, buf: &[u8]) -> bool {
177        crate::memcached::memcached_request_complete(buf)
178    }
179    fn response_complete(&self, buf: &[u8]) -> bool {
180        crate::memcached::memcached_response_complete(buf)
181    }
182}
183
184// ─── Kafka ──────────────────────────────────────────────────────────────────
185
186pub struct KafkaHandler;
187
188impl ProtocolHandler for KafkaHandler {
189    fn parse_request(&self, buf: &[u8]) -> Option<String> {
190        crate::kafka::parse_kafka_request(buf)
191    }
192    fn extract_full_command(&self, buf: &[u8]) -> Option<String> {
193        crate::kafka::extract_kafka_full_command(buf)
194    }
195    fn parse_response(&self, buf: &[u8]) -> Option<String> {
196        crate::kafka::parse_kafka_response(buf)
197    }
198    fn format_response_detail(&self, buf: &[u8]) -> Option<String> {
199        crate::kafka::format_kafka_response_detail(buf)
200    }
201    fn needs_request_buffering(&self) -> bool { true }
202    fn needs_response_buffering(&self) -> bool { true }
203    fn request_complete(&self, buf: &[u8]) -> bool {
204        crate::kafka::kafka_frame_complete(buf)
205    }
206    fn response_complete(&self, buf: &[u8]) -> bool {
207        crate::kafka::kafka_frame_complete(buf)
208    }
209}