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()] });