Skip to main content

freeswitch_sofia_trace_parser/
grep.rs

1use 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}