rocket_http/parse/
accept.rs

1use pear::macros::{parser, parse_error};
2use pear::combinators::{series, surrounded};
3
4use crate::{Accept, QMediaType};
5use crate::parse::checkers::is_whitespace;
6use crate::parse::media_type::media_type;
7
8type Input<'a> = pear::input::Pear<pear::input::Cursor<&'a str>>;
9type Result<'a, T> = pear::input::Result<T, Input<'a>>;
10
11#[parser]
12fn weighted_media_type<'a>(input: &mut Input<'a>) -> Result<'a, QMediaType> {
13    let media_type = media_type()?;
14    let q = match media_type.params().next() {
15        Some((name, value)) if name  == "q" => Some(value),
16        _ => None
17    };
18
19    let weight = match q {
20        Some(value) if value.len() <= 5 => match value.parse::<f32>().ok() {
21            Some(q) if q > 1. => parse_error!("q value must be <= 1")?,
22            Some(q) if q < 0. => parse_error!("q value must be > 0")?,
23            Some(q) => Some(q),
24            None => parse_error!("invalid media-type weight")?
25        },
26        _ => None
27    };
28
29    QMediaType(media_type, weight)
30}
31
32#[parser]
33fn accept<'a>(input: &mut Input<'a>) -> Result<'a, Accept> {
34    Accept(series(|i| surrounded(i, weighted_media_type, is_whitespace), ',')?)
35}
36
37pub fn parse_accept(input: &str) -> Result<'_, Accept> {
38    parse!(accept: Input::new(input))
39}
40
41#[cfg(test)]
42mod test {
43    use crate::MediaType;
44    use super::parse_accept;
45
46    macro_rules! assert_parse {
47        ($string:expr) => ({
48            match parse_accept($string) {
49                Ok(accept) => accept,
50                Err(e) => panic!("{:?} failed to parse: {}", $string, e)
51            }
52        });
53    }
54
55    macro_rules! assert_parse_eq {
56        ($string:expr, [$($mt:expr),*]) => ({
57            let expected = vec![$($mt),*];
58            let result = assert_parse!($string);
59            for (i, wmt) in result.iter().enumerate() {
60                assert_eq!(wmt.media_type(), &expected[i]);
61            }
62        });
63    }
64
65    #[test]
66    fn check_does_parse() {
67        assert_parse!("text/html");
68        assert_parse!("*/*, a/b; q=1.0; v=1, application/something, a/b");
69        assert_parse!("a/b, b/c");
70        assert_parse!("text/*");
71        assert_parse!("text/*; q=1");
72        assert_parse!("text/*; q=1; level=2");
73        assert_parse!("audio/*; q=0.2, audio/basic");
74        assert_parse!("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c");
75        assert_parse!("text/*, text/html, text/html;level=1, */*");
76        assert_parse!("text/*;q=0.3, text/html;q=0.7, text/html;level=1, \
77               text/html;level=2;q=0.4, */*;q=0.5");
78    }
79
80    #[test]
81    fn check_parse_eq() {
82        assert_parse_eq!("text/html", [MediaType::HTML]);
83        assert_parse_eq!("text/html, application/json",
84                         [MediaType::HTML, MediaType::JSON]);
85        assert_parse_eq!("text/html; charset=utf-8; v=1, application/json",
86                         [MediaType::HTML, MediaType::JSON]);
87        assert_parse_eq!("text/html, text/html; q=0.1, text/html; q=0.2",
88                         [MediaType::HTML, MediaType::HTML, MediaType::HTML]);
89    }
90}