hyperx/header/
raw.rs

1use std::borrow::Cow;
2use std::fmt;
3use bytes::Bytes;
4
5/// Trait for raw bytes parsing access to header values (aka lines) for a single
6/// header name.
7pub trait RawLike<'a> {
8    /// The associated type of `Iterator` over values.
9    type IntoIter: Iterator<Item=&'a [u8]> + 'a;
10
11    /// Return the number of values (lines) in the headers.
12    fn len(&'a self) -> usize;
13
14    /// Return the single value (line), if and only if there is exactly
15    /// one. Otherwise return `None`.
16    fn one(&'a self) -> Option<&'a [u8]>;
17
18    /// Iterate the values (lines) as raw bytes.
19    fn iter(&'a self) -> Self::IntoIter;
20}
21
22/// A raw header value.
23#[derive(Clone, Debug)]
24pub struct Raw(Lines);
25
26impl Raw {
27    /// Append a line to this `Raw` header value.
28    pub fn push<V: Into<Raw>>(&mut self, val: V) {
29        let raw = val.into();
30        match raw.0 {
31            Lines::Empty => (),
32            Lines::One(one) => self.push_line(one),
33            Lines::Many(lines) => {
34                for line in lines {
35                    self.push_line(line);
36                }
37            }
38        }
39    }
40
41    fn push_line(&mut self, line: Bytes) {
42        let lines = ::std::mem::replace(&mut self.0, Lines::Empty);
43        match lines {
44            Lines::Empty => {
45                self.0 = Lines::One(line);
46            }
47            Lines::One(one) => {
48                self.0 = Lines::Many(vec![one, line]);
49            }
50            Lines::Many(mut lines) => {
51                lines.push(line);
52                self.0 = Lines::Many(lines);
53            }
54        }
55    }
56}
57
58impl<'a> RawLike<'a> for Raw {
59    type IntoIter = RawLines<'a>;
60
61    #[inline]
62    fn len(&'a self) -> usize {
63        match self.0 {
64            Lines::Empty => 0,
65            Lines::One(..) => 1,
66            Lines::Many(ref lines) => lines.len()
67        }
68    }
69
70    #[inline]
71    fn one(&'a self) -> Option<&'a [u8]> {
72        match self.0 {
73            Lines::One(ref line) => Some(line.as_ref()),
74            Lines::Many(ref lines) if lines.len() == 1 => Some(lines[0].as_ref()),
75            _ => None
76        }
77    }
78
79    #[inline]
80    fn iter(&'a self) -> RawLines<'a> {
81        RawLines {
82            inner: &self.0,
83            pos: 0,
84        }
85    }
86}
87
88#[derive(Clone)]
89enum Lines {
90    Empty,
91    One(Bytes),
92    Many(Vec<Bytes>),
93}
94
95fn eq_many<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool {
96    if a.len() != b.len() {
97        false
98    } else {
99        for (a, b) in a.iter().zip(b.iter()) {
100            if a.as_ref() != b.as_ref() {
101                return false
102            }
103        }
104        true
105    }
106}
107
108fn eq<B: AsRef<[u8]>>(raw: &Raw, b: &[B]) -> bool {
109    match raw.0 {
110        Lines::Empty => b.is_empty(),
111        Lines::One(ref line) => eq_many(&[line], b),
112        Lines::Many(ref lines) => eq_many(lines, b)
113    }
114}
115
116impl PartialEq for Raw {
117    fn eq(&self, other: &Raw) -> bool {
118        match other.0 {
119            Lines::Empty => eq(self, &[] as &[Bytes]),
120            Lines::One(ref line) => eq(self, &[line]),
121            Lines::Many(ref lines) => eq(self, lines),
122        }
123    }
124}
125
126impl Eq for Raw {}
127
128impl PartialEq<[Vec<u8>]> for Raw {
129    fn eq(&self, bytes: &[Vec<u8>]) -> bool {
130        eq(self, bytes)
131    }
132}
133
134impl<'a> PartialEq<[&'a [u8]]> for Raw {
135    fn eq(&self, bytes: &[&[u8]]) -> bool {
136        eq(self, bytes)
137    }
138}
139
140impl PartialEq<[String]> for Raw {
141    fn eq(&self, bytes: &[String]) -> bool {
142        eq(self, bytes)
143    }
144}
145
146impl<'a> PartialEq<[&'a str]> for Raw {
147    fn eq(&self, bytes: &[&'a str]) -> bool {
148        eq(self, bytes)
149    }
150}
151
152impl PartialEq<[u8]> for Raw {
153    fn eq(&self, bytes: &[u8]) -> bool {
154        match self.0 {
155            Lines::Empty => bytes.is_empty(),
156            Lines::One(ref line) => line.as_ref() == bytes,
157            Lines::Many(..) => false
158        }
159    }
160}
161
162impl PartialEq<str> for Raw {
163    fn eq(&self, s: &str) -> bool {
164        self == s.as_bytes()
165    }
166}
167
168impl From<Vec<Vec<u8>>> for Raw {
169    #[inline]
170    fn from(val: Vec<Vec<u8>>) -> Raw {
171        Raw(Lines::Many(
172            val.into_iter()
173                .map(|vec| maybe_literal(vec.into()))
174                .collect()
175        ))
176    }
177}
178
179impl From<String> for Raw {
180    #[inline]
181    fn from(val: String) -> Raw {
182        Raw::from(val.into_bytes())
183    }
184}
185
186impl From<Vec<u8>> for Raw {
187    #[inline]
188    fn from(val: Vec<u8>) -> Raw {
189        Raw(Lines::One(maybe_literal(val.into())))
190    }
191}
192
193impl<'a> From<&'a str> for Raw {
194    fn from(val: &'a str) -> Raw {
195        Raw::from(val.as_bytes())
196    }
197}
198
199impl<'a> From<&'a [u8]> for Raw {
200    fn from(val: &'a [u8]) -> Raw {
201        Raw(Lines::One(maybe_literal(val.into())))
202    }
203}
204
205impl From<Bytes> for Raw {
206    #[inline]
207    fn from(val: Bytes) -> Raw {
208        Raw(Lines::One(val))
209    }
210}
211
212#[cfg(feature = "headers")]
213pub fn parsed(val: Bytes) -> Raw {
214    Raw(Lines::One(From::from(val)))
215}
216
217#[cfg(feature = "headers")]
218pub fn push(raw: &mut Raw, val: Bytes) {
219    raw.push_line(val);
220}
221
222#[cfg(feature = "headers")]
223pub fn new() -> Raw {
224    Raw(Lines::Empty)
225}
226
227impl fmt::Debug for Lines {
228    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229        match *self {
230            Lines::Empty => f.pad("[]"),
231            Lines::One(ref line) => fmt::Debug::fmt(&[line], f),
232            Lines::Many(ref lines) => fmt::Debug::fmt(lines, f)
233        }
234    }
235}
236
237impl ::std::ops::Index<usize> for Raw {
238    type Output = [u8];
239
240    fn index(&self, idx: usize) -> &[u8] {
241        match self.0 {
242            Lines::Empty => panic!("index of out of bounds: {}", idx),
243            Lines::One(ref line) => if idx == 0 {
244                line.as_ref()
245            } else {
246                panic!("index out of bounds: {}", idx)
247            },
248            Lines::Many(ref lines) => lines[idx].as_ref()
249        }
250    }
251}
252
253macro_rules! literals {
254    ($($len:expr => $($value:expr),+;)+) => (
255        fn maybe_literal(s: Cow<[u8]>) -> Bytes {
256            match s.len() {
257                $($len => {
258                    $(
259                    if s.as_ref() == $value {
260                        return Bytes::from_static($value);
261                    }
262                    )+
263                })+
264
265                _ => ()
266            }
267
268            Bytes::from(s.into_owned())
269        }
270
271        #[test]
272        fn test_literal_lens() {
273            $(
274            $({
275                let s = $value;
276                assert!(s.len() == $len, "{:?} has len of {}, listed as {}", s, s.len(), $len);
277            })+
278            )+
279        }
280    );
281}
282
283literals! {
284    1  => b"*", b"0";
285    3  => b"*/*";
286    4  => b"gzip";
287    5  => b"close";
288    7  => b"chunked";
289    10 => b"keep-alive";
290}
291
292impl<'a> IntoIterator for &'a Raw {
293    type IntoIter = RawLines<'a>;
294    type Item = &'a [u8];
295
296    fn into_iter(self) -> RawLines<'a> {
297        self.iter()
298    }
299}
300
301pub struct RawLines<'a> {
302    inner: &'a Lines,
303    pos: usize,
304}
305
306impl<'a> fmt::Debug for RawLines<'a> {
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        f.debug_tuple("RawLines")
309            .field(&self.inner)
310            .finish()
311    }
312}
313
314impl<'a> Iterator for RawLines<'a> {
315    type Item = &'a [u8];
316
317    #[inline]
318    fn next(&mut self) -> Option<&'a [u8]> {
319        let current_pos = self.pos;
320        self.pos += 1;
321        match *self.inner {
322            Lines::Empty => None,
323            Lines::One(ref line) => {
324                if current_pos == 0 {
325                    Some(line.as_ref())
326                } else {
327                    None
328                }
329            }
330            Lines::Many(ref lines) => lines.get(current_pos).map(|l| l.as_ref()),
331        }
332    }
333}