1use std::borrow::{Cow, ToOwned};
80#[cfg(feature = "compat")]
81use std::convert::From;
82use std::iter::{FromIterator, IntoIterator};
83use std::{mem, fmt};
84
85#[cfg(feature = "compat")]
86use http;
87
88use unicase::Ascii;
89
90use self::internals::{Item, VecMap, Entry};
91use self::sealed::HeaderClone;
92
93pub use self::shared::*;
94pub use self::common::*;
95pub use self::raw::Raw;
96use bytes::Bytes;
97
98mod common;
99mod internals;
100mod raw;
101mod shared;
102pub mod parsing;
103
104
105pub trait Header: 'static + HeaderClone + Send + Sync {
110 fn header_name() -> &'static str where Self: Sized;
114 fn parse_header(raw: &Raw) -> ::Result<Self> where Self: Sized;
122 #[inline]
136 fn fmt_header(&self, f: &mut Formatter) -> fmt::Result;
137}
138
139mod sealed {
140 use super::Header;
141
142 #[doc(hidden)]
143 pub trait HeaderClone {
144 fn clone_box(&self) -> Box<Header + Send + Sync>;
145 }
146
147 impl<T: Header + Clone> HeaderClone for T {
148 #[inline]
149 fn clone_box(&self) -> Box<Header + Send + Sync> {
150 Box::new(self.clone())
151 }
152 }
153}
154
155
156#[allow(missing_debug_implementations)]
158pub struct Formatter<'a, 'b: 'a>(Multi<'a, 'b>);
159
160enum Multi<'a, 'b: 'a> {
161 Line(&'a str, &'a mut fmt::Formatter<'b>),
162 Join(bool, &'a mut fmt::Formatter<'b>),
163 Raw(&'a mut Raw),
164}
165
166impl<'a, 'b> Formatter<'a, 'b> {
167
168 pub fn fmt_line(&mut self, line: &fmt::Display) -> fmt::Result {
180 use std::fmt::Write;
181 match self.0 {
182 Multi::Line(name, ref mut f) => {
183 try!(f.write_str(name));
184 try!(f.write_str(": "));
185 try!(write!(NewlineReplacer(*f), "{}", line));
186 f.write_str("\r\n")
187 },
188 Multi::Join(ref mut first, ref mut f) => {
189 if !*first {
190 try!(f.write_str(", "));
191 } else {
192 *first = false;
193 }
194 write!(NewlineReplacer(*f), "{}", line)
195 }
196 Multi::Raw(ref mut raw) => {
197 let mut s = String::new();
198 try!(write!(NewlineReplacer(&mut s), "{}", line));
199 raw.push(s);
200 Ok(())
201 }
202 }
203 }
204
205 fn danger_fmt_line_without_newline_replacer<T: fmt::Display>(&mut self, line: &T) -> fmt::Result {
206 use std::fmt::Write;
207 match self.0 {
208 Multi::Line(name, ref mut f) => {
209 try!(f.write_str(name));
210 try!(f.write_str(": "));
211 try!(fmt::Display::fmt(line, f));
212 f.write_str("\r\n")
213 },
214 Multi::Join(ref mut first, ref mut f) => {
215 if !*first {
216 try!(f.write_str(", "));
217 } else {
218 *first = false;
219 }
220 fmt::Display::fmt(line, f)
221 }
222 Multi::Raw(ref mut raw) => {
223 let mut s = String::new();
224 try!(write!(s, "{}", line));
225 raw.push(s);
226 Ok(())
227 }
228 }
229 }
230}
231
232struct ValueString<'a>(&'a Item);
233
234impl<'a> fmt::Debug for ValueString<'a> {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 try!(f.write_str("\""));
237 try!(self.0.write_h1(&mut Formatter(Multi::Join(true, f))));
238 f.write_str("\"")
239 }
240}
241
242impl<'a> fmt::Display for ValueString<'a> {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244 self.0.write_h1(&mut Formatter(Multi::Join(true, f)))
245 }
246}
247
248struct NewlineReplacer<'a, F: fmt::Write + 'a>(&'a mut F);
249
250impl<'a, F: fmt::Write + 'a> fmt::Write for NewlineReplacer<'a, F> {
251 #[inline]
252 fn write_str(&mut self, s: &str) -> fmt::Result {
253 let mut since = 0;
254 for (i, &byte) in s.as_bytes().iter().enumerate() {
255 if byte == b'\r' || byte == b'\n' {
256 try!(self.0.write_str(&s[since..i]));
257 try!(self.0.write_str(" "));
258 since = i + 1;
259 }
260 }
261 if since < s.len() {
262 self.0.write_str(&s[since..])
263 } else {
264 Ok(())
265 }
266 }
267
268 #[inline]
269 fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
270 fmt::write(self, args)
271 }
272}
273
274
275impl Header + Send + Sync {
276 #[inline]
285 unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
286 &*(mem::transmute::<*const _, (*const (), *const ())>(self).0 as *const T)
287 }
288
289 #[inline]
290 unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
291 &mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T)
292 }
293
294 #[inline]
295 unsafe fn downcast_unchecked<T: 'static>(self: Box<Self>) -> T {
296 *Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
297 }
298}
299
300impl Clone for Box<Header + Send + Sync> {
301 #[inline]
302 fn clone(&self) -> Box<Header + Send + Sync> {
303 self.clone_box()
304 }
305}
306
307#[inline]
308fn header_name<T: Header>() -> &'static str {
309 <T as Header>::header_name()
310}
311
312#[derive(Clone)]
314pub struct Headers {
315 data: VecMap<HeaderName, Item>,
316}
317
318impl Default for Headers {
319 fn default() -> Headers {
320 Headers::new()
321 }
322}
323
324macro_rules! literals {
325 ($($len:expr => $($header:path),+;)+) => (
326 fn maybe_literal(s: &str) -> Cow<'static, str> {
327 match s.len() {
328 $($len => {
329 $(
330 if Ascii::new(<$header>::header_name()) == Ascii::new(s) {
331 return Cow::Borrowed(<$header>::header_name());
332 }
333 )+
334 })+
335
336 _ => ()
337 }
338
339 trace!("maybe_literal not found, copying {:?}", s);
340 Cow::Owned(s.to_owned())
341 }
342
343 #[test]
344 fn test_literal_lens() {
345 $(
346 $({
347 let s = <$header>::header_name();
348 assert!(s.len() == $len, "{:?} has len of {}, listed as {}", s, s.len(), $len);
349 })+
350 )+
351 }
352 );
353}
354
355literals! {
356 4 => Host, Date, ETag;
357 5 => Allow, Range;
358 6 => Accept, Cookie, Server, Expect;
359 7 => Upgrade, Referer, Expires;
360 8 => Location, IfMatch, IfRange;
361 10 => UserAgent, Connection, SetCookie;
362 12 => ContentType;
363 13 => Authorization<String>, CacheControl, LastModified, IfNoneMatch, AcceptRanges, ContentRange;
364 14 => ContentLength, AcceptCharset;
365 15 => AcceptEncoding, AcceptLanguage;
366 17 => TransferEncoding;
367 25 => StrictTransportSecurity;
368 27 => AccessControlAllowOrigin;
369}
370
371impl Headers {
372
373 #[inline]
375 pub fn new() -> Headers {
376 Headers::with_capacity(0)
377 }
378
379 #[inline]
381 pub fn with_capacity(len: usize) -> Headers {
382 Headers {
383 data: VecMap::with_capacity(len)
384 }
385 }
386
387 pub fn set<H: Header>(&mut self, value: H) {
391 self.data.insert(HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))),
392 Item::new_typed(value));
393 }
394
395 #[doc(hidden)]
396 pub fn __internal_set_pos<H: Header>(&mut self, pos: usize, value: H) {
397 self.data.insert_pos(
398 HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))),
399 Item::new_typed(value),
400 pos,
401 );
402 }
403
404 pub fn get<H: Header>(&self) -> Option<&H> {
406 self.data.get(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
407 .and_then(Item::typed::<H>)
408 }
409
410 pub fn get_mut<H: Header>(&mut self) -> Option<&mut H> {
412 self.data.get_mut(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
413 .and_then(Item::typed_mut::<H>)
414 }
415
416 pub fn has<H: Header>(&self) -> bool {
428 self.data.contains_key(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
429 }
430
431 pub fn remove<H: Header>(&mut self) -> Option<H> {
437 self.data.remove(&HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))))
438 .and_then(Item::into_typed::<H>)
439 }
440
441 pub fn iter(&self) -> HeadersItems {
443 HeadersItems {
444 inner: self.data.iter()
445 }
446 }
447
448 pub fn len(&self) -> usize {
450 self.data.len()
451 }
452
453 pub fn clear(&mut self) {
455 self.data.clear()
456 }
457
458 pub fn get_raw(&self, name: &str) -> Option<&Raw> {
472 self.data
473 .get(name)
474 .map(Item::raw)
475 }
476
477 pub fn set_raw<K: Into<Cow<'static, str>>, V: Into<Raw>>(&mut self, name: K, value: V) {
490 let name = name.into();
491 let value = value.into();
492 self.data.insert(HeaderName(Ascii::new(name)), Item::new_raw(value));
493 }
494
495 pub fn append_raw<K: Into<Cow<'static, str>>, V: Into<Raw>>(&mut self, name: K, value: V) {
511 let name = name.into();
512 let value = value.into();
513 let name = HeaderName(Ascii::new(name));
514 if let Some(item) = self.data.get_mut(&name) {
515 item.raw_mut().push(value);
516 return;
517 }
518 self.data.insert(name, Item::new_raw(value));
519 }
520
521 pub fn remove_raw(&mut self, name: &str) {
523 self.data.remove(name);
524 }
525
526}
527
528impl PartialEq for Headers {
529 fn eq(&self, other: &Headers) -> bool {
530 if self.len() != other.len() {
531 return false;
532 }
533
534 for header in self.iter() {
535 match other.get_raw(header.name()) {
536 Some(val) if val == self.get_raw(header.name()).unwrap() => {},
537 _ => { return false; }
538 }
539 }
540 true
541 }
542}
543
544impl fmt::Display for Headers {
545 #[inline]
546 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547 for header in self.iter() {
548 try!(fmt::Display::fmt(&header, f));
549 }
550 Ok(())
551 }
552}
553
554impl fmt::Debug for Headers {
555 #[inline]
556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557 f.debug_map()
558 .entries(self.iter().map(|view| (view.0.as_ref(), ValueString(view.1))))
559 .finish()
560 }
561}
562
563#[cfg(feature = "compat")]
564impl From<http::HeaderMap> for Headers {
565 fn from(mut header_map: http::HeaderMap) -> Headers {
566 let mut headers = Headers::new();
567 for (name, mut value_drain) in header_map.drain() {
568 if let Some(first_value) = value_drain.next() {
569 let mut raw: Raw = first_value.as_bytes().into();
570 for value in value_drain {
571 raw.push(value.as_bytes());
572 }
573 headers.append_raw(name.as_str().to_string(), raw);
574 }
575 }
576 headers
577 }
578}
579
580#[cfg(feature = "compat")]
581impl From<Headers> for http::HeaderMap {
582 fn from(headers: Headers) -> http::HeaderMap {
583 let mut header_map = http::HeaderMap::new();
584 for header in headers.iter() {
585 let entry = header_map.entry(header.name())
586 .expect("attempted to convert invalid header name");
587 let mut value_iter = header.raw().iter().map(|line| {
588 http::header::HeaderValue::from_bytes(line)
589 .expect("attempted to convert invalid header value")
590 });
591 match entry {
592 http::header::Entry::Occupied(mut occupied) => {
593 for value in value_iter {
594 occupied.append(value);
595 }
596 },
597 http::header::Entry::Vacant(vacant) => {
598 if let Some(first_value) = value_iter.next() {
599 let mut occupied = vacant.insert_entry(first_value);
600 for value in value_iter {
601 occupied.append(value);
602 }
603 }
604 }
605 }
606 }
607 header_map
608 }
609}
610
611#[allow(missing_debug_implementations)]
613pub struct HeadersItems<'a> {
614 inner: ::std::slice::Iter<'a, (HeaderName, Item)>
615}
616
617impl<'a> Iterator for HeadersItems<'a> {
618 type Item = HeaderView<'a>;
619
620 fn next(&mut self) -> Option<HeaderView<'a>> {
621 self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
622 }
623}
624
625pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
627
628impl<'a> HeaderView<'a> {
629 #[inline]
631 pub fn is<H: Header>(&self) -> bool {
632 HeaderName(Ascii::new(Cow::Borrowed(header_name::<H>()))) == *self.0
633 }
634
635 #[inline]
637 pub fn name(&self) -> &'a str {
638 self.0.as_ref()
639 }
640
641 #[inline]
643 pub fn value<H: Header>(&self) -> Option<&'a H> {
644 self.1.typed::<H>()
645 }
646
647 #[inline]
654 pub fn value_string(&self) -> String {
655 ValueString(self.1).to_string()
656 }
657
658 #[inline]
660 pub fn raw(&self) -> &Raw {
661 self.1.raw()
662 }
663}
664
665impl<'a> fmt::Display for HeaderView<'a> {
666 #[inline]
667 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
668 self.1.write_h1(&mut Formatter(Multi::Line(self.0.as_ref(), f)))
669 }
670}
671
672impl<'a> fmt::Debug for HeaderView<'a> {
673 #[inline]
674 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
675 fmt::Display::fmt(self, f)
676 }
677}
678
679impl<'a> Extend<HeaderView<'a>> for Headers {
680 fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
681 for header in iter {
682 self.data.insert((*header.0).clone(), (*header.1).clone());
683 }
684 }
685}
686
687impl<'a> Extend<(&'a str, Bytes)> for Headers {
688 fn extend<I: IntoIterator<Item=(&'a str, Bytes)>>(&mut self, iter: I) {
689 for (name, value) in iter {
690 let name = HeaderName(Ascii::new(maybe_literal(name)));
691 match self.data.entry(name) {
694 Entry::Vacant(entry) => {
695 entry.insert(Item::new_raw(self::raw::parsed(value)));
696 }
697 Entry::Occupied(entry) => {
698 self::raw::push(entry.into_mut().raw_mut(), value);
699 }
700 };
701 }
702 }
703}
704
705impl<'a> FromIterator<HeaderView<'a>> for Headers {
706 fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
707 let mut headers = Headers::new();
708 headers.extend(iter);
709 headers
710 }
711}
712
713#[derive(Clone, Debug)]
714struct HeaderName(Ascii<Cow<'static, str>>);
715
716impl fmt::Display for HeaderName {
717 #[inline]
718 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
719 fmt::Display::fmt(self.0.as_ref(), f)
720 }
721}
722
723impl AsRef<str> for HeaderName {
724 fn as_ref(&self) -> &str {
725 self.0.as_ref()
726 }
727}
728
729impl PartialEq for HeaderName {
730 #[inline]
731 fn eq(&self, other: &HeaderName) -> bool {
732 let s = self.as_ref();
733 let k = other.as_ref();
734 if s.as_ptr() == k.as_ptr() && s.len() == k.len() {
735 true
736 } else {
737 self.0 == other.0
738 }
739 }
740}
741
742impl PartialEq<HeaderName> for str {
743 fn eq(&self, other: &HeaderName) -> bool {
744 let k = other.as_ref();
745 if self.as_ptr() == k.as_ptr() && self.len() == k.len() {
746 true
747 } else {
748 other.0 == self
749 }
750 }
751}
752
753#[cfg(test)]
754mod tests {
755 use std::fmt;
756 use super::{Headers, Header, Raw, ContentLength, ContentType, Host, SetCookie};
757
758 #[cfg(feature = "nightly")]
759 use test::Bencher;
760
761 macro_rules! make_header {
762 ($name:expr, $value:expr) => ({
763 let mut headers = Headers::new();
764 headers.set_raw(String::from_utf8($name.to_vec()).unwrap(), $value.to_vec());
765 headers
766 });
767 ($text:expr) => ({
768 let bytes = $text;
769 let colon = bytes.iter().position(|&x| x == b':').unwrap();
770 make_header!(&bytes[..colon], &bytes[colon + 2..])
771 })
772 }
773 #[test]
774 fn test_from_raw() {
775 let headers = make_header!(b"Content-Length", b"10");
776 assert_eq!(headers.get(), Some(&ContentLength(10)));
777 }
778
779 #[derive(Clone, PartialEq, Debug)]
780 struct CrazyLength(Option<bool>, usize);
781
782 impl Header for CrazyLength {
783 fn header_name() -> &'static str {
784 "content-length"
785 }
786 fn parse_header(raw: &Raw) -> ::Result<CrazyLength> {
787 use std::str::from_utf8;
788 use std::str::FromStr;
789
790 if let Some(line) = raw.one() {
791 let s = try!(from_utf8(line).map(|s| FromStr::from_str(s).map_err(|_| ::Error::Header)));
792 s.map(|u| CrazyLength(Some(false), u))
793 } else {
794 Err(::Error::Header)
795 }
796 }
797
798 fn fmt_header(&self, f: &mut super::Formatter) -> fmt::Result {
799 f.fmt_line(self)
800 }
801 }
802
803 impl fmt::Display for CrazyLength {
804 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
805 let CrazyLength(ref opt, ref value) = *self;
806 write!(f, "{:?}, {:?}", opt, value)
807 }
808 }
809
810 #[test]
811 fn test_different_structs_for_same_header() {
812 let headers = make_header!(b"Content-Length: 10");
813 assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
814 assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
815 }
816
817 #[test]
818 fn test_trailing_whitespace() {
819 let headers = make_header!(b"Content-Length: 10 ");
820 assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
821 }
822
823 #[test]
824 fn test_multiple_reads() {
825 let headers = make_header!(b"Content-Length: 10");
826 let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
827 let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
828 assert_eq!(one, two);
829 }
830
831 #[test]
832 fn test_different_reads() {
833 let mut headers = Headers::new();
834 headers.set_raw("Content-Length", "10");
835 headers.set_raw("Content-Type", "text/plain");
836 let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
837 let ContentType(_) = *headers.get::<ContentType>().unwrap();
838 }
839
840 #[test]
841 fn test_typed_get_raw() {
842 let mut headers = Headers::new();
843 headers.set(ContentLength(15));
844 assert_eq!(headers.get_raw("content-length").unwrap(), "15");
845
846 headers.set(SetCookie(vec![
847 "foo=bar".to_string(),
848 "baz=quux; Path=/path".to_string()
849 ]));
850 assert_eq!(headers.get_raw("set-cookie").unwrap(), &["foo=bar", "baz=quux; Path=/path"][..]);
851 }
852
853 #[test]
854 fn test_get_mutable() {
855 let mut headers = make_header!(b"Content-Length: 10");
856 *headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
857 assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
858 assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
859 }
860
861 #[test]
862 fn test_headers_to_string() {
863 let mut headers = Headers::new();
864 headers.set(ContentLength(15));
865 headers.set(Host::new("foo.bar", None));
866
867 let s = headers.to_string();
868 assert!(s.contains("Host: foo.bar\r\n"));
869 assert!(s.contains("Content-Length: 15\r\n"));
870 }
871
872 #[test]
873 fn test_headers_to_string_raw() {
874 let mut headers = make_header!(b"Content-Length: 10");
875 headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
876 let s = headers.to_string();
877 assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
878 }
879
880 #[test]
881 fn test_set_raw() {
882 let mut headers = Headers::new();
883 headers.set(ContentLength(10));
884 headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
885 assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
886 assert_eq!(headers.get(), Some(&ContentLength(20)));
887 }
888
889 #[test]
890 fn test_append_raw() {
891 let mut headers = Headers::new();
892 headers.set(ContentLength(10));
893 headers.append_raw("content-LENGTH", b"20".to_vec());
894 assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
895 headers.append_raw("x-foo", "bar");
896 assert_eq!(headers.get_raw("x-foo").unwrap(), &[b"bar".to_vec()][..]);
897 }
898
899 #[test]
900 fn test_remove_raw() {
901 let mut headers = Headers::new();
902 headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
903 headers.remove_raw("content-LENGTH");
904 assert_eq!(headers.get_raw("Content-length"), None);
905 }
906
907 #[test]
908 fn test_remove() {
909 let mut headers = Headers::new();
910 headers.set(ContentLength(10));
911 assert_eq!(headers.remove(), Some(ContentLength(10)));
912 assert_eq!(headers.len(), 0);
913
914 headers.set(ContentLength(9));
915 assert_eq!(headers.len(), 1);
916 assert!(headers.remove::<CrazyLength>().is_none());
917 assert_eq!(headers.len(), 0);
918 }
919
920 #[test]
921 fn test_len() {
922 let mut headers = Headers::new();
923 headers.set(ContentLength(10));
924 assert_eq!(headers.len(), 1);
925 headers.set(ContentType::json());
926 assert_eq!(headers.len(), 2);
927 headers.set(ContentLength(20));
929 assert_eq!(headers.len(), 2);
930 }
931
932 #[test]
933 fn test_clear() {
934 let mut headers = Headers::new();
935 headers.set(ContentLength(10));
936 headers.set(ContentType::json());
937 assert_eq!(headers.len(), 2);
938 headers.clear();
939 assert_eq!(headers.len(), 0);
940 }
941
942 #[test]
943 fn test_iter() {
944 let mut headers = Headers::new();
945 headers.set(ContentLength(11));
946 for header in headers.iter() {
947 assert!(header.is::<ContentLength>());
948 assert_eq!(header.name(), <ContentLength as Header>::header_name());
949 assert_eq!(header.value(), Some(&ContentLength(11)));
950 assert_eq!(header.value_string(), "11".to_owned());
951 }
952 }
953
954 #[test]
955 fn test_header_view_value_string() {
956 let mut headers = Headers::new();
957 headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
958 for header in headers.iter() {
959 assert_eq!(header.name(), "foo");
960 assert_eq!(header.value_string(), "one, two");
961 }
962 }
963
964 #[test]
965 fn test_header_view_raw() {
966 let mut headers = Headers::new();
967 headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
968 for header in headers.iter() {
969 assert_eq!(header.name(), "foo");
970 let values: Vec<&[u8]> = header.raw().iter().collect();
971 assert_eq!(values, vec![b"one", b"two"]);
972 }
973 }
974
975 #[test]
976 fn test_eq() {
977 let mut headers1 = Headers::new();
978 let mut headers2 = Headers::new();
979
980 assert_eq!(headers1, headers2);
981
982 headers1.set(ContentLength(11));
983 headers2.set(Host::new("foo.bar", None));
984 assert_ne!(headers1, headers2);
985
986 headers1 = Headers::new();
987 headers2 = Headers::new();
988
989 headers1.set(ContentLength(11));
990 headers2.set(ContentLength(11));
991 assert_eq!(headers1, headers2);
992
993 headers1.set(ContentLength(10));
994 assert_ne!(headers1, headers2);
995
996 headers1 = Headers::new();
997 headers2 = Headers::new();
998
999 headers1.set(Host::new("foo.bar", None));
1000 headers1.set(ContentLength(11));
1001 headers2.set(ContentLength(11));
1002 assert_ne!(headers1, headers2);
1003 }
1004
1005 #[test]
1006 #[cfg(feature = "compat")]
1007 fn test_compat() {
1008 use http;
1009
1010 let mut orig_hyper_headers = Headers::new();
1011 orig_hyper_headers.set(ContentLength(11));
1012 orig_hyper_headers.set(Host::new("foo.bar", None));
1013 orig_hyper_headers.append_raw("x-foo", b"bar".to_vec());
1014 orig_hyper_headers.append_raw("x-foo", b"quux".to_vec());
1015
1016 let mut orig_http_headers = http::HeaderMap::new();
1017 orig_http_headers.insert(http::header::CONTENT_LENGTH, "11".parse().unwrap());
1018 orig_http_headers.insert(http::header::HOST, "foo.bar".parse().unwrap());
1019 orig_http_headers.append("x-foo", "bar".parse().unwrap());
1020 orig_http_headers.append("x-foo", "quux".parse().unwrap());
1021
1022 let conv_hyper_headers: Headers = orig_http_headers.clone().into();
1023 let conv_http_headers: http::HeaderMap = orig_hyper_headers.clone().into();
1024 assert_eq!(orig_hyper_headers, conv_hyper_headers);
1025 assert_eq!(orig_http_headers, conv_http_headers);
1026 }
1027
1028 #[cfg(feature = "nightly")]
1029 #[bench]
1030 fn bench_headers_new(b: &mut Bencher) {
1031 b.iter(|| {
1032 let mut h = Headers::new();
1033 h.set(ContentLength(11));
1034 h
1035 })
1036 }
1037
1038 #[cfg(feature = "nightly")]
1039 #[bench]
1040 fn bench_headers_get(b: &mut Bencher) {
1041 let mut headers = Headers::new();
1042 headers.set(ContentLength(11));
1043 b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
1044 }
1045
1046 #[cfg(feature = "nightly")]
1047 #[bench]
1048 fn bench_headers_get_miss(b: &mut Bencher) {
1049 let headers = Headers::new();
1050 b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
1051 }
1052
1053 #[cfg(feature = "nightly")]
1054 #[bench]
1055 fn bench_headers_get_miss_previous_10(b: &mut Bencher) {
1056 let mut headers = Headers::new();
1057 for i in 0..10 {
1058 headers.set_raw(format!("non-standard-{}", i), "hi");
1059 }
1060 b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
1061 }
1062
1063 #[cfg(feature = "nightly")]
1064 #[bench]
1065 fn bench_headers_set(b: &mut Bencher) {
1066 let mut headers = Headers::new();
1067 b.iter(|| headers.set(ContentLength(12)))
1068 }
1069
1070 #[cfg(feature = "nightly")]
1071 #[bench]
1072 fn bench_headers_set_previous_10(b: &mut Bencher) {
1073 let mut headers = Headers::new();
1074 for i in 0..10 {
1075 headers.set_raw(format!("non-standard-{}", i), "hi");
1076 }
1077 b.iter(|| headers.set(ContentLength(12)))
1078 }
1079
1080 #[cfg(feature = "nightly")]
1081 #[bench]
1082 fn bench_headers_set_raw(b: &mut Bencher) {
1083 let mut headers = Headers::new();
1084 b.iter(|| headers.set_raw("non-standard", "hello"))
1085 }
1086
1087 #[cfg(feature = "nightly")]
1088 #[bench]
1089 fn bench_headers_set_raw_previous_10(b: &mut Bencher) {
1090 let mut headers = Headers::new();
1091 for i in 0..10 {
1092 headers.set_raw(format!("non-standard-{}", i), "hi");
1093 }
1094 b.iter(|| headers.set_raw("non-standard", "hello"))
1095 }
1096
1097 #[cfg(feature = "nightly")]
1098 #[bench]
1099 fn bench_headers_has(b: &mut Bencher) {
1100 let mut headers = Headers::new();
1101 headers.set(ContentLength(11));
1102 b.iter(|| assert!(headers.has::<ContentLength>()))
1103 }
1104
1105 #[cfg(feature = "nightly")]
1106 #[bench]
1107 fn bench_headers_view_is(b: &mut Bencher) {
1108 let mut headers = Headers::new();
1109 headers.set(ContentLength(11));
1110 let mut iter = headers.iter();
1111 let view = iter.next().unwrap();
1112 b.iter(|| assert!(view.is::<ContentLength>()))
1113 }
1114
1115 #[cfg(feature = "nightly")]
1116 #[bench]
1117 fn bench_headers_fmt(b: &mut Bencher) {
1118 use std::fmt::Write;
1119 let mut buf = String::with_capacity(64);
1120 let mut headers = Headers::new();
1121 headers.set(ContentLength(11));
1122 headers.set(ContentType::json());
1123 b.bytes = headers.to_string().len() as u64;
1124 b.iter(|| {
1125 let _ = write!(buf, "{}", headers);
1126 ::test::black_box(&buf);
1127 unsafe { buf.as_mut_vec().set_len(0); }
1128 })
1129 }
1130}