diff --git a/actix-files/src/named.rs b/actix-files/src/named.rs
index 717b058c..1f54c828 100644
--- a/actix-files/src/named.rs
+++ b/actix-files/src/named.rs
@@ -344,7 +344,7 @@ impl Responder for NamedFile {
         // check last modified
         let not_modified = if !none_match(etag.as_ref(), req) {
             true
-        } else if req.headers().contains_key(header::IF_NONE_MATCH) {
+        } else if req.headers().contains_key(&header::IF_NONE_MATCH) {
             false
         } else if let (Some(ref m), Some(header::IfModifiedSince(ref since))) =
             (last_modified, req.get_header())
@@ -378,7 +378,7 @@ impl Responder for NamedFile {
         let mut offset = 0;
 
         // check for range header
-        if let Some(ranges) = req.headers().get(header::RANGE) {
+        if let Some(ranges) = req.headers().get(&header::RANGE) {
             if let Ok(rangesheader) = ranges.to_str() {
                 if let Ok(rangesvec) = HttpRange::parse(rangesheader, length) {
                     length = rangesvec[0].length;
diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml
index 315dcd5c..fe9b62d1 100644
--- a/actix-http/Cargo.toml
+++ b/actix-http/Cargo.toml
@@ -60,6 +60,7 @@ bitflags = "1.0"
 bytes = "0.4"
 byteorder = "1.2"
 derive_more = "0.14"
+either = "1.5.2"
 encoding = "0.2"
 futures = "0.1"
 hashbrown = "0.1.8"
diff --git a/actix-http/src/client/h2proto.rs b/actix-http/src/client/h2proto.rs
index d45716ab..222e442c 100644
--- a/actix-http/src/client/h2proto.rs
+++ b/actix-http/src/client/h2proto.rs
@@ -107,7 +107,7 @@ where
             let mut head = ResponseHead::default();
             head.version = parts.version;
             head.status = parts.status;
-            head.headers = parts.headers;
+            head.headers = parts.headers.into();
 
             Ok((head, payload))
         })
diff --git a/actix-http/src/encoding/decoder.rs b/actix-http/src/encoding/decoder.rs
index 16d15e90..4b56a1b6 100644
--- a/actix-http/src/encoding/decoder.rs
+++ b/actix-http/src/encoding/decoder.rs
@@ -55,7 +55,7 @@ where
     #[inline]
     pub fn from_headers(stream: S, headers: &HeaderMap) -> Decoder<S> {
         // check content-encoding
-        let encoding = if let Some(enc) = headers.get(CONTENT_ENCODING) {
+        let encoding = if let Some(enc) = headers.get(&CONTENT_ENCODING) {
             if let Ok(enc) = enc.to_str() {
                 ContentEncoding::from(enc)
             } else {
diff --git a/actix-http/src/encoding/encoder.rs b/actix-http/src/encoding/encoder.rs
index 50e9d068..6537379f 100644
--- a/actix-http/src/encoding/encoder.rs
+++ b/actix-http/src/encoding/encoder.rs
@@ -31,7 +31,7 @@ impl<B: MessageBody> Encoder<B> {
         head: &mut ResponseHead,
         body: ResponseBody<B>,
     ) -> ResponseBody<Encoder<B>> {
-        let can_encode = !(head.headers().contains_key(CONTENT_ENCODING)
+        let can_encode = !(head.headers().contains_key(&CONTENT_ENCODING)
             || head.status == StatusCode::SWITCHING_PROTOCOLS
             || encoding == ContentEncoding::Identity
             || encoding == ContentEncoding::Auto);
diff --git a/actix-http/src/h1/codec.rs b/actix-http/src/h1/codec.rs
index 3834254a..1f3983ad 100644
--- a/actix-http/src/h1/codec.rs
+++ b/actix-http/src/h1/codec.rs
@@ -22,8 +22,8 @@ use crate::response::Response;
 bitflags! {
     struct Flags: u8 {
         const HEAD              = 0b0000_0001;
-        const KEEPALIVE_ENABLED = 0b0000_1000;
-        const STREAM            = 0b0001_0000;
+        const KEEPALIVE_ENABLED = 0b0000_0010;
+        const STREAM            = 0b0000_0100;
     }
 }
 
@@ -39,8 +39,8 @@ pub struct Codec {
 
     // encoder part
     flags: Flags,
-    headers_size: u32,
     encoder: encoder::MessageEncoder<Response<()>>,
+    // headers_size: u32,
 }
 
 impl Default for Codec {
@@ -73,7 +73,7 @@ impl Codec {
             ctype: ConnectionType::Close,
 
             flags,
-            headers_size: 0,
+            // headers_size: 0,
             encoder: encoder::MessageEncoder::default(),
         }
     }
@@ -159,37 +159,33 @@ impl Encoder for Codec {
     ) -> Result<(), Self::Error> {
         match item {
             Message::Item((mut res, length)) => {
-                if res.head().status == StatusCode::CONTINUE {
-                    dst.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
-                } else {
-                    // set response version
-                    res.head_mut().version = self.version;
+                // set response version
+                res.head_mut().version = self.version;
 
-                    // connection status
-                    self.ctype = if let Some(ct) = res.head().ctype() {
-                        if ct == ConnectionType::KeepAlive {
-                            self.ctype
-                        } else {
-                            ct
-                        }
-                    } else {
+                // connection status
+                self.ctype = if let Some(ct) = res.head().ctype() {
+                    if ct == ConnectionType::KeepAlive {
                         self.ctype
-                    };
+                    } else {
+                        ct
+                    }
+                } else {
+                    self.ctype
+                };
 
-                    // encode message
-                    let len = dst.len();
-                    self.encoder.encode(
-                        dst,
-                        &mut res,
-                        self.flags.contains(Flags::HEAD),
-                        self.flags.contains(Flags::STREAM),
-                        self.version,
-                        length,
-                        self.ctype,
-                        &self.config,
-                    )?;
-                    self.headers_size = (dst.len() - len) as u32;
-                }
+                // encode message
+                let len = dst.len();
+                self.encoder.encode(
+                    dst,
+                    &mut res,
+                    self.flags.contains(Flags::HEAD),
+                    self.flags.contains(Flags::STREAM),
+                    self.version,
+                    length,
+                    self.ctype,
+                    &self.config,
+                )?;
+                // self.headers_size = (dst.len() - len) as u32;
             }
             Message::Chunk(Some(bytes)) => {
                 self.encoder.encode_chunk(bytes.as_ref(), dst)?;
diff --git a/actix-http/src/h1/decoder.rs b/actix-http/src/h1/decoder.rs
index 88de9bc6..417441c6 100644
--- a/actix-http/src/h1/decoder.rs
+++ b/actix-http/src/h1/decoder.rs
@@ -5,11 +5,12 @@ use actix_codec::Decoder;
 use bytes::{Bytes, BytesMut};
 use futures::{Async, Poll};
 use http::header::{HeaderName, HeaderValue};
-use http::{header, HeaderMap, HttpTryFrom, Method, StatusCode, Uri, Version};
+use http::{header, HttpTryFrom, Method, StatusCode, Uri, Version};
 use httparse;
 use log::{debug, error, trace};
 
 use crate::error::ParseError;
+use crate::header::HeaderMap;
 use crate::message::{ConnectionType, ResponseHead};
 use crate::request::Request;
 
@@ -630,6 +631,7 @@ mod tests {
 
     use super::*;
     use crate::error::ParseError;
+    use crate::http::header::{HeaderName, SET_COOKIE};
     use crate::httpmessage::HttpMessage;
 
     impl PayloadType {
@@ -790,7 +792,13 @@ mod tests {
         assert_eq!(req.version(), Version::HTTP_11);
         assert_eq!(*req.method(), Method::GET);
         assert_eq!(req.path(), "/test");
-        assert_eq!(req.headers().get("test").unwrap().as_bytes(), b"value");
+        assert_eq!(
+            req.headers()
+                .get(HeaderName::try_from("test").unwrap())
+                .unwrap()
+                .as_bytes(),
+            b"value"
+        );
     }
 
     #[test]
@@ -805,12 +813,11 @@ mod tests {
 
         let val: Vec<_> = req
             .headers()
-            .get_all("Set-Cookie")
-            .iter()
+            .get_all(SET_COOKIE)
             .map(|v| v.to_str().unwrap().to_owned())
             .collect();
-        assert_eq!(val[0], "c1=cookie1");
-        assert_eq!(val[1], "c2=cookie2");
+        assert_eq!(val[1], "c1=cookie1");
+        assert_eq!(val[0], "c2=cookie2");
     }
 
     #[test]
diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs
index 374b8bec..9a81fb2b 100644
--- a/actix-http/src/h1/encoder.rs
+++ b/actix-http/src/h1/encoder.rs
@@ -6,15 +6,16 @@ use std::str::FromStr;
 use std::{cmp, fmt, io, mem};
 
 use bytes::{BufMut, Bytes, BytesMut};
-use http::header::{
-    HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
-};
-use http::{HeaderMap, Method, StatusCode, Version};
 
 use crate::body::BodySize;
 use crate::config::ServiceConfig;
+use crate::header::map;
 use crate::header::ContentEncoding;
 use crate::helpers;
+use crate::http::header::{
+    HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
+};
+use crate::http::{HeaderMap, Method, StatusCode, Version};
 use crate::message::{ConnectionType, Head, RequestHead, ResponseHead};
 use crate::request::Request;
 use crate::response::Response;
@@ -109,7 +110,7 @@ pub(crate) trait MessageType: Sized {
         let mut has_date = false;
         let mut remaining = dst.remaining_mut();
         let mut buf = unsafe { &mut *(dst.bytes_mut() as *mut [u8]) };
-        for (key, value) in self.headers() {
+        for (key, value) in self.headers().inner.iter() {
             match *key {
                 CONNECTION => continue,
                 TRANSFER_ENCODING | CONTENT_LENGTH if skip_len => continue,
@@ -118,31 +119,59 @@ pub(crate) trait MessageType: Sized {
                 }
                 _ => (),
             }
-
-            let v = value.as_ref();
             let k = key.as_str().as_bytes();
-            let len = k.len() + v.len() + 4;
-            if len > remaining {
-                unsafe {
-                    dst.advance_mut(pos);
+            match value {
+                map::Value::One(ref val) => {
+                    let v = val.as_ref();
+                    let len = k.len() + v.len() + 4;
+                    if len > remaining {
+                        unsafe {
+                            dst.advance_mut(pos);
+                        }
+                        pos = 0;
+                        dst.reserve(len);
+                        remaining = dst.remaining_mut();
+                        unsafe {
+                            buf = &mut *(dst.bytes_mut() as *mut _);
+                        }
+                    }
+                    buf[pos..pos + k.len()].copy_from_slice(k);
+                    pos += k.len();
+                    buf[pos..pos + 2].copy_from_slice(b": ");
+                    pos += 2;
+                    buf[pos..pos + v.len()].copy_from_slice(v);
+                    pos += v.len();
+                    buf[pos..pos + 2].copy_from_slice(b"\r\n");
+                    pos += 2;
+                    remaining -= len;
                 }
-                pos = 0;
-                dst.reserve(len);
-                remaining = dst.remaining_mut();
-                unsafe {
-                    buf = &mut *(dst.bytes_mut() as *mut _);
+                map::Value::Multi(ref vec) => {
+                    for val in vec {
+                        let v = val.as_ref();
+                        let len = k.len() + v.len() + 4;
+                        if len > remaining {
+                            unsafe {
+                                dst.advance_mut(pos);
+                            }
+                            pos = 0;
+                            dst.reserve(len);
+                            remaining = dst.remaining_mut();
+                            unsafe {
+                                buf = &mut *(dst.bytes_mut() as *mut _);
+                            }
+                        }
+                        buf[pos..pos + k.len()].copy_from_slice(k);
+                        pos += k.len();
+                        buf[pos..pos + 2].copy_from_slice(b": ");
+                        pos += 2;
+                        buf[pos..pos + v.len()].copy_from_slice(v);
+                        pos += v.len();
+                        buf[pos..pos + 2].copy_from_slice(b"\r\n");
+                        pos += 2;
+                        remaining -= len;
+                    }
                 }
             }
-
-            buf[pos..pos + k.len()].copy_from_slice(k);
-            pos += k.len();
-            buf[pos..pos + 2].copy_from_slice(b": ");
-            pos += 2;
-            buf[pos..pos + v.len()].copy_from_slice(v);
-            pos += v.len();
-            buf[pos..pos + 2].copy_from_slice(b"\r\n");
-            pos += 2;
-            remaining -= len;
         }
         unsafe {
             dst.advance_mut(pos);
diff --git a/actix-http/src/h2/dispatcher.rs b/actix-http/src/h2/dispatcher.rs
index e0099604..cbb74f60 100644
--- a/actix-http/src/h2/dispatcher.rs
+++ b/actix-http/src/h2/dispatcher.rs
@@ -116,7 +116,7 @@ where
                     head.uri = parts.uri;
                     head.method = parts.method;
                     head.version = parts.version;
-                    head.headers = parts.headers;
+                    head.headers = parts.headers.into();
                     tokio_current_thread::spawn(ServiceResponse::<S::Future, B> {
                         state: ServiceResponseState::ServiceCall(
                             self.service.call(req),
diff --git a/actix-http/src/header/common/cache_control.rs b/actix-http/src/header/common/cache_control.rs
index 0b79ea7c..55774619 100644
--- a/actix-http/src/header/common/cache_control.rs
+++ b/actix-http/src/header/common/cache_control.rs
@@ -64,7 +64,7 @@ impl Header for CacheControl {
     where
         T: crate::HttpMessage,
     {
-        let directives = from_comma_delimited(msg.headers().get_all(Self::name()))?;
+        let directives = from_comma_delimited(msg.headers().get_all(&Self::name()))?;
         if !directives.is_empty() {
             Ok(CacheControl(directives))
         } else {
diff --git a/actix-http/src/header/common/content_disposition.rs b/actix-http/src/header/common/content_disposition.rs
index 700400da..badf307a 100644
--- a/actix-http/src/header/common/content_disposition.rs
+++ b/actix-http/src/header/common/content_disposition.rs
@@ -444,7 +444,7 @@ impl Header for ContentDisposition {
     }
 
     fn parse<T: crate::HttpMessage>(msg: &T) -> Result<Self, crate::error::ParseError> {
-        if let Some(h) = msg.headers().get(Self::name()) {
+        if let Some(h) = msg.headers().get(&Self::name()) {
             Self::from_raw(&h)
         } else {
             Err(crate::error::ParseError::Header)
diff --git a/actix-http/src/header/common/if_range.rs b/actix-http/src/header/common/if_range.rs
index 2140ccbb..e910ebd9 100644
--- a/actix-http/src/header/common/if_range.rs
+++ b/actix-http/src/header/common/if_range.rs
@@ -73,12 +73,12 @@ impl Header for IfRange {
         T: HttpMessage,
     {
         let etag: Result<EntityTag, _> =
-            from_one_raw_str(msg.headers().get(header::IF_RANGE));
+            from_one_raw_str(msg.headers().get(&header::IF_RANGE));
         if let Ok(etag) = etag {
             return Ok(IfRange::EntityTag(etag));
         }
         let date: Result<HttpDate, _> =
-            from_one_raw_str(msg.headers().get(header::IF_RANGE));
+            from_one_raw_str(msg.headers().get(&header::IF_RANGE));
         if let Ok(date) = date {
             return Ok(IfRange::Date(date));
         }
diff --git a/actix-http/src/header/map.rs b/actix-http/src/header/map.rs
new file mode 100644
index 00000000..694aed02
--- /dev/null
+++ b/actix-http/src/header/map.rs
@@ -0,0 +1,384 @@
+use either::Either;
+use hashbrown::hash_map::{self, Entry};
+use hashbrown::HashMap;
+use http::header::{HeaderName, HeaderValue};
+use http::HttpTryFrom;
+
+/// A set of HTTP headers
+///
+/// `HeaderMap` is an multimap of [`HeaderName`] to values.
+///
+/// [`HeaderName`]: struct.HeaderName.html
+#[derive(Debug)]
+pub struct HeaderMap {
+    pub(crate) inner: HashMap<HeaderName, Value>,
+}
+
+#[derive(Debug)]
+pub(crate) enum Value {
+    One(HeaderValue),
+    Multi(Vec<HeaderValue>),
+}
+
+impl Value {
+    fn get(&self) -> &HeaderValue {
+        match self {
+            Value::One(ref val) => val,
+            Value::Multi(ref val) => &val[0],
+        }
+    }
+
+    fn get_mut(&mut self) -> &mut HeaderValue {
+        match self {
+            Value::One(ref mut val) => val,
+            Value::Multi(ref mut val) => &mut val[0],
+        }
+    }
+
+    fn append(&mut self, val: HeaderValue) {
+        match self {
+            Value::One(_) => {
+                let data = std::mem::replace(self, Value::Multi(vec![val]));
+                match data {
+                    Value::One(val) => self.append(val),
+                    Value::Multi(_) => unreachable!(),
+                }
+            }
+            Value::Multi(ref mut vec) => vec.push(val),
+        }
+    }
+}
+
+impl HeaderMap {
+    /// Create an empty `HeaderMap`.
+    ///
+    /// The map will be created without any capacity. This function will not
+    /// allocate.
+    pub fn new() -> Self {
+        HeaderMap {
+            inner: HashMap::new(),
+        }
+    }
+
+    /// Create an empty `HeaderMap` with the specified capacity.
+    ///
+    /// The returned map will allocate internal storage in order to hold about
+    /// `capacity` elements without reallocating. However, this is a "best
+    /// effort" as there are usage patterns that could cause additional
+    /// allocations before `capacity` headers are stored in the map.
+    ///
+    /// More capacity than requested may be allocated.
+    pub fn with_capacity(capacity: usize) -> HeaderMap {
+        HeaderMap {
+            inner: HashMap::with_capacity(capacity),
+        }
+    }
+
+    /// Returns the number of keys stored in the map.
+    ///
+    /// This number could be be less than or equal to actual headers stored in
+    /// the map.
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    /// Returns true if the map contains no elements.
+    pub fn is_empty(&self) -> bool {
+        self.inner.len() == 0
+    }
+
+    /// Clears the map, removing all key-value pairs. Keeps the allocated memory
+    /// for reuse.
+    pub fn clear(&mut self) {
+        self.inner.clear();
+    }
+
+    /// Returns the number of headers the map can hold without reallocating.
+    ///
+    /// This number is an approximation as certain usage patterns could cause
+    /// additional allocations before the returned capacity is filled.
+    pub fn capacity(&self) -> usize {
+        self.inner.capacity()
+    }
+
+    /// Reserves capacity for at least `additional` more headers to be inserted
+    /// into the `HeaderMap`.
+    ///
+    /// The header map may reserve more space to avoid frequent reallocations.
+    /// Like with `with_capacity`, this will be a "best effort" to avoid
+    /// allocations until `additional` more headers are inserted. Certain usage
+    /// patterns could cause additional allocations before the number is
+    /// reached.
+    pub fn reserve(&mut self, additional: usize) {
+        self.inner.reserve(additional)
+    }
+
+    /// Returns a reference to the value associated with the key.
+    ///
+    /// If there are multiple values associated with the key, then the first one
+    /// is returned. Use `get_all` to get all values associated with a given
+    /// key. Returns `None` if there are no values associated with the key.
+    pub fn get<N: AsName>(&self, name: N) -> Option<&HeaderValue> {
+        self.get2(name).map(|v| v.get())
+    }
+
+    fn get2<N: AsName>(&self, name: N) -> Option<&Value> {
+        match name.as_name() {
+            Either::Left(name) => self.inner.get(name),
+            Either::Right(s) => {
+                if let Ok(name) = HeaderName::try_from(s) {
+                    self.inner.get(&name)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    /// Returns a view of all values associated with a key.
+    ///
+    /// The returned view does not incur any allocations and allows iterating
+    /// the values associated with the key.  See [`GetAll`] for more details.
+    /// Returns `None` if there are no values associated with the key.
+    ///
+    /// [`GetAll`]: struct.GetAll.html
+    pub fn get_all<N: AsName>(&self, name: N) -> GetAll {
+        GetAll {
+            idx: 0,
+            item: self.get2(name),
+        }
+    }
+
+    /// Returns a mutable reference to the value associated with the key.
+    ///
+    /// If there are multiple values associated with the key, then the first one
+    /// is returned. Use `entry` to get all values associated with a given
+    /// key. Returns `None` if there are no values associated with the key.
+    pub fn get_mut<N: AsName>(&mut self, name: N) -> Option<&mut HeaderValue> {
+        match name.as_name() {
+            Either::Left(name) => self.inner.get_mut(name).map(|v| v.get_mut()),
+            Either::Right(s) => {
+                if let Ok(name) = HeaderName::try_from(s) {
+                    self.inner.get_mut(&name).map(|v| v.get_mut())
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    /// Returns true if the map contains a value for the specified key.
+    pub fn contains_key<N: AsName>(&self, key: N) -> bool {
+        match key.as_name() {
+            Either::Left(name) => self.inner.contains_key(name),
+            Either::Right(s) => {
+                if let Ok(name) = HeaderName::try_from(s) {
+                    self.inner.contains_key(&name)
+                } else {
+                    false
+                }
+            }
+        }
+    }
+
+    /// An iterator visiting all key-value pairs.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version. Each key will be yielded once per associated
+    /// value. So, if a key has 3 associated values, it will be yielded 3 times.
+    pub fn iter(&self) -> Iter {
+        Iter::new(self.inner.iter())
+    }
+
+    /// An iterator visiting all keys.
+    ///
+    /// The iteration order is arbitrary, but consistent across platforms for
+    /// the same crate version. Each key will be yielded only once even if it
+    /// has multiple associated values.
+    pub fn keys(&self) -> Keys {
+        Keys(self.inner.keys())
+    }
+
+    /// Inserts a key-value pair into the map.
+    ///
+    /// If the map did not previously have this key present, then `None` is
+    /// returned.
+    ///
+    /// If the map did have this key present, the new value is associated with
+    /// the key and all previous values are removed. **Note** that only a single
+    /// one of the previous values is returned. If there are multiple values
+    /// that have been previously associated with the key, then the first one is
+    /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns
+    /// all values.
+    ///
+    /// The key is not updated, though; this matters for types that can be `==`
+    /// without being identical.
+    pub fn insert(&mut self, key: HeaderName, val: HeaderValue) {
+        let _ = self.inner.insert(key, Value::One(val));
+    }
+
+    /// Inserts a key-value pair into the map.
+    ///
+    /// If the map did not previously have this key present, then `false` is
+    /// returned.
+    ///
+    /// If the map did have this key present, the new value is pushed to the end
+    /// of the list of values currently associated with the key. The key is not
+    /// updated, though; this matters for types that can be `==` without being
+    /// identical.
+    pub fn append(&mut self, key: HeaderName, value: HeaderValue) {
+        match self.inner.entry(key) {
+            Entry::Occupied(mut entry) => entry.get_mut().append(value),
+            Entry::Vacant(entry) => {
+                entry.insert(Value::One(value));
+            }
+        }
+    }
+
+    /// Removes all headers for a particular header name from the map.
+    pub fn remove<N: AsName>(&mut self, key: N) {
+        match key.as_name() {
+            Either::Left(name) => {
+                let _ = self.inner.remove(name);
+            }
+            Either::Right(s) => {
+                if let Ok(name) = HeaderName::try_from(s) {
+                    let _ = self.inner.remove(&name);
+                }
+            }
+        }
+    }
+}
+
+#[doc(hidden)]
+pub trait AsName {
+    fn as_name(&self) -> Either<&HeaderName, &str>;
+}
+
+impl AsName for HeaderName {
+    fn as_name(&self) -> Either<&HeaderName, &str> {
+        Either::Left(self)
+    }
+}
+
+impl<'a> AsName for &'a HeaderName {
+    fn as_name(&self) -> Either<&HeaderName, &str> {
+        Either::Left(self)
+    }
+}
+
+impl<'a> AsName for &'a str {
+    fn as_name(&self) -> Either<&HeaderName, &str> {
+        Either::Right(self)
+    }
+}
+
+impl AsName for String {
+    fn as_name(&self) -> Either<&HeaderName, &str> {
+        Either::Right(self.as_str())
+    }
+}
+
+impl<'a> AsName for &'a String {
+    fn as_name(&self) -> Either<&HeaderName, &str> {
+        Either::Right(self.as_str())
+    }
+}
+
+pub struct GetAll<'a> {
+    idx: usize,
+    item: Option<&'a Value>,
+}
+
+impl<'a> Iterator for GetAll<'a> {
+    type Item = &'a HeaderValue;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a HeaderValue> {
+        if let Some(ref val) = self.item {
+            match val {
+                Value::One(ref val) => {
+                    self.item.take();
+                    Some(val)
+                }
+                Value::Multi(ref vec) => {
+                    if self.idx < vec.len() {
+                        let item = Some(&vec[self.idx]);
+                        self.idx += 1;
+                        item
+                    } else {
+                        self.item.take();
+                        None
+                    }
+                }
+            }
+        } else {
+            None
+        }
+    }
+}
+
+pub struct Keys<'a>(hash_map::Keys<'a, HeaderName, Value>);
+
+impl<'a> Iterator for Keys<'a> {
+    type Item = &'a HeaderName;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a HeaderName> {
+        self.0.next()
+    }
+}
+
+impl<'a> IntoIterator for &'a HeaderMap {
+    type Item = (&'a HeaderName, &'a HeaderValue);
+    type IntoIter = Iter<'a>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+pub struct Iter<'a> {
+    idx: usize,
+    current: Option<(&'a HeaderName, &'a Vec<HeaderValue>)>,
+    iter: hash_map::Iter<'a, HeaderName, Value>,
+}
+
+impl<'a> Iter<'a> {
+    fn new(iter: hash_map::Iter<'a, HeaderName, Value>) -> Self {
+        Self {
+            iter,
+            idx: 0,
+            current: None,
+        }
+    }
+}
+
+impl<'a> Iterator for Iter<'a> {
+    type Item = (&'a HeaderName, &'a HeaderValue);
+
+    #[inline]
+    fn next(&mut self) -> Option<(&'a HeaderName, &'a HeaderValue)> {
+        if let Some(ref mut item) = self.current {
+            if self.idx < item.1.len() {
+                let item = (item.0, &item.1[self.idx]);
+                self.idx += 1;
+                return Some(item);
+            } else {
+                self.idx = 0;
+                self.current.take();
+            }
+        }
+        if let Some(item) = self.iter.next() {
+            match item.1 {
+                Value::One(ref value) => Some((item.0, value)),
+                Value::Multi(ref vec) => {
+                    self.current = Some((item.0, vec));
+                    self.next()
+                }
+            }
+        } else {
+            None
+        }
+    }
+}
diff --git a/actix-http/src/header/mod.rs b/actix-http/src/header/mod.rs
index deedd693..62018347 100644
--- a/actix-http/src/header/mod.rs
+++ b/actix-http/src/header/mod.rs
@@ -4,7 +4,6 @@
 use std::{fmt, str::FromStr};
 
 use bytes::{Bytes, BytesMut};
-use http::header::GetAll;
 use http::Error as HttpError;
 use mime::Mime;
 
@@ -14,12 +13,17 @@ use crate::error::ParseError;
 use crate::httpmessage::HttpMessage;
 
 mod common;
+pub(crate) mod map;
 mod shared;
 #[doc(hidden)]
 pub use self::common::*;
 #[doc(hidden)]
 pub use self::shared::*;
 
+#[doc(hidden)]
+pub use self::map::GetAll;
+pub use self::map::HeaderMap;
+
 /// A trait for any object that will represent a header field and value.
 pub trait Header
 where
@@ -220,8 +224,8 @@ impl fmt::Write for Writer {
 #[inline]
 #[doc(hidden)]
 /// Reads a comma-delimited raw header into a Vec.
-pub fn from_comma_delimited<T: FromStr>(
-    all: GetAll<HeaderValue>,
+pub fn from_comma_delimited<'a, I: Iterator<Item = &'a HeaderValue> + 'a, T: FromStr>(
+    all: I,
 ) -> Result<Vec<T>, ParseError> {
     let mut result = Vec::new();
     for h in all {
@@ -379,6 +383,17 @@ pub fn http_percent_encode(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result
     fmt::Display::fmt(&encoded, f)
 }
 
+/// Convert http::HeaderMap to a HeaderMap
+impl From<http::HeaderMap> for HeaderMap {
+    fn from(map: http::HeaderMap) -> HeaderMap {
+        let mut new_map = HeaderMap::with_capacity(map.capacity());
+        for (h, v) in map.iter() {
+            new_map.append(h.clone(), v.clone());
+        }
+        new_map
+    }
+}
+
 mod percent_encoding_http {
     use percent_encoding::{self, define_encode_set};
 
diff --git a/actix-http/src/httpmessage.rs b/actix-http/src/httpmessage.rs
index 7a2db52d..1534973a 100644
--- a/actix-http/src/httpmessage.rs
+++ b/actix-http/src/httpmessage.rs
@@ -4,13 +4,13 @@ use std::str;
 use encoding::all::UTF_8;
 use encoding::label::encoding_from_whatwg_label;
 use encoding::EncodingRef;
-use http::{header, HeaderMap};
+use http::header;
 use mime::Mime;
 
 use crate::cookie::Cookie;
 use crate::error::{ContentTypeError, CookieParseError, ParseError};
 use crate::extensions::Extensions;
-use crate::header::Header;
+use crate::header::{Header, HeaderMap};
 use crate::payload::Payload;
 
 struct Cookies(Vec<Cookie<'static>>);
diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs
index ed3669e8..5879e191 100644
--- a/actix-http/src/lib.rs
+++ b/actix-http/src/lib.rs
@@ -45,10 +45,11 @@ pub mod http {
     // re-exports
     pub use http::header::{HeaderName, HeaderValue};
     pub use http::uri::PathAndQuery;
-    pub use http::{uri, Error, HeaderMap, HttpTryFrom, Uri};
+    pub use http::{uri, Error, HttpTryFrom, Uri};
     pub use http::{Method, StatusCode, Version};
 
     pub use crate::cookie::{Cookie, CookieBuilder};
+    pub use crate::header::HeaderMap;
 
     /// Various http headers
     pub mod header {
diff --git a/actix-http/src/message.rs b/actix-http/src/message.rs
index 2fdb28e4..25bc55ba 100644
--- a/actix-http/src/message.rs
+++ b/actix-http/src/message.rs
@@ -5,7 +5,8 @@ use std::rc::Rc;
 use bitflags::bitflags;
 
 use crate::extensions::Extensions;
-use crate::http::{header, HeaderMap, Method, StatusCode, Uri, Version};
+use crate::header::HeaderMap;
+use crate::http::{header, Method, StatusCode, Uri, Version};
 
 /// Represents various types of connection
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -174,7 +175,7 @@ impl Default for ResponseHead {
         ResponseHead {
             version: Version::default(),
             status: StatusCode::OK,
-            headers: HeaderMap::with_capacity(16),
+            headers: HeaderMap::with_capacity(12),
             reason: None,
             flags: Flags::empty(),
             extensions: RefCell::new(Extensions::new()),
@@ -182,18 +183,6 @@ impl Default for ResponseHead {
     }
 }
 
-impl Head for ResponseHead {
-    fn clear(&mut self) {
-        self.reason = None;
-        self.flags = Flags::empty();
-        self.headers.clear();
-    }
-
-    fn pool() -> &'static MessagePool<Self> {
-        RESPONSE_POOL.with(|p| *p)
-    }
-}
-
 impl ResponseHead {
     /// Message extensions
     #[inline]
@@ -300,7 +289,6 @@ impl ResponseHead {
 
 pub struct Message<T: Head> {
     head: Rc<T>,
-    pool: &'static MessagePool<T>,
 }
 
 impl<T: Head> Message<T> {
@@ -314,7 +302,6 @@ impl<T: Head> Clone for Message<T> {
     fn clone(&self) -> Self {
         Message {
             head: self.head.clone(),
-            pool: self.pool,
         }
     }
 }
@@ -336,17 +323,52 @@ impl<T: Head> std::ops::DerefMut for Message<T> {
 impl<T: Head> Drop for Message<T> {
     fn drop(&mut self) {
         if Rc::strong_count(&self.head) == 1 {
-            self.pool.release(self.head.clone());
+            T::pool().release(self.head.clone());
         }
     }
 }
 
+pub(crate) struct BoxedResponseHead {
+    head: Option<Box<ResponseHead>>,
+}
+
+impl BoxedResponseHead {
+    /// Get new message from the pool of objects
+    pub fn new() -> Self {
+        RESPONSE_POOL.with(|p| p.get_message())
+    }
+}
+
+impl std::ops::Deref for BoxedResponseHead {
+    type Target = ResponseHead;
+
+    fn deref(&self) -> &Self::Target {
+        self.head.as_ref().unwrap()
+    }
+}
+
+impl std::ops::DerefMut for BoxedResponseHead {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.head.as_mut().unwrap()
+    }
+}
+
+impl Drop for BoxedResponseHead {
+    fn drop(&mut self) {
+        RESPONSE_POOL.with(|p| p.release(self.head.take().unwrap()))
+    }
+}
+
 #[doc(hidden)]
 /// Request's objects pool
 pub struct MessagePool<T: Head>(RefCell<VecDeque<Rc<T>>>);
 
+#[doc(hidden)]
+/// Request's objects pool
+pub struct BoxedResponsePool(RefCell<VecDeque<Box<ResponseHead>>>);
+
 thread_local!(static REQUEST_POOL: &'static MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
-thread_local!(static RESPONSE_POOL: &'static MessagePool<ResponseHead> = MessagePool::<ResponseHead>::create());
+thread_local!(static RESPONSE_POOL: &'static BoxedResponsePool = BoxedResponsePool::create());
 
 impl<T: Head> MessagePool<T> {
     fn create() -> &'static MessagePool<T> {
@@ -361,14 +383,10 @@ impl<T: Head> MessagePool<T> {
             if let Some(r) = Rc::get_mut(&mut msg) {
                 r.clear();
             }
-            Message {
-                head: msg,
-                pool: self,
-            }
+            Message { head: msg }
         } else {
             Message {
                 head: Rc::new(T::default()),
-                pool: self,
             }
         }
     }
@@ -382,3 +400,34 @@ impl<T: Head> MessagePool<T> {
         }
     }
 }
+
+impl BoxedResponsePool {
+    fn create() -> &'static BoxedResponsePool {
+        let pool = BoxedResponsePool(RefCell::new(VecDeque::with_capacity(128)));
+        Box::leak(Box::new(pool))
+    }
+
+    /// Get message from the pool
+    #[inline]
+    fn get_message(&'static self) -> BoxedResponseHead {
+        if let Some(mut head) = self.0.borrow_mut().pop_front() {
+            head.reason = None;
+            head.headers.clear();
+            head.flags = Flags::empty();
+            BoxedResponseHead { head: Some(head) }
+        } else {
+            BoxedResponseHead {
+                head: Some(Box::new(ResponseHead::default())),
+            }
+        }
+    }
+
+    #[inline]
+    /// Release request instance
+    fn release(&self, msg: Box<ResponseHead>) {
+        let v = &mut self.0.borrow_mut();
+        if v.len() < 128 {
+            v.push_front(msg);
+        }
+    }
+}
diff --git a/actix-http/src/request.rs b/actix-http/src/request.rs
index a645c7ae..468b4e33 100644
--- a/actix-http/src/request.rs
+++ b/actix-http/src/request.rs
@@ -1,9 +1,10 @@
 use std::cell::{Ref, RefMut};
 use std::fmt;
 
-use http::{header, HeaderMap, Method, Uri, Version};
+use http::{header, Method, Uri, Version};
 
 use crate::extensions::Extensions;
+use crate::header::HeaderMap;
 use crate::httpmessage::HttpMessage;
 use crate::message::{Message, RequestHead};
 use crate::payload::{Payload, PayloadStream};
@@ -161,7 +162,7 @@ impl<P> fmt::Debug for Request<P> {
             writeln!(f, "  query: ?{:?}", q)?;
         }
         writeln!(f, "  headers:")?;
-        for (key, val) in self.headers().iter() {
+        for (key, val) in self.headers() {
             writeln!(f, "    {:?}: {:?}", key, val)?;
         }
         Ok(())
diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs
index c3fed133..707c9af6 100644
--- a/actix-http/src/response.rs
+++ b/actix-http/src/response.rs
@@ -6,8 +6,6 @@ use std::{fmt, io, str};
 use bytes::{BufMut, Bytes, BytesMut};
 use futures::future::{ok, FutureResult, IntoFuture};
 use futures::Stream;
-use http::header::{self, HeaderName, HeaderValue};
-use http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode};
 use serde::Serialize;
 use serde_json;
 
@@ -16,11 +14,13 @@ use crate::cookie::{Cookie, CookieJar};
 use crate::error::Error;
 use crate::extensions::Extensions;
 use crate::header::{Header, IntoHeaderValue};
-use crate::message::{ConnectionType, Message, ResponseHead};
+use crate::http::header::{self, HeaderName, HeaderValue};
+use crate::http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode};
+use crate::message::{BoxedResponseHead, ConnectionType, ResponseHead};
 
 /// An HTTP Response
 pub struct Response<B = Body> {
-    head: Message<ResponseHead>,
+    head: BoxedResponseHead,
     body: ResponseBody<B>,
     error: Option<Error>,
 }
@@ -41,7 +41,7 @@ impl Response<Body> {
     /// Constructs a response
     #[inline]
     pub fn new(status: StatusCode) -> Response {
-        let mut head: Message<ResponseHead> = Message::new();
+        let mut head = BoxedResponseHead::new();
         head.status = status;
 
         Response {
@@ -93,7 +93,7 @@ impl<B> Response<B> {
     /// Constructs a response with body
     #[inline]
     pub fn with_body(status: StatusCode, body: B) -> Response<B> {
-        let mut head: Message<ResponseHead> = Message::new();
+        let mut head = BoxedResponseHead::new();
         head.status = status;
         Response {
             head,
@@ -136,7 +136,7 @@ impl<B> Response<B> {
     #[inline]
     pub fn cookies(&self) -> CookieIter {
         CookieIter {
-            iter: self.head.headers.get_all(header::SET_COOKIE).iter(),
+            iter: self.head.headers.get_all(header::SET_COOKIE),
         }
     }
 
@@ -158,7 +158,6 @@ impl<B> Response<B> {
         let h = &mut self.head.headers;
         let vals: Vec<HeaderValue> = h
             .get_all(header::SET_COOKIE)
-            .iter()
             .map(|v| v.to_owned())
             .collect();
         h.remove(header::SET_COOKIE);
@@ -286,7 +285,7 @@ impl IntoFuture for Response {
 }
 
 pub struct CookieIter<'a> {
-    iter: header::ValueIter<'a, HeaderValue>,
+    iter: header::GetAll<'a>,
 }
 
 impl<'a> Iterator for CookieIter<'a> {
@@ -320,7 +319,7 @@ impl<'a> io::Write for Writer<'a> {
 /// This type can be used to construct an instance of `Response` through a
 /// builder-like pattern.
 pub struct ResponseBuilder {
-    head: Option<Message<ResponseHead>>,
+    head: Option<BoxedResponseHead>,
     err: Option<HttpError>,
     cookies: Option<CookieJar>,
 }
@@ -328,7 +327,7 @@ pub struct ResponseBuilder {
 impl ResponseBuilder {
     /// Create response builder
     pub fn new(status: StatusCode) -> Self {
-        let mut head: Message<ResponseHead> = Message::new();
+        let mut head = BoxedResponseHead::new();
         head.status = status;
 
         ResponseBuilder {
@@ -701,13 +700,13 @@ impl ResponseBuilder {
 
 #[inline]
 fn parts<'a>(
-    parts: &'a mut Option<Message<ResponseHead>>,
+    parts: &'a mut Option<BoxedResponseHead>,
     err: &Option<HttpError>,
-) -> Option<&'a mut Message<ResponseHead>> {
+) -> Option<&'a mut ResponseHead> {
     if err.is_some() {
         return None;
     }
-    parts.as_mut()
+    parts.as_mut().map(|r| &mut **r)
 }
 
 /// Convert `Response` to a `ResponseBuilder`. Body get dropped.
@@ -740,7 +739,7 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
         let mut jar: Option<CookieJar> = None;
 
         let cookies = CookieIter {
-            iter: head.headers.get_all(header::SET_COOKIE).iter(),
+            iter: head.headers.get_all(header::SET_COOKIE),
         };
         for c in cookies {
             if let Some(ref mut j) = jar {
@@ -752,11 +751,11 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder {
             }
         }
 
-        let mut msg: Message<ResponseHead> = Message::new();
+        let mut msg = BoxedResponseHead::new();
         msg.version = head.version;
         msg.status = head.status;
         msg.reason = head.reason;
-        msg.headers = head.headers.clone();
+        // msg.headers = head.headers.clone();
         msg.no_chunking(!head.chunked());
 
         ResponseBuilder {
@@ -845,7 +844,7 @@ impl From<BytesMut> for Response {
 mod tests {
     use super::*;
     use crate::body::Body;
-    use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE};
+    use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE, SET_COOKIE};
 
     #[test]
     fn test_debug() {
@@ -876,13 +875,12 @@ mod tests {
                     .max_age(time::Duration::days(1))
                     .finish(),
             )
-            .del_cookie(&cookies[0])
+            .del_cookie(&cookies[1])
             .finish();
 
         let mut val: Vec<_> = resp
             .headers()
-            .get_all("Set-Cookie")
-            .iter()
+            .get_all(SET_COOKIE)
             .map(|v| v.to_str().unwrap().to_owned())
             .collect();
         val.sort();
@@ -911,9 +909,9 @@ mod tests {
 
         let mut iter = r.cookies();
         let v = iter.next().unwrap();
-        assert_eq!((v.name(), v.value()), ("original", "val100"));
-        let v = iter.next().unwrap();
         assert_eq!((v.name(), v.value()), ("cookie3", "val300"));
+        let v = iter.next().unwrap();
+        assert_eq!((v.name(), v.value()), ("original", "val100"));
     }
 
     #[test]
@@ -1049,6 +1047,7 @@ mod tests {
             resp.headers().get(CONTENT_TYPE).unwrap(),
             HeaderValue::from_static("application/octet-stream")
         );
+
         assert_eq!(resp.status(), StatusCode::OK);
         assert_eq!(resp.body().get_ref(), b"test");
     }
diff --git a/actix-http/src/test.rs b/actix-http/src/test.rs
index 02316124..302d75d7 100644
--- a/actix-http/src/test.rs
+++ b/actix-http/src/test.rs
@@ -4,10 +4,11 @@ use std::str::FromStr;
 
 use bytes::Bytes;
 use http::header::{self, HeaderName, HeaderValue};
-use http::{HeaderMap, HttpTryFrom, Method, Uri, Version};
+use http::{HttpTryFrom, Method, Uri, Version};
 use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
 
 use crate::cookie::{Cookie, CookieJar};
+use crate::header::HeaderMap;
 use crate::header::{Header, IntoHeaderValue};
 use crate::payload::Payload;
 use crate::Request;
diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs
index c1536af6..39559b08 100644
--- a/actix-multipart/src/server.rs
+++ b/actix-multipart/src/server.rs
@@ -92,7 +92,7 @@ impl Multipart {
 
     /// Extract boundary info from headers.
     fn boundary(headers: &HeaderMap) -> Result<String, MultipartError> {
-        if let Some(content_type) = headers.get(header::CONTENT_TYPE) {
+        if let Some(content_type) = headers.get(&header::CONTENT_TYPE) {
             if let Ok(content_type) = content_type.to_str() {
                 if let Ok(ct) = content_type.parse::<mime::Mime>() {
                     if let Some(boundary) = ct.get_param(mime::BOUNDARY) {
@@ -334,7 +334,7 @@ impl InnerMultipart {
 
             // content type
             let mut mt = mime::APPLICATION_OCTET_STREAM;
-            if let Some(content_type) = headers.get(header::CONTENT_TYPE) {
+            if let Some(content_type) = headers.get(&header::CONTENT_TYPE) {
                 if let Ok(content_type) = content_type.to_str() {
                     if let Ok(ct) = content_type.parse::<mime::Mime>() {
                         mt = ct;
@@ -427,7 +427,7 @@ impl Field {
     pub fn content_disposition(&self) -> Option<ContentDisposition> {
         // RFC 7578: 'Each part MUST contain a Content-Disposition header field
         // where the disposition type is "form-data".'
-        if let Some(content_disposition) = self.headers.get(header::CONTENT_DISPOSITION)
+        if let Some(content_disposition) = self.headers.get(&header::CONTENT_DISPOSITION)
         {
             ContentDisposition::from_raw(content_disposition).ok()
         } else {
@@ -480,7 +480,7 @@ impl InnerField {
         boundary: String,
         headers: &HeaderMap,
     ) -> Result<InnerField, PayloadError> {
-        let len = if let Some(len) = headers.get(header::CONTENT_LENGTH) {
+        let len = if let Some(len) = headers.get(&header::CONTENT_LENGTH) {
             if let Ok(s) = len.to_str() {
                 if let Ok(len) = s.parse::<u64>() {
                     Some(len)
diff --git a/actix-web-actors/src/ws.rs b/actix-web-actors/src/ws.rs
index 64222256..0ef3c916 100644
--- a/actix-web-actors/src/ws.rs
+++ b/actix-web-actors/src/ws.rs
@@ -50,7 +50,7 @@ pub fn handshake(req: &HttpRequest) -> Result<HttpResponseBuilder, HandshakeErro
     }
 
     // Check for "UPGRADE" to websocket header
-    let has_hdr = if let Some(hdr) = req.headers().get(header::UPGRADE) {
+    let has_hdr = if let Some(hdr) = req.headers().get(&header::UPGRADE) {
         if let Ok(s) = hdr.to_str() {
             s.to_ascii_lowercase().contains("websocket")
         } else {
@@ -69,11 +69,11 @@ pub fn handshake(req: &HttpRequest) -> Result<HttpResponseBuilder, HandshakeErro
     }
 
     // check supported version
-    if !req.headers().contains_key(header::SEC_WEBSOCKET_VERSION) {
+    if !req.headers().contains_key(&header::SEC_WEBSOCKET_VERSION) {
         return Err(HandshakeError::NoVersionHeader);
     }
     let supported_ver = {
-        if let Some(hdr) = req.headers().get(header::SEC_WEBSOCKET_VERSION) {
+        if let Some(hdr) = req.headers().get(&header::SEC_WEBSOCKET_VERSION) {
             hdr == "13" || hdr == "8" || hdr == "7"
         } else {
             false
@@ -84,11 +84,11 @@ pub fn handshake(req: &HttpRequest) -> Result<HttpResponseBuilder, HandshakeErro
     }
 
     // check client handshake for validity
-    if !req.headers().contains_key(header::SEC_WEBSOCKET_KEY) {
+    if !req.headers().contains_key(&header::SEC_WEBSOCKET_KEY) {
         return Err(HandshakeError::BadWebsocketKey);
     }
     let key = {
-        let key = req.headers().get(header::SEC_WEBSOCKET_KEY).unwrap();
+        let key = req.headers().get(&header::SEC_WEBSOCKET_KEY).unwrap();
         hash_key(key.as_ref())
     };
 
diff --git a/awc/src/lib.rs b/awc/src/lib.rs
index bd08c3c3..8c1bc80b 100644
--- a/awc/src/lib.rs
+++ b/awc/src/lib.rs
@@ -104,7 +104,7 @@ impl Client {
     {
         let mut req = ClientRequest::new(method, url, self.0.clone());
 
-        for (key, value) in &self.0.headers {
+        for (key, value) in self.0.headers.iter() {
             req = req.set_header_if_none(key.clone(), value.clone());
         }
         req
@@ -119,7 +119,7 @@ impl Client {
         Uri: HttpTryFrom<U>,
     {
         let mut req = self.request(head.method.clone(), url);
-        for (key, value) in &head.headers {
+        for (key, value) in head.headers.iter() {
             req = req.set_header_if_none(key.clone(), value.clone());
         }
         req
@@ -187,7 +187,7 @@ impl Client {
         Uri: HttpTryFrom<U>,
     {
         let mut req = ws::WebsocketsRequest::new(url, self.0.clone());
-        for (key, value) in &self.0.headers {
+        for (key, value) in self.0.headers.iter() {
             req.head.headers.insert(key.clone(), value.clone());
         }
         req
diff --git a/awc/src/request.rs b/awc/src/request.rs
index 32ab7d78..09a7eecc 100644
--- a/awc/src/request.rs
+++ b/awc/src/request.rs
@@ -396,7 +396,7 @@ impl ClientRequest {
         if self.default_headers {
             // set request host header
             if let Some(host) = self.head.uri.host() {
-                if !self.head.headers.contains_key(header::HOST) {
+                if !self.head.headers.contains_key(&header::HOST) {
                     let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
 
                     let _ = match self.head.uri.port_u16() {
@@ -414,7 +414,7 @@ impl ClientRequest {
             }
 
             // user agent
-            if !self.head.headers.contains_key(header::USER_AGENT) {
+            if !self.head.headers.contains_key(&header::USER_AGENT) {
                 self.head.headers.insert(
                     header::USER_AGENT,
                     HeaderValue::from_static(concat!("awc/", env!("CARGO_PKG_VERSION"))),
diff --git a/awc/src/response.rs b/awc/src/response.rs
index b6d7bba6..b9b007b8 100644
--- a/awc/src/response.rs
+++ b/awc/src/response.rs
@@ -46,7 +46,7 @@ impl<S> HttpMessage for ClientResponse<S> {
 
         if self.extensions().get::<Cookies>().is_none() {
             let mut cookies = Vec::new();
-            for hdr in self.headers().get_all(SET_COOKIE) {
+            for hdr in self.headers().get_all(&SET_COOKIE) {
                 let s = std::str::from_utf8(hdr.as_bytes())
                     .map_err(CookieParseError::from)?;
                 cookies.push(Cookie::parse_encoded(s)?.into_owned());
@@ -160,7 +160,7 @@ where
     /// Create `MessageBody` for request.
     pub fn new(res: &mut ClientResponse<S>) -> MessageBody<S> {
         let mut len = None;
-        if let Some(l) = res.headers().get(CONTENT_LENGTH) {
+        if let Some(l) = res.headers().get(&CONTENT_LENGTH) {
             if let Ok(s) = l.to_str() {
                 if let Ok(l) = s.parse::<usize>() {
                     len = Some(l)
@@ -254,7 +254,7 @@ where
         }
 
         let mut len = None;
-        if let Some(l) = req.headers().get(CONTENT_LENGTH) {
+        if let Some(l) = req.headers().get(&CONTENT_LENGTH) {
             if let Ok(s) = l.to_str() {
                 if let Ok(l) = s.parse::<usize>() {
                     len = Some(l)
diff --git a/awc/src/ws.rs b/awc/src/ws.rs
index a2851898..967820f3 100644
--- a/awc/src/ws.rs
+++ b/awc/src/ws.rs
@@ -236,7 +236,7 @@ impl WebsocketsRequest {
         let mut slf = if self.default_headers {
             // set request host header
             if let Some(host) = self.head.uri.host() {
-                if !self.head.headers.contains_key(header::HOST) {
+                if !self.head.headers.contains_key(&header::HOST) {
                     let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
 
                     let _ = match self.head.uri.port_u16() {
@@ -324,7 +324,7 @@ impl WebsocketsRequest {
                     return Err(WsClientError::InvalidResponseStatus(head.status));
                 }
                 // Check for "UPGRADE" to websocket header
-                let has_hdr = if let Some(hdr) = head.headers.get(header::UPGRADE) {
+                let has_hdr = if let Some(hdr) = head.headers.get(&header::UPGRADE) {
                     if let Ok(s) = hdr.to_str() {
                         s.to_ascii_lowercase().contains("websocket")
                     } else {
@@ -338,7 +338,7 @@ impl WebsocketsRequest {
                     return Err(WsClientError::InvalidUpgradeHeader);
                 }
                 // Check for "CONNECTION" header
-                if let Some(conn) = head.headers.get(header::CONNECTION) {
+                if let Some(conn) = head.headers.get(&header::CONNECTION) {
                     if let Ok(s) = conn.to_str() {
                         if !s.to_ascii_lowercase().contains("upgrade") {
                             log::trace!("Invalid connection header: {}", s);
@@ -355,7 +355,7 @@ impl WebsocketsRequest {
                     return Err(WsClientError::MissingConnectionHeader);
                 }
 
-                if let Some(hdr_key) = head.headers.get(header::SEC_WEBSOCKET_ACCEPT) {
+                if let Some(hdr_key) = head.headers.get(&header::SEC_WEBSOCKET_ACCEPT) {
                     let encoded = ws::hash_key(key.as_ref());
                     if hdr_key.as_bytes() != encoded.as_bytes() {
                         log::trace!(
diff --git a/src/info.rs b/src/info.rs
index 9a97c335..ece17bf0 100644
--- a/src/info.rs
+++ b/src/info.rs
@@ -33,7 +33,7 @@ impl ConnectionInfo {
         let peer = None;
 
         // load forwarded header
-        for hdr in req.headers.get_all(header::FORWARDED) {
+        for hdr in req.headers.get_all(&header::FORWARDED) {
             if let Ok(val) = hdr.to_str() {
                 for pair in val.split(';') {
                     for el in pair.split(',') {
@@ -69,7 +69,7 @@ impl ConnectionInfo {
         if scheme.is_none() {
             if let Some(h) = req
                 .headers
-                .get(HeaderName::from_lowercase(X_FORWARDED_PROTO).unwrap())
+                .get(&HeaderName::from_lowercase(X_FORWARDED_PROTO).unwrap())
             {
                 if let Ok(h) = h.to_str() {
                     scheme = h.split(',').next().map(|v| v.trim());
@@ -87,14 +87,14 @@ impl ConnectionInfo {
         if host.is_none() {
             if let Some(h) = req
                 .headers
-                .get(HeaderName::from_lowercase(X_FORWARDED_HOST).unwrap())
+                .get(&HeaderName::from_lowercase(X_FORWARDED_HOST).unwrap())
             {
                 if let Ok(h) = h.to_str() {
                     host = h.split(',').next().map(|v| v.trim());
                 }
             }
             if host.is_none() {
-                if let Some(h) = req.headers.get(header::HOST) {
+                if let Some(h) = req.headers.get(&header::HOST) {
                     host = h.to_str().ok();
                 }
                 if host.is_none() {
@@ -110,7 +110,7 @@ impl ConnectionInfo {
         if remote.is_none() {
             if let Some(h) = req
                 .headers
-                .get(HeaderName::from_lowercase(X_FORWARDED_FOR).unwrap())
+                .get(&HeaderName::from_lowercase(X_FORWARDED_FOR).unwrap())
             {
                 if let Ok(h) = h.to_str() {
                     remote = h.split(',').next().map(|v| v.trim());
diff --git a/src/middleware/compress.rs b/src/middleware/compress.rs
index ed394371..a4b6a460 100644
--- a/src/middleware/compress.rs
+++ b/src/middleware/compress.rs
@@ -109,7 +109,7 @@ where
 
     fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
         // negotiate content-encoding
-        let encoding = if let Some(val) = req.headers().get(ACCEPT_ENCODING) {
+        let encoding = if let Some(val) = req.headers().get(&ACCEPT_ENCODING) {
             if let Ok(enc) = val.to_str() {
                 AcceptEncoding::parse(enc, self.encoding)
             } else {
diff --git a/src/middleware/cors.rs b/src/middleware/cors.rs
index f003ac95..27d24b43 100644
--- a/src/middleware/cors.rs
+++ b/src/middleware/cors.rs
@@ -584,7 +584,7 @@ struct Inner {
 
 impl Inner {
     fn validate_origin(&self, req: &RequestHead) -> Result<(), CorsError> {
-        if let Some(hdr) = req.headers().get(header::ORIGIN) {
+        if let Some(hdr) = req.headers().get(&header::ORIGIN) {
             if let Ok(origin) = hdr.to_str() {
                 return match self.origins {
                     AllOrSome::All => Ok(()),
@@ -608,7 +608,7 @@ impl Inner {
             AllOrSome::All => {
                 if self.send_wildcard {
                     Some(HeaderValue::from_static("*"))
-                } else if let Some(origin) = req.headers().get(header::ORIGIN) {
+                } else if let Some(origin) = req.headers().get(&header::ORIGIN) {
                     Some(origin.clone())
                 } else {
                     None
@@ -617,7 +617,7 @@ impl Inner {
             AllOrSome::Some(ref origins) => {
                 if let Some(origin) =
                     req.headers()
-                        .get(header::ORIGIN)
+                        .get(&header::ORIGIN)
                         .filter(|o| match o.to_str() {
                             Ok(os) => origins.contains(os),
                             _ => false,
@@ -632,7 +632,7 @@ impl Inner {
     }
 
     fn validate_allowed_method(&self, req: &RequestHead) -> Result<(), CorsError> {
-        if let Some(hdr) = req.headers().get(header::ACCESS_CONTROL_REQUEST_METHOD) {
+        if let Some(hdr) = req.headers().get(&header::ACCESS_CONTROL_REQUEST_METHOD) {
             if let Ok(meth) = hdr.to_str() {
                 if let Ok(method) = Method::try_from(meth) {
                     return self
@@ -653,7 +653,7 @@ impl Inner {
             AllOrSome::All => Ok(()),
             AllOrSome::Some(ref allowed_headers) => {
                 if let Some(hdr) =
-                    req.headers().get(header::ACCESS_CONTROL_REQUEST_HEADERS)
+                    req.headers().get(&header::ACCESS_CONTROL_REQUEST_HEADERS)
                 {
                     if let Ok(headers) = hdr.to_str() {
                         let mut hdrs = HashSet::new();
@@ -720,7 +720,7 @@ where
                     .unwrap(),
                 )
             } else if let Some(hdr) =
-                req.headers().get(header::ACCESS_CONTROL_REQUEST_HEADERS)
+                req.headers().get(&header::ACCESS_CONTROL_REQUEST_HEADERS)
             {
                 Some(hdr.clone())
             } else {
@@ -759,7 +759,7 @@ where
                 .into_body();
 
             Either::A(ok(req.into_response(res)))
-        } else if req.headers().contains_key(header::ORIGIN) {
+        } else if req.headers().contains_key(&header::ORIGIN) {
             // Only check requests with a origin header.
             if let Err(e) = self.inner.validate_origin(req.head()) {
                 return Either::A(ok(req.error_response(e)));
@@ -790,7 +790,7 @@ where
                     }
                     if inner.vary_header {
                         let value =
-                            if let Some(hdr) = res.headers_mut().get(header::VARY) {
+                            if let Some(hdr) = res.headers_mut().get(&header::VARY) {
                                 let mut val: Vec<u8> =
                                     Vec::with_capacity(hdr.as_bytes().len() + 8);
                                 val.extend(hdr.as_bytes());
@@ -893,20 +893,20 @@ mod tests {
         assert_eq!(
             &b"*"[..],
             resp.headers()
-                .get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
+                .get(&header::ACCESS_CONTROL_ALLOW_ORIGIN)
                 .unwrap()
                 .as_bytes()
         );
         assert_eq!(
             &b"3600"[..],
             resp.headers()
-                .get(header::ACCESS_CONTROL_MAX_AGE)
+                .get(&header::ACCESS_CONTROL_MAX_AGE)
                 .unwrap()
                 .as_bytes()
         );
         let hdr = resp
             .headers()
-            .get(header::ACCESS_CONTROL_ALLOW_HEADERS)
+            .get(&header::ACCESS_CONTROL_ALLOW_HEADERS)
             .unwrap()
             .to_str()
             .unwrap();
diff --git a/src/middleware/defaultheaders.rs b/src/middleware/defaultheaders.rs
index 72e866db..a2bc6f27 100644
--- a/src/middleware/defaultheaders.rs
+++ b/src/middleware/defaultheaders.rs
@@ -131,11 +131,11 @@ where
             // set response headers
             for (key, value) in inner.headers.iter() {
                 if !res.headers().contains_key(key) {
-                    res.headers_mut().insert(key, value.clone());
+                    res.headers_mut().insert(key.clone(), value.clone());
                 }
             }
             // default content-type
-            if inner.ct && !res.headers().contains_key(CONTENT_TYPE) {
+            if inner.ct && !res.headers().contains_key(&CONTENT_TYPE) {
                 res.headers_mut().insert(
                     CONTENT_TYPE,
                     HeaderValue::from_static("application/octet-stream"),
diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs
index f4b7517d..aaf38138 100644
--- a/src/middleware/logger.rs
+++ b/src/middleware/logger.rs
@@ -14,6 +14,7 @@ use time;
 
 use crate::dev::{BodySize, MessageBody, ResponseBody};
 use crate::error::{Error, Result};
+use crate::http::{HeaderName, HttpTryFrom};
 use crate::service::{ServiceRequest, ServiceResponse};
 use crate::HttpResponse;
 
@@ -288,8 +289,12 @@ impl Format {
 
             if let Some(key) = cap.get(2) {
                 results.push(match cap.get(3).unwrap().as_str() {
-                    "i" => FormatText::RequestHeader(key.as_str().to_owned()),
-                    "o" => FormatText::ResponseHeader(key.as_str().to_owned()),
+                    "i" => FormatText::RequestHeader(
+                        HeaderName::try_from(key.as_str()).unwrap(),
+                    ),
+                    "o" => FormatText::ResponseHeader(
+                        HeaderName::try_from(key.as_str()).unwrap(),
+                    ),
                     "e" => FormatText::EnvironHeader(key.as_str().to_owned()),
                     _ => unreachable!(),
                 })
@@ -332,8 +337,8 @@ pub enum FormatText {
     TimeMillis,
     RemoteAddr,
     UrlPath,
-    RequestHeader(String),
-    ResponseHeader(String),
+    RequestHeader(HeaderName),
+    ResponseHeader(HeaderName),
     EnvironHeader(String),
 }
 
diff --git a/src/request.rs b/src/request.rs
index b5ba7412..2eab1ee1 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -286,10 +286,10 @@ mod tests {
         {
             let cookies = req.cookies().unwrap();
             assert_eq!(cookies.len(), 2);
-            assert_eq!(cookies[0].name(), "cookie1");
-            assert_eq!(cookies[0].value(), "value1");
-            assert_eq!(cookies[1].name(), "cookie2");
-            assert_eq!(cookies[1].value(), "value2");
+            assert_eq!(cookies[0].name(), "cookie2");
+            assert_eq!(cookies[0].value(), "value2");
+            assert_eq!(cookies[1].name(), "cookie1");
+            assert_eq!(cookies[1].value(), "value1");
         }
 
         let cookie = req.cookie("cookie1");
diff --git a/src/types/form.rs b/src/types/form.rs
index 812a08e5..b2171e54 100644
--- a/src/types/form.rs
+++ b/src/types/form.rs
@@ -209,7 +209,7 @@ where
         };
 
         let mut len = None;
-        if let Some(l) = req.headers().get(CONTENT_LENGTH) {
+        if let Some(l) = req.headers().get(&CONTENT_LENGTH) {
             if let Ok(s) = l.to_str() {
                 if let Ok(l) = s.parse::<usize>() {
                     len = Some(l)
diff --git a/src/types/json.rs b/src/types/json.rs
index c8ed5afd..f7b94a9b 100644
--- a/src/types/json.rs
+++ b/src/types/json.rs
@@ -297,7 +297,7 @@ where
         }
 
         let mut len = None;
-        if let Some(l) = req.headers().get(CONTENT_LENGTH) {
+        if let Some(l) = req.headers().get(&CONTENT_LENGTH) {
             if let Ok(s) = l.to_str() {
                 if let Ok(l) = s.parse::<usize>() {
                     len = Some(l)
diff --git a/src/types/payload.rs b/src/types/payload.rs
index 170b9c62..9cdbd057 100644
--- a/src/types/payload.rs
+++ b/src/types/payload.rs
@@ -313,7 +313,7 @@ where
     /// Create `MessageBody` for request.
     pub fn new(req: &mut T) -> HttpMessageBody<T> {
         let mut len = None;
-        if let Some(l) = req.headers().get(header::CONTENT_LENGTH) {
+        if let Some(l) = req.headers().get(&header::CONTENT_LENGTH) {
             if let Ok(s) = l.to_str() {
                 if let Ok(l) = s.parse::<usize>() {
                     len = Some(l)