ocular_protocol/
handlers.rs1use crate::handler::ProtocolHandler;
2use crate::ProxyEvent;
3
4pub 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
17pub 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
49pub 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
72pub 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
89pub 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
108pub 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
160pub 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
184pub 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}