mco_http/header/
mod.rs

1//! Headers container, and common header fields.
2//!
3//! mco_http 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//! Hyper 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. Hyper includes a `header!` macro for defining
20//! many wrapper-style headers.
21//!
22//! ```
23//! #[macro_use] extern crate mco_http;
24//! use mco_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 mco_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>]) -> mco_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(mco_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                f.write_str(*name)?;
166                f.write_str(": ")?;
167                write!(NewlineReplacer(*f), "{}", line)?;
168                f.write_str("\r\n")
169            },
170            Multi::Join(ref mut first, ref mut f) => {
171                if !*first {
172                    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                self.0.write_str(&s[since..i])?;
207                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(size:usize)-> Headers{
286        Headers {
287            data: VecMap::with_capacity(size)
288        }
289    }
290
291    #[doc(hidden)]
292    pub fn from_raw(raw: &[httparse::Header]) -> crate::Result<Headers> {
293        let mut headers = Headers::new();
294        for header in raw {
295            trace!("raw header: {:?}={:?}", header.name, &header.value[..]);
296            let name = UniCase(CowStr(Cow::Owned(header.name.to_owned())));
297            let item = match headers.data.entry(name) {
298                Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])),
299                Entry::Occupied(entry) => entry.into_mut()
300            };
301            let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count();
302            let value = &header.value[.. header.value.len() - trim];
303            item.raw_mut().push(value.to_vec());
304        }
305        Ok(headers)
306    }
307
308    /// Set a header field to the corresponding value.
309    ///
310    /// The field is determined by the type of the value being set.
311    pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
312        trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
313        self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
314                         Item::new_typed(Box::new(value)));
315    }
316
317    /// Access the raw value of a header.
318    ///
319    /// Prefer to use the typed getters instead.
320    ///
321    /// Example:
322    ///
323    /// ```
324    /// # use mco_http::header::Headers;
325    /// # let mut headers = Headers::new();
326    /// let raw_content_type = headers.get_raw("content-type");
327    /// ```
328    pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> {
329        self.data
330            .get(&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))))
331            .map(Item::raw)
332    }
333
334    /// Set the raw value of a header, bypassing any typed headers.
335    ///
336    /// Note: This will completely replace any current value for this
337    /// header name.
338    ///
339    /// Example:
340    ///
341    /// ```
342    /// # use mco_http::header::Headers;
343    /// # let mut headers = Headers::new();
344    /// headers.set_raw("content-length", vec![b"5".to_vec()]);
345    /// ```
346    pub fn set_raw<K: Into<Cow<'static, str>>>(&mut self, name: K,
347            value: Vec<Vec<u8>>) {
348        let name = name.into();
349        trace!("Headers.set_raw( {:?}, {:?} )", name, value);
350        self.data.insert(UniCase(CowStr(name)), Item::new_raw(value));
351    }
352
353    /// Append a value to raw value of this header.
354    ///
355    /// If a header already contains a value, this will add another line to it.
356    ///
357    /// If a header doesnot exist for this name, a new one will be created with
358    /// the value.
359    ///
360    /// Example:
361    ///
362    /// ```
363    /// # use mco_http::header::Headers;
364    /// # let mut headers = Headers::new();
365    /// headers.append_raw("x-foo", b"bar".to_vec());
366    /// headers.append_raw("x-foo", b"quux".to_vec());
367    /// ```
368    pub fn append_raw<K: Into<Cow<'static, str>>>(&mut self, name: K, value: Vec<u8>) {
369        let name = name.into();
370        trace!("Headers.append_raw( {:?}, {:?} )", name, value);
371        let name = UniCase(CowStr(name));
372        if let Some(item) = self.data.get_mut(&name) {
373            item.raw_mut().push(value);
374            return;
375        }
376        self.data.insert(name, Item::new_raw(vec![value]));
377    }
378
379    /// Remove a header set by set_raw
380    pub fn remove_raw(&mut self, name: &str) {
381        trace!("Headers.remove_raw( {:?} )", name);
382        self.data.remove(
383            &UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
384        );
385    }
386
387    /// Get a reference to the header field's value, if it exists.
388    pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
389        self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
390        .and_then(Item::typed::<H>)
391    }
392
393    /// Get a mutable reference to the header field's value, if it exists.
394    pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
395        self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
396        .and_then(Item::typed_mut::<H>)
397    }
398
399    /// Returns a boolean of whether a certain header is in the map.
400    ///
401    /// Example:
402    ///
403    /// ```
404    /// # use mco_http::header::Headers;
405    /// # use mco_http::header::ContentType;
406    /// # let mut headers = Headers::new();
407    /// let has_type = headers.has::<ContentType>();
408    /// ```
409    pub fn has<H: Header + HeaderFormat>(&self) -> bool {
410        self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
411    }
412
413    /// Removes a header from the map, if one existed.
414    /// Returns true if a header has been removed.
415    pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
416        trace!("Headers.remove( {:?} )", header_name::<H>());
417        self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
418    }
419
420    /// Returns an iterator over the header fields.
421    pub fn iter(&self) -> HeadersItems {
422        HeadersItems {
423            inner: self.data.iter()
424        }
425    }
426
427    /// Returns the number of headers in the map.
428    pub fn len(&self) -> usize {
429        self.data.len()
430    }
431
432    /// Remove all headers from the map.
433    pub fn clear(&mut self) {
434        self.data.clear()
435    }
436}
437
438impl PartialEq for Headers {
439    fn eq(&self, other: &Headers) -> bool {
440        if self.len() != other.len() {
441            return false;
442        }
443
444        for header in self.iter() {
445            match other.get_raw(header.name()) {
446                Some(val) if val == self.get_raw(header.name()).unwrap() => {},
447                _ => { return false; }
448            }
449        }
450        true
451    }
452}
453
454impl fmt::Display for Headers {
455   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456        for header in self.iter() {
457            fmt::Display::fmt(&header, f)?;
458        }
459        Ok(())
460    }
461}
462
463impl fmt::Debug for Headers {
464    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465        f.write_str("Headers { ")?;
466        for header in self.iter() {
467            write!(f, "{:?}, ", header)?;
468        }
469        f.write_str("}")?;
470        Ok(())
471    }
472}
473
474/// An `Iterator` over the fields in a `Headers` map.
475pub struct HeadersItems<'a> {
476    inner: ::std::slice::Iter<'a, (HeaderName, Item)>
477}
478
479impl<'a> Iterator for HeadersItems<'a> {
480    type Item = HeaderView<'a>;
481
482    fn next(&mut self) -> Option<HeaderView<'a>> {
483        self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
484    }
485}
486
487/// Returned with the `HeadersItems` iterator.
488pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
489
490impl<'a> HeaderView<'a> {
491    /// Check if a HeaderView is a certain Header.
492    #[inline]
493    pub fn is<H: Header>(&self) -> bool {
494        UniCase(CowStr(Cow::Borrowed(header_name::<H>()))) == *self.0
495    }
496
497    /// Get the Header name as a slice.
498    #[inline]
499    pub fn name(&self) -> &'a str {
500        self.0.as_ref()
501    }
502
503    /// Cast the value to a certain Header type.
504    #[inline]
505    pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
506        self.1.typed::<H>()
507    }
508
509    /// Get just the header value as a String.
510    ///
511    /// This will join multiple values of this header with a `, `.
512    ///
513    /// **Warning:** This may not be the format that should be used to send
514    /// a Request or Response.
515    #[inline]
516    pub fn value_string(&self) -> String {
517        ValueString(self.1).to_string()
518    }
519}
520
521impl<'a> fmt::Display for HeaderView<'a> {
522    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
523        self.1.write_h1(&mut MultilineFormatter(Multi::Line(&self.0, f)))
524    }
525}
526
527impl<'a> fmt::Debug for HeaderView<'a> {
528    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
529        fmt::Display::fmt(self, f)
530    }
531}
532
533impl<'a> Extend<HeaderView<'a>> for Headers {
534    fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
535        for header in iter {
536            self.data.insert((*header.0).clone(), (*header.1).clone());
537        }
538    }
539}
540
541impl<'a> FromIterator<HeaderView<'a>> for Headers {
542    fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
543        let mut headers = Headers::new();
544        headers.extend(iter);
545        headers
546    }
547}
548
549//#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
550impl<'a> fmt::Display for &'a (dyn HeaderFormat + Send + Sync) {
551    #[inline]
552    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
553        let mut multi = MultilineFormatter(Multi::Join(true, f));
554        self.fmt_multi_header(&mut multi)
555    }
556}
557
558/// A wrapper around any Header with a Display impl that calls fmt_header.
559///
560/// This can be used like so: `format!("{}", HeaderFormatter(&header))` to
561/// get the 'value string' representation of this Header.
562///
563/// Note: This may not necessarily be the value written to stream, such
564/// as with the SetCookie header.
565#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
566pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
567
568#[allow(deprecated)]
569impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
570    #[inline]
571    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
572        let mut multi = MultilineFormatter(Multi::Join(true, f));
573        self.0.fmt_multi_header(&mut multi)
574    }
575}
576
577#[allow(deprecated)]
578impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
579    #[inline]
580    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
581        fmt::Display::fmt(self, f)
582    }
583}
584
585#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
586struct CowStr(Cow<'static, str>);
587
588impl Deref for CowStr {
589    type Target = Cow<'static, str>;
590
591    fn deref(&self) -> &Cow<'static, str> {
592        &self.0
593    }
594}
595
596impl fmt::Debug for CowStr {
597    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598        fmt::Debug::fmt(&self.0, f)
599    }
600}
601
602impl fmt::Display for CowStr {
603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
604        fmt::Display::fmt(&self.0, f)
605    }
606}
607
608impl DerefMut for CowStr {
609    fn deref_mut(&mut self) -> &mut Cow<'static, str> {
610        &mut self.0
611    }
612}
613
614impl AsRef<str> for CowStr {
615    fn as_ref(&self) -> &str {
616        self
617    }
618}
619
620
621#[cfg(test)]
622mod tests {
623    use std::fmt;
624    use mime::Mime;
625    use mime::TopLevel::Text;
626    use mime::SubLevel::Plain;
627    use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
628                Accept, Host, qitem};
629    use httparse;
630
631    #[cfg(feature = "nightly")]
632    use test::Bencher;
633
634    // Slice.position_elem was unstable
635    fn index_of(slice: &[u8], byte: u8) -> Option<usize> {
636        for (index, &b) in slice.iter().enumerate() {
637            if b == byte {
638                return Some(index);
639            }
640        }
641        None
642    }
643
644    macro_rules! raw {
645        ($($line:expr),*) => ({
646            [$({
647                let line = $line;
648                let pos = index_of(line, b':').expect("raw splits on ':', not found");
649                httparse::Header {
650                    name: ::std::str::from_utf8(&line[..pos]).unwrap(),
651                    value: &line[pos + 2..]
652                }
653            }),*]
654        })
655    }
656
657    #[test]
658    fn test_from_raw() {
659        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
660        assert_eq!(headers.get(), Some(&ContentLength(10)));
661    }
662
663    #[test]
664    fn test_content_type() {
665        let content_type = Header::parse_header([b"text/plain".to_vec()].as_ref());
666        assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
667    }
668
669    #[test]
670    fn test_accept() {
671        let text_plain = qitem(Mime(Text, Plain, vec![]));
672        let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
673
674        let accept = Header::parse_header([b"text/plain".to_vec()].as_ref());
675        assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
676
677        let bytevec = [b"application/vnd.github.v3.full+json; q=0.5, text/plain".to_vec()];
678        let accept = Header::parse_header(bytevec.as_ref());
679        assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
680    }
681
682    #[derive(Clone, PartialEq, Debug)]
683    struct CrazyLength(Option<bool>, usize);
684
685    impl Header for CrazyLength {
686        fn header_name() -> &'static str {
687            "content-length"
688        }
689        fn parse_header(raw: &[Vec<u8>]) -> crate::Result<CrazyLength> {
690            use std::str::from_utf8;
691            use std::str::FromStr;
692
693            if raw.len() != 1 {
694                return Err(crate::Error::Header);
695            }
696            // we JUST checked that raw.len() == 1, so raw[0] WILL exist.
697            match match from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
698                Ok(s) => FromStr::from_str(s).ok(),
699                Err(_) => None
700            }.map(|u| CrazyLength(Some(false), u)) {
701                Some(x) => Ok(x),
702                None => Err(crate::Error::Header),
703            }
704        }
705    }
706
707    impl HeaderFormat for CrazyLength {
708        fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
709            let CrazyLength(ref opt, ref value) = *self;
710            write!(f, "{:?}, {:?}", opt, value)
711        }
712    }
713
714    #[test]
715    fn test_different_structs_for_same_header() {
716        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
717        assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
718        assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
719    }
720
721    #[test]
722    fn test_trailing_whitespace() {
723        let headers = Headers::from_raw(&raw!(b"Content-Length: 10   ")).unwrap();
724        assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
725    }
726
727    #[test]
728    fn test_multiple_reads() {
729        let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
730        let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
731        let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
732        assert_eq!(one, two);
733    }
734
735    #[test]
736    fn test_different_reads() {
737        let headers = Headers::from_raw(
738            &raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap();
739        let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
740        let ContentType(_) = *headers.get::<ContentType>().unwrap();
741    }
742
743    #[test]
744    fn test_get_mutable() {
745        let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
746        *headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
747        assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
748        assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
749    }
750
751    #[test]
752    fn test_headers_fmt() {
753        let mut headers = Headers::new();
754        headers.set(ContentLength(15));
755        headers.set(Host { hostname: "foo.bar".to_owned(), port: None });
756
757        let s = headers.to_string();
758        assert!(s.contains("Host: foo.bar\r\n"));
759        assert!(s.contains("Content-Length: 15\r\n"));
760    }
761
762    #[test]
763    fn test_headers_fmt_raw() {
764        let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
765        headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
766        let s = headers.to_string();
767        assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
768    }
769
770    #[test]
771    fn test_set_raw() {
772        let mut headers = Headers::new();
773        headers.set(ContentLength(10));
774        headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
775        assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
776        assert_eq!(headers.get(), Some(&ContentLength(20)));
777    }
778
779    #[test]
780    fn test_append_raw() {
781        let mut headers = Headers::new();
782        headers.set(ContentLength(10));
783        headers.append_raw("content-LENGTH", b"20".to_vec());
784        assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
785        headers.append_raw("x-foo", b"bar".to_vec());
786        assert_eq!(headers.get_raw("x-foo"), Some(&[b"bar".to_vec()][..]));
787    }
788
789    #[test]
790    fn test_remove_raw() {
791        let mut headers = Headers::new();
792        headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
793        headers.remove_raw("content-LENGTH");
794        assert_eq!(headers.get_raw("Content-length"), None);
795    }
796
797    #[test]
798    fn test_len() {
799        let mut headers = Headers::new();
800        headers.set(ContentLength(10));
801        assert_eq!(headers.len(), 1);
802        headers.set(ContentType(Mime(Text, Plain, vec![])));
803        assert_eq!(headers.len(), 2);
804        // Redundant, should not increase count.
805        headers.set(ContentLength(20));
806        assert_eq!(headers.len(), 2);
807    }
808
809    #[test]
810    fn test_clear() {
811        let mut headers = Headers::new();
812        headers.set(ContentLength(10));
813        headers.set(ContentType(Mime(Text, Plain, vec![])));
814        assert_eq!(headers.len(), 2);
815        headers.clear();
816        assert_eq!(headers.len(), 0);
817    }
818
819    #[test]
820    fn test_iter() {
821        let mut headers = Headers::new();
822        headers.set(ContentLength(11));
823        for header in headers.iter() {
824            assert!(header.is::<ContentLength>());
825            assert_eq!(header.name(), <ContentLength as Header>::header_name());
826            assert_eq!(header.value(), Some(&ContentLength(11)));
827            assert_eq!(header.value_string(), "11".to_owned());
828        }
829    }
830
831    #[test]
832    fn test_header_view_value_string() {
833        let mut headers = Headers::new();
834        headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
835        for header in headers.iter() {
836            assert_eq!(header.name(), "foo");
837            assert_eq!(header.value_string(), "one, two");
838        }
839    }
840
841    #[test]
842    fn test_eq() {
843        let mut headers1 = Headers::new();
844        let mut headers2 = Headers::new();
845
846        assert_eq!(headers1, headers2);
847
848        headers1.set(ContentLength(11));
849        headers2.set(Host {hostname: "foo.bar".to_owned(), port: None});
850        assert!(headers1 != headers2);
851
852        headers1 = Headers::new();
853        headers2 = Headers::new();
854
855        headers1.set(ContentLength(11));
856        headers2.set(ContentLength(11));
857        assert_eq!(headers1, headers2);
858
859        headers1.set(ContentLength(10));
860        assert!(headers1 != headers2);
861
862        headers1 = Headers::new();
863        headers2 = Headers::new();
864
865        headers1.set(Host { hostname: "foo.bar".to_owned(), port: None });
866        headers1.set(ContentLength(11));
867        headers2.set(ContentLength(11));
868        assert!(headers1 != headers2);
869    }
870
871    #[cfg(feature = "nightly")]
872    #[bench]
873    fn bench_headers_new(b: &mut Bencher) {
874        b.iter(|| {
875            let mut h = Headers::new();
876            h.set(ContentLength(11));
877            h
878        })
879    }
880
881    #[cfg(feature = "nightly")]
882    #[bench]
883    fn bench_headers_from_raw(b: &mut Bencher) {
884        let raw = raw!(b"Content-Length: 10");
885        b.iter(|| Headers::from_raw(&raw).unwrap())
886    }
887
888    #[cfg(feature = "nightly")]
889    #[bench]
890    fn bench_headers_get(b: &mut Bencher) {
891        let mut headers = Headers::new();
892        headers.set(ContentLength(11));
893        b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
894    }
895
896    #[cfg(feature = "nightly")]
897    #[bench]
898    fn bench_headers_get_miss(b: &mut Bencher) {
899        let headers = Headers::new();
900        b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
901    }
902
903    #[cfg(feature = "nightly")]
904    #[bench]
905    fn bench_headers_set(b: &mut Bencher) {
906        let mut headers = Headers::new();
907        b.iter(|| headers.set(ContentLength(12)))
908    }
909
910    #[cfg(feature = "nightly")]
911    #[bench]
912    fn bench_headers_has(b: &mut Bencher) {
913        let mut headers = Headers::new();
914        headers.set(ContentLength(11));
915        b.iter(|| assert!(headers.has::<ContentLength>()))
916    }
917
918    #[cfg(feature = "nightly")]
919    #[bench]
920    fn bench_headers_view_is(b: &mut Bencher) {
921        let mut headers = Headers::new();
922        headers.set(ContentLength(11));
923        let mut iter = headers.iter();
924        let view = iter.next().unwrap();
925        b.iter(|| assert!(view.is::<ContentLength>()))
926    }
927
928    #[cfg(feature = "nightly")]
929    #[bench]
930    fn bench_headers_fmt(b: &mut Bencher) {
931        let mut headers = Headers::new();
932        headers.set(ContentLength(11));
933        b.iter(|| headers.to_string())
934    }
935}