cogo_http/header/
mod.rs

1//! Headers container, and common header fields.
2//!
3//! hyper has the opinion that Headers should be strongly-typed, because that's
4//! why we're using Rust in the first place. To set or get any header, an object
5//! must implement the `Header` trait from this module. Several common headers
6//! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others.
7//!
8//! # Why Typed?
9//!
10//! Or, why not stringly-typed? Types give the following advantages:
11//!
12//! - More difficult to typo, since typos in types should be caught by the compiler
13//! - Parsing to a proper type by default
14//!
15//! # Defining Custom Headers
16//!
17//! cogo-http provides many of the most commonly used headers in HTTP. If
18//! you need to define a custom header, it's easy to do while still taking
19//! advantage of the type system. cogo-http includes a `header!` macro for defining
20//! many wrapper-style headers.
21//!
22//! ```
23//! #[macro_use] extern crate cogo_http;
24//! use cogo_http::header::Headers;
25//! header! { (XRequestGuid, "X-Request-Guid") => [String] }
26//!
27//! fn main () {
28//!     let mut headers = Headers::new();
29//!
30//!     headers.set(XRequestGuid("a proper guid".to_owned()))
31//! }
32//! ```
33//!
34//! This works well for simple "string" headers. But the header system
35//! actually involves 2 parts: parsing, and formatting. If you need to
36//! customize either part, you can do so.
37//!
38//! ## `Header` and `HeaderFormat`
39//!
40//! Consider a Do Not Track header. It can be true or false, but it represents
41//! that via the numerals `1` and `0`.
42//!
43//! ```
44//! use std::fmt;
45//! use cogo_http::header::{Header, HeaderFormat};
46//!
47//! #[derive(Debug, Clone, Copy)]
48//! struct Dnt(bool);
49//!
50//! impl Header for Dnt {
51//!     fn header_name() -> &'static str {
52//!         "DNT"
53//!     }
54//!
55//!     fn parse_header(raw: &[Vec<u8>]) -> cogo_http::Result<Dnt> {
56//!         if raw.len() == 1 {
57//!             let line = &raw[0];
58//!             if line.len() == 1 {
59//!                 let byte = line[0];
60//!                 match byte {
61//!                     b'0' => return Ok(Dnt(true)),
62//!                     b'1' => return Ok(Dnt(false)),
63//!                     _ => ()
64//!                 }
65//!             }
66//!         }
67//!         Err(cogo_http::Error::Header)
68//!     }
69//! }
70//!
71//! impl HeaderFormat for Dnt {
72//!     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
73//!         if self.0 {
74//!             f.write_str("1")
75//!         } else {
76//!             f.write_str("0")
77//!         }
78//!     }
79//! }
80//! ```
81use std::any::Any;
82use std::borrow::{Cow, ToOwned};
83//use std::collections::HashMap;
84//use std::collections::hash_map::{Iter, Entry};
85use std::iter::{FromIterator, IntoIterator};
86use std::ops::{Deref, DerefMut};
87use std::{mem, fmt};
88
89use {httparse, traitobject};
90use typeable::Typeable;
91use unicase::UniCase;
92
93use self::internals::{Item, VecMap, Entry};
94use self::sealed::Sealed;
95
96pub use self::shared::*;
97pub use self::common::*;
98
99mod common;
100mod internals;
101mod shared;
102pub mod parsing;
103
104type HeaderName = UniCase<CowStr>;
105
106/// A trait for any object that will represent a header field and value.
107///
108/// This trait represents the construction and identification of headers,
109/// and contains trait-object unsafe methods.
110pub trait Header: Clone + Any + Send + Sync {
111    /// Returns the name of the header field this belongs to.
112    ///
113    /// This will become an associated constant once available.
114    fn header_name() -> &'static str;
115    /// Parse a header from a raw stream of bytes.
116    ///
117    /// It's possible that a request can include a header field more than once,
118    /// and in that case, the slice will have a length greater than 1. However,
119    /// it's not necessarily the case that a Header is *allowed* to have more
120    /// than one field value. If that's the case, you **should** return `None`
121    /// if `raw.len() > 1`.
122    fn parse_header(raw: &[Vec<u8>]) -> crate::Result<Self>;
123
124}
125
126/// A trait for any object that will represent a header field and value.
127///
128/// This trait represents the formatting of a `Header` for output to a TcpStream.
129pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync {
130    /// Format a header to be output into a TcpStream.
131    ///
132    /// This method is not allowed to introduce an Err not produced
133    /// by the passed-in Formatter.
134    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
135
136    /// Formats a header over multiple lines.
137    ///
138    /// The main example here is `Set-Cookie`, which requires that every
139    /// cookie being set be specified in a separate line.
140    ///
141    /// The API here is still being explored, so this is hidden by default.
142    /// The passed in formatter doesn't have any public methods, so it would
143    /// be quite difficult to depend on this externally.
144    #[doc(hidden)]
145    #[inline]
146    fn fmt_multi_header(&self, f: &mut MultilineFormatter) -> fmt::Result {
147        f.fmt_line(&FmtHeader(self))
148    }
149}
150
151#[doc(hidden)]
152#[allow(missing_debug_implementations)]
153pub struct MultilineFormatter<'a, 'b: 'a>(Multi<'a, 'b>);
154
155enum Multi<'a, 'b: 'a> {
156    Line(&'a str, &'a mut fmt::Formatter<'b>),
157    Join(bool, &'a mut fmt::Formatter<'b>),
158}
159
160impl<'a, 'b> MultilineFormatter<'a, 'b> {
161    fn fmt_line(&mut self, line: &dyn fmt::Display) -> fmt::Result {
162        use std::fmt::Write;
163        match self.0 {
164            Multi::Line(ref name, ref mut f) => {
165                r#try!(f.write_str(*name));
166                r#try!(f.write_str(": "));
167                r#try!(write!(NewlineReplacer(*f), "{}", line));
168                f.write_str("\r\n")
169            },
170            Multi::Join(ref mut first, ref mut f) => {
171                if !*first {
172                    r#try!(f.write_str(", "));
173                } else {
174                    *first = false;
175                }
176                write!(NewlineReplacer(*f), "{}", line)
177            }
178        }
179    }
180}
181
182// Internal helper to wrap fmt_header into a fmt::Display
183struct FmtHeader<'a, H: ?Sized + 'a>(&'a H);
184
185impl<'a, H: HeaderFormat + ?Sized + 'a> fmt::Display for FmtHeader<'a, H> {
186    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187        self.0.fmt_header(f)
188    }
189}
190
191struct ValueString<'a>(&'a Item);
192
193impl<'a> fmt::Display for ValueString<'a> {
194    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195        self.0.write_h1(&mut MultilineFormatter(Multi::Join(true, f)))
196    }
197}
198
199struct NewlineReplacer<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);
200
201impl<'a, 'b> fmt::Write for NewlineReplacer<'a, 'b> {
202    fn write_str(&mut self, s: &str) -> fmt::Result {
203        let mut since = 0;
204        for (i, &byte) in s.as_bytes().iter().enumerate() {
205            if byte == b'\r' || byte == b'\n' {
206                r#try!(self.0.write_str(&s[since..i]));
207                r#try!(self.0.write_str(" "));
208                since = i + 1;
209            }
210        }
211        if since < s.len() {
212            self.0.write_str(&s[since..])
213        } else {
214            Ok(())
215        }
216    }
217}
218
219/// Internal implementation detail.
220///
221/// This trait is automatically implemented for all types that implement
222/// `HeaderFormat + Clone`. No methods are exposed, and so is not useful
223/// outside this crate.
224pub trait HeaderClone: Sealed {}
225impl<T: Sealed> HeaderClone for T {}
226
227mod sealed {
228    use super::HeaderFormat;
229
230    #[doc(hidden)]
231    pub trait Sealed {
232        #[doc(hidden)]
233        fn clone_box(&self) -> Box<dyn HeaderFormat + Send + Sync>;
234    }
235
236    #[doc(hidden)]
237    impl<T: HeaderFormat + Clone> Sealed for T {
238        #[inline]
239        fn clone_box(&self) -> Box<dyn HeaderFormat + Send + Sync> {
240            Box::new(self.clone())
241        }
242    }
243}
244
245impl dyn HeaderFormat + Send + Sync {
246    #[inline]
247    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
248        mem::transmute(traitobject::data(self))
249    }
250
251    #[inline]
252    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
253        mem::transmute(traitobject::data_mut(self))
254    }
255}
256
257impl Clone for Box<dyn HeaderFormat + Send + Sync> {
258    #[inline]
259    fn clone(&self) -> Box<dyn HeaderFormat + Send + Sync> {
260        self.clone_box()
261    }
262}
263
264#[inline]
265fn header_name<T: Header>() -> &'static str {
266    <T as Header>::header_name()
267}
268
269/// A map of header fields on requests and responses.
270#[derive(Clone)]
271pub struct Headers {
272    //data: HashMap<HeaderName, Item>
273    data: VecMap<HeaderName, Item>,
274}
275
276impl Headers {
277
278    /// Creates a new, empty headers map.
279    pub fn new() -> Headers {
280        Headers {
281            data: VecMap::new()
282        }
283    }
284
285    pub fn with_capacity(capacity: usize) -> Headers {
286        Headers {
287            data: VecMap::with_capacity(capacity)
288        }
289    }
290
291    pub fn from_raw(raw: &[httparse::Header]) -> crate::Result<Headers> {
292        let mut headers = Headers::new();
293        for header in raw {
294            let name = UniCase(CowStr(Cow::Owned(header.name.to_owned())));
295            let item = match headers.data.entry(name) {
296                Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])),
297                Entry::Occupied(entry) => entry.into_mut()
298            };
299            item.raw_mut().push(header.value.to_vec());
300        }
301        Ok(headers)
302    }
303
304    /// Set a header field to the corresponding value.
305    ///
306    /// The field is determined by the type of the value being set.
307    pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
308        trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
309        self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
310                         Item::new_typed(Box::new(value)));
311    }
312
313    /// Access the raw value of a header.
314    ///
315    /// Prefer to use the typed getters instead.
316    ///
317    /// Example:
318    ///
319    /// ```
320    /// # use cogo_http::header::Headers;
321    /// # let mut headers = Headers::new();
322    /// let raw_content_type = headers.get_raw("content-type");
323    /// ```
324    pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> {
325        self.data
326            .get(&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))))
327            .map(Item::raw)
328    }
329
330    /// Set the raw value of a header, bypassing any typed headers.
331    ///
332    /// Note: This will completely replace any current value for this
333    /// header name.
334    ///
335    /// Example:
336    ///
337    /// ```
338    /// # use cogo_http::header::Headers;
339    /// # let mut headers = Headers::new();
340    /// headers.set_raw("content-length", vec![b"5".to_vec()]);
341    /// ```
342    pub fn set_raw<K: Into<Cow<'static, str>>>(&mut self, name: K,
343            value: Vec<Vec<u8>>) {
344        let name = name.into();
345        trace!("Headers.set_raw( {:?}, {:?} )", name, value);
346        self.data.insert(UniCase(CowStr(name)), Item::new_raw(value));
347    }
348
349    /// Append a value to raw value of this header.
350    ///
351    /// If a header already contains a value, this will add another line to it.
352    ///
353    /// If a header doesnot exist for this name, a new one will be created with
354    /// the value.
355    ///
356    /// Example:
357    ///
358    /// ```
359    /// # use cogo_http::header::Headers;
360    /// # let mut headers = Headers::new();
361    /// headers.append_raw("x-foo", b"bar".to_vec());
362    /// headers.append_raw("x-foo", b"quux".to_vec());
363    /// ```
364    pub fn append_raw<K: Into<Cow<'static, str>>>(&mut self, name: K, value: Vec<u8>) {
365        let name = name.into();
366        trace!("Headers.append_raw( {:?}, {:?} )", name, value);
367        let name = UniCase(CowStr(name));
368        if let Some(item) = self.data.get_mut(&name) {
369            item.raw_mut().push(value);
370            return;
371        }
372        self.data.insert(name, Item::new_raw(vec![value]));
373    }
374
375    /// Remove a header set by set_raw
376    pub fn remove_raw(&mut self, name: &str) {
377        trace!("Headers.remove_raw( {:?} )", name);
378        self.data.remove(
379            &UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
380        );
381    }
382
383    /// Get a reference to the header field's value, if it exists.
384    pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
385        self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
386        .and_then(Item::typed::<H>)
387    }
388
389    /// Get a mutable reference to the header field's value, if it exists.
390    pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
391        self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
392        .and_then(Item::typed_mut::<H>)
393    }
394
395    /// Returns a boolean of whether a certain header is in the map.
396    ///
397    /// Example:
398    ///
399    /// ```
400    /// # use cogo_http::header::Headers;
401    /// # use cogo_http::header::ContentType;
402    /// # let mut headers = Headers::new();
403    /// let has_type = headers.has::<ContentType>();
404    /// ```
405    pub fn has<H: Header + HeaderFormat>(&self) -> bool {
406        self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
407    }
408
409    /// Removes a header from the map, if one existed.
410    /// Returns true if a header has been removed.
411    pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
412        trace!("Headers.remove( {:?} )", header_name::<H>());
413        self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
414    }
415
416    /// Returns an iterator over the header fields.
417    pub fn iter(&self) -> HeadersItems {
418        HeadersItems {
419            inner: self.data.iter()
420        }
421    }
422
423    /// Returns the number of headers in the map.
424    pub fn len(&self) -> usize {
425        self.data.len()
426    }
427
428    /// Remove all headers from the map.
429    pub fn clear(&mut self) {
430        self.data.clear()
431    }
432}
433
434impl PartialEq for Headers {
435    fn eq(&self, other: &Headers) -> bool {
436        if self.len() != other.len() {
437            return false;
438        }
439
440        for header in self.iter() {
441            match other.get_raw(header.name()) {
442                Some(val) if val == self.get_raw(header.name()).unwrap() => {},
443                _ => { return false; }
444            }
445        }
446        true
447    }
448}
449
450impl fmt::Display for Headers {
451   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452        for header in self.iter() {
453            r#try!(fmt::Display::fmt(&header, f));
454        }
455        Ok(())
456    }
457}
458
459impl fmt::Debug for Headers {
460    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461        r#try!(f.write_str("Headers { "));
462        for header in self.iter() {
463            r#try!(write!(f, "{:?}, ", header));
464        }
465        r#try!(f.write_str("}"));
466        Ok(())
467    }
468}
469
470/// An `Iterator` over the fields in a `Headers` map.
471pub struct HeadersItems<'a> {
472    inner: ::std::slice::Iter<'a, (HeaderName, Item)>
473}
474
475impl<'a> Iterator for HeadersItems<'a> {
476    type Item = HeaderView<'a>;
477
478    fn next(&mut self) -> Option<HeaderView<'a>> {
479        self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
480    }
481}
482
483/// Returned with the `HeadersItems` iterator.
484pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
485
486impl<'a> HeaderView<'a> {
487    /// Check if a HeaderView is a certain Header.
488    #[inline]
489    pub fn is<H: Header>(&self) -> bool {
490        UniCase(CowStr(Cow::Borrowed(header_name::<H>()))) == *self.0
491    }
492
493    /// Get the Header name as a slice.
494    #[inline]
495    pub fn name(&self) -> &'a str {
496        self.0.as_ref()
497    }
498
499    /// Cast the value to a certain Header type.
500    #[inline]
501    pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
502        self.1.typed::<H>()
503    }
504
505    /// Get just the header value as a String.
506    ///
507    /// This will join multiple values of this header with a `, `.
508    ///
509    /// **Warning:** This may not be the format that should be used to send
510    /// a Request or Response.
511    #[inline]
512    pub fn value_string(&self) -> String {
513        ValueString(self.1).to_string()
514    }
515}
516
517impl<'a> fmt::Display for HeaderView<'a> {
518    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
519        self.1.write_h1(&mut MultilineFormatter(Multi::Line(&self.0, f)))
520    }
521}
522
523impl<'a> fmt::Debug for HeaderView<'a> {
524    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
525        fmt::Display::fmt(self, f)
526    }
527}
528
529impl<'a> Extend<HeaderView<'a>> for Headers {
530    fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
531        for header in iter {
532            self.data.insert((*header.0).clone(), (*header.1).clone());
533        }
534    }
535}
536
537impl<'a> FromIterator<HeaderView<'a>> for Headers {
538    fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
539        let mut headers = Headers::new();
540        headers.extend(iter);
541        headers
542    }
543}
544
545//#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
546impl<'a> fmt::Display for &'a (dyn HeaderFormat + Send + Sync) {
547    #[inline]
548    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
549        let mut multi = MultilineFormatter(Multi::Join(true, f));
550        self.fmt_multi_header(&mut multi)
551    }
552}
553
554/// A wrapper around any Header with a Display impl that calls fmt_header.
555///
556/// This can be used like so: `format!("{}", HeaderFormatter(&header))` to
557/// get the 'value string' representation of this Header.
558///
559/// Note: This may not necessarily be the value written to stream, such
560/// as with the SetCookie header.
561#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
562pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
563
564#[allow(deprecated)]
565impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
566    #[inline]
567    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
568        let mut multi = MultilineFormatter(Multi::Join(true, f));
569        self.0.fmt_multi_header(&mut multi)
570    }
571}
572
573#[allow(deprecated)]
574impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
575    #[inline]
576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577        fmt::Display::fmt(self, f)
578    }
579}
580
581#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
582struct CowStr(Cow<'static, str>);
583
584impl Deref for CowStr {
585    type Target = Cow<'static, str>;
586
587    fn deref(&self) -> &Cow<'static, str> {
588        &self.0
589    }
590}
591
592impl fmt::Debug for CowStr {
593    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594        fmt::Debug::fmt(&self.0, f)
595    }
596}
597
598impl fmt::Display for CowStr {
599    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600        fmt::Display::fmt(&self.0, f)
601    }
602}
603
604impl DerefMut for CowStr {
605    fn deref_mut(&mut self) -> &mut Cow<'static, str> {
606        &mut self.0
607    }
608}
609
610impl AsRef<str> for CowStr {
611    fn as_ref(&self) -> &str {
612        self
613    }
614}
615
616
617#[cfg(test)]
618mod tests {
619    use std::fmt;
620    use mime::Mime;
621    use mime::TopLevel::Text;
622    use mime::SubLevel::Plain;
623    use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
624                Accept, Host, qitem};
625    use httparse;
626
627    #[cfg(feature = "nightly")]
628    use test::Bencher;
629
630    // Slice.position_elem was unstable
631    fn index_of(slice: &[u8], byte: u8) -> Option<usize> {
632        for (index, &b) in slice.iter().enumerate() {
633            if b == byte {
634                return Some(index);
635            }
636        }
637        None
638    }
639
640    macro_rules! raw {
641        ($($line:expr),*) => ({
642            [$({
643                let line = $line;
644                let pos = index_of(line, b':').expect("raw splits on ':', not found");
645                httparse::Header {
646                    name: ::std::str::from_utf8(&line[..pos]).unwrap(),
647                    value: &line[pos + 2..]
648                }
649            }),*]
650        })
651    }
652
653    #[test]
654    fn test_from_raw() {
655        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
656        assert_eq!(headers.get(), Some(&ContentLength(10)));
657    }
658
659    #[test]
660    fn test_content_type() {
661        let content_type = Header::parse_header([b"text/plain".to_vec()].as_ref());
662        assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
663    }
664
665    #[test]
666    fn test_accept() {
667        let text_plain = qitem(Mime(Text, Plain, vec![]));
668        let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
669
670        let accept = Header::parse_header([b"text/plain".to_vec()].as_ref());
671        assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
672
673        let bytevec = [b"application/vnd.github.v3.full+json; q=0.5, text/plain".to_vec()];
674        let accept = Header::parse_header(bytevec.as_ref());
675        assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
676    }
677
678    #[derive(Clone, PartialEq, Debug)]
679    struct CrazyLength(Option<bool>, usize);
680
681    impl Header for CrazyLength {
682        fn header_name() -> &'static str {
683            "content-length"
684        }
685        fn parse_header(raw: &[Vec<u8>]) -> crate::Result<CrazyLength> {
686            use std::str::from_utf8;
687            use std::str::FromStr;
688
689            if raw.len() != 1 {
690                return Err(crate::Error::Header);
691            }
692            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
693            match match from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
694                Ok(s) => FromStr::from_str(s).ok(),
695                Err(_) => None
696            }.map(|u| CrazyLength(Some(false), u)) {
697                Some(x) => Ok(x),
698                None => Err(crate::Error::Header),
699            }
700        }
701    }
702
703    impl HeaderFormat for CrazyLength {
704        fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
705            let CrazyLength(ref opt, ref value) = *self;
706            write!(f, "{:?}, {:?}", opt, value)
707        }
708    }
709
710    #[test]
711    fn test_different_structs_for_same_header() {
712        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
713        assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
714        assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
715    }
716
717    #[test]
718    fn test_trailing_whitespace() {
719        let headers = Headers::from_raw(&raw!(b"Content-Length: 10   ")).unwrap();
720        assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
721    }
722
723    #[test]
724    fn test_multiple_reads() {
725        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
726        let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
727        let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
728        assert_eq!(one, two);
729    }
730
731    #[test]
732    fn test_different_reads() {
733        let headers = Headers::from_raw(
734            &raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap();
735        let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
736        let ContentType(_) = *headers.get::<ContentType>().unwrap();
737    }
738
739    #[test]
740    fn test_get_mutable() {
741        let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
742        *headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
743        assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
744        assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
745    }
746
747    #[test]
748    fn test_headers_fmt() {
749        let mut headers = Headers::new();
750        headers.set(ContentLength(15));
751        headers.set(Host { hostname: "foo.bar".to_owned(), port: None });
752
753        let s = headers.to_string();
754        assert!(s.contains("Host: foo.bar\r\n"));
755        assert!(s.contains("Content-Length: 15\r\n"));
756    }
757
758    #[test]
759    fn test_headers_fmt_raw() {
760        let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
761        headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
762        let s = headers.to_string();
763        assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
764    }
765
766    #[test]
767    fn test_set_raw() {
768        let mut headers = Headers::new();
769        headers.set(ContentLength(10));
770        headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
771        assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
772        assert_eq!(headers.get(), Some(&ContentLength(20)));
773    }
774
775    #[test]
776    fn test_append_raw() {
777        let mut headers = Headers::new();
778        headers.set(ContentLength(10));
779        headers.append_raw("content-LENGTH", b"20".to_vec());
780        assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
781        headers.append_raw("x-foo", b"bar".to_vec());
782        assert_eq!(headers.get_raw("x-foo"), Some(&[b"bar".to_vec()][..]));
783    }
784
785    #[test]
786    fn test_remove_raw() {
787        let mut headers = Headers::new();
788        headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
789        headers.remove_raw("content-LENGTH");
790        assert_eq!(headers.get_raw("Content-length"), None);
791    }
792
793    #[test]
794    fn test_len() {
795        let mut headers = Headers::new();
796        headers.set(ContentLength(10));
797        assert_eq!(headers.len(), 1);
798        headers.set(ContentType(Mime(Text, Plain, vec![])));
799        assert_eq!(headers.len(), 2);
800        // Redundant, should not increase count.
801        headers.set(ContentLength(20));
802        assert_eq!(headers.len(), 2);
803    }
804
805    #[test]
806    fn test_clear() {
807        let mut headers = Headers::new();
808        headers.set(ContentLength(10));
809        headers.set(ContentType(Mime(Text, Plain, vec![])));
810        assert_eq!(headers.len(), 2);
811        headers.clear();
812        assert_eq!(headers.len(), 0);
813    }
814
815    #[test]
816    fn test_iter() {
817        let mut headers = Headers::new();
818        headers.set(ContentLength(11));
819        for header in headers.iter() {
820            assert!(header.is::<ContentLength>());
821            assert_eq!(header.name(), <ContentLength as Header>::header_name());
822            assert_eq!(header.value(), Some(&ContentLength(11)));
823            assert_eq!(header.value_string(), "11".to_owned());
824        }
825    }
826
827    #[test]
828    fn test_header_view_value_string() {
829        let mut headers = Headers::new();
830        headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
831        for header in headers.iter() {
832            assert_eq!(header.name(), "foo");
833            assert_eq!(header.value_string(), "one, two");
834        }
835    }
836
837    #[test]
838    fn test_eq() {
839        let mut headers1 = Headers::new();
840        let mut headers2 = Headers::new();
841
842        assert_eq!(headers1, headers2);
843
844        headers1.set(ContentLength(11));
845        headers2.set(Host {hostname: "foo.bar".to_owned(), port: None});
846        assert!(headers1 != headers2);
847
848        headers1 = Headers::new();
849        headers2 = Headers::new();
850
851        headers1.set(ContentLength(11));
852        headers2.set(ContentLength(11));
853        assert_eq!(headers1, headers2);
854
855        headers1.set(ContentLength(10));
856        assert!(headers1 != headers2);
857
858        headers1 = Headers::new();
859        headers2 = Headers::new();
860
861        headers1.set(Host { hostname: "foo.bar".to_owned(), port: None });
862        headers1.set(ContentLength(11));
863        headers2.set(ContentLength(11));
864        assert!(headers1 != headers2);
865    }
866
867    #[cfg(feature = "nightly")]
868    #[bench]
869    fn bench_headers_new(b: &mut Bencher) {
870        b.iter(|| {
871            let mut h = Headers::new();
872            h.set(ContentLength(11));
873            h
874        })
875    }
876
877    #[cfg(feature = "nightly")]
878    #[bench]
879    fn bench_headers_from_raw(b: &mut Bencher) {
880        let raw = raw!(b"Content-Length: 10");
881        b.iter(|| Headers::from_raw(&raw).unwrap())
882    }
883
884    #[cfg(feature = "nightly")]
885    #[bench]
886    fn bench_headers_get(b: &mut Bencher) {
887        let mut headers = Headers::new();
888        headers.set(ContentLength(11));
889        b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
890    }
891
892    #[cfg(feature = "nightly")]
893    #[bench]
894    fn bench_headers_get_miss(b: &mut Bencher) {
895        let headers = Headers::new();
896        b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
897    }
898
899    #[cfg(feature = "nightly")]
900    #[bench]
901    fn bench_headers_set(b: &mut Bencher) {
902        let mut headers = Headers::new();
903        b.iter(|| headers.set(ContentLength(12)))
904    }
905
906    #[cfg(feature = "nightly")]
907    #[bench]
908    fn bench_headers_has(b: &mut Bencher) {
909        let mut headers = Headers::new();
910        headers.set(ContentLength(11));
911        b.iter(|| assert!(headers.has::<ContentLength>()))
912    }
913
914    #[cfg(feature = "nightly")]
915    #[bench]
916    fn bench_headers_view_is(b: &mut Bencher) {
917        let mut headers = Headers::new();
918        headers.set(ContentLength(11));
919        let mut iter = headers.iter();
920        let view = iter.next().unwrap();
921        b.iter(|| assert!(view.is::<ContentLength>()))
922    }
923
924    #[cfg(feature = "nightly")]
925    #[bench]
926    fn bench_headers_fmt(b: &mut Bencher) {
927        let mut headers = Headers::new();
928        headers.set(ContentLength(11));
929        b.iter(|| headers.to_string())
930    }
931}