Skip to main content

msf_rtsp/header/
mod.rs

1//! Header fields.
2
3pub mod props;
4pub mod range;
5pub mod rtpinfo;
6pub mod session;
7pub mod speed;
8pub mod transport;
9
10use std::fmt::{self, Display, Formatter};
11
12use str_reader::{ParseError, StringReader};
13
14use crate::Error;
15
16pub use crate::ttpkit::header::{
17    FieldIter, HeaderField, HeaderFieldDecoder, HeaderFieldEncoder, HeaderFieldName,
18    HeaderFieldValue, HeaderFields, Iter, ValueParseError,
19};
20
21pub use self::{
22    props::MediaPropertiesHeader,
23    rtpinfo::RTPInfo,
24    session::SessionHeader,
25    speed::SpeedHeader,
26    transport::{TransportHeader, TransportHeaderV10, TransportHeaderV20},
27};
28
29/// Formatter for a list of items separated by a given separator.
30#[derive(Clone)]
31pub struct ValueListDisplay<S, T> {
32    separator: S,
33    items: T,
34}
35
36impl<S, T> ValueListDisplay<S, T> {
37    /// Create a new list formatter.
38    #[inline]
39    pub const fn new(separator: S, items: T) -> Self {
40        Self { separator, items }
41    }
42}
43
44impl<S, T, I> Display for ValueListDisplay<S, T>
45where
46    S: Display,
47    T: IntoIterator<Item = I> + Clone,
48    I: Display,
49{
50    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
51        let mut items = self.items.clone().into_iter();
52
53        if let Some(item) = items.next() {
54            Display::fmt(&item, f)?;
55        }
56
57        for item in items {
58            write!(f, "{}{}", self.separator, item)?;
59        }
60
61        Ok(())
62    }
63}
64
65impl<S, T, I> From<ValueListDisplay<S, T>> for HeaderFieldValue
66where
67    S: Display,
68    T: IntoIterator<Item = I> + Clone,
69    I: Display,
70{
71    fn from(value: ValueListDisplay<S, T>) -> Self {
72        HeaderFieldValue::from(value.to_string())
73    }
74}
75
76/// Parse a given header parameter.
77fn parse_header_parameter(s: &str) -> (&str, &str) {
78    let (n, v) = s.split_once('=').unwrap_or((s, ""));
79
80    let name = n.trim();
81    let value = v.trim();
82
83    (name, value)
84}
85
86/// Character extensions.
87trait CharExt {
88    /// Check if the character is an RTSP token character.
89    fn is_rtsp_token(&self) -> bool;
90
91    /// Check if the character is an RTSP unreserved character.
92    fn is_rtsp_unreserved(&self) -> bool;
93}
94
95impl CharExt for char {
96    fn is_rtsp_token(&self) -> bool {
97        match *self {
98            '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '.' | '^' | '_' | '`' | '|'
99            | '~' => true,
100            _ => self.is_ascii_alphanumeric(),
101        }
102    }
103
104    fn is_rtsp_unreserved(&self) -> bool {
105        match *self {
106            '!' | '$' | '\'' | '(' | ')' | '*' | '+' | '-' | '.' | '_' => true,
107            _ => self.is_ascii_alphanumeric(),
108        }
109    }
110}
111
112/// String reader extension.
113trait StringReaderExt<'a> {
114    /// Read characters while a given condition holds.
115    fn read_while<F>(&mut self, condition: F) -> &'a str
116    where
117        F: FnMut(char) -> bool;
118
119    /// Match a given RTSP separator.
120    fn match_rtsp_separator(&mut self, separator: char) -> Result<(), ParseError>;
121
122    /// Read an RTP token.
123    fn read_rtsp_token(&mut self) -> Result<&'a str, Error>;
124
125    /// Read a positive float number.
126    fn read_positive_float(&mut self) -> Result<&'a str, Error>;
127
128    /// Parse a positive f32 number.
129    fn parse_positive_f32(&mut self) -> Result<f32, Error>;
130
131    /// Read a float number.
132    fn read_float(&mut self) -> Result<&'a str, Error>;
133
134    /// Parse an f32 number.
135    fn parse_f32(&mut self) -> Result<f32, Error>;
136
137    /// Read an RTSP quoted string.
138    fn read_rtsp_quoted_string(&mut self) -> Result<&'a str, Error>;
139
140    /// Parse an RTSP quoted string.
141    fn parse_rtsp_quoted_string(&mut self) -> Result<String, Error>;
142}
143
144impl<'a> StringReaderExt<'a> for StringReader<'a> {
145    fn read_while<F>(&mut self, mut condition: F) -> &'a str
146    where
147        F: FnMut(char) -> bool,
148    {
149        self.read_until(|char| !condition(char))
150    }
151
152    fn match_rtsp_separator(&mut self, separator: char) -> Result<(), ParseError> {
153        let mut reader = StringReader::new(self.as_str());
154
155        reader.skip_whitespace();
156        reader.match_char(separator)?;
157        reader.skip_whitespace();
158
159        *self = reader;
160
161        Ok(())
162    }
163
164    fn read_rtsp_token(&mut self) -> Result<&'a str, Error> {
165        let res = self.read_while(|c| c.is_rtsp_token());
166
167        if !res.is_empty() {
168            Ok(res)
169        } else if self.is_empty() {
170            Err(Error::from_static_msg("unexpected end of input"))
171        } else {
172            Err(Error::from_static_msg("invalid RTSP token"))
173        }
174    }
175
176    fn read_positive_float(&mut self) -> Result<&'a str, Error> {
177        let s = self.as_str();
178
179        let mut reader = StringReader::new(s);
180
181        reader.read_while(|c| c.is_ascii_digit());
182
183        if reader.match_char('.').is_ok() {
184            reader.read_while(|c| c.is_ascii_digit());
185        }
186
187        *self = reader;
188
189        let r = self.as_str();
190
191        let original_len = s.len();
192        let remaining_len = r.len();
193
194        let len = original_len - remaining_len;
195
196        if len == 0 {
197            Err(Error::from_static_msg("invalid float number"))
198        } else {
199            Ok(&s[..len])
200        }
201    }
202
203    fn parse_positive_f32(&mut self) -> Result<f32, Error> {
204        self.read_positive_float()
205            .ok()
206            .map(|v| v.parse())
207            .and_then(|r| r.ok())
208            .ok_or_else(|| Error::from_static_msg("invalid float number"))
209    }
210
211    fn read_float(&mut self) -> Result<&'a str, Error> {
212        let s = self.as_str();
213
214        let mut reader = StringReader::new(s);
215
216        let _ = reader.match_char('-');
217
218        reader.read_positive_float()?;
219
220        *self = reader;
221
222        let r = self.as_str();
223
224        let original_len = s.len();
225        let remaining_len = r.len();
226
227        let len = original_len - remaining_len;
228
229        Ok(&s[..len])
230    }
231
232    fn parse_f32(&mut self) -> Result<f32, Error> {
233        self.read_float()
234            .ok()
235            .map(|v| v.parse())
236            .and_then(|r| r.ok())
237            .ok_or_else(|| Error::from_static_msg("invalid float number"))
238    }
239
240    fn read_rtsp_quoted_string(&mut self) -> Result<&'a str, Error> {
241        let s = self.as_str();
242
243        let mut reader = StringReader::new(s);
244
245        reader.match_char('"')?;
246
247        loop {
248            match reader.read_char()? {
249                '"' => break,
250                '\\' => match reader.read_char()? {
251                    '"' | '\\' => (),
252                    _ => return Err(Error::from_static_msg("unexpected escape character")),
253                },
254                _ => (),
255            }
256        }
257
258        *self = reader;
259
260        let r = self.as_str();
261
262        let original_len = s.len();
263        let remaining_len = r.len();
264
265        let len = original_len - remaining_len;
266
267        Ok(&s[..len])
268    }
269
270    fn parse_rtsp_quoted_string(&mut self) -> Result<String, Error> {
271        let res = self
272            .read_rtsp_quoted_string()?
273            .trim_matches('"')
274            .replace("\\\"", "\"")
275            .replace("\\\\", "\\");
276
277        Ok(res)
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use str_reader::StringReader;
284
285    use super::StringReaderExt;
286
287    #[test]
288    fn test_match_rtsp_separator() {
289        let mut reader = StringReader::new("a,b ,c, d , e\t, f\n,g ; h");
290
291        assert!(reader.match_str("a").is_ok());
292        assert!(reader.match_rtsp_separator(',').is_ok());
293        assert!(reader.match_str("b").is_ok());
294        assert!(reader.match_rtsp_separator(',').is_ok());
295        assert!(reader.match_str("c").is_ok());
296        assert!(reader.match_rtsp_separator(',').is_ok());
297        assert!(reader.match_str("d").is_ok());
298        assert!(reader.match_rtsp_separator(',').is_ok());
299        assert!(reader.match_str("e").is_ok());
300        assert!(reader.match_rtsp_separator(',').is_ok());
301        assert!(reader.match_str("f").is_ok());
302        assert!(reader.match_rtsp_separator(',').is_ok());
303        assert!(reader.match_str("g").is_ok());
304
305        assert!(reader.match_rtsp_separator(',').is_err());
306
307        assert_eq!(reader.as_str(), " ; h");
308
309        assert!(reader.match_rtsp_separator(';').is_ok());
310        assert!(reader.match_str("h").is_ok());
311
312        assert!(reader.is_empty());
313    }
314
315    #[test]
316    fn test_read_rtsp_quoted_string() {
317        let mut reader = StringReader::new("");
318
319        assert!(reader.read_rtsp_quoted_string().is_err());
320
321        let mut reader = StringReader::new("a");
322
323        assert!(reader.read_rtsp_quoted_string().is_err());
324
325        let mut reader = StringReader::new(" \"\" ");
326
327        assert!(reader.read_rtsp_quoted_string().is_err());
328
329        let mut reader = StringReader::new("\" ");
330
331        assert!(reader.read_rtsp_quoted_string().is_err());
332
333        let mut reader = StringReader::new("\"\\\"");
334
335        assert!(reader.read_rtsp_quoted_string().is_err());
336
337        let mut reader = StringReader::new("\"\\a\"");
338
339        assert!(reader.read_rtsp_quoted_string().is_err());
340
341        let mut reader = StringReader::new("\"\" ");
342
343        let res = reader.read_rtsp_quoted_string();
344
345        assert!(matches!(res, Ok("\"\"")));
346        assert_eq!(reader.as_str(), " ");
347
348        let mut reader = StringReader::new("\"abc \t\n\\\"\\\\def \"");
349
350        assert!(matches!(
351            reader.read_rtsp_quoted_string(),
352            Ok("\"abc \t\n\\\"\\\\def \"")
353        ));
354    }
355
356    #[test]
357    fn test_parse_rtsp_quoted_string() {
358        let mut reader = StringReader::new("\"\" ");
359
360        let res = reader.parse_rtsp_quoted_string();
361
362        assert!(matches!(res.as_deref(), Ok("")));
363        assert_eq!(reader.as_str(), " ");
364
365        let mut reader = StringReader::new("\"abc \t\n\\\"\\\\def \"");
366
367        let res = reader.parse_rtsp_quoted_string();
368
369        assert!(matches!(res.as_deref(), Ok("abc \t\n\"\\def ")));
370    }
371
372    #[test]
373    fn test_read_rtsp_token() {
374        let input = " abc \nd1f\tfoo-bar";
375        let mut reader = StringReader::new(input);
376
377        assert!(reader.read_rtsp_token().is_err());
378        assert_eq!(reader.as_str(), input);
379
380        reader.skip_whitespace();
381
382        assert!(matches!(reader.read_rtsp_token(), Ok("abc")));
383
384        reader.skip_whitespace();
385
386        assert!(matches!(reader.read_rtsp_token(), Ok("d1f")));
387
388        reader.skip_whitespace();
389
390        assert!(matches!(reader.read_rtsp_token(), Ok("foo-bar")));
391
392        assert!(reader.is_empty());
393    }
394
395    #[test]
396    fn test_parse_f32() {
397        let mut reader = StringReader::new("1.0");
398
399        assert!(matches!(reader.parse_f32(), Ok(1.0)));
400        assert!(reader.is_empty());
401
402        let mut reader = StringReader::new("-1.0");
403
404        assert!(matches!(reader.parse_f32(), Ok(-1.0)));
405        assert!(reader.is_empty());
406
407        let mut reader = StringReader::new("1.0 ");
408
409        assert!(matches!(reader.parse_f32(), Ok(1.0)));
410        assert_eq!(reader.as_str(), " ");
411
412        let mut reader = StringReader::new("1.0a");
413
414        assert!(matches!(reader.parse_f32(), Ok(1.0)));
415        assert_eq!(reader.as_str(), "a");
416
417        let mut reader = StringReader::new("a1.0");
418
419        assert!(reader.parse_f32().is_err());
420        assert_eq!(reader.as_str(), "a1.0");
421    }
422}