freeswitch_sofia_trace_parser/
grep.rs1use std::io::{BufRead, BufReader, Read};
2
3pub struct GrepFilter<R> {
4 inner: BufReader<R>,
5 buf: Vec<u8>,
6 pos: usize,
7}
8
9impl<R: Read> GrepFilter<R> {
10 pub fn new(reader: R) -> Self {
11 Self {
12 inner: BufReader::new(reader),
13 buf: Vec::new(),
14 pos: 0,
15 }
16 }
17}
18
19fn is_grep_separator(line: &[u8]) -> bool {
20 line == b"--\n" || line == b"--\r\n"
21}
22
23impl<R: Read> Read for GrepFilter<R> {
24 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
25 if self.pos < self.buf.len() {
26 let available = &self.buf[self.pos..];
27 let n = buf.len().min(available.len());
28 buf[..n].copy_from_slice(&available[..n]);
29 self.pos += n;
30 if self.pos == self.buf.len() {
31 self.buf.clear();
32 self.pos = 0;
33 }
34 return Ok(n);
35 }
36
37 self.buf.clear();
38 self.pos = 0;
39
40 while self.buf.len() < buf.len() {
41 let old_len = self.buf.len();
42 let n = self.inner.read_until(b'\n', &mut self.buf)?;
43 if n == 0 {
44 break;
45 }
46 if is_grep_separator(&self.buf[old_len..]) {
47 self.buf.truncate(old_len);
48 }
49 }
50
51 let n = buf.len().min(self.buf.len());
52 buf[..n].copy_from_slice(&self.buf[..n]);
53 self.pos = n;
54 if self.pos == self.buf.len() {
55 self.buf.clear();
56 self.pos = 0;
57 }
58 Ok(n)
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use std::io::Read;
66
67 fn filter(input: &[u8]) -> Vec<u8> {
68 let mut out = Vec::new();
69 GrepFilter::new(input).read_to_end(&mut out).unwrap();
70 out
71 }
72
73 #[test]
74 fn strip_separator() {
75 assert_eq!(filter(b"hello\n--\nworld\n"), b"hello\nworld\n");
76 }
77
78 #[test]
79 fn strip_crlf_separator() {
80 assert_eq!(filter(b"hello\n--\r\nworld\n"), b"hello\nworld\n");
81 }
82
83 #[test]
84 fn passthrough_no_separators() {
85 let input = b"line one\nline two\nline three\n";
86 assert_eq!(filter(input), input);
87 }
88
89 #[test]
90 fn consecutive_separators() {
91 assert_eq!(filter(b"a\n--\n--\n--\nb\n"), b"a\nb\n");
92 }
93
94 #[test]
95 fn separator_at_start() {
96 assert_eq!(filter(b"--\nhello\n"), b"hello\n");
97 }
98
99 #[test]
100 fn partial_separator_preserved() {
101 let input = b"---\n-- \n--x\n";
102 assert_eq!(filter(input), input);
103 }
104
105 #[test]
106 fn empty_input() {
107 assert_eq!(filter(b""), b"");
108 }
109
110 #[test]
111 fn only_separators() {
112 assert_eq!(filter(b"--\n--\n--\n"), b"");
113 }
114
115 #[test]
116 fn no_trailing_newline() {
117 assert_eq!(filter(b"hello"), b"hello");
118 }
119
120 #[test]
121 fn binary_content_with_separator_like_bytes() {
122 let input = b"data\x00--\nmore\n";
123 assert_eq!(filter(input), input);
124 }
125
126 #[test]
127 fn frame_iterator_grep_separator_between_frames() {
128 use crate::FrameIterator;
129
130 let mut data = Vec::new();
131 data.extend_from_slice(
132 b"recv 5 bytes from tcp/1.1.1.1:5060 at 00:00:00.000000:\nhello\x0B\n",
133 );
134 data.extend_from_slice(
135 b"sent 5 bytes to tcp/1.1.1.1:5060 at 00:00:00.000001:\nworld\x0B\n",
136 );
137
138 let filtered = GrepFilter::new(&data[..]);
139 let frames: Vec<_> = FrameIterator::new(filtered)
140 .collect::<Result<Vec<_>, _>>()
141 .unwrap();
142 assert_eq!(frames.len(), 2);
143 assert_eq!(frames[0].content, b"hello");
144 assert_eq!(frames[1].content, b"world");
145 }
146
147 #[test]
148 fn frame_iterator_grep_partial_context() {
149 use crate::FrameIterator;
150
151 let mut data = Vec::new();
152 data.extend_from_slice(
153 b"recv 5 bytes from tcp/1.1.1.1:5060 at 00:00:00.000000:\nhello\x0B\n",
154 );
155 data.extend_from_slice(b"Accept: application/sdp\r\nContent-Length: 0\r\n\r\n");
156 data.extend_from_slice(b"\x0B\n");
157 data.extend_from_slice(b"sent 3 bytes to tcp/2.2.2.2:5060 at 00:00:01.000000:\nbye\x0B\n");
158
159 let filtered = GrepFilter::new(&data[..]);
160 let items: Vec<_> = FrameIterator::new(filtered).collect();
161 let frames: Vec<_> = items.into_iter().filter_map(Result::ok).collect();
162 assert_eq!(frames.len(), 2);
163 assert_eq!(frames[0].content, b"hello");
164 assert_eq!(frames[1].content, b"bye");
165 }
166
167 #[test]
168 fn frame_iterator_grep_separator_strips_from_content() {
169 use crate::FrameIterator;
170
171 let content = b"SIP/2.0 200 OK\r\nVia: a\r\nContent-Length: 0\r\n\r\n";
172 let mut data = Vec::new();
173 let header = format!(
174 "recv {} bytes from tcp/1.1.1.1:5060 at 00:00:00.000000:\n",
175 content.len()
176 );
177 data.extend_from_slice(header.as_bytes());
178 data.extend_from_slice(b"SIP/2.0 200 OK\r\nVia: a\r\n--\nContent-Length: 0\r\n\r\n");
179 data.extend_from_slice(b"\x0B\n");
180
181 let filtered = GrepFilter::new(&data[..]);
182 let frames: Vec<_> = FrameIterator::new(filtered)
183 .collect::<Result<Vec<_>, _>>()
184 .unwrap();
185 assert_eq!(frames.len(), 1);
186 assert_eq!(frames[0].content, content);
187 }
188}