hyperx/header/common/
preference_applied.rs

1use std::fmt;
2use header::{Header, RawLike, Preference};
3use header::parsing::{from_comma_delimited, fmt_comma_delimited};
4
5/// `Preference-Applied` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240)
6///
7/// The `Preference-Applied` response header may be included within a
8/// response message as an indication as to which `Prefer` header tokens were
9/// honored by the server and applied to the processing of a request.
10///
11/// # ABNF
12///
13/// ```text
14/// Preference-Applied = "Preference-Applied" ":" 1#applied-pref
15/// applied-pref = token [ BWS "=" BWS word ]
16/// ```
17///
18/// # Example values
19///
20/// * `respond-async`
21/// * `return=minimal`
22/// * `wait=30`
23///
24/// # Examples
25///
26/// ```
27/// # extern crate http;
28/// use hyperx::header::{PreferenceApplied, Preference, TypedHeaders};
29///
30/// let mut headers = http::HeaderMap::new();
31/// headers.insert(
32///     "preference-applied",
33///     PreferenceApplied(vec![
34///         Preference::RespondAsync
35///     ]).to_string().parse().unwrap()
36/// );
37/// ```
38///
39/// ```
40/// # extern crate http;
41/// use hyperx::header::{PreferenceApplied, Preference, TypedHeaders};
42///
43/// let mut headers = http::HeaderMap::new();
44/// headers.insert(
45///     "preference-applied",
46///     PreferenceApplied(vec![
47///         Preference::RespondAsync,
48///         Preference::ReturnRepresentation,
49///         Preference::Wait(10u32),
50///         Preference::Extension("foo".to_owned(),
51///                               "bar".to_owned(),
52///                               vec![]),
53///     ]).to_string().parse().unwrap()
54/// );
55/// ```
56#[derive(PartialEq, Clone, Debug)]
57pub struct PreferenceApplied(pub Vec<Preference>);
58
59__hyper__deref!(PreferenceApplied => Vec<Preference>);
60
61impl Header for PreferenceApplied {
62    fn header_name() -> &'static str {
63        static NAME: &'static str = "Preference-Applied";
64        NAME
65    }
66
67    fn parse_header<'a, T>(raw: &'a T) -> ::Result<PreferenceApplied>
68    where T: RawLike<'a>
69    {
70        let preferences = from_comma_delimited(raw)?;
71        if !preferences.is_empty() {
72            Ok(PreferenceApplied(preferences))
73        } else {
74            Err(::Error::Header)
75        }
76    }
77
78    fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result {
79        f.fmt_line(self)
80    }
81}
82
83impl fmt::Display for PreferenceApplied {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        //TODO: format this without allocating a Vec and cloning contents
86        let preferences: Vec<_> = self.0.iter().map(|pref| match pref {
87            // The spec ignores parameters in `Preferences-Applied`
88            &Preference::Extension(ref name, ref value, _) => Preference::Extension(
89              name.to_owned(),
90              value.to_owned(),
91              vec![]
92            ),
93            preference => preference.clone()
94        }).collect();
95        fmt_comma_delimited(f, &preferences)
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use header::Preference;
102    use super::*;
103
104    #[test]
105    fn test_format_ignore_parameters() {
106        assert_eq!(
107            format!("{}", PreferenceApplied(vec![Preference::Extension(
108                "foo".to_owned(),
109                "bar".to_owned(),
110                vec![("bar".to_owned(), "foo".to_owned()), ("buz".to_owned(), "".to_owned())]
111            )])),
112            "foo=bar".to_owned()
113        );
114    }
115}
116
117bench_header!(normal,
118    PreferenceApplied, { vec![b"respond-async, return=representation".to_vec(), b"wait=100".to_vec()] });