diff --git a/src/client/connection.rs b/src/client/connection.rs
index 8de23bd24..e8c1201aa 100644
--- a/src/client/connection.rs
+++ b/src/client/connection.rs
@@ -6,11 +6,11 @@ use futures::Future;
 use h2::client::SendRequest;
 
 use crate::body::MessageBody;
-use crate::message::RequestHead;
+use crate::message::{RequestHead, ResponseHead};
+use crate::payload::Payload;
 
 use super::error::SendRequestError;
 use super::pool::Acquired;
-use super::response::ClientResponse;
 use super::{h1proto, h2proto};
 
 pub(crate) enum ConnectionType<Io> {
@@ -19,7 +19,7 @@ pub(crate) enum ConnectionType<Io> {
 }
 
 pub trait Connection {
-    type Future: Future<Item = ClientResponse, Error = SendRequestError>;
+    type Future: Future<Item = (ResponseHead, Payload), Error = SendRequestError>;
 
     /// Send request and body
     fn send_request<B: MessageBody + 'static>(
@@ -80,7 +80,7 @@ impl<T> Connection for IoConnection<T>
 where
     T: AsyncRead + AsyncWrite + 'static,
 {
-    type Future = Box<Future<Item = ClientResponse, Error = SendRequestError>>;
+    type Future = Box<Future<Item = (ResponseHead, Payload), Error = SendRequestError>>;
 
     fn send_request<B: MessageBody + 'static>(
         mut self,
@@ -117,7 +117,7 @@ where
     A: AsyncRead + AsyncWrite + 'static,
     B: AsyncRead + AsyncWrite + 'static,
 {
-    type Future = Box<Future<Item = ClientResponse, Error = SendRequestError>>;
+    type Future = Box<Future<Item = (ResponseHead, Payload), Error = SendRequestError>>;
 
     fn send_request<RB: MessageBody + 'static>(
         self,
diff --git a/src/client/h1proto.rs b/src/client/h1proto.rs
index 34521cc2f..2e29484ff 100644
--- a/src/client/h1proto.rs
+++ b/src/client/h1proto.rs
@@ -2,17 +2,18 @@ use std::{io, time};
 
 use actix_codec::{AsyncRead, AsyncWrite, Framed};
 use bytes::Bytes;
-use futures::future::{err, ok, Either};
+use futures::future::{ok, Either};
 use futures::{Async, Future, Poll, Sink, Stream};
 
+use crate::error::PayloadError;
+use crate::h1;
+use crate::message::{RequestHead, ResponseHead};
+use crate::payload::{Payload, PayloadStream};
+
 use super::connection::{ConnectionLifetime, ConnectionType, IoConnection};
 use super::error::{ConnectError, SendRequestError};
 use super::pool::Acquired;
-use super::response::ClientResponse;
 use crate::body::{BodyLength, MessageBody};
-use crate::error::PayloadError;
-use crate::h1;
-use crate::message::RequestHead;
 
 pub(crate) fn send_request<T, B>(
     io: T,
@@ -20,7 +21,7 @@ pub(crate) fn send_request<T, B>(
     body: B,
     created: time::Instant,
     pool: Option<Acquired<T>>,
-) -> impl Future<Item = ClientResponse, Error = SendRequestError>
+) -> impl Future<Item = (ResponseHead, Payload), Error = SendRequestError>
 where
     T: AsyncRead + AsyncWrite + 'static,
     B: MessageBody,
@@ -50,19 +51,20 @@ where
                 .into_future()
                 .map_err(|(e, _)| SendRequestError::from(e))
                 .and_then(|(item, framed)| {
-                    if let Some(mut res) = item {
+                    if let Some(res) = item {
                         match framed.get_codec().message_type() {
                             h1::MessageType::None => {
                                 let force_close = !framed.get_codec().keepalive();
-                                release_connection(framed, force_close)
+                                release_connection(framed, force_close);
+                                Ok((res, Payload::None))
                             }
                             _ => {
-                                res.set_payload(Payload::stream(framed).into());
+                                let pl: PayloadStream = Box::new(PlStream::new(framed));
+                                Ok((res, pl.into()))
                             }
                         }
-                        ok(res)
                     } else {
-                        err(ConnectError::Disconnected.into())
+                        Err(ConnectError::Disconnected.into())
                     }
                 })
         })
@@ -199,21 +201,19 @@ where
     }
 }
 
-pub(crate) struct Payload<Io> {
+pub(crate) struct PlStream<Io> {
     framed: Option<Framed<Io, h1::ClientPayloadCodec>>,
 }
 
-impl<Io: ConnectionLifetime> Payload<Io> {
-    pub fn stream(
-        framed: Framed<Io, h1::ClientCodec>,
-    ) -> Box<Stream<Item = Bytes, Error = PayloadError>> {
-        Box::new(Payload {
+impl<Io: ConnectionLifetime> PlStream<Io> {
+    fn new(framed: Framed<Io, h1::ClientCodec>) -> Self {
+        PlStream {
             framed: Some(framed.map_codec(|codec| codec.into_payload_codec())),
-        })
+        }
     }
 }
 
-impl<Io: ConnectionLifetime> Stream for Payload<Io> {
+impl<Io: ConnectionLifetime> Stream for PlStream<Io> {
     type Item = Bytes;
     type Error = PayloadError;
 
diff --git a/src/client/h2proto.rs b/src/client/h2proto.rs
index bf2d3e1b2..9ad722627 100644
--- a/src/client/h2proto.rs
+++ b/src/client/h2proto.rs
@@ -9,13 +9,12 @@ use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING};
 use http::{request::Request, HttpTryFrom, Method, Version};
 
 use crate::body::{BodyLength, MessageBody};
-use crate::message::{Message, RequestHead, ResponseHead};
+use crate::message::{RequestHead, ResponseHead};
 use crate::payload::Payload;
 
 use super::connection::{ConnectionType, IoConnection};
 use super::error::SendRequestError;
 use super::pool::Acquired;
-use super::response::ClientResponse;
 
 pub(crate) fn send_request<T, B>(
     io: SendRequest<Bytes>,
@@ -23,7 +22,7 @@ pub(crate) fn send_request<T, B>(
     body: B,
     created: time::Instant,
     pool: Option<Acquired<T>>,
-) -> impl Future<Item = ClientResponse, Error = SendRequestError>
+) -> impl Future<Item = (ResponseHead, Payload), Error = SendRequestError>
 where
     T: AsyncRead + AsyncWrite + 'static,
     B: MessageBody,
@@ -105,12 +104,12 @@ where
             let (parts, body) = resp.into_parts();
             let payload = if head_req { Payload::None } else { body.into() };
 
-            let mut head: Message<ResponseHead> = Message::new();
+            let mut head = ResponseHead::default();
             head.version = parts.version;
             head.status = parts.status;
             head.headers = parts.headers;
 
-            Ok(ClientResponse { head, payload })
+            Ok((head, payload))
         })
         .from_err()
 }
diff --git a/src/client/mod.rs b/src/client/mod.rs
index 86b1a0cc0..87c374742 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -5,11 +5,7 @@ mod error;
 mod h1proto;
 mod h2proto;
 mod pool;
-mod request;
-mod response;
 
 pub use self::connection::Connection;
 pub use self::connector::Connector;
 pub use self::error::{ConnectError, InvalidUrl, SendRequestError};
-pub use self::request::{ClientRequest, ClientRequestBuilder};
-pub use self::response::ClientResponse;
diff --git a/src/client/request.rs b/src/client/request.rs
deleted file mode 100644
index 134a42640..000000000
--- a/src/client/request.rs
+++ /dev/null
@@ -1,699 +0,0 @@
-use std::fmt;
-use std::io::Write;
-
-use actix_service::Service;
-use bytes::{BufMut, Bytes, BytesMut};
-#[cfg(feature = "cookies")]
-use cookie::{Cookie, CookieJar};
-use futures::future::{err, Either};
-use futures::{Future, Stream};
-use serde::Serialize;
-use serde_json;
-
-use crate::body::{BodyStream, MessageBody};
-use crate::error::Error;
-use crate::header::{self, Header, IntoHeaderValue};
-use crate::http::{
-    uri, Error as HttpError, HeaderMap, HeaderName, HeaderValue, HttpTryFrom, Method,
-    Uri, Version,
-};
-use crate::message::{ConnectionType, Head, RequestHead};
-
-use super::connection::Connection;
-use super::error::{ConnectError, InvalidUrl, SendRequestError};
-use super::response::ClientResponse;
-
-/// An HTTP Client Request
-///
-/// ```rust
-/// use futures::future::{Future, lazy};
-/// use actix_rt::System;
-/// use actix_http::client;
-///
-/// fn main() {
-///     System::new("test").block_on(lazy(|| {
-///        let mut connector = client::Connector::new().service();
-///
-///        client::ClientRequest::get("http://www.rust-lang.org") // <- Create request builder
-///           .header("User-Agent", "Actix-web")
-///           .finish().unwrap()
-///           .send(&mut connector)                      // <- Send http request
-///           .map_err(|_| ())
-///           .and_then(|response| {                     // <- server http response
-///                println!("Response: {:?}", response);
-///                Ok(())
-///           })
-///     }));
-/// }
-/// ```
-pub struct ClientRequest<B: MessageBody = ()> {
-    head: RequestHead,
-    body: B,
-}
-
-impl ClientRequest<()> {
-    /// Create client request builder
-    pub fn build() -> ClientRequestBuilder {
-        ClientRequestBuilder {
-            head: Some(RequestHead::default()),
-            err: None,
-            #[cfg(feature = "cookies")]
-            cookies: None,
-            default_headers: true,
-        }
-    }
-
-    /// Create request builder for `GET` request
-    pub fn get<U>(uri: U) -> ClientRequestBuilder
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        let mut builder = ClientRequest::build();
-        builder.method(Method::GET).uri(uri);
-        builder
-    }
-
-    /// Create request builder for `HEAD` request
-    pub fn head<U>(uri: U) -> ClientRequestBuilder
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        let mut builder = ClientRequest::build();
-        builder.method(Method::HEAD).uri(uri);
-        builder
-    }
-
-    /// Create request builder for `POST` request
-    pub fn post<U>(uri: U) -> ClientRequestBuilder
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        let mut builder = ClientRequest::build();
-        builder.method(Method::POST).uri(uri);
-        builder
-    }
-
-    /// Create request builder for `PUT` request
-    pub fn put<U>(uri: U) -> ClientRequestBuilder
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        let mut builder = ClientRequest::build();
-        builder.method(Method::PUT).uri(uri);
-        builder
-    }
-
-    /// Create request builder for `DELETE` request
-    pub fn delete<U>(uri: U) -> ClientRequestBuilder
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        let mut builder = ClientRequest::build();
-        builder.method(Method::DELETE).uri(uri);
-        builder
-    }
-}
-
-impl<B> ClientRequest<B>
-where
-    B: MessageBody,
-{
-    /// Create new client request
-    pub fn new(head: RequestHead, body: B) -> Self {
-        ClientRequest { head, body }
-    }
-
-    /// Get the request URI
-    #[inline]
-    pub fn uri(&self) -> &Uri {
-        &self.head.uri
-    }
-
-    /// Set client request URI
-    #[inline]
-    pub fn set_uri(&mut self, uri: Uri) {
-        self.head.uri = uri
-    }
-
-    /// Get the request method
-    #[inline]
-    pub fn method(&self) -> &Method {
-        &self.head.method
-    }
-
-    /// Set HTTP `Method` for the request
-    #[inline]
-    pub fn set_method(&mut self, method: Method) {
-        self.head.method = method
-    }
-
-    /// Get HTTP version for the request
-    #[inline]
-    pub fn version(&self) -> Version {
-        self.head.version
-    }
-
-    /// Set http `Version` for the request
-    #[inline]
-    pub fn set_version(&mut self, version: Version) {
-        self.head.version = version
-    }
-
-    /// Get the headers from the request
-    #[inline]
-    pub fn headers(&self) -> &HeaderMap {
-        &self.head.headers
-    }
-
-    /// Get a mutable reference to the headers
-    #[inline]
-    pub fn headers_mut(&mut self) -> &mut HeaderMap {
-        &mut self.head.headers
-    }
-
-    /// Deconstruct ClientRequest to a RequestHead and body tuple
-    pub fn into_parts(self) -> (RequestHead, B) {
-        (self.head, self.body)
-    }
-
-    // Send request
-    ///
-    /// This method returns a future that resolves to a ClientResponse
-    pub fn send<T>(
-        self,
-        connector: &mut T,
-    ) -> impl Future<Item = ClientResponse, Error = SendRequestError>
-    where
-        B: 'static,
-        T: Service<Request = Uri, Error = ConnectError>,
-        T::Response: Connection,
-    {
-        let Self { head, body } = self;
-
-        let uri = head.uri.clone();
-
-        // validate uri
-        if uri.host().is_none() {
-            Either::A(err(InvalidUrl::MissingHost.into()))
-        } else if uri.scheme_part().is_none() {
-            Either::A(err(InvalidUrl::MissingScheme.into()))
-        } else if let Some(scheme) = uri.scheme_part() {
-            match scheme.as_str() {
-                "http" | "ws" | "https" | "wss" => Either::B(
-                    connector
-                        // connect to the host
-                        .call(uri)
-                        .from_err()
-                        // send request
-                        .and_then(move |connection| connection.send_request(head, body)),
-                ),
-                _ => Either::A(err(InvalidUrl::UnknownScheme.into())),
-            }
-        } else {
-            Either::A(err(InvalidUrl::UnknownScheme.into()))
-        }
-    }
-}
-
-impl<B> fmt::Debug for ClientRequest<B>
-where
-    B: MessageBody,
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        writeln!(
-            f,
-            "\nClientRequest {:?} {}:{}",
-            self.head.version, self.head.method, self.head.uri
-        )?;
-        writeln!(f, "  headers:")?;
-        for (key, val) in self.head.headers.iter() {
-            writeln!(f, "    {:?}: {:?}", key, val)?;
-        }
-        Ok(())
-    }
-}
-
-/// An HTTP Client request builder
-///
-/// This type can be used to construct an instance of `ClientRequest` through a
-/// builder-like pattern.
-pub struct ClientRequestBuilder {
-    head: Option<RequestHead>,
-    err: Option<HttpError>,
-    #[cfg(feature = "cookies")]
-    cookies: Option<CookieJar>,
-    default_headers: bool,
-}
-
-impl ClientRequestBuilder {
-    /// Set HTTP URI of request.
-    #[inline]
-    pub fn uri<U>(&mut self, uri: U) -> &mut Self
-    where
-        Uri: HttpTryFrom<U>,
-    {
-        match Uri::try_from(uri) {
-            Ok(uri) => {
-                if let Some(parts) = parts(&mut self.head, &self.err) {
-                    parts.uri = uri;
-                }
-            }
-            Err(e) => self.err = Some(e.into()),
-        }
-        self
-    }
-
-    /// Set HTTP method of this request.
-    #[inline]
-    pub fn method(&mut self, method: Method) -> &mut Self {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            parts.method = method;
-        }
-        self
-    }
-
-    /// Set HTTP method of this request.
-    #[inline]
-    pub fn get_method(&mut self) -> &Method {
-        let parts = self.head.as_ref().expect("cannot reuse request builder");
-        &parts.method
-    }
-
-    /// Set HTTP version of this request.
-    ///
-    /// By default requests's HTTP version depends on network stream
-    #[inline]
-    pub fn version(&mut self, version: Version) -> &mut Self {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            parts.version = version;
-        }
-        self
-    }
-
-    /// Set a header.
-    ///
-    /// ```rust
-    /// # extern crate mime;
-    /// # extern crate actix_http;
-    /// #
-    /// use actix_http::{client, http};
-    ///
-    /// fn main() {
-    ///     let req = client::ClientRequest::build()
-    ///         .set(http::header::Date::now())
-    ///         .set(http::header::ContentType(mime::TEXT_HTML))
-    ///         .finish()
-    ///         .unwrap();
-    /// }
-    /// ```
-    pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            match hdr.try_into() {
-                Ok(value) => {
-                    parts.headers.insert(H::name(), value);
-                }
-                Err(e) => self.err = Some(e.into()),
-            }
-        }
-        self
-    }
-
-    /// Append a header.
-    ///
-    /// Header gets appended to existing header.
-    /// To override header use `set_header()` method.
-    ///
-    /// ```rust
-    /// # extern crate actix_http;
-    /// #
-    /// use actix_http::{client, http};
-    ///
-    /// fn main() {
-    ///     let req = client::ClientRequest::build()
-    ///         .header("X-TEST", "value")
-    ///         .header(http::header::CONTENT_TYPE, "application/json")
-    ///         .finish()
-    ///         .unwrap();
-    /// }
-    /// ```
-    pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
-    where
-        HeaderName: HttpTryFrom<K>,
-        V: IntoHeaderValue,
-    {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            match HeaderName::try_from(key) {
-                Ok(key) => match value.try_into() {
-                    Ok(value) => {
-                        parts.headers.append(key, value);
-                    }
-                    Err(e) => self.err = Some(e.into()),
-                },
-                Err(e) => self.err = Some(e.into()),
-            };
-        }
-        self
-    }
-
-    /// Set a header.
-    pub fn set_header<K, V>(&mut self, key: K, value: V) -> &mut Self
-    where
-        HeaderName: HttpTryFrom<K>,
-        V: IntoHeaderValue,
-    {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            match HeaderName::try_from(key) {
-                Ok(key) => match value.try_into() {
-                    Ok(value) => {
-                        parts.headers.insert(key, value);
-                    }
-                    Err(e) => self.err = Some(e.into()),
-                },
-                Err(e) => self.err = Some(e.into()),
-            };
-        }
-        self
-    }
-
-    /// Set a header only if it is not yet set.
-    pub fn set_header_if_none<K, V>(&mut self, key: K, value: V) -> &mut Self
-    where
-        HeaderName: HttpTryFrom<K>,
-        V: IntoHeaderValue,
-    {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            match HeaderName::try_from(key) {
-                Ok(key) => {
-                    if !parts.headers.contains_key(&key) {
-                        match value.try_into() {
-                            Ok(value) => {
-                                parts.headers.insert(key, value);
-                            }
-                            Err(e) => self.err = Some(e.into()),
-                        }
-                    }
-                }
-                Err(e) => self.err = Some(e.into()),
-            };
-        }
-        self
-    }
-
-    /// Enable connection upgrade
-    #[inline]
-    pub fn upgrade<V>(&mut self, value: V) -> &mut Self
-    where
-        V: IntoHeaderValue,
-    {
-        {
-            if let Some(parts) = parts(&mut self.head, &self.err) {
-                parts.set_connection_type(ConnectionType::Upgrade);
-            }
-        }
-        self.set_header(header::UPGRADE, value)
-    }
-
-    /// Close connection
-    #[inline]
-    pub fn close(&mut self) -> &mut Self {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            parts.set_connection_type(ConnectionType::Close);
-        }
-        self
-    }
-
-    /// Set request's content type
-    #[inline]
-    pub fn content_type<V>(&mut self, value: V) -> &mut Self
-    where
-        HeaderValue: HttpTryFrom<V>,
-    {
-        if let Some(parts) = parts(&mut self.head, &self.err) {
-            match HeaderValue::try_from(value) {
-                Ok(value) => {
-                    parts.headers.insert(header::CONTENT_TYPE, value);
-                }
-                Err(e) => self.err = Some(e.into()),
-            };
-        }
-        self
-    }
-
-    /// Set content length
-    #[inline]
-    pub fn content_length(&mut self, len: u64) -> &mut Self {
-        let mut wrt = BytesMut::new().writer();
-        let _ = write!(wrt, "{}", len);
-        self.header(header::CONTENT_LENGTH, wrt.get_mut().take().freeze())
-    }
-
-    #[cfg(feature = "cookies")]
-    /// Set a cookie
-    ///
-    /// ```rust
-    /// # extern crate actix_http;
-    /// use actix_http::{client, http};
-    ///
-    /// fn main() {
-    ///     let req = client::ClientRequest::build()
-    ///         .cookie(
-    ///             http::Cookie::build("name", "value")
-    ///                 .domain("www.rust-lang.org")
-    ///                 .path("/")
-    ///                 .secure(true)
-    ///                 .http_only(true)
-    ///                 .finish(),
-    ///         )
-    ///         .finish()
-    ///         .unwrap();
-    /// }
-    /// ```
-    pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
-        if self.cookies.is_none() {
-            let mut jar = CookieJar::new();
-            jar.add(cookie.into_owned());
-            self.cookies = Some(jar)
-        } else {
-            self.cookies.as_mut().unwrap().add(cookie.into_owned());
-        }
-        self
-    }
-
-    /// Do not add default request headers.
-    /// By default `Accept-Encoding` and `User-Agent` headers are set.
-    pub fn no_default_headers(&mut self) -> &mut Self {
-        self.default_headers = false;
-        self
-    }
-
-    /// This method calls provided closure with builder reference if
-    /// value is `true`.
-    pub fn if_true<F>(&mut self, value: bool, f: F) -> &mut Self
-    where
-        F: FnOnce(&mut ClientRequestBuilder),
-    {
-        if value {
-            f(self);
-        }
-        self
-    }
-
-    /// This method calls provided closure with builder reference if
-    /// value is `Some`.
-    pub fn if_some<T, F>(&mut self, value: Option<T>, f: F) -> &mut Self
-    where
-        F: FnOnce(T, &mut ClientRequestBuilder),
-    {
-        if let Some(val) = value {
-            f(val, self);
-        }
-        self
-    }
-
-    /// Set a body and generate `ClientRequest`.
-    ///
-    /// `ClientRequestBuilder` can not be used after this call.
-    pub fn body<B: MessageBody>(
-        &mut self,
-        body: B,
-    ) -> Result<ClientRequest<B>, HttpError> {
-        if let Some(e) = self.err.take() {
-            return Err(e);
-        }
-
-        if self.default_headers {
-            // enable br only for https
-            let https = if let Some(parts) = parts(&mut self.head, &self.err) {
-                parts
-                    .uri
-                    .scheme_part()
-                    .map(|s| s == &uri::Scheme::HTTPS)
-                    .unwrap_or(true)
-            } else {
-                true
-            };
-
-            if https {
-                self.set_header_if_none(header::ACCEPT_ENCODING, "br, gzip, deflate");
-            } else {
-                self.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate");
-            }
-
-            // set request host header
-            if let Some(parts) = parts(&mut self.head, &self.err) {
-                if let Some(host) = parts.uri.host() {
-                    if !parts.headers.contains_key(header::HOST) {
-                        let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
-
-                        let _ = match parts.uri.port_u16() {
-                            None | Some(80) | Some(443) => write!(wrt, "{}", host),
-                            Some(port) => write!(wrt, "{}:{}", host, port),
-                        };
-
-                        match wrt.get_mut().take().freeze().try_into() {
-                            Ok(value) => {
-                                parts.headers.insert(header::HOST, value);
-                            }
-                            Err(e) => self.err = Some(e.into()),
-                        }
-                    }
-                }
-            }
-
-            // user agent
-            self.set_header_if_none(
-                header::USER_AGENT,
-                concat!("actix-http/", env!("CARGO_PKG_VERSION")),
-            );
-        }
-
-        #[allow(unused_mut)]
-        let mut head = self.head.take().expect("cannot reuse request builder");
-
-        #[cfg(feature = "cookies")]
-        {
-            use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
-            use std::fmt::Write;
-
-            // set cookies
-            if let Some(ref mut jar) = self.cookies {
-                let mut cookie = String::new();
-                for c in jar.delta() {
-                    let name = percent_encode(c.name().as_bytes(), USERINFO_ENCODE_SET);
-                    let value =
-                        percent_encode(c.value().as_bytes(), USERINFO_ENCODE_SET);
-                    let _ = write!(&mut cookie, "; {}={}", name, value);
-                }
-                head.headers.insert(
-                    header::COOKIE,
-                    HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
-                );
-            }
-        }
-        Ok(ClientRequest { head, body })
-    }
-
-    /// Set a JSON body and generate `ClientRequest`
-    ///
-    /// `ClientRequestBuilder` can not be used after this call.
-    pub fn json<T: Serialize>(
-        &mut self,
-        value: T,
-    ) -> Result<ClientRequest<String>, Error> {
-        let body = serde_json::to_string(&value)?;
-
-        let contains = if let Some(head) = parts(&mut self.head, &self.err) {
-            head.headers.contains_key(header::CONTENT_TYPE)
-        } else {
-            true
-        };
-        if !contains {
-            self.header(header::CONTENT_TYPE, "application/json");
-        }
-
-        Ok(self.body(body)?)
-    }
-
-    /// Set a urlencoded body and generate `ClientRequest`
-    ///
-    /// `ClientRequestBuilder` can not be used after this call.
-    pub fn form<T: Serialize>(
-        &mut self,
-        value: T,
-    ) -> Result<ClientRequest<String>, Error> {
-        let body = serde_urlencoded::to_string(&value)?;
-
-        let contains = if let Some(head) = parts(&mut self.head, &self.err) {
-            head.headers.contains_key(header::CONTENT_TYPE)
-        } else {
-            true
-        };
-        if !contains {
-            self.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded");
-        }
-
-        Ok(self.body(body)?)
-    }
-
-    /// Set an streaming body and generate `ClientRequest`.
-    ///
-    /// `ClientRequestBuilder` can not be used after this call.
-    pub fn stream<S, E>(
-        &mut self,
-        stream: S,
-    ) -> Result<ClientRequest<impl MessageBody>, HttpError>
-    where
-        S: Stream<Item = Bytes, Error = E>,
-        E: Into<Error> + 'static,
-    {
-        self.body(BodyStream::new(stream))
-    }
-
-    /// Set an empty body and generate `ClientRequest`.
-    ///
-    /// `ClientRequestBuilder` can not be used after this call.
-    pub fn finish(&mut self) -> Result<ClientRequest<()>, HttpError> {
-        self.body(())
-    }
-
-    /// This method construct new `ClientRequestBuilder`
-    pub fn take(&mut self) -> ClientRequestBuilder {
-        ClientRequestBuilder {
-            head: self.head.take(),
-            err: self.err.take(),
-            #[cfg(feature = "cookies")]
-            cookies: self.cookies.take(),
-            default_headers: self.default_headers,
-        }
-    }
-}
-
-#[inline]
-fn parts<'a>(
-    parts: &'a mut Option<RequestHead>,
-    err: &Option<HttpError>,
-) -> Option<&'a mut RequestHead> {
-    if err.is_some() {
-        return None;
-    }
-    parts.as_mut()
-}
-
-impl fmt::Debug for ClientRequestBuilder {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if let Some(ref parts) = self.head {
-            writeln!(
-                f,
-                "\nClientRequestBuilder {:?} {}:{}",
-                parts.version, parts.method, parts.uri
-            )?;
-            writeln!(f, "  headers:")?;
-            for (key, val) in parts.headers.iter() {
-                writeln!(f, "    {:?}: {:?}", key, val)?;
-            }
-            Ok(())
-        } else {
-            write!(f, "ClientRequestBuilder(Consumed)")
-        }
-    }
-}
diff --git a/src/client/response.rs b/src/client/response.rs
deleted file mode 100644
index 7c6cdf643..000000000
--- a/src/client/response.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-use std::cell::{Ref, RefMut};
-use std::fmt;
-
-use bytes::Bytes;
-use futures::{Poll, Stream};
-use http::{HeaderMap, StatusCode, Version};
-
-use crate::error::PayloadError;
-use crate::extensions::Extensions;
-use crate::httpmessage::HttpMessage;
-use crate::message::{Head, Message, ResponseHead};
-use crate::payload::{Payload, PayloadStream};
-
-/// Client Response
-pub struct ClientResponse {
-    pub(crate) head: Message<ResponseHead>,
-    pub(crate) payload: Payload,
-}
-
-impl HttpMessage for ClientResponse {
-    type Stream = PayloadStream;
-
-    fn headers(&self) -> &HeaderMap {
-        &self.head.headers
-    }
-
-    fn extensions(&self) -> Ref<Extensions> {
-        self.head.extensions()
-    }
-
-    fn extensions_mut(&self) -> RefMut<Extensions> {
-        self.head.extensions_mut()
-    }
-
-    fn take_payload(&mut self) -> Payload {
-        std::mem::replace(&mut self.payload, Payload::None)
-    }
-}
-
-impl ClientResponse {
-    /// Create new Request instance
-    pub fn new() -> ClientResponse {
-        let head: Message<ResponseHead> = Message::new();
-        head.extensions_mut().clear();
-
-        ClientResponse {
-            head,
-            payload: Payload::None,
-        }
-    }
-
-    #[inline]
-    pub(crate) fn head(&self) -> &ResponseHead {
-        &self.head
-    }
-
-    #[inline]
-    pub(crate) fn head_mut(&mut self) -> &mut ResponseHead {
-        &mut self.head
-    }
-
-    /// Read the Request Version.
-    #[inline]
-    pub fn version(&self) -> Version {
-        self.head().version
-    }
-
-    /// Get the status from the server.
-    #[inline]
-    pub fn status(&self) -> StatusCode {
-        self.head().status
-    }
-
-    #[inline]
-    /// Returns Request's headers.
-    pub fn headers(&self) -> &HeaderMap {
-        &self.head().headers
-    }
-
-    #[inline]
-    /// Returns mutable Request's headers.
-    pub fn headers_mut(&mut self) -> &mut HeaderMap {
-        &mut self.head_mut().headers
-    }
-
-    /// Checks if a connection should be kept alive.
-    #[inline]
-    pub fn keep_alive(&self) -> bool {
-        self.head().keep_alive()
-    }
-
-    /// Set response payload
-    pub fn set_payload(&mut self, payload: Payload) {
-        self.payload = payload;
-    }
-}
-
-impl Stream for ClientResponse {
-    type Item = Bytes;
-    type Error = PayloadError;
-
-    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
-        self.payload.poll()
-    }
-}
-
-impl fmt::Debug for ClientResponse {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?;
-        writeln!(f, "  headers:")?;
-        for (key, val) in self.headers().iter() {
-            writeln!(f, "    {:?}: {:?}", key, val)?;
-        }
-        Ok(())
-    }
-}
diff --git a/src/h1/client.rs b/src/h1/client.rs
index 851851266..b3a5a5d9f 100644
--- a/src/h1/client.rs
+++ b/src/h1/client.rs
@@ -13,11 +13,10 @@ use super::decoder::{PayloadDecoder, PayloadItem, PayloadType};
 use super::{decoder, encoder};
 use super::{Message, MessageType};
 use crate::body::BodyLength;
-use crate::client::ClientResponse;
 use crate::config::ServiceConfig;
 use crate::error::{ParseError, PayloadError};
 use crate::helpers;
-use crate::message::{ConnectionType, Head, MessagePool, RequestHead};
+use crate::message::{ConnectionType, Head, MessagePool, RequestHead, ResponseHead};
 
 bitflags! {
     struct Flags: u8 {
@@ -41,7 +40,7 @@ pub struct ClientPayloadCodec {
 
 struct ClientCodecInner {
     config: ServiceConfig,
-    decoder: decoder::MessageDecoder<ClientResponse>,
+    decoder: decoder::MessageDecoder<ResponseHead>,
     payload: Option<PayloadDecoder>,
     version: Version,
     ctype: ConnectionType,
@@ -123,14 +122,14 @@ impl ClientPayloadCodec {
 }
 
 impl Decoder for ClientCodec {
-    type Item = ClientResponse;
+    type Item = ResponseHead;
     type Error = ParseError;
 
     fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
         debug_assert!(!self.inner.payload.is_some(), "Payload decoder is set");
 
         if let Some((req, payload)) = self.inner.decoder.decode(src)? {
-            if let Some(ctype) = req.head().ctype {
+            if let Some(ctype) = req.ctype {
                 // do not use peer's keep-alive
                 self.inner.ctype = if ctype == ConnectionType::KeepAlive {
                     self.inner.ctype
diff --git a/src/h1/decoder.rs b/src/h1/decoder.rs
index 77b76c242..a1b221c06 100644
--- a/src/h1/decoder.rs
+++ b/src/h1/decoder.rs
@@ -9,9 +9,8 @@ use http::{header, HeaderMap, HttpTryFrom, Method, StatusCode, Uri, Version};
 use httparse;
 use log::{debug, error, trace};
 
-use crate::client::ClientResponse;
 use crate::error::ParseError;
-use crate::message::ConnectionType;
+use crate::message::{ConnectionType, ResponseHead};
 use crate::request::Request;
 
 const MAX_BUFFER_SIZE: usize = 131_072;
@@ -227,13 +226,13 @@ impl MessageType for Request {
     }
 }
 
-impl MessageType for ClientResponse {
+impl MessageType for ResponseHead {
     fn set_connection_type(&mut self, ctype: Option<ConnectionType>) {
-        self.head.ctype = ctype;
+        self.ctype = ctype;
     }
 
     fn headers_mut(&mut self) -> &mut HeaderMap {
-        self.headers_mut()
+        &mut self.headers
     }
 
     fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError> {
@@ -263,7 +262,7 @@ impl MessageType for ClientResponse {
             }
         };
 
-        let mut msg = ClientResponse::new();
+        let mut msg = ResponseHead::default();
 
         // convert headers
         let len = msg.set_headers(&src.split_to(len).freeze(), &headers[..h_len])?;
@@ -281,8 +280,8 @@ impl MessageType for ClientResponse {
             PayloadType::None
         };
 
-        msg.head.status = status;
-        msg.head.version = ver;
+        msg.status = status;
+        msg.version = ver;
 
         Ok(Some((msg, decoder)))
     }
diff --git a/src/h1/dispatcher.rs b/src/h1/dispatcher.rs
index afeabc825..09a17fcf7 100644
--- a/src/h1/dispatcher.rs
+++ b/src/h1/dispatcher.rs
@@ -553,7 +553,7 @@ mod tests {
 
     use actix_codec::{AsyncRead, AsyncWrite};
     use actix_service::IntoService;
-    use bytes::{Buf, Bytes, BytesMut};
+    use bytes::{Buf, Bytes};
     use futures::future::{lazy, ok};
 
     use super::*;
diff --git a/src/lib.rs b/src/lib.rs
index 85efe5e44..b41ce7ae8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,64 +1,4 @@
-//! Actix web is a small, pragmatic, and extremely fast web framework
-//! for Rust.
-//!
-//! ```rust,ignore
-//! use actix_web::{server, App, Path, Responder};
-//! # use std::thread;
-//!
-//! fn index(info: Path<(String, u32)>) -> impl Responder {
-//!     format!("Hello {}! id:{}", info.0, info.1)
-//! }
-//!
-//! fn main() {
-//!     # thread::spawn(|| {
-//!     server::new(|| {
-//!         App::new().resource("/{name}/{id}/index.html", |r| r.with(index))
-//!     }).bind("127.0.0.1:8080")
-//!         .unwrap()
-//!         .run();
-//!     # });
-//! }
-//! ```
-//!
-//! ## Documentation & community resources
-//!
-//! Besides the API documentation (which you are currently looking
-//! at!), several other resources are available:
-//!
-//! * [User Guide](https://actix.rs/docs/)
-//! * [Chat on gitter](https://gitter.im/actix/actix)
-//! * [GitHub repository](https://github.com/actix/actix-web)
-//! * [Cargo package](https://crates.io/crates/actix-web)
-//!
-//! To get started navigating the API documentation you may want to
-//! consider looking at the following pages:
-//!
-//! * [App](struct.App.html): This struct represents an actix-web
-//!   application and is used to configure routes and other common
-//!   settings.
-//!
-//! * [HttpServer](server/struct.HttpServer.html): This struct
-//!   represents an HTTP server instance and is used to instantiate and
-//!   configure servers.
-//!
-//! * [Request](struct.Request.html) and
-//!   [Response](struct.Response.html): These structs
-//!   represent HTTP requests and responses and expose various methods
-//!   for inspecting, creating and otherwise utilizing them.
-//!
-//! ## Features
-//!
-//! * Supported *HTTP/1.x* protocol
-//! * Streaming and pipelining
-//! * Keep-alive and slow requests handling
-//! * `WebSockets` server/client
-//! * Supported Rust version: 1.26 or later
-//!
-//! ## Package feature
-//!
-//! * `session` - enables session support, includes `ring` crate as
-//!   dependency
-//!
+//! Basic http primitives for actix-net framework.
 #![allow(
     clippy::type_complexity,
     clippy::new_without_default,
diff --git a/src/response.rs b/src/response.rs
index 5281c2d95..31c0010ab 100644
--- a/src/response.rs
+++ b/src/response.rs
@@ -1042,8 +1042,6 @@ mod tests {
     #[test]
     #[cfg(feature = "cookies")]
     fn test_into_builder() {
-        use crate::httpmessage::HttpMessage;
-
         let mut resp: Response = "test".into();
         assert_eq!(resp.status(), StatusCode::OK);
 
diff --git a/src/ws/client/connect.rs b/src/ws/client/connect.rs
index 5e877a645..2760967e0 100644
--- a/src/ws/client/connect.rs
+++ b/src/ws/client/connect.rs
@@ -4,15 +4,15 @@ use std::str;
 #[cfg(feature = "cookies")]
 use cookie::Cookie;
 use http::header::{HeaderName, HeaderValue};
-use http::{Error as HttpError, HttpTryFrom};
+use http::{Error as HttpError, HttpTryFrom, Uri};
 
 use super::ClientError;
-use crate::client::{ClientRequest, ClientRequestBuilder};
 use crate::header::IntoHeaderValue;
+use crate::message::RequestHead;
 
 /// `WebSocket` connection
 pub struct Connect {
-    pub(super) request: ClientRequestBuilder,
+    pub(super) head: RequestHead,
     pub(super) err: Option<ClientError>,
     pub(super) http_err: Option<HttpError>,
     pub(super) origin: Option<HeaderValue>,
@@ -25,7 +25,7 @@ impl Connect {
     /// Create new websocket connection
     pub fn new<S: AsRef<str>>(uri: S) -> Connect {
         let mut cl = Connect {
-            request: ClientRequest::build(),
+            head: RequestHead::default(),
             err: None,
             http_err: None,
             origin: None,
@@ -33,7 +33,12 @@ impl Connect {
             max_size: 65_536,
             server_mode: false,
         };
-        cl.request.uri(uri.as_ref());
+
+        match Uri::try_from(uri.as_ref()) {
+            Ok(uri) => cl.head.uri = uri,
+            Err(e) => cl.http_err = Some(e.into()),
+        }
+
         cl
     }
 
@@ -51,12 +56,12 @@ impl Connect {
         self
     }
 
-    #[cfg(feature = "cookies")]
-    /// Set cookie for handshake request
-    pub fn cookie(mut self, cookie: Cookie) -> Self {
-        self.request.cookie(cookie);
-        self
-    }
+    // #[cfg(feature = "cookies")]
+    // /// Set cookie for handshake request
+    // pub fn cookie(mut self, cookie: Cookie) -> Self {
+    //    self.request.cookie(cookie);
+    //    self
+    // }
 
     /// Set request Origin
     pub fn origin<V>(mut self, origin: V) -> Self
@@ -90,7 +95,15 @@ impl Connect {
         HeaderName: HttpTryFrom<K>,
         V: IntoHeaderValue,
     {
-        self.request.header(key, value);
+        match HeaderName::try_from(key) {
+            Ok(key) => match value.try_into() {
+                Ok(value) => {
+                    self.head.headers.append(key, value);
+                }
+                Err(e) => self.http_err = Some(e.into()),
+            },
+            Err(e) => self.http_err = Some(e.into()),
+        }
         self
     }
 }
diff --git a/src/ws/client/service.rs b/src/ws/client/service.rs
index a0a9b2030..8a0840f90 100644
--- a/src/ws/client/service.rs
+++ b/src/ws/client/service.rs
@@ -14,8 +14,8 @@ use rand;
 use sha1::Sha1;
 
 use crate::body::BodyLength;
-use crate::client::ClientResponse;
 use crate::h1;
+use crate::message::{ConnectionType, Head, ResponseHead};
 use crate::ws::Codec;
 
 use super::{ClientError, Connect, Protocol};
@@ -89,27 +89,35 @@ where
         } else {
             // origin
             if let Some(origin) = req.origin.take() {
-                req.request.set_header(header::ORIGIN, origin);
+                req.head.headers.insert(header::ORIGIN, origin);
             }
 
-            req.request.upgrade("websocket");
-            req.request.set_header(header::SEC_WEBSOCKET_VERSION, "13");
+            req.head.set_connection_type(ConnectionType::Upgrade);
+            req.head
+                .headers
+                .insert(header::UPGRADE, HeaderValue::from_static("websocket"));
+            req.head.headers.insert(
+                header::SEC_WEBSOCKET_VERSION,
+                HeaderValue::from_static("13"),
+            );
 
             if let Some(protocols) = req.protocols.take() {
-                req.request
-                    .set_header(header::SEC_WEBSOCKET_PROTOCOL, protocols.as_str());
+                req.head.headers.insert(
+                    header::SEC_WEBSOCKET_PROTOCOL,
+                    HeaderValue::try_from(protocols.as_str()).unwrap(),
+                );
             }
-            let mut request = match req.request.finish() {
-                Ok(req) => req,
-                Err(e) => return Either::A(err(e.into())),
+            if let Some(e) = req.http_err {
+                return Either::A(err(e.into()));
             };
 
-            if request.uri().host().is_none() {
+            let mut request = req.head;
+            if request.uri.host().is_none() {
                 return Either::A(err(ClientError::InvalidUrl));
             }
 
             // supported protocols
-            let proto = if let Some(scheme) = request.uri().scheme_part() {
+            let proto = if let Some(scheme) = request.uri.scheme_part() {
                 match Protocol::from(scheme.as_str()) {
                     Some(proto) => proto,
                     None => return Either::A(err(ClientError::InvalidUrl)),
@@ -124,14 +132,14 @@ where
             let sec_key: [u8; 16] = rand::random();
             let key = base64::encode(&sec_key);
 
-            request.headers_mut().insert(
+            request.headers.insert(
                 header::SEC_WEBSOCKET_KEY,
                 HeaderValue::try_from(key.as_str()).unwrap(),
             );
 
             // prep connection
-            let connect = TcpConnect::new(request.uri().host().unwrap().to_string())
-                .set_port(request.uri().port_u16().unwrap_or_else(|| proto.port()));
+            let connect = TcpConnect::new(request.uri.host().unwrap().to_string())
+                .set_port(request.uri.port_u16().unwrap_or_else(|| proto.port()));
 
             let fut = Box::new(
                 self.connector
@@ -141,7 +149,7 @@ where
                         // h1 protocol
                         let framed = Framed::new(io, h1::ClientCodec::default());
                         framed
-                            .send((request.into_parts().0, BodyLength::None).into())
+                            .send((request, BodyLength::None).into())
                             .map_err(ClientError::from)
                             .and_then(|framed| {
                                 framed
@@ -172,7 +180,7 @@ where
 {
     fut: Box<
         Future<
-            Item = (Option<ClientResponse>, Framed<T, h1::ClientCodec>),
+            Item = (Option<ResponseHead>, Framed<T, h1::ClientCodec>),
             Error = ClientError,
         >,
     >,
@@ -198,11 +206,11 @@ where
         };
 
         // verify response
-        if res.status() != StatusCode::SWITCHING_PROTOCOLS {
-            return Err(ClientError::InvalidResponseStatus(res.status()));
+        if res.status != StatusCode::SWITCHING_PROTOCOLS {
+            return Err(ClientError::InvalidResponseStatus(res.status));
         }
         // Check for "UPGRADE" to websocket header
-        let has_hdr = if let Some(hdr) = res.headers().get(header::UPGRADE) {
+        let has_hdr = if let Some(hdr) = res.headers.get(header::UPGRADE) {
             if let Ok(s) = hdr.to_str() {
                 s.to_lowercase().contains("websocket")
             } else {
@@ -216,7 +224,7 @@ where
             return Err(ClientError::InvalidUpgradeHeader);
         }
         // Check for "CONNECTION" header
-        if let Some(conn) = res.headers().get(header::CONNECTION) {
+        if let Some(conn) = res.headers.get(header::CONNECTION) {
             if let Ok(s) = conn.to_str() {
                 if !s.to_lowercase().contains("upgrade") {
                     trace!("Invalid connection header: {}", s);
@@ -231,7 +239,7 @@ where
             return Err(ClientError::MissingConnectionHeader);
         }
 
-        if let Some(key) = res.headers().get(header::SEC_WEBSOCKET_ACCEPT) {
+        if let Some(key) = res.headers.get(header::SEC_WEBSOCKET_ACCEPT) {
             // field is constructed by concatenating /key/
             // with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
             const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml
index b7535f99c..313bc55cf 100644
--- a/test-server/Cargo.toml
+++ b/test-server/Cargo.toml
@@ -29,7 +29,7 @@ default = ["session"]
 session = ["cookie/secure"]
 
 # openssl
-ssl = ["openssl", "actix-http/ssl", "actix-server/ssl"]
+ssl = ["openssl", "actix-http/ssl", "actix-server/ssl", "awc/ssl"]
 
 [dependencies]
 actix-codec = "0.1.1"
@@ -38,6 +38,7 @@ actix-http = { path=".." }
 actix-service = "0.3.4"
 actix-server = "0.4.0"
 actix-utils = "0.3.4"
+awc = { git = "https://github.com/actix/actix-web.git" }
 
 base64 = "0.10"
 bytes = "0.4"
diff --git a/test-server/src/lib.rs b/test-server/src/lib.rs
index 26bca787e..77329e700 100644
--- a/test-server/src/lib.rs
+++ b/test-server/src/lib.rs
@@ -3,15 +3,12 @@ use std::sync::mpsc;
 use std::{net, thread, time};
 
 use actix_codec::{AsyncRead, AsyncWrite, Framed};
-use actix_http::body::MessageBody;
-use actix_http::client::{
-    ClientRequest, ClientRequestBuilder, ClientResponse, ConnectError, Connection,
-    Connector, SendRequestError,
-};
-use actix_http::{http::Uri, ws};
+use actix_http::client::Connector;
+use actix_http::ws;
 use actix_rt::{Runtime, System};
 use actix_server::{Server, StreamServiceFactory};
 use actix_service::Service;
+use awc::{Client, ClientRequest};
 use futures::future::{lazy, Future};
 use http::Method;
 use net2::TcpBuilder;
@@ -47,6 +44,7 @@ pub struct TestServer;
 pub struct TestServerRuntime {
     addr: net::SocketAddr,
     rt: Runtime,
+    client: Client,
 }
 
 impl TestServer {
@@ -71,11 +69,39 @@ impl TestServer {
         });
 
         let (system, addr) = rx.recv().unwrap();
+        let mut rt = Runtime::new().unwrap();
+
+        let client = rt
+            .block_on(lazy(move || {
+                let connector = {
+                    #[cfg(feature = "ssl")]
+                    {
+                        use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
+
+                        let mut builder =
+                            SslConnector::builder(SslMethod::tls()).unwrap();
+                        builder.set_verify(SslVerifyMode::NONE);
+                        let _ = builder.set_alpn_protos(b"\x02h2\x08http/1.1").map_err(
+                            |e| log::error!("Can not set alpn protocol: {:?}", e),
+                        );
+                        Connector::new()
+                            .timeout(time::Duration::from_millis(500))
+                            .ssl(builder.build())
+                            .service()
+                    }
+                    #[cfg(not(feature = "ssl"))]
+                    {
+                        Connector::new()
+                            .timeout(time::Duration::from_millis(500))
+                            .service()
+                    }
+                };
+
+                Ok::<Client, ()>(Client::build().connector(connector).finish())
+            }))
+            .unwrap();
         System::set_current(system);
-        TestServerRuntime {
-            addr,
-            rt: Runtime::new().unwrap(),
-        }
+        TestServerRuntime { addr, rt, client }
     }
 
     /// Get firat available unused address
@@ -130,64 +156,38 @@ impl TestServerRuntime {
     }
 
     /// Create `GET` request
-    pub fn get(&self) -> ClientRequestBuilder {
-        ClientRequest::get(self.url("/").as_str())
+    pub fn get(&self) -> ClientRequest {
+        self.client.get(self.url("/").as_str())
     }
 
     /// Create https `GET` request
-    pub fn sget(&self) -> ClientRequestBuilder {
-        ClientRequest::get(self.surl("/").as_str())
+    pub fn sget(&self) -> ClientRequest {
+        self.client.get(self.surl("/").as_str())
     }
 
     /// Create `POST` request
-    pub fn post(&self) -> ClientRequestBuilder {
-        ClientRequest::post(self.url("/").as_str())
+    pub fn post(&self) -> ClientRequest {
+        self.client.post(self.url("/").as_str())
+    }
+
+    /// Create https `POST` request
+    pub fn spost(&self) -> ClientRequest {
+        self.client.post(self.surl("/").as_str())
     }
 
     /// Create `HEAD` request
-    pub fn head(&self) -> ClientRequestBuilder {
-        ClientRequest::head(self.url("/").as_str())
+    pub fn head(&self) -> ClientRequest {
+        self.client.head(self.url("/").as_str())
+    }
+
+    /// Create https `HEAD` request
+    pub fn shead(&self) -> ClientRequest {
+        self.client.head(self.surl("/").as_str())
     }
 
     /// Connect to test http server
-    pub fn client(&self, meth: Method, path: &str) -> ClientRequestBuilder {
-        ClientRequest::build()
-            .method(meth)
-            .uri(self.url(path).as_str())
-            .take()
-    }
-
-    fn new_connector(
-    ) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
-    {
-        #[cfg(feature = "ssl")]
-        {
-            use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
-
-            let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
-            builder.set_verify(SslVerifyMode::NONE);
-            let _ = builder
-                .set_alpn_protos(b"\x02h2\x08http/1.1")
-                .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
-            Connector::new()
-                .timeout(time::Duration::from_millis(500))
-                .ssl(builder.build())
-                .service()
-        }
-        #[cfg(not(feature = "ssl"))]
-        {
-            Connector::new()
-                .timeout(time::Duration::from_millis(500))
-                .service()
-        }
-    }
-
-    /// Http connector
-    pub fn connector(
-        &mut self,
-    ) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
-    {
-        self.execute(|| TestServerRuntime::new_connector())
+    pub fn request<S: AsRef<str>>(&self, method: Method, path: S) -> ClientRequest {
+        self.client.request(method, path.as_ref())
     }
 
     /// Stop http server
@@ -213,15 +213,6 @@ impl TestServerRuntime {
     ) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, ws::ClientError> {
         self.ws_at("/")
     }
-
-    /// Send request and read response message
-    pub fn send_request<B: MessageBody + 'static>(
-        &mut self,
-        req: ClientRequest<B>,
-    ) -> Result<ClientResponse, SendRequestError> {
-        let mut conn = self.connector();
-        self.rt.block_on(req.send(&mut conn))
-    }
 }
 
 impl Drop for TestServerRuntime {
diff --git a/tests/test_client.rs b/tests/test_client.rs
index 2832b1b70..1ca7437d6 100644
--- a/tests/test_client.rs
+++ b/tests/test_client.rs
@@ -4,7 +4,7 @@ use futures::future::{self, ok};
 use futures::{Future, Stream};
 
 use actix_http::{
-    client, error::PayloadError, HttpMessage, HttpService, Request, Response,
+    error::PayloadError, http, HttpMessage, HttpService, Request, Response,
 };
 use actix_http_test::TestServer;
 
@@ -48,26 +48,18 @@ fn test_h1_v2() {
             .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
             .map(|_| ())
     });
-    let mut connector = srv.connector();
-
-    let request = srv.get().finish().unwrap();
-    let response = srv.block_on(request.send(&mut connector)).unwrap();
+    let response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 
-    let request = srv.get().header("x-test", "111").finish().unwrap();
-    let repr = format!("{:?}", request);
-    assert!(repr.contains("ClientRequest"));
-    assert!(repr.contains("x-test"));
-
-    let mut response = srv.block_on(request.send(&mut connector)).unwrap();
+    let request = srv.get().header("x-test", "111").send();
+    let mut response = srv.block_on(request).unwrap();
     assert!(response.status().is_success());
 
     // read response
     let bytes = srv.block_on(load_body(response.take_payload())).unwrap();
     assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
 
-    let request = srv.post().finish().unwrap();
-    let mut response = srv.block_on(request.send(&mut connector)).unwrap();
+    let mut response = srv.block_on(srv.post().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -82,10 +74,7 @@ fn test_connection_close() {
             .finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
             .map(|_| ())
     });
-    let mut connector = srv.connector();
-
-    let request = srv.get().close().finish().unwrap();
-    let response = srv.block_on(request.send(&mut connector)).unwrap();
+    let response = srv.block_on(srv.get().close_connection().send()).unwrap();
     assert!(response.status().is_success());
 }
 
@@ -102,12 +91,8 @@ fn test_with_query_parameter() {
             })
             .map(|_| ())
     });
-    let mut connector = srv.connector();
 
-    let request = client::ClientRequest::get(srv.url("/?qp=5"))
-        .finish()
-        .unwrap();
-
-    let response = srv.block_on(request.send(&mut connector)).unwrap();
+    let request = srv.request(http::Method::GET, srv.url("/?qp=5")).send();
+    let response = srv.block_on(request).unwrap();
     assert!(response.status().is_success());
 }
diff --git a/tests/test_server.rs b/tests/test_server.rs
index 8a7316cdf..5777c5691 100644
--- a/tests/test_server.rs
+++ b/tests/test_server.rs
@@ -13,8 +13,8 @@ use futures::stream::{once, Stream};
 use actix_http::body::Body;
 use actix_http::error::PayloadError;
 use actix_http::{
-    body, client, error, http, http::header, Error, HttpMessage as HttpMessage2,
-    HttpService, KeepAlive, Request, Response,
+    body, error, http, http::header, Error, HttpMessage as HttpMessage2, HttpService,
+    KeepAlive, Request, Response,
 };
 
 fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
@@ -37,8 +37,7 @@ fn test_h1() {
             .h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
     });
 
-    let req = client::ClientRequest::get(srv.url("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 }
 
@@ -56,8 +55,7 @@ fn test_h1_2() {
             .map(|_| ())
     });
 
-    let req = client::ClientRequest::get(srv.url("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 }
 
@@ -100,8 +98,7 @@ fn test_h2() -> std::io::Result<()> {
             )
     });
 
-    let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
     Ok(())
 }
@@ -124,8 +121,7 @@ fn test_h2_1() -> std::io::Result<()> {
             )
     });
 
-    let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
     Ok(())
 }
@@ -149,10 +145,7 @@ fn test_h2_body() -> std::io::Result<()> {
             )
     });
 
-    let req = client::ClientRequest::get(srv.surl("/"))
-        .body(data.clone())
-        .unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send_body(data.clone())).unwrap();
     assert!(response.status().is_success());
 
     let body = srv.block_on(load_body(response.take_payload())).unwrap();
@@ -331,24 +324,24 @@ fn test_content_length() {
 
     {
         for i in 0..4 {
-            let req = client::ClientRequest::get(srv.url(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::GET, srv.url(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), None);
 
-            let req = client::ClientRequest::head(srv.url(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::HEAD, srv.url(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), None);
         }
 
         for i in 4..6 {
-            let req = client::ClientRequest::get(srv.url(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::GET, srv.url(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), Some(&value));
         }
     }
@@ -389,24 +382,24 @@ fn test_h2_content_length() {
 
     {
         for i in 0..4 {
-            let req = client::ClientRequest::get(srv.surl(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::GET, srv.surl(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), None);
 
-            let req = client::ClientRequest::head(srv.surl(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::HEAD, srv.surl(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), None);
         }
 
         for i in 4..6 {
-            let req = client::ClientRequest::get(srv.surl(&format!("/{}", i)))
-                .finish()
-                .unwrap();
-            let response = srv.send_request(req).unwrap();
+            let req = srv
+                .request(http::Method::GET, srv.surl(&format!("/{}", i)))
+                .send();
+            let response = srv.block_on(req).unwrap();
             assert_eq!(response.headers().get(&header), Some(&value));
         }
     }
@@ -442,11 +435,8 @@ fn test_h1_headers() {
             future::ok::<_, ()>(builder.body(data.clone()))
         })
     });
-    let mut connector = srv.connector();
 
-    let req = srv.get().finish().unwrap();
-
-    let mut response = srv.block_on(req.send(&mut connector)).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -489,10 +479,8 @@ fn test_h2_headers() {
             future::ok::<_, ()>(builder.body(data.clone()))
         }).map_err(|_| ()))
     });
-    let mut connector = srv.connector();
 
-    let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap();
-    let mut response = srv.block_on(req.send(&mut connector)).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -528,8 +516,7 @@ fn test_h1_body() {
         HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -551,8 +538,7 @@ fn test_h2_body2() {
             )
     });
 
-    let req = srv.sget().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -566,8 +552,7 @@ fn test_h1_head_empty() {
         HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR)))
     });
 
-    let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.head().send()).unwrap();
     assert!(response.status().is_success());
 
     {
@@ -597,8 +582,7 @@ fn test_h2_head_empty() {
             )
     });
 
-    let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.shead().send()).unwrap();
     assert!(response.status().is_success());
     assert_eq!(response.version(), http::Version::HTTP_2);
 
@@ -623,8 +607,7 @@ fn test_h1_head_binary() {
         })
     });
 
-    let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.head().send()).unwrap();
     assert!(response.status().is_success());
 
     {
@@ -658,8 +641,7 @@ fn test_h2_head_binary() {
             )
     });
 
-    let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.shead().send()).unwrap();
     assert!(response.status().is_success());
 
     {
@@ -681,8 +663,7 @@ fn test_h1_head_binary2() {
         HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR)))
     });
 
-    let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.head().send()).unwrap();
     assert!(response.status().is_success());
 
     {
@@ -708,8 +689,7 @@ fn test_h2_head_binary2() {
             )
     });
 
-    let req = client::ClientRequest::head(srv.surl("/")).finish().unwrap();
-    let response = srv.send_request(req).unwrap();
+    let response = srv.block_on(srv.shead().send()).unwrap();
     assert!(response.status().is_success());
 
     {
@@ -733,8 +713,7 @@ fn test_h1_body_length() {
         })
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -761,8 +740,7 @@ fn test_h2_body_length() {
             )
     });
 
-    let req = srv.sget().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
 
     // read response
@@ -783,8 +761,7 @@ fn test_h1_body_chunked_explicit() {
         })
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
     assert_eq!(
         response
@@ -825,8 +802,7 @@ fn test_h2_body_chunked_explicit() {
             )
     });
 
-    let req = srv.sget().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert!(response.status().is_success());
     assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
 
@@ -846,8 +822,7 @@ fn test_h1_body_chunked_implicit() {
         })
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert!(response.status().is_success());
     assert_eq!(
         response
@@ -879,8 +854,7 @@ fn test_h1_response_http_error_handling() {
         }))
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
 
     // read response
@@ -912,8 +886,7 @@ fn test_h2_response_http_error_handling() {
             )
     });
 
-    let req = srv.sget().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
 
     // read response
@@ -928,8 +901,7 @@ fn test_h1_service_error() {
             .h1(|_| Err::<Response, Error>(error::ErrorBadRequest("error")))
     });
 
-    let req = srv.get().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.get().send()).unwrap();
     assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
 
     // read response
@@ -952,8 +924,7 @@ fn test_h2_service_error() {
             )
     });
 
-    let req = srv.sget().finish().unwrap();
-    let mut response = srv.send_request(req).unwrap();
+    let mut response = srv.block_on(srv.sget().send()).unwrap();
     assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
 
     // read response