Repository: seanmonstar/reqwest (language: rust)

Issue:
Make the async Client the default
With async/await maturing, it's probably time to start shifting some defaults around. Until now, there has been `reqwest::async::Client` and a blocking `reqwest::Client`. This issue proposes to move the async client to `reqwest::Client`, and the blocking client to `reqwest::blocking::Client`.


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 6d4c33308..d20bcb190 100644
--- a/README.md
+++ b/README.md
@@ -20,13 +20,29 @@ preparing breaking changes, for most recently released code, look to the
 
 ## Example
 
+Async:
+
 ```rust,no_run
-extern crate reqwest;
+use std::collections::HashMap;
 
+#[tokio::main]
+async fn main() -> Result<(), Box<std::error::Error>> {
+    let resp: HashMap<String, String> = reqwest::get("https://httpbin.org/ip")
+        .await?
+        .json()
+        .await?;
+    println!("{:#?}", resp);
+    Ok(())
+}
+```
+
+Blocking:
+
+```rust,no_run
 use std::collections::HashMap;
 
 fn main() -> Result<(), Box<std::error::Error>> {
-    let resp: HashMap<String, String> = reqwest::get("https://httpbin.org/ip")?
+    let resp: HashMap<String, String> = reqwest::blocking::get("https://httpbin.org/ip")?
         .json()?;
     println!("{:#?}", resp);
     Ok(())
diff --git a/examples/async.rs b/examples/async.rs
deleted file mode 100644
index c4dad41ab..000000000
--- a/examples/async.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![deny(warnings)]
-
-use reqwest::r#async::Client;
-
-#[tokio::main]
-async fn main() -> Result<(), reqwest::Error> {
-    let mut res = Client::new().get("https://hyper.rs").send().await?;
-
-    println!("Status: {}", res.status());
-
-    let body = res.text().await?;
-
-    println!("Body:\n\n{}", body);
-
-    Ok(())
-}
diff --git a/examples/async_multiple_requests.rs b/examples/async_multiple_requests.rs
deleted file mode 100644
index d52a60fe6..000000000
--- a/examples/async_multiple_requests.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-#![deny(warnings)]
-
-use reqwest::r#async::{Client, Response};
-use serde::Deserialize;
-use std::future::Future;
-
-#[derive(Deserialize, Debug)]
-struct Slideshow {
-    title: String,
-    author: String,
-}
-
-#[derive(Deserialize, Debug)]
-struct SlideshowContainer {
-    slideshow: Slideshow,
-}
-
-async fn into_json<F>(f: F) -> Result<SlideshowContainer, reqwest::Error>
-where
-    F: Future<Output = Result<Response, reqwest::Error>>,
-{
-    let mut resp = f.await?;
-    resp.json::<SlideshowContainer>().await
-}
-
-#[tokio::main]
-async fn main() -> Result<(), reqwest::Error> {
-    let client = Client::new();
-
-    let request1 = client.get("https://httpbin.org/json").send();
-
-    let request2 = client.get("https://httpbin.org/json").send();
-
-    let (try_json1, try_json2) =
-        futures::future::join(into_json(request1), into_json(request2)).await;
-
-    println!("{:?}", try_json1?);
-    println!("{:?}", try_json2?);
-
-    Ok(())
-}
diff --git a/examples/blocking.rs b/examples/blocking.rs
new file mode 100644
index 000000000..32ecabe59
--- /dev/null
+++ b/examples/blocking.rs
@@ -0,0 +1,19 @@
+//! `cargo run --example blocking`
+#![deny(warnings)]
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    env_logger::init();
+
+    println!("GET https://www.rust-lang.org");
+
+    let mut res = reqwest::blocking::get("https://www.rust-lang.org/")?;
+
+    println!("Status: {}", res.status());
+    println!("Headers:\n{:?}", res.headers());
+
+    // copy the response body directly to stdout
+    res.copy_to(&mut std::io::stdout())?;
+
+    println!("\n\nDone.");
+    Ok(())
+}
diff --git a/examples/form.rs b/examples/form.rs
index 7c8d0591f..cfdb6e4e8 100644
--- a/examples/form.rs
+++ b/examples/form.rs
@@ -1,7 +1,9 @@
-fn main() {
+#[tokio::main]
+async fn main() {
     reqwest::Client::new()
         .post("http://www.baidu.com")
         .form(&[("one", "1")])
         .send()
+        .await
         .unwrap();
 }
diff --git a/examples/json_dynamic.rs b/examples/json_dynamic.rs
index 1a31f6191..5673420fe 100644
--- a/examples/json_dynamic.rs
+++ b/examples/json_dynamic.rs
@@ -4,7 +4,8 @@
 //! really care about the structure of the JSON and just need to display it or
 //! process it at runtime.
 
-fn main() -> Result<(), reqwest::Error> {
+#[tokio::main]
+async fn main() -> Result<(), reqwest::Error> {
     let echo_json: serde_json::Value = reqwest::Client::new()
         .post("https://jsonplaceholder.typicode.com/posts")
         .json(&serde_json::json!({
@@ -12,8 +13,10 @@ fn main() -> Result<(), reqwest::Error> {
             "body": "https://docs.rs/reqwest",
             "userId": 1
         }))
-        .send()?
-        .json()?;
+        .send()
+        .await?
+        .json()
+        .await?;
 
     println!("{:#?}", echo_json);
     // Object(
diff --git a/examples/json_typed.rs b/examples/json_typed.rs
index 1cbd2180b..16a329fbe 100644
--- a/examples/json_typed.rs
+++ b/examples/json_typed.rs
@@ -15,7 +15,8 @@ struct Post {
     user_id: i32,
 }
 
-fn main() -> Result<(), reqwest::Error> {
+#[tokio::main]
+async fn main() -> Result<(), reqwest::Error> {
     let new_post = Post {
         id: None,
         title: "Reqwest.rs".into(),
@@ -25,8 +26,10 @@ fn main() -> Result<(), reqwest::Error> {
     let new_post: Post = reqwest::Client::new()
         .post("https://jsonplaceholder.typicode.com/posts")
         .json(&new_post)
-        .send()?
-        .json()?;
+        .send()
+        .await?
+        .json()
+        .await?;
 
     println!("{:#?}", new_post);
     // Post {
diff --git a/examples/simple.rs b/examples/simple.rs
index 73753dadb..c42f83e35 100644
--- a/examples/simple.rs
+++ b/examples/simple.rs
@@ -1,19 +1,17 @@
-//! `cargo run --example simple`
 #![deny(warnings)]
 
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    env_logger::init();
-
-    println!("GET https://www.rust-lang.org");
-
-    let mut res = reqwest::get("https://www.rust-lang.org/")?;
+#[tokio::main]
+async fn main() -> Result<(), reqwest::Error> {
+    let mut res = reqwest::Client::new()
+        .get("https://hyper.rs")
+        .send()
+        .await?;
 
     println!("Status: {}", res.status());
-    println!("Headers:\n{:?}", res.headers());
 
-    // copy the response body directly to stdout
-    res.copy_to(&mut std::io::stdout())?;
+    let body = res.text().await?;
+
+    println!("Body:\n\n{}", body);
 
-    println!("\n\nDone.");
     Ok(())
 }
diff --git a/src/async_impl/body.rs b/src/async_impl/body.rs
index dd4ac00cf..9afbc252c 100644
--- a/src/async_impl/body.rs
+++ b/src/async_impl/body.rs
@@ -33,7 +33,7 @@ impl Body {
     /// # Example
     ///
     /// ```
-    /// # use reqwest::r#async::Body;
+    /// # use reqwest::Body;
     /// # use futures;
     /// # fn main() {
     /// let chunks: Vec<Result<_, ::std::io::Error>> = vec![
diff --git a/src/async_impl/multipart.rs b/src/async_impl/multipart.rs
index 48ec7d1e0..96c9c94fa 100644
--- a/src/async_impl/multipart.rs
+++ b/src/async_impl/multipart.rs
@@ -61,7 +61,7 @@ impl Form {
     /// # Examples
     ///
     /// ```
-    /// let form = reqwest::r#async::multipart::Form::new()
+    /// let form = reqwest::multipart::Form::new()
     ///     .text("username", "seanmonstar")
     ///     .text("password", "secret");
     /// ```
diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs
index a3e1d3002..18f9f489e 100644
--- a/src/async_impl/request.rs
+++ b/src/async_impl/request.rs
@@ -194,8 +194,8 @@ impl RequestBuilder {
     /// # use reqwest::Error;
     ///
     /// # async fn run() -> Result<(), Error> {
-    /// let client = reqwest::r#async::Client::new();
-    /// let form = reqwest::r#async::multipart::Form::new()
+    /// let client = reqwest::Client::new();
+    /// let form = reqwest::multipart::Form::new()
     ///     .text("key3", "value3")
     ///     .text("key4", "value4");
     ///
@@ -329,7 +329,7 @@ impl RequestBuilder {
     /// # use reqwest::Error;
     /// #
     /// # async fn run() -> Result<(), Error> {
-    /// let response = reqwest::r#async::Client::new()
+    /// let response = reqwest::Client::new()
     ///     .get("https://hyper.rs")
     ///     .send()
     ///     .await?;
diff --git a/src/async_impl/response.rs b/src/async_impl/response.rs
index 441345789..4f7e39cb1 100644
--- a/src/async_impl/response.rs
+++ b/src/async_impl/response.rs
@@ -186,7 +186,7 @@ impl Response {
     /// # Example
     ///
     /// ```
-    /// # use reqwest::r#async::Response;
+    /// # use reqwest::Response;
     /// fn on_response(res: Response) {
     ///     match res.error_for_status() {
     ///         Ok(_res) => (),
@@ -216,7 +216,7 @@ impl Response {
     /// # Example
     ///
     /// ```
-    /// # use reqwest::r#async::Response;
+    /// # use reqwest::Response;
     /// fn on_response(res: &Response) {
     ///     match res.error_for_status_ref() {
     ///         Ok(_res) => (),
@@ -347,25 +347,6 @@ struct ResponseUrl(Url);
 pub trait ResponseBuilderExt {
     /// A builder method for the `http::response::Builder` type that allows the user to add a `Url`
     /// to the `http::Response`
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # extern crate url;
-    /// # extern crate http;
-    /// # extern crate reqwest;
-    /// # use std::error::Error;
-    /// use url::Url;
-    /// use http::response::Builder;
-    /// use reqwest::r#async::ResponseBuilderExt;
-    /// # fn main() -> Result<(), Box<dyn Error>> {
-    /// let response = Builder::new()
-    ///     .status(200)
-    ///     .url(Url::parse("http://example.com")?)
-    ///     .body(())?;
-    ///
-    /// #   Ok(())
-    /// # }
     fn url(&mut self, url: Url) -> &mut Self;
 }
 
diff --git a/src/body.rs b/src/blocking/body.rs
similarity index 98%
rename from src/body.rs
rename to src/blocking/body.rs
index 5712af45e..851981443 100644
--- a/src/body.rs
+++ b/src/blocking/body.rs
@@ -32,7 +32,7 @@ impl Body {
     ///
     /// ```rust
     /// # use std::fs::File;
-    /// # use reqwest::Body;
+    /// # use reqwest::blocking::Body;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// let file = File::open("national_secrets.txt")?;
     /// let body = Body::new(file);
@@ -45,7 +45,7 @@ impl Body {
     /// it can be reused.
     ///
     /// ```rust
-    /// # use reqwest::Body;
+    /// # use reqwest::blocking::Body;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// let s = "A stringy body";
     /// let body = Body::from(s);
@@ -64,7 +64,7 @@ impl Body {
     ///
     /// ```rust
     /// # use std::fs::File;
-    /// # use reqwest::Body;
+    /// # use reqwest::blocking::Body;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// let file = File::open("a_large_file.txt")?;
     /// let file_size = file.metadata()?.len();
diff --git a/src/client.rs b/src/blocking/client.rs
similarity index 96%
rename from src/client.rs
rename to src/blocking/client.rs
index e34e54ec9..59dc3b5da 100644
--- a/src/client.rs
+++ b/src/blocking/client.rs
@@ -10,9 +10,10 @@ use futures::{StreamExt, TryFutureExt};
 
 use log::{error, trace};
 
-use crate::request::{Request, RequestBuilder};
-use crate::response::Response;
-use crate::{async_impl, header, wait, IntoUrl, Method, Proxy, RedirectPolicy};
+use super::request::{Request, RequestBuilder};
+use super::response::Response;
+use super::wait;
+use crate::{async_impl, header, IntoUrl, Method, Proxy, RedirectPolicy};
 #[cfg(feature = "tls")]
 use crate::{Certificate, Identity};
 
@@ -28,9 +29,9 @@ use crate::{Certificate, Identity};
 /// # Examples
 ///
 /// ```rust
-/// # use reqwest::{Error, Client};
+/// use reqwest::blocking::Client;
 /// #
-/// # fn run() -> Result<(), Error> {
+/// # fn run() -> Result<(), reqwest::Error> {
 /// let client = Client::new();
 /// let resp = client.get("http://httpbin.org/").send()?;
 /// #   drop(resp);
@@ -51,7 +52,7 @@ pub struct Client {
 /// # fn run() -> Result<(), reqwest::Error> {
 /// use std::time::Duration;
 ///
-/// let client = reqwest::Client::builder()
+/// let client = reqwest::blocking::Client::builder()
 ///     .gzip(true)
 ///     .timeout(Duration::from_secs(10))
 ///     .build()?;
@@ -130,7 +131,7 @@ impl ClientBuilder {
     /// let cert = reqwest::Certificate::from_der(&buf)?;
     ///
     /// // get a client builder
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .add_root_certificate(cert)
     ///     .build()?;
     /// # drop(client);
@@ -170,7 +171,7 @@ impl ClientBuilder {
     /// let pkcs12 = reqwest::Identity::from_pem(&buf)?;
     ///
     /// // get a client builder
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .identity(pkcs12)
     ///     .build()?;
     /// # drop(client);
@@ -224,7 +225,7 @@ impl ClientBuilder {
     /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
     ///
     /// // get a client builder
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .default_headers(headers)
     ///     .build()?;
     /// let res = client.get("https://www.rust-lang.org").send()?;
@@ -241,7 +242,7 @@ impl ClientBuilder {
     /// headers.insert(header::AUTHORIZATION, header::HeaderValue::from_static("secret"));
     ///
     /// // get a client builder
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .default_headers(headers)
     ///     .build()?;
     /// let res = client
@@ -337,7 +338,7 @@ impl ClientBuilder {
     /// # Example
     ///
     /// ```
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .h2_prior_knowledge()
     ///     .build().unwrap();
     /// ```
@@ -350,7 +351,7 @@ impl ClientBuilder {
     /// # Example
     ///
     /// ```
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .http1_title_case_headers()
     ///     .build().unwrap();
     /// ```
@@ -365,7 +366,7 @@ impl ClientBuilder {
     /// ```
     /// use std::net::IpAddr;
     /// let local_addr = IpAddr::from([12, 4, 1, 8]);
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .local_address(local_addr)
     ///     .build().unwrap();
     /// ```
@@ -386,7 +387,7 @@ impl ClientBuilder {
     /// # Example
     ///
     /// ```
-    /// let client = reqwest::Client::builder()
+    /// let client = reqwest::blocking::Client::builder()
     ///     .cookie_store(true)
     ///     .build()
     ///     .unwrap();
diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs
new file mode 100644
index 000000000..6d54f37dd
--- /dev/null
+++ b/src/blocking/mod.rs
@@ -0,0 +1,98 @@
+//! A blocking Client API.
+//!
+//! The blocking `Client` will block the current thread to execute, instead
+//! of returning futures that need to be executed on a runtime.
+//!
+//! ## Making a GET request
+//!
+//! For a single request, you can use the [`get`](get) shortcut method.
+//!
+//! ```rust
+//! # use reqwest::{Error, Response};
+//!
+//! # fn run() -> Result<(), Error> {
+//! let body = reqwest::blocking::get("https://www.rust-lang.org")?
+//!     .text()?;
+//!
+//! println!("body = {:?}", body);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! Additionally, the blocking [`Response`](Response) struct implements Rust's
+//! `Read` trait, so many useful standard library and third party crates will
+//! have convenience methods that take a `Response` anywhere `T: Read` is
+//! acceptable.
+//!
+//! **NOTE**: If you plan to perform multiple requests, it is best to create a
+//! [`Client`](Client) and reuse it, taking advantage of keep-alive connection
+//! pooling.
+//!
+//! ## Making POST requests (or setting request bodies)
+//!
+//! There are several ways you can set the body of a request. The basic one is
+//! by using the `body()` method of a [`RequestBuilder`](RequestBuilder). This lets you set the
+//! exact raw bytes of what the body should be. It accepts various types,
+//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
+//! Reader, you can use the `reqwest::blocking::Body::new()` constructor.
+//!
+//! ```rust
+//! # use reqwest::Error;
+//! #
+//! # fn run() -> Result<(), Error> {
+//! let client = reqwest::blocking::Client::new();
+//! let res = client.post("http://httpbin.org/post")
+//!     .body("the exact body that is sent")
+//!     .send()?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ## And More
+//!
+//! Most features available to the asynchronous `Client` are also available,
+//! on the blocking `Client`, see those docs for more.
+
+mod body;
+mod client;
+pub mod multipart;
+mod request;
+mod response;
+mod wait;
+
+pub(crate) use self::wait::Waited;
+
+pub use self::body::Body;
+pub use self::client::{Client, ClientBuilder};
+pub use self::request::{Request, RequestBuilder};
+pub use self::response::Response;
+
+/// Shortcut method to quickly make a *blocking* `GET` request.
+///
+/// **NOTE**: This function creates a new internal `Client` on each call,
+/// and so should not be used if making many requests. Create a
+/// [`Client`](./struct.Client.html) instead.
+///
+/// # Examples
+///
+/// ```rust
+/// # fn run() -> Result<(), reqwest::Error> {
+/// let body = reqwest::blocking::get("https://www.rust-lang.org")?
+///     .text()?;
+/// # Ok(())
+/// # }
+/// # fn main() { }
+/// ```
+///
+/// # Errors
+///
+/// This function fails if:
+///
+/// - native TLS backend cannot be initialized
+/// - supplied `Url` cannot be parsed
+/// - there was an error while sending request
+/// - redirect loop was detected
+/// - redirect limit was exhausted
+pub fn get<T: crate::IntoUrl>(url: T) -> crate::Result<Response> {
+    Client::builder().build()?.get(url).send()
+}
diff --git a/src/multipart.rs b/src/blocking/multipart.rs
similarity index 98%
rename from src/multipart.rs
rename to src/blocking/multipart.rs
index 1b7bc4651..0f1cecf95 100644
--- a/src/multipart.rs
+++ b/src/blocking/multipart.rs
@@ -7,7 +7,7 @@
 //! # Example
 //!
 //! ```
-//! use reqwest::multipart;
+//! use reqwest::blocking::multipart;
 //!
 //! # fn run() -> Result<(), Box<dyn std::error::Error>> {
 //! let form = multipart::Form::new()
@@ -25,7 +25,7 @@
 //! let form = form.part("biography", bio);
 //!
 //! // And finally, send the form
-//! let client = reqwest::Client::new();
+//! let client = reqwest::blocking::Client::new();
 //! let resp = client
 //!     .post("http://localhost:8080/user")
 //!     .multipart(form)
@@ -44,8 +44,8 @@ use std::path::Path;
 
 use mime_guess::{self, Mime};
 
+use super::Body;
 use crate::async_impl::multipart::{FormParts, PartMetadata, PartProps};
-use crate::Body;
 
 /// A multipart/form-data request.
 pub struct Form {
@@ -77,7 +77,7 @@ impl Form {
     /// # Examples
     ///
     /// ```
-    /// let form = reqwest::multipart::Form::new()
+    /// let form = reqwest::blocking::multipart::Form::new()
     ///     .text("username", "seanmonstar")
     ///     .text("password", "secret");
     /// ```
@@ -97,7 +97,7 @@ impl Form {
     ///
     /// ```no_run
     /// # fn run() -> std::io::Result<()> {
-    /// let files = reqwest::multipart::Form::new()
+    /// let files = reqwest::blocking::multipart::Form::new()
     ///     .file("key", "/path/to/file")?;
     /// # Ok(())
     /// # }
diff --git a/src/request.rs b/src/blocking/request.rs
similarity index 92%
rename from src/request.rs
rename to src/blocking/request.rs
index e994b8e38..87f3a0dc8 100644
--- a/src/request.rs
+++ b/src/blocking/request.rs
@@ -1,14 +1,16 @@
 use std::fmt;
 
 use base64::encode;
+use http::HttpTryFrom;
 use serde::Serialize;
 use serde_json;
 use serde_urlencoded;
 
-use crate::body::{self, Body};
+use super::body::{self, Body};
+use super::multipart;
+use super::Client;
 use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
-use crate::{async_impl, Client, Method, Url};
-use http::HttpTryFrom;
+use crate::{async_impl, Method, Url};
 
 /// A request which can be executed with `Client::execute()`.
 pub struct Request {
@@ -128,7 +130,7 @@ impl RequestBuilder {
     /// use reqwest::header::USER_AGENT;
     ///
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.get("https://www.rust-lang.org")
     ///     .header(USER_AGENT, "foo")
     ///     .send()?;
@@ -175,7 +177,7 @@ impl RequestBuilder {
     ///
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// let file = fs::File::open("much_beauty.png")?;
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org/post")
     ///     .headers(construct_headers())
     ///     .body(file)
@@ -190,36 +192,11 @@ impl RequestBuilder {
         self
     }
 
-    /// Set a header with a type implementing hyper v0.11's `Header` trait.
-    ///
-    /// This method is provided to ease migration, and requires the `hyper-011`
-    /// Cargo feature enabled on `reqwest`.
-    #[cfg(feature = "hyper-011")]
-    pub fn header_011<H>(self, header: H) -> RequestBuilder
-    where
-        H: crate::hyper_011::header::Header,
-    {
-        let mut headers = crate::hyper_011::Headers::new();
-        headers.set(header);
-        let map = crate::header::HeaderMap::from(headers);
-        self.headers(map)
-    }
-
-    /// Set multiple headers using hyper v0.11's `Headers` map.
-    ///
-    /// This method is provided to ease migration, and requires the `hyper-011`
-    /// Cargo feature enabled on `reqwest`.
-    #[cfg(feature = "hyper-011")]
-    pub fn headers_011(self, headers: crate::hyper_011::Headers) -> RequestBuilder {
-        let map = crate::header::HeaderMap::from(headers);
-        self.headers(map)
-    }
-
     /// Enable HTTP basic authentication.
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let resp = client.delete("http://httpbin.org/delete")
     ///     .basic_auth("admin", Some("good password"))
     ///     .send()?;
@@ -243,7 +220,7 @@ impl RequestBuilder {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let resp = client.delete("http://httpbin.org/delete")
     ///     .bearer_auth("token")
     ///     .send()?;
@@ -266,7 +243,7 @@ impl RequestBuilder {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org/post")
     ///     .body("from a &str!")
     ///     .send()?;
@@ -277,10 +254,9 @@ impl RequestBuilder {
     /// Using a `File`:
     ///
     /// ```rust
-    /// # use std::fs;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let file = fs::File::open("from_a_file.txt")?;
-    /// let client = reqwest::Client::new();
+    /// let file = std::fs::File::open("from_a_file.txt")?;
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org/post")
     ///     .body(file)
     ///     .send()?;
@@ -295,7 +271,7 @@ impl RequestBuilder {
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// // from bytes!
     /// let bytes: Vec<u8> = vec![1, 10, 100];
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org/post")
     ///     .body(bytes)
     ///     .send()?;
@@ -322,7 +298,7 @@ impl RequestBuilder {
     /// # use reqwest::Error;
     /// #
     /// # fn run() -> Result<(), Error> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.get("http://httpbin.org")
     ///     .query(&[("lang", "rust")])
     ///     .send()?;
@@ -375,7 +351,7 @@ impl RequestBuilder {
     /// let mut params = HashMap::new();
     /// params.insert("lang", "rust");
     ///
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org")
     ///     .form(&params)
     ///     .send()?;
@@ -420,7 +396,7 @@ impl RequestBuilder {
     /// let mut map = HashMap::new();
     /// map.insert("lang", "rust");
     ///
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let res = client.post("http://httpbin.org")
     ///     .json(&map)
     ///     .send()?;
@@ -456,8 +432,8 @@ impl RequestBuilder {
     /// # use reqwest::Error;
     ///
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
-    /// let form = reqwest::multipart::Form::new()
+    /// let client = reqwest::blocking::Client::new();
+    /// let form = reqwest::blocking::multipart::Form::new()
     ///     .text("key3", "value3")
     ///     .file("file", "/path/to/field")?;
     ///
@@ -469,7 +445,7 @@ impl RequestBuilder {
     /// ```
     ///
     /// See [`multipart`](multipart/) for more examples.
-    pub fn multipart(self, mut multipart: crate::multipart::Form) -> RequestBuilder {
+    pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
         let mut builder = self.header(
             CONTENT_TYPE,
             format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
@@ -495,7 +471,7 @@ impl RequestBuilder {
     ///
     /// This method fails if there was an error while sending request,
     /// redirect loop was detected or redirect limit was exhausted.
-    pub fn send(self) -> crate::Result<crate::Response> {
+    pub fn send(self) -> crate::Result<super::Response> {
         self.client.execute(self.request?)
     }
 
@@ -510,7 +486,7 @@ impl RequestBuilder {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let builder = client.post("http://httpbin.org/post")
     ///     .body("from a &str!");
     /// let clone = builder.try_clone();
@@ -523,7 +499,7 @@ impl RequestBuilder {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let builder = client.get("http://httpbin.org/get");
     /// let clone = builder.try_clone();
     /// assert!(clone.is_some());
@@ -535,9 +511,9 @@ impl RequestBuilder {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let client = reqwest::Client::new();
+    /// let client = reqwest::blocking::Client::new();
     /// let builder = client.get("http://httpbin.org/get")
-    ///     .body(reqwest::Body::new(std::io::empty()));
+    ///     .body(reqwest::blocking::Body::new(std::io::empty()));
     /// let clone = builder.try_clone();
     /// assert!(clone.is_none());
     /// # Ok(())
@@ -572,8 +548,9 @@ fn fmt_request_fields<'a, 'b>(
 
 #[cfg(test)]
 mod tests {
+    use super::super::{body, Client};
     use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
-    use crate::{body, Client, Method};
+    use crate::Method;
     use serde::Serialize;
     use serde_json;
     use serde_urlencoded;
diff --git a/src/response.rs b/src/blocking/response.rs
similarity index 92%
rename from src/response.rs
rename to src/blocking/response.rs
index cd68dcf32..798a6222a 100644
--- a/src/response.rs
+++ b/src/blocking/response.rs
@@ -6,12 +6,13 @@ use std::pin::Pin;
 use std::time::Duration;
 
 use http;
+use hyper::header::HeaderMap;
 use serde::de::DeserializeOwned;
 
-use crate::client::KeepCoreThreadAlive;
+use super::client::KeepCoreThreadAlive;
+use super::wait;
 use crate::cookie;
-use crate::{async_impl, wait, StatusCode, Url, Version};
-use hyper::header::HeaderMap;
+use crate::{async_impl, StatusCode, Url, Version};
 
 /// A Response to a submitted `Request`.
 pub struct Response {
@@ -49,7 +50,7 @@ impl Response {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let resp = reqwest::get("http://httpbin.org/get")?;
+    /// let resp = reqwest::blocking::get("http://httpbin.org/get")?;
     /// if resp.status().is_success() {
     ///     println!("success!");
     /// } else if resp.status().is_server_error() {
@@ -64,7 +65,7 @@ impl Response {
     /// Checking for specific status codes:
     ///
     /// ```rust
-    /// use reqwest::Client;
+    /// use reqwest::blocking::Client;
     /// use reqwest::StatusCode;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
     /// let client = Client::new();
@@ -95,7 +96,7 @@ impl Response {
     /// Saving an etag when caching a file:
     ///
     /// ```
-    /// use reqwest::Client;
+    /// use reqwest::blocking::Client;
     /// use reqwest::header::ETAG;
     ///
     /// # fn run() -> Result<(), Box<std::error::Error>> {
@@ -136,7 +137,7 @@ impl Response {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let resp = reqwest::get("http://httpbin.org/redirect/1")?;
+    /// let resp = reqwest::blocking::get("http://httpbin.org/redirect/1")?;
     /// assert_eq!(resp.url().as_str(), "http://httpbin.org/get");
     /// # Ok(())
     /// # }
@@ -152,7 +153,7 @@ impl Response {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let resp = reqwest::get("http://httpbin.org/redirect/1")?;
+    /// let resp = reqwest::blocking::get("http://httpbin.org/redirect/1")?;
     /// println!("httpbin.org address: {:?}", resp.remote_addr());
     /// # Ok(())
     /// # }
@@ -189,7 +190,7 @@ impl Response {
     /// }
     ///
     /// # fn run() -> Result<(), Error> {
-    /// let json: Ip = reqwest::get("http://httpbin.org/ip")?.json()?;
+    /// let json: Ip = reqwest::blocking::get("http://httpbin.org/ip")?.json()?;
     /// # Ok(())
     /// # }
     /// #
@@ -223,7 +224,7 @@ impl Response {
     /// ```rust
     /// # extern crate reqwest;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let content = reqwest::get("http://httpbin.org/range/26")?.text()?;
+    /// let content = reqwest::blocking::get("http://httpbin.org/range/26")?.text()?;
     /// # Ok(())
     /// # }
     /// ```
@@ -250,7 +251,8 @@ impl Response {
     /// ```rust
     /// # extern crate reqwest;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let content = reqwest::get("http://httpbin.org/range/26")?.text_with_charset("utf-8")?;
+    /// let content = reqwest::blocking::get("http://httpbin.org/range/26")?
+    ///     .text_with_charset("utf-8")?;
     /// # Ok(())
     /// # }
     /// ```
@@ -282,7 +284,7 @@ impl Response {
     ///
     /// ```rust
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let mut resp = reqwest::get("http://httpbin.org/range/5")?;
+    /// let mut resp = reqwest::blocking::get("http://httpbin.org/range/5")?;
     /// let mut buf: Vec<u8> = vec![];
     /// resp.copy_to(&mut buf)?;
     /// assert_eq!(b"abcde", buf.as_slice());
@@ -303,7 +305,7 @@ impl Response {
     /// ```rust,no_run
     /// # extern crate reqwest;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let res = reqwest::get("http://httpbin.org/status/400")?
+    /// let res = reqwest::blocking::get("http://httpbin.org/status/400")?
     ///     .error_for_status();
     /// if let Err(err) = res {
     ///     assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST));
@@ -312,7 +314,6 @@ impl Response {
     /// # }
     /// # fn main() {}
     /// ```
-    #[inline]
     pub fn error_for_status(self) -> crate::Result<Self> {
         let Response {
             body,
@@ -335,7 +336,7 @@ impl Response {
     /// ```rust,no_run
     /// # extern crate reqwest;
     /// # fn run() -> Result<(), Box<std::error::Error>> {
-    /// let res = reqwest::get("http://httpbin.org/status/400")?;
+    /// let res = reqwest::blocking::get("http://httpbin.org/status/400")?;
     /// let res = res.error_for_status_ref();
     /// if let Err(err) = res {
     ///     assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST));
@@ -344,7 +345,6 @@ impl Response {
     /// # }
     /// # fn main() {}
     /// ```
-    #[inline]
     pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
         self.inner.error_for_status_ref().and_then(|_| Ok(self))
     }
diff --git a/src/wait.rs b/src/blocking/wait.rs
similarity index 100%
rename from src/wait.rs
rename to src/blocking/wait.rs
diff --git a/src/error.rs b/src/error.rs
index 69d1d4905..e18dc1a94 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -20,15 +20,15 @@ use crate::{StatusCode, Url};
 /// }
 /// # fn main() { }
 ///
-/// fn run() {
-///    match make_request() {
+/// async fn run() {
+///    match make_request().await {
 ///        Err(e) => handler(e),
 ///        Ok(_)  => return,
 ///    }
 /// }
 /// // Response is not a json object conforming to the Simple struct
-/// fn make_request() -> Result<Simple, reqwest::Error> {
-///   reqwest::get("http://httpbin.org/ip")?.json()
+/// async fn make_request() -> Result<Simple, reqwest::Error> {
+///   reqwest::get("http://httpbin.org/ip").await?.json().await
 /// }
 ///
 /// fn handler(e: reqwest::Error) {
@@ -75,9 +75,9 @@ impl Error {
     /// # Examples
     ///
     /// ```
-    /// # fn run() {
+    /// # async fn run() {
     /// // displays last stop of a redirect loop
-    /// let response = reqwest::get("http://site.with.redirect.loop");
+    /// let response = reqwest::get("http://site.with.redirect.loop").await;
     /// if let Err(e) = response {
     ///     if e.is_redirect() {
     ///         if let Some(final_stop) = e.url() {
@@ -108,14 +108,14 @@ impl Error {
     /// extern crate url;
     /// # extern crate reqwest;
     /// // retries requests with no host on localhost
-    /// # fn run() {
+    /// # async fn run() {
     /// let invalid_request = "http://";
-    /// let mut response = reqwest::get(invalid_request);
+    /// let mut response = reqwest::get(invalid_request).await;
     /// if let Err(e) = response {
     ///     match e.get_ref().and_then(|e| e.downcast_ref::<url::ParseError>()) {
     ///         Some(&url::ParseError::EmptyHost) => {
     ///             let valid_request = format!("{}{}",invalid_request, "localhost");
-    ///             response = reqwest::get(&valid_request);
+    ///             response = reqwest::get(&valid_request).await;
     ///         },
     ///         _ => (),
     ///     }
@@ -123,7 +123,6 @@ impl Error {
     /// # }
     /// # fn main() {}
     /// ```
-    #[inline]
     pub fn get_ref(&self) -> Option<&(dyn StdError + Send + Sync + 'static)> {
         match self.inner.kind {
             Kind::Http(ref e) => Some(e),
@@ -152,7 +151,6 @@ impl Error {
     }
 
     /// Returns true if the error is related to HTTP.
-    #[inline]
     pub fn is_http(&self) -> bool {
         match self.inner.kind {
             Kind::Http(_) => true,
@@ -175,7 +173,6 @@ impl Error {
     }
 
     /// Returns true if the error is serialization related.
-    #[inline]
     pub fn is_serialization(&self) -> bool {
         match self.inner.kind {
             Kind::Json(_) | Kind::UrlEncoded(_) => true,
@@ -184,7 +181,6 @@ impl Error {
     }
 
     /// Returns true if the error is from a `RedirectPolicy`.
-    #[inline]
     pub fn is_redirect(&self) -> bool {
         match self.inner.kind {
             Kind::TooManyRedirects | Kind::RedirectLoop => true,
@@ -193,7 +189,6 @@ impl Error {
     }
 
     /// Returns true if the error is from a request returning a 4xx error.
-    #[inline]
     pub fn is_client_error(&self) -> bool {
         match self.inner.kind {
             Kind::Status(code) => code.is_client_error(),
@@ -202,7 +197,6 @@ impl Error {
     }
 
     /// Returns true if the error is from a request returning a 5xx error.
-    #[inline]
     pub fn is_server_error(&self) -> bool {
         match self.inner.kind {
             Kind::Status(code) => code.is_server_error(),
@@ -211,7 +205,6 @@ impl Error {
     }
 
     /// Returns the status code, if the error was generated from a response.
-    #[inline]
     pub fn status(&self) -> Option<StatusCode> {
         match self.inner.kind {
             Kind::Status(code) => Some(code),
@@ -466,15 +459,15 @@ impl From<rustls::TLSError> for Kind {
     }
 }
 
-impl<T> From<crate::wait::Waited<T>> for Kind
+impl<T> From<crate::blocking::Waited<T>> for Kind
 where
     T: Into<Kind>,
 {
-    fn from(err: crate::wait::Waited<T>) -> Kind {
+    fn from(err: crate::blocking::Waited<T>) -> Kind {
         match err {
-            crate::wait::Waited::TimedOut => io_timeout().into(),
-            crate::wait::Waited::Executor(e) => e.into(),
-            crate::wait::Waited::Inner(e) => e.into(),
+            crate::blocking::Waited::TimedOut => io_timeout().into(),
+            crate::blocking::Waited::Executor(e) => e.into(),
+            crate::blocking::Waited::Inner(e) => e.into(),
         }
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index cd144ff09..524ec34a0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,15 +11,16 @@
 //! It handles many of the things that most people just expect an HTTP client
 //! to do for them.
 //!
+//! - Async and [blocking](blocking) Clients
 //! - Plain bodies, [JSON](#json), [urlencoded](#forms), [multipart](multipart)
 //! - Customizable [redirect policy](#redirect-policy)
 //! - HTTP [Proxies](#proxies)
 //! - Uses system-native [TLS](#tls)
 //! - Cookies
 //!
-//! The [`reqwest::Client`][client] is synchronous, making it a great fit for
-//! applications that only require a few HTTP requests, and wish to handle
-//! them synchronously.
+//! The [`reqwest::Client`][client] is asynchronous. For applications wishing
+//! to only make a few HTTP requests, the [`reqwest::blocking`](blocking) API
+//! may be more convenient.
 //!
 //! Additional learning resources include:
 //!
@@ -31,22 +32,17 @@
 //! For a single request, you can use the [`get`][get] shortcut method.
 //!
 //! ```rust
-//! # use reqwest::{Error, Response};
-//!
-//! # fn run() -> Result<(), Error> {
-//! let body = reqwest::get("https://www.rust-lang.org")?
-//!     .text()?;
+//! # async fn run() -> Result<(), reqwest::Error> {
+//! let body = reqwest::get("https://www.rust-lang.org")
+//!     .await?
+//!     .text()
+//!     .await?;
 //!
 //! println!("body = {:?}", body);
 //! # Ok(())
 //! # }
 //! ```
 //!
-//! Additionally, reqwest's [`Response`][response] struct implements Rust's
-//! `Read` trait, so many useful standard library and third party crates will
-//! have convenience methods that take a `Response` anywhere `T: Read` is
-//! acceptable.
-//!
 //! **NOTE**: If you plan to perform multiple requests, it is best to create a
 //! [`Client`][client] and reuse it, taking advantage of keep-alive connection
 //! pooling.
@@ -57,16 +53,17 @@
 //! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
 //! exact raw bytes of what the body should be. It accepts various types,
 //! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
-//! Reader, you can use the `reqwest::Body::new()` constructor.
+//! type, you can use the `reqwest::Body` constructors.
 //!
 //! ```rust
 //! # use reqwest::Error;
 //! #
-//! # fn run() -> Result<(), Error> {
+//! # async fn run() -> Result<(), Error> {
 //! let client = reqwest::Client::new();
 //! let res = client.post("http://httpbin.org/post")
 //!     .body("the exact body that is sent")
-//!     .send()?;
+//!     .send()
+//!     .await?;
 //! # Ok(())
 //! # }
 //! ```
@@ -82,13 +79,14 @@
 //! ```rust
 //! # use reqwest::Error;
 //! #
-//! # fn run() -> Result<(), Error> {
+//! # async fn run() -> Result<(), Error> {
 //! // This will POST a body of `foo=bar&baz=quux`
 //! let params = [("foo", "bar"), ("baz", "quux")];
 //! let client = reqwest::Client::new();
 //! let res = client.post("http://httpbin.org/post")
 //!     .form(&params)
-//!     .send()?;
+//!     .send()
+//!     .await?;
 //! # Ok(())
 //! # }
 //! ```
@@ -103,7 +101,7 @@
 //! # use reqwest::Error;
 //! # use std::collections::HashMap;
 //! #
-//! # fn run() -> Result<(), Error> {
+//! # async fn run() -> Result<(), Error> {
 //! // This will POST a body of `{"lang":"rust","body":"json"}`
 //! let mut map = HashMap::new();
 //! map.insert("lang", "rust");
@@ -112,7 +110,8 @@
 //! let client = reqwest::Client::new();
 //! let res = client.post("http://httpbin.org/post")
 //!     .json(&map)
-//!     .send()?;
+//!     .send()
+//!     .await?;
 //! # Ok(())
 //! # }
 //! ```
@@ -157,8 +156,6 @@
 //!   `native-tls` library to connect over HTTPS.
 //! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`.
 //! - **rustls-tls**: Provides TLS support via the `rustls` library.
-//! - **socks**: Provides SOCKS5 proxy support.
-//! - **hyper-011**: Provides support for hyper's old typed headers.
 //!
 //!
 //! [hyper]: http://hyper.rs
@@ -171,12 +168,11 @@
 //! [Proxy]: ./struct.Proxy.html
 //! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section
 
+////! - **socks**: Provides SOCKS5 proxy support.
 ////! - **trust-dns**: Enables a trust-dns async resolver instead of default
 ////!   threadpool using `getaddrinfo`.
 
 extern crate cookie as cookie_crate;
-#[cfg(feature = "hyper-011")]
-pub use hyper_old_types as hyper_011;
 
 #[cfg(test)]
 #[macro_use]
@@ -191,14 +187,17 @@ pub use hyper::{StatusCode, Version};
 pub use url::ParseError as UrlError;
 pub use url::Url;
 
-pub use self::body::Body;
-pub use self::client::{Client, ClientBuilder};
+pub use self::r#async::{
+    multipart, Body, Client, ClientBuilder, Decoder, Request, RequestBuilder, Response,
+};
+//pub use self::body::Body;
+//pub use self::client::{Client, ClientBuilder};
 pub use self::error::{Error, Result};
 pub use self::into_url::IntoUrl;
 pub use self::proxy::Proxy;
 pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy};
-pub use self::request::{Request, RequestBuilder};
-pub use self::response::Response;
+//pub use self::request::{Request, RequestBuilder};
+//pub use self::response::Response;
 #[cfg(feature = "tls")]
 pub use self::tls::{Certificate, Identity};
 
@@ -207,8 +206,7 @@ pub use self::tls::{Certificate, Identity};
 mod error;
 
 mod async_impl;
-mod body;
-mod client;
+pub mod blocking;
 mod connect;
 pub mod cookie;
 //#[cfg(feature = "trust-dns")]
@@ -216,19 +214,16 @@ pub mod cookie;
 mod into_url;
 mod proxy;
 mod redirect;
-mod request;
-mod response;
 #[cfg(feature = "tls")]
 mod tls;
-mod wait;
 
-pub mod multipart;
+//pub mod multipart;
 
-/// An 'async' implementation of the reqwest `Client`.
+#[doc(hidden)]
+#[deprecated(note = "types moved to top of crate")]
 pub mod r#async {
     pub use crate::async_impl::{
         multipart, Body, Chunk, Client, ClientBuilder, Decoder, Request, RequestBuilder, Response,
-        ResponseBuilderExt,
     };
 }
 
@@ -244,12 +239,11 @@ pub mod r#async {
 /// # Examples
 ///
 /// ```rust
-/// # fn run() -> Result<(), reqwest::Error> {
-/// let body = reqwest::get("https://www.rust-lang.org")?
-///     .text()?;
+/// # async fn run() -> Result<(), reqwest::Error> {
+/// let body = reqwest::get("https://www.rust-lang.org").await?
+///     .text().await?;
 /// # Ok(())
 /// # }
-/// # fn main() { }
 /// ```
 ///
 /// # Errors
@@ -261,8 +255,8 @@ pub mod r#async {
 /// - there was an error while sending request
 /// - redirect loop was detected
 /// - redirect limit was exhausted
-pub fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
-    Client::builder().build()?.get(url).send()
+pub async fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
+    Client::builder().build()?.get(url).send().await
 }
 
 fn _assert_impls() {


Test patch:
diff --git a/tests/async.rs b/tests/async.rs
deleted file mode 100644
index d8a6ea753..000000000
--- a/tests/async.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-#[macro_use]
-mod support;
-
-use std::io::Write;
-use std::time::Duration;
-
-use futures::TryStreamExt;
-
-use reqwest::r#async::multipart::{Form, Part};
-use reqwest::r#async::{Body, Client};
-
-use bytes::Bytes;
-
-#[tokio::test]
-async fn gzip_response() {
-    gzip_case(10_000, 4096).await;
-}
-
-#[tokio::test]
-async fn gzip_single_byte_chunks() {
-    gzip_case(10, 1).await;
-}
-
-#[tokio::test]
-async fn response_text() {
-    let _ = env_logger::try_init();
-
-    let server = server! {
-        request: b"\
-            GET /text HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Content-Length: 5\r\n\
-            \r\n\
-            Hello\
-            "
-    };
-
-    let client = Client::new();
-
-    let mut res = client
-        .get(&format!("http://{}/text", server.addr()))
-        .send()
-        .await
-        .expect("Failed to get");
-    let text = res.text().await.expect("Failed to get text");
-    assert_eq!("Hello", text);
-}
-
-#[tokio::test]
-async fn response_json() {
-    let _ = env_logger::try_init();
-
-    let server = server! {
-        request: b"\
-            GET /json HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Content-Length: 7\r\n\
-            \r\n\
-            \"Hello\"\
-            "
-    };
-
-    let client = Client::new();
-
-    let mut res = client
-        .get(&format!("http://{}/json", server.addr()))
-        .send()
-        .await
-        .expect("Failed to get");
-    let text = res.json::<String>().await.expect("Failed to get json");
-    assert_eq!("Hello", text);
-}
-
-#[tokio::test]
-async fn multipart() {
-    let _ = env_logger::try_init();
-
-    let stream = futures::stream::once(futures::future::ready::<Result<_, hyper::Error>>(Ok(
-        hyper::Chunk::from("part1 part2".to_owned()),
-    )));
-    let part = Part::stream(stream);
-
-    let form = Form::new().text("foo", "bar").part("part_stream", part);
-
-    let expected_body = format!(
-        "\
-         24\r\n\
-         --{0}\r\n\r\n\
-         2E\r\n\
-         Content-Disposition: form-data; name=\"foo\"\r\n\r\n\r\n\
-         3\r\n\
-         bar\r\n\
-         2\r\n\
-         \r\n\r\n\
-         24\r\n\
-         --{0}\r\n\r\n\
-         36\r\n\
-         Content-Disposition: form-data; name=\"part_stream\"\r\n\r\n\r\n\
-         B\r\n\
-         part1 part2\r\n\
-         2\r\n\
-         \r\n\r\n\
-         26\r\n\
-         --{0}--\r\n\r\n\
-         0\r\n\r\n\
-         ",
-        form.boundary()
-    );
-
-    let server = server! {
-        request: format!("\
-            POST /multipart/1 HTTP/1.1\r\n\
-            content-type: multipart/form-data; boundary={}\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            transfer-encoding: chunked\r\n\
-            \r\n\
-            {}\
-            ", form.boundary(), expected_body),
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: multipart\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
-    };
-
-    let url = format!("http://{}/multipart/1", server.addr());
-
-    let client = Client::new();
-
-    let res = client
-        .post(&url)
-        .multipart(form)
-        .send()
-        .await
-        .expect("Failed to post multipart");
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-}
-
-#[tokio::test]
-async fn request_timeout() {
-    let _ = env_logger::try_init();
-
-    let server = server! {
-        request: b"\
-            GET /slow HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Content-Length: 5\r\n\
-            \r\n\
-            Hello\
-            ",
-        read_timeout: Duration::from_secs(2)
-    };
-
-    let client = Client::builder()
-        .timeout(Duration::from_millis(500))
-        .build()
-        .unwrap();
-
-    let url = format!("http://{}/slow", server.addr());
-
-    let res = client.get(&url).send().await;
-
-    let err = res.unwrap_err();
-
-    assert!(err.is_timeout());
-    assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
-}
-
-#[tokio::test]
-async fn response_timeout() {
-    let _ = env_logger::try_init();
-
-    let server = server! {
-        request: b"\
-            GET /slow HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Content-Length: 5\r\n\
-            \r\n\
-            Hello\
-            ",
-        write_timeout: Duration::from_secs(2)
-    };
-
-    let client = Client::builder()
-        .timeout(Duration::from_millis(500))
-        .build()
-        .unwrap();
-
-    let url = format!("http://{}/slow", server.addr());
-    let res = client.get(&url).send().await.expect("Failed to get");
-    let body: Result<_, _> = res.into_body().try_concat().await;
-
-    let err = body.unwrap_err();
-
-    assert!(err.is_timeout());
-}
-
-async fn gzip_case(response_size: usize, chunk_size: usize) {
-    let content: String = (0..response_size)
-        .into_iter()
-        .map(|i| format!("test {}", i))
-        .collect();
-    let mut encoder = libflate::gzip::Encoder::new(Vec::new()).unwrap();
-    match encoder.write(content.as_bytes()) {
-        Ok(n) => assert!(n > 0, "Failed to write to encoder."),
-        _ => panic!("Failed to gzip encode string."),
-    };
-
-    let gzipped_content = encoder.finish().into_result().unwrap();
-
-    let mut response = format!(
-        "\
-         HTTP/1.1 200 OK\r\n\
-         Server: test-accept\r\n\
-         Content-Encoding: gzip\r\n\
-         Content-Length: {}\r\n\
-         \r\n",
-        &gzipped_content.len()
-    )
-    .into_bytes();
-    response.extend(&gzipped_content);
-
-    let server = server! {
-        request: b"\
-            GET /gzip HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        chunk_size: chunk_size,
-        write_timeout: Duration::from_millis(10),
-        response: response
-    };
-
-    let client = Client::new();
-
-    let mut res = client
-        .get(&format!("http://{}/gzip", server.addr()))
-        .send()
-        .await
-        .expect("response");
-
-    let body = res.text().await.expect("text");
-    assert_eq!(body, content);
-}
-
-#[tokio::test]
-async fn body_stream() {
-    let _ = env_logger::try_init();
-
-    let source = futures::stream::iter::<Vec<Result<Bytes, std::io::Error>>>(vec![
-        Ok(Bytes::from_static(b"123")),
-        Ok(Bytes::from_static(b"4567")),
-    ]);
-
-    let expected_body = "3\r\n123\r\n4\r\n4567\r\n0\r\n\r\n";
-
-    let server = server! {
-        request: format!("\
-            POST /post HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            transfer-encoding: chunked\r\n\
-            \r\n\
-            {}\
-            ", expected_body),
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: post\r\n\
-            Content-Length: 7\r\n\
-            \r\n\
-            "
-    };
-
-    let url = format!("http://{}/post", server.addr());
-
-    let client = Client::new();
-
-    let res = client
-        .post(&url)
-        .body(Body::wrap_stream(source))
-        .send()
-        .await
-        .expect("Failed to post");
-
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-}
diff --git a/tests/badssl.rs b/tests/badssl.rs
index eb843f5df..d3c285067 100644
--- a/tests/badssl.rs
+++ b/tests/badssl.rs
@@ -1,57 +1,65 @@
 #[cfg(feature = "tls")]
-#[test]
-fn test_badssl_modern() {
+#[tokio::test]
+async fn test_badssl_modern() {
     let text = reqwest::get("https://mozilla-modern.badssl.com/")
+        .await
         .unwrap()
         .text()
+        .await
         .unwrap();
 
     assert!(text.contains("<title>mozilla-modern.badssl.com</title>"));
 }
 
 #[cfg(feature = "rustls-tls")]
-#[test]
-fn test_rustls_badssl_modern() {
+#[tokio::test]
+async fn test_rustls_badssl_modern() {
     let text = reqwest::Client::builder()
         .use_rustls_tls()
         .build()
         .unwrap()
         .get("https://mozilla-modern.badssl.com/")
         .send()
+        .await
         .unwrap()
         .text()
+        .await
         .unwrap();
 
     assert!(text.contains("<title>mozilla-modern.badssl.com</title>"));
 }
 
 #[cfg(feature = "tls")]
-#[test]
-fn test_badssl_self_signed() {
+#[tokio::test]
+async fn test_badssl_self_signed() {
     let text = reqwest::Client::builder()
         .danger_accept_invalid_certs(true)
         .build()
         .unwrap()
         .get("https://self-signed.badssl.com/")
         .send()
+        .await
         .unwrap()
         .text()
+        .await
         .unwrap();
 
     assert!(text.contains("<title>self-signed.badssl.com</title>"));
 }
 
 #[cfg(feature = "default-tls")]
-#[test]
-fn test_badssl_wrong_host() {
+#[tokio::test]
+async fn test_badssl_wrong_host() {
     let text = reqwest::Client::builder()
         .danger_accept_invalid_hostnames(true)
         .build()
         .unwrap()
         .get("https://wrong.host.badssl.com/")
         .send()
+        .await
         .unwrap()
         .text()
+        .await
         .unwrap();
 
     assert!(text.contains("<title>wrong.host.badssl.com</title>"));
@@ -61,7 +69,8 @@ fn test_badssl_wrong_host() {
         .build()
         .unwrap()
         .get("https://self-signed.badssl.com/")
-        .send();
+        .send()
+        .await;
 
     assert!(result.is_err());
 }
diff --git a/tests/blocking.rs b/tests/blocking.rs
new file mode 100644
index 000000000..d41c0f410
--- /dev/null
+++ b/tests/blocking.rs
@@ -0,0 +1,512 @@
+#[macro_use]
+mod support;
+
+#[test]
+fn test_response_text() {
+    let server = server! {
+        request: b"\
+            GET /text HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 5\r\n\
+            \r\n\
+            Hello\
+            "
+    };
+
+    let url = format!("http://{}/text", server.addr());
+    let mut res = reqwest::blocking::get(&url).unwrap();
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"5"
+    );
+
+    let body = res.text().unwrap();
+    assert_eq!(b"Hello", body.as_bytes());
+}
+
+#[test]
+fn test_response_non_utf_8_text() {
+    let server = server! {
+        request: b"\
+            GET /text HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 4\r\n\
+            Content-Type: text/plain; charset=gbk\r\n\
+            \r\n\
+            \xc4\xe3\xba\xc3\
+            "
+    };
+
+    let url = format!("http://{}/text", server.addr());
+    let mut res = reqwest::blocking::get(&url).unwrap();
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"4"
+    );
+
+    let body = res.text().unwrap();
+    assert_eq!("你好", &body);
+    assert_eq!(b"\xe4\xbd\xa0\xe5\xa5\xbd", body.as_bytes()); // Now it's utf-8
+}
+
+#[test]
+fn test_response_json() {
+    let server = server! {
+        request: b"\
+            GET /json HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 7\r\n\
+            \r\n\
+            \"Hello\"\
+            "
+    };
+
+    let url = format!("http://{}/json", server.addr());
+    let mut res = reqwest::blocking::get(&url).unwrap();
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"7"
+    );
+
+    let body = res.json::<String>().unwrap();
+    assert_eq!("Hello", body);
+}
+
+#[test]
+fn test_response_copy_to() {
+    let server = server! {
+        request: b"\
+            GET /1 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 5\r\n\
+            \r\n\
+            Hello\
+            "
+    };
+
+    let url = format!("http://{}/1", server.addr());
+    let mut res = reqwest::blocking::get(&url).unwrap();
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"5"
+    );
+
+    assert_eq!("Hello".to_owned(), res.text().unwrap());
+}
+
+#[test]
+fn test_get() {
+    let server = server! {
+        request: b"\
+            GET /1 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/1", server.addr());
+    let mut res = reqwest::blocking::get(&url).unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+    assert_eq!(res.remote_addr(), Some(server.addr()));
+
+    assert_eq!(res.text().unwrap().len(), 0)
+}
+
+#[test]
+fn test_post() {
+    let server = server! {
+        request: b"\
+            POST /2 HTTP/1.1\r\n\
+            content-length: 5\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            Hello\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: post\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/2", server.addr());
+    let mut res = reqwest::blocking::Client::new()
+        .post(&url)
+        .body("Hello")
+        .send()
+        .unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"post");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+
+    assert_eq!(res.text().unwrap().len(), 0)
+}
+
+#[test]
+fn test_post_form() {
+    let server = server! {
+        request: b"\
+            POST /form HTTP/1.1\r\n\
+            content-type: application/x-www-form-urlencoded\r\n\
+            content-length: 24\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            hello=world&sean=monstar\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: post-form\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let form = &[("hello", "world"), ("sean", "monstar")];
+
+    let url = format!("http://{}/form", server.addr());
+    let res = reqwest::blocking::Client::new()
+        .post(&url)
+        .form(form)
+        .send()
+        .expect("request send");
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+}
+
+/// Calling `Response::error_for_status`` on a response with status in 4xx
+/// returns a error.
+#[test]
+fn test_error_for_status_4xx() {
+    let server = server! {
+        request: b"\
+            GET /1 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 400 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/1", server.addr());
+    let res = reqwest::blocking::get(&url).unwrap();
+
+    let err = res.error_for_status().err().unwrap();
+    assert!(err.is_client_error());
+    assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST));
+}
+
+/// Calling `Response::error_for_status`` on a response with status in 5xx
+/// returns a error.
+#[test]
+fn test_error_for_status_5xx() {
+    let server = server! {
+        request: b"\
+            GET /1 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 500 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/1", server.addr());
+    let res = reqwest::blocking::get(&url).unwrap();
+
+    let err = res.error_for_status().err().unwrap();
+    assert!(err.is_server_error());
+    assert_eq!(
+        err.status(),
+        Some(reqwest::StatusCode::INTERNAL_SERVER_ERROR)
+    );
+}
+
+#[test]
+fn test_default_headers() {
+    use reqwest::header;
+    let mut headers = header::HeaderMap::with_capacity(1);
+    headers.insert(header::COOKIE, header::HeaderValue::from_static("a=b;c=d"));
+    let client = reqwest::blocking::Client::builder()
+        .default_headers(headers)
+        .build()
+        .unwrap();
+
+    let server = server! {
+        request: b"\
+            GET /1 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            cookie: a=b;c=d\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/1", server.addr());
+    let res = client.get(&url).send().unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+
+    let server = server! {
+        request: b"\
+            GET /2 HTTP/1.1\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            cookie: a=b;c=d\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/2", server.addr());
+    let res = client.get(&url).send().unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+}
+
+#[test]
+fn test_override_default_headers() {
+    use reqwest::header;
+    let mut headers = header::HeaderMap::with_capacity(1);
+    headers.insert(
+        header::AUTHORIZATION,
+        header::HeaderValue::from_static("iamatoken"),
+    );
+    let client = reqwest::blocking::Client::builder()
+        .default_headers(headers)
+        .build()
+        .unwrap();
+
+    let server = server! {
+        request: b"\
+            GET /3 HTTP/1.1\r\n\
+            authorization: secret\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/3", server.addr());
+    let res = client
+        .get(&url)
+        .header(
+            header::AUTHORIZATION,
+            header::HeaderValue::from_static("secret"),
+        )
+        .send()
+        .unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+}
+
+#[test]
+fn test_appended_headers_not_overwritten() {
+    let client = reqwest::blocking::Client::new();
+
+    let server = server! {
+        request: b"\
+            GET /4 HTTP/1.1\r\n\
+            accept: application/json\r\n\
+            accept: application/json+hal\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/4", server.addr());
+    let res = client
+        .get(&url)
+        .header(header::ACCEPT, "application/json")
+        .header(header::ACCEPT, "application/json+hal")
+        .send()
+        .unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+
+    // make sure this also works with default headers
+    use reqwest::header;
+    let mut headers = header::HeaderMap::with_capacity(1);
+    headers.insert(
+        header::ACCEPT,
+        header::HeaderValue::from_static("text/html"),
+    );
+    let client = reqwest::blocking::Client::builder()
+        .default_headers(headers)
+        .build()
+        .unwrap();
+
+    let server = server! {
+        request: b"\
+            GET /4 HTTP/1.1\r\n\
+            accept: application/json\r\n\
+            accept: application/json+hal\r\n\
+            user-agent: $USERAGENT\r\n\
+            accept-encoding: gzip\r\n\
+            host: $HOST\r\n\
+            \r\n\
+            ",
+        response: b"\
+            HTTP/1.1 200 OK\r\n\
+            Server: test\r\n\
+            Content-Length: 0\r\n\
+            \r\n\
+            "
+    };
+
+    let url = format!("http://{}/4", server.addr());
+    let res = client
+        .get(&url)
+        .header(header::ACCEPT, "application/json")
+        .header(header::ACCEPT, "application/json+hal")
+        .send()
+        .unwrap();
+
+    assert_eq!(res.url().as_str(), &url);
+    assert_eq!(res.status(), reqwest::StatusCode::OK);
+    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
+    assert_eq!(
+        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
+        &"0"
+    );
+}
diff --git a/tests/client.rs b/tests/client.rs
index 85ba69131..598e812f6 100644
--- a/tests/client.rs
+++ b/tests/client.rs
@@ -1,42 +1,30 @@
 #[macro_use]
 mod support;
 
-#[test]
-fn test_response_text() {
-    let server = server! {
-        request: b"\
-            GET /text HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 5\r\n\
-            \r\n\
-            Hello\
-            "
-    };
+use std::io::Write;
+use std::time::Duration;
 
-    let url = format!("http://{}/text", server.addr());
-    let mut res = reqwest::get(&url).unwrap();
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"5"
-    );
+use futures::TryStreamExt;
+
+use reqwest::multipart::{Form, Part};
+use reqwest::{Body, Client};
 
-    let body = res.text().unwrap();
-    assert_eq!(b"Hello", body.as_bytes());
+use bytes::Bytes;
+
+#[tokio::test]
+async fn gzip_response() {
+    gzip_case(10_000, 4096).await;
+}
+
+#[tokio::test]
+async fn gzip_single_byte_chunks() {
+    gzip_case(10, 1).await;
 }
 
-#[test]
-fn test_response_non_utf_8_text() {
+#[tokio::test]
+async fn response_text() {
+    let _ = env_logger::try_init();
+
     let server = server! {
         request: b"\
             GET /text HTTP/1.1\r\n\
@@ -48,31 +36,27 @@ fn test_response_non_utf_8_text() {
             ",
         response: b"\
             HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 4\r\n\
-            Content-Type: text/plain; charset=gbk\r\n\
+            Content-Length: 5\r\n\
             \r\n\
-            \xc4\xe3\xba\xc3\
+            Hello\
             "
     };
 
-    let url = format!("http://{}/text", server.addr());
-    let mut res = reqwest::get(&url).unwrap();
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"4"
-    );
+    let client = Client::new();
 
-    let body = res.text().unwrap();
-    assert_eq!("你好", &body);
-    assert_eq!(b"\xe4\xbd\xa0\xe5\xa5\xbd", body.as_bytes()); // Now it's utf-8
+    let mut res = client
+        .get(&format!("http://{}/text", server.addr()))
+        .send()
+        .await
+        .expect("Failed to get");
+    let text = res.text().await.expect("Failed to get text");
+    assert_eq!("Hello", text);
 }
 
-#[test]
-fn test_response_json() {
+#[tokio::test]
+async fn response_json() {
+    let _ = env_logger::try_init();
+
     let server = server! {
         request: b"\
             GET /json HTTP/1.1\r\n\
@@ -84,204 +68,137 @@ fn test_response_json() {
             ",
         response: b"\
             HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
             Content-Length: 7\r\n\
             \r\n\
             \"Hello\"\
             "
     };
 
-    let url = format!("http://{}/json", server.addr());
-    let mut res = reqwest::get(&url).unwrap();
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"7"
-    );
+    let client = Client::new();
 
-    let body = res.json::<String>().unwrap();
-    assert_eq!("Hello", body);
+    let mut res = client
+        .get(&format!("http://{}/json", server.addr()))
+        .send()
+        .await
+        .expect("Failed to get");
+    let text = res.json::<String>().await.expect("Failed to get json");
+    assert_eq!("Hello", text);
 }
 
-#[test]
-fn test_response_copy_to() {
-    let server = server! {
-        request: b"\
-            GET /1 HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 5\r\n\
-            \r\n\
-            Hello\
-            "
-    };
-
-    let url = format!("http://{}/1", server.addr());
-    let mut res = reqwest::get(&url).unwrap();
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"5"
+#[tokio::test]
+async fn multipart() {
+    let _ = env_logger::try_init();
+
+    let stream = futures::stream::once(futures::future::ready::<Result<_, hyper::Error>>(Ok(
+        hyper::Chunk::from("part1 part2".to_owned()),
+    )));
+    let part = Part::stream(stream);
+
+    let form = Form::new().text("foo", "bar").part("part_stream", part);
+
+    let expected_body = format!(
+        "\
+         24\r\n\
+         --{0}\r\n\r\n\
+         2E\r\n\
+         Content-Disposition: form-data; name=\"foo\"\r\n\r\n\r\n\
+         3\r\n\
+         bar\r\n\
+         2\r\n\
+         \r\n\r\n\
+         24\r\n\
+         --{0}\r\n\r\n\
+         36\r\n\
+         Content-Disposition: form-data; name=\"part_stream\"\r\n\r\n\r\n\
+         B\r\n\
+         part1 part2\r\n\
+         2\r\n\
+         \r\n\r\n\
+         26\r\n\
+         --{0}--\r\n\r\n\
+         0\r\n\r\n\
+         ",
+        form.boundary()
     );
 
-    assert_eq!("Hello".to_owned(), res.text().unwrap());
-}
-
-#[test]
-fn test_get() {
     let server = server! {
-        request: b"\
-            GET /1 HTTP/1.1\r\n\
+        request: format!("\
+            POST /multipart/1 HTTP/1.1\r\n\
+            content-type: multipart/form-data; boundary={}\r\n\
             user-agent: $USERAGENT\r\n\
             accept: */*\r\n\
             accept-encoding: gzip\r\n\
             host: $HOST\r\n\
+            transfer-encoding: chunked\r\n\
             \r\n\
-            ",
+            {}\
+            ", form.boundary(), expected_body),
         response: b"\
             HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
+            Server: multipart\r\n\
             Content-Length: 0\r\n\
             \r\n\
             "
     };
 
-    let url = format!("http://{}/1", server.addr());
-    let mut res = reqwest::get(&url).unwrap();
+    let url = format!("http://{}/multipart/1", server.addr());
 
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
-    assert_eq!(res.remote_addr(), Some(server.addr()));
-
-    assert_eq!(res.text().unwrap().len(), 0)
-}
-
-#[test]
-fn test_post() {
-    let server = server! {
-        request: b"\
-            POST /2 HTTP/1.1\r\n\
-            content-length: 5\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            Hello\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: post\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
-    };
+    let client = Client::new();
 
-    let url = format!("http://{}/2", server.addr());
-    let mut res = reqwest::Client::new()
+    let res = client
         .post(&url)
-        .body("Hello")
+        .multipart(form)
         .send()
-        .unwrap();
-
+        .await
+        .expect("Failed to post multipart");
     assert_eq!(res.url().as_str(), &url);
     assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"post");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
-
-    assert_eq!(res.text().unwrap().len(), 0)
 }
 
-#[test]
-fn test_post_form() {
+#[tokio::test]
+async fn request_timeout() {
+    let _ = env_logger::try_init();
+
     let server = server! {
         request: b"\
-            POST /form HTTP/1.1\r\n\
-            content-type: application/x-www-form-urlencoded\r\n\
-            content-length: 24\r\n\
+            GET /slow HTTP/1.1\r\n\
             user-agent: $USERAGENT\r\n\
             accept: */*\r\n\
             accept-encoding: gzip\r\n\
             host: $HOST\r\n\
             \r\n\
-            hello=world&sean=monstar\
             ",
         response: b"\
             HTTP/1.1 200 OK\r\n\
-            Server: post-form\r\n\
-            Content-Length: 0\r\n\
+            Content-Length: 5\r\n\
             \r\n\
-            "
+            Hello\
+            ",
+        read_timeout: Duration::from_secs(2)
     };
 
-    let form = &[("hello", "world"), ("sean", "monstar")];
+    let client = Client::builder()
+        .timeout(Duration::from_millis(500))
+        .build()
+        .unwrap();
 
-    let url = format!("http://{}/form", server.addr());
-    let res = reqwest::Client::new()
-        .post(&url)
-        .form(form)
-        .send()
-        .expect("request send");
+    let url = format!("http://{}/slow", server.addr());
 
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-}
+    let res = client.get(&url).send().await;
 
-/// Calling `Response::error_for_status`` on a response with status in 4xx
-/// returns a error.
-#[test]
-fn test_error_for_status_4xx() {
-    let server = server! {
-        request: b"\
-            GET /1 HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 400 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
-    };
-
-    let url = format!("http://{}/1", server.addr());
-    let res = reqwest::get(&url).unwrap();
+    let err = res.unwrap_err();
 
-    let err = res.error_for_status().err().unwrap();
-    assert!(err.is_client_error());
-    assert_eq!(err.status(), Some(reqwest::StatusCode::BAD_REQUEST));
+    assert!(err.is_timeout());
+    assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
 }
 
-/// Calling `Response::error_for_status`` on a response with status in 5xx
-/// returns a error.
-#[test]
-fn test_error_for_status_5xx() {
+#[tokio::test]
+async fn response_timeout() {
+    let _ = env_logger::try_init();
+
     let server = server! {
         request: b"\
-            GET /1 HTTP/1.1\r\n\
+            GET /slow HTTP/1.1\r\n\
             user-agent: $USERAGENT\r\n\
             accept: */*\r\n\
             accept-encoding: gzip\r\n\
@@ -289,224 +206,120 @@ fn test_error_for_status_5xx() {
             \r\n\
             ",
         response: b"\
-            HTTP/1.1 500 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
+            HTTP/1.1 200 OK\r\n\
+            Content-Length: 5\r\n\
             \r\n\
-            "
+            Hello\
+            ",
+        write_timeout: Duration::from_secs(2)
     };
 
-    let url = format!("http://{}/1", server.addr());
-    let res = reqwest::get(&url).unwrap();
-
-    let err = res.error_for_status().err().unwrap();
-    assert!(err.is_server_error());
-    assert_eq!(
-        err.status(),
-        Some(reqwest::StatusCode::INTERNAL_SERVER_ERROR)
-    );
-}
-
-#[test]
-fn test_default_headers() {
-    use reqwest::header;
-    let mut headers = header::HeaderMap::with_capacity(1);
-    headers.insert(header::COOKIE, header::HeaderValue::from_static("a=b;c=d"));
-    let client = reqwest::Client::builder()
-        .default_headers(headers)
+    let client = Client::builder()
+        .timeout(Duration::from_millis(500))
         .build()
         .unwrap();
 
-    let server = server! {
-        request: b"\
-            GET /1 HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            cookie: a=b;c=d\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
-    };
+    let url = format!("http://{}/slow", server.addr());
+    let res = client.get(&url).send().await.expect("Failed to get");
+    let body: Result<_, _> = res.into_body().try_concat().await;
 
-    let url = format!("http://{}/1", server.addr());
-    let res = client.get(&url).send().unwrap();
+    let err = body.unwrap_err();
 
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
+    assert!(err.is_timeout());
+}
 
-    let server = server! {
-        request: b"\
-            GET /2 HTTP/1.1\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept: */*\r\n\
-            cookie: a=b;c=d\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
+async fn gzip_case(response_size: usize, chunk_size: usize) {
+    let content: String = (0..response_size)
+        .into_iter()
+        .map(|i| format!("test {}", i))
+        .collect();
+    let mut encoder = libflate::gzip::Encoder::new(Vec::new()).unwrap();
+    match encoder.write(content.as_bytes()) {
+        Ok(n) => assert!(n > 0, "Failed to write to encoder."),
+        _ => panic!("Failed to gzip encode string."),
     };
 
-    let url = format!("http://{}/2", server.addr());
-    let res = client.get(&url).send().unwrap();
+    let gzipped_content = encoder.finish().into_result().unwrap();
 
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
-}
-
-#[test]
-fn test_override_default_headers() {
-    use reqwest::header;
-    let mut headers = header::HeaderMap::with_capacity(1);
-    headers.insert(
-        header::AUTHORIZATION,
-        header::HeaderValue::from_static("iamatoken"),
-    );
-    let client = reqwest::Client::builder()
-        .default_headers(headers)
-        .build()
-        .unwrap();
+    let mut response = format!(
+        "\
+         HTTP/1.1 200 OK\r\n\
+         Server: test-accept\r\n\
+         Content-Encoding: gzip\r\n\
+         Content-Length: {}\r\n\
+         \r\n",
+        &gzipped_content.len()
+    )
+    .into_bytes();
+    response.extend(&gzipped_content);
 
     let server = server! {
         request: b"\
-            GET /3 HTTP/1.1\r\n\
-            authorization: secret\r\n\
+            GET /gzip HTTP/1.1\r\n\
             user-agent: $USERAGENT\r\n\
             accept: */*\r\n\
             accept-encoding: gzip\r\n\
             host: $HOST\r\n\
             \r\n\
             ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
+        chunk_size: chunk_size,
+        write_timeout: Duration::from_millis(10),
+        response: response
     };
 
-    let url = format!("http://{}/3", server.addr());
-    let res = client
-        .get(&url)
-        .header(
-            header::AUTHORIZATION,
-            header::HeaderValue::from_static("secret"),
-        )
+    let client = Client::new();
+
+    let mut res = client
+        .get(&format!("http://{}/gzip", server.addr()))
         .send()
-        .unwrap();
+        .await
+        .expect("response");
 
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
+    let body = res.text().await.expect("text");
+    assert_eq!(body, content);
 }
 
-#[test]
-fn test_appended_headers_not_overwritten() {
-    let client = reqwest::Client::new();
+#[tokio::test]
+async fn body_stream() {
+    let _ = env_logger::try_init();
 
-    let server = server! {
-        request: b"\
-            GET /4 HTTP/1.1\r\n\
-            accept: application/json\r\n\
-            accept: application/json+hal\r\n\
-            user-agent: $USERAGENT\r\n\
-            accept-encoding: gzip\r\n\
-            host: $HOST\r\n\
-            \r\n\
-            ",
-        response: b"\
-            HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
-            \r\n\
-            "
-    };
+    let source = futures::stream::iter::<Vec<Result<Bytes, std::io::Error>>>(vec![
+        Ok(Bytes::from_static(b"123")),
+        Ok(Bytes::from_static(b"4567")),
+    ]);
 
-    let url = format!("http://{}/4", server.addr());
-    let res = client
-        .get(&url)
-        .header(header::ACCEPT, "application/json")
-        .header(header::ACCEPT, "application/json+hal")
-        .send()
-        .unwrap();
-
-    assert_eq!(res.url().as_str(), &url);
-    assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
-
-    // make sure this also works with default headers
-    use reqwest::header;
-    let mut headers = header::HeaderMap::with_capacity(1);
-    headers.insert(
-        header::ACCEPT,
-        header::HeaderValue::from_static("text/html"),
-    );
-    let client = reqwest::Client::builder()
-        .default_headers(headers)
-        .build()
-        .unwrap();
+    let expected_body = "3\r\n123\r\n4\r\n4567\r\n0\r\n\r\n";
 
     let server = server! {
-        request: b"\
-            GET /4 HTTP/1.1\r\n\
-            accept: application/json\r\n\
-            accept: application/json+hal\r\n\
+        request: format!("\
+            POST /post HTTP/1.1\r\n\
             user-agent: $USERAGENT\r\n\
+            accept: */*\r\n\
             accept-encoding: gzip\r\n\
             host: $HOST\r\n\
+            transfer-encoding: chunked\r\n\
             \r\n\
-            ",
+            {}\
+            ", expected_body),
         response: b"\
             HTTP/1.1 200 OK\r\n\
-            Server: test\r\n\
-            Content-Length: 0\r\n\
+            Server: post\r\n\
+            Content-Length: 7\r\n\
             \r\n\
             "
     };
 
-    let url = format!("http://{}/4", server.addr());
+    let url = format!("http://{}/post", server.addr());
+
+    let client = Client::new();
+
     let res = client
-        .get(&url)
-        .header(header::ACCEPT, "application/json")
-        .header(header::ACCEPT, "application/json+hal")
+        .post(&url)
+        .body(Body::wrap_stream(source))
         .send()
-        .unwrap();
+        .await
+        .expect("Failed to post");
 
     assert_eq!(res.url().as_str(), &url);
     assert_eq!(res.status(), reqwest::StatusCode::OK);
-    assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test");
-    assert_eq!(
-        res.headers().get(reqwest::header::CONTENT_LENGTH).unwrap(),
-        &"0"
-    );
 }
diff --git a/tests/gzip.rs b/tests/gzip.rs
index f6d7578c6..c1bf596dc 100644
--- a/tests/gzip.rs
+++ b/tests/gzip.rs
@@ -41,7 +41,7 @@ fn test_gzip_response() {
         write_timeout: Duration::from_millis(10),
         response: response
     };
-    let mut res = reqwest::get(&format!("http://{}/gzip", server.addr())).unwrap();
+    let mut res = reqwest::blocking::get(&format!("http://{}/gzip", server.addr())).unwrap();
 
     let mut body = String::new();
     res.read_to_string(&mut body).unwrap();
@@ -68,7 +68,7 @@ fn test_gzip_empty_body() {
             \r\n"
     };
 
-    let client = reqwest::Client::new();
+    let client = reqwest::blocking::Client::new();
     let mut res = client
         .head(&format!("http://{}/gzip", server.addr()))
         .send()
@@ -100,7 +100,7 @@ fn test_gzip_invalid_body() {
             0"
     };
 
-    let mut res = reqwest::get(&format!("http://{}/gzip", server.addr())).unwrap();
+    let mut res = reqwest::blocking::get(&format!("http://{}/gzip", server.addr())).unwrap();
     // this tests that the request.send() didn't error, but that the error
     // is in reading the body
 
@@ -126,7 +126,7 @@ fn test_accept_header_is_not_changed_if_set() {
             \r\n\
             "
     };
-    let client = reqwest::Client::new();
+    let client = reqwest::blocking::Client::new();
 
     let res = client
         .get(&format!("http://{}/accept", server.addr()))
@@ -158,7 +158,7 @@ fn test_accept_encoding_header_is_not_changed_if_set() {
             \r\n\
             "
     };
-    let client = reqwest::Client::new();
+    let client = reqwest::blocking::Client::new();
 
     let res = client
         .get(&format!("http://{}/accept-encoding", server.addr()))
diff --git a/tests/multipart.rs b/tests/multipart.rs
index 0d68bd902..631ad8195 100644
--- a/tests/multipart.rs
+++ b/tests/multipart.rs
@@ -5,7 +5,7 @@ mod support;
 fn text_part() {
     let _ = env_logger::try_init();
 
-    let form = reqwest::multipart::Form::new().text("foo", "bar");
+    let form = reqwest::blocking::multipart::Form::new().text("foo", "bar");
 
     let expected_body = format!(
         "\
@@ -39,7 +39,7 @@ fn text_part() {
 
     let url = format!("http://{}/multipart/1", server.addr());
 
-    let res = reqwest::Client::new()
+    let res = reqwest::blocking::Client::new()
         .post(&url)
         .multipart(form)
         .send()
@@ -53,7 +53,7 @@ fn text_part() {
 fn file() {
     let _ = env_logger::try_init();
 
-    let form = reqwest::multipart::Form::new()
+    let form = reqwest::blocking::multipart::Form::new()
         .file("foo", "Cargo.lock")
         .unwrap();
 
@@ -93,7 +93,7 @@ fn file() {
 
     let url = format!("http://{}/multipart/2", server.addr());
 
-    let res = reqwest::Client::new()
+    let res = reqwest::blocking::Client::new()
         .post(&url)
         .multipart(form)
         .send()
diff --git a/tests/proxy.rs b/tests/proxy.rs
index 08f3b99df..2c62c32e9 100644
--- a/tests/proxy.rs
+++ b/tests/proxy.rs
@@ -3,8 +3,8 @@ mod support;
 
 use std::env;
 
-#[test]
-fn http_proxy() {
+#[tokio::test]
+async fn http_proxy() {
     let server = server! {
         request: b"\
             GET http://hyper.rs/prox HTTP/1.1\r\n\
@@ -31,6 +31,7 @@ fn http_proxy() {
         .unwrap()
         .get(url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), url);
@@ -41,8 +42,8 @@ fn http_proxy() {
     );
 }
 
-#[test]
-fn http_proxy_basic_auth() {
+#[tokio::test]
+async fn http_proxy_basic_auth() {
     let server = server! {
         request: b"\
             GET http://hyper.rs/prox HTTP/1.1\r\n\
@@ -74,6 +75,7 @@ fn http_proxy_basic_auth() {
         .unwrap()
         .get(url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), url);
@@ -84,8 +86,8 @@ fn http_proxy_basic_auth() {
     );
 }
 
-#[test]
-fn http_proxy_basic_auth_parsed() {
+#[tokio::test]
+async fn http_proxy_basic_auth_parsed() {
     let server = server! {
         request: b"\
             GET http://hyper.rs/prox HTTP/1.1\r\n\
@@ -113,6 +115,7 @@ fn http_proxy_basic_auth_parsed() {
         .unwrap()
         .get(url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), url);
@@ -123,8 +126,8 @@ fn http_proxy_basic_auth_parsed() {
     );
 }
 
-#[test]
-fn test_no_proxy() {
+#[tokio::test]
+async fn test_no_proxy() {
     let server = server! {
         request: b"\
             GET /4 HTTP/1.1\r\n\
@@ -152,14 +155,15 @@ fn test_no_proxy() {
         .unwrap()
         .get(&url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), &url);
     assert_eq!(res.status(), reqwest::StatusCode::OK);
 }
 
-#[test]
-fn test_using_system_proxy() {
+#[tokio::test]
+async fn test_using_system_proxy() {
     let server = server! {
         request: b"\
             GET http://hyper.rs/prox HTTP/1.1\r\n\
@@ -188,6 +192,7 @@ fn test_using_system_proxy() {
         .unwrap()
         .get(url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), url);
diff --git a/tests/redirect.rs b/tests/redirect.rs
index 2da9d328f..eef165362 100644
--- a/tests/redirect.rs
+++ b/tests/redirect.rs
@@ -1,8 +1,8 @@
 #[macro_use]
 mod support;
 
-#[test]
-fn test_redirect_301_and_302_and_303_changes_post_to_get() {
+#[tokio::test]
+async fn test_redirect_301_and_302_and_303_changes_post_to_get() {
     let client = reqwest::Client::new();
     let codes = [301, 302, 303];
 
@@ -45,7 +45,7 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() {
 
         let url = format!("http://{}/{}", redirect.addr(), code);
         let dst = format!("http://{}/{}", redirect.addr(), "dst");
-        let res = client.post(&url).send().unwrap();
+        let res = client.post(&url).send().await.unwrap();
         assert_eq!(res.url().as_str(), dst);
         assert_eq!(res.status(), reqwest::StatusCode::OK);
         assert_eq!(
@@ -55,8 +55,8 @@ fn test_redirect_301_and_302_and_303_changes_post_to_get() {
     }
 }
 
-#[test]
-fn test_redirect_307_and_308_tries_to_get_again() {
+#[tokio::test]
+async fn test_redirect_307_and_308_tries_to_get_again() {
     let client = reqwest::Client::new();
     let codes = [307, 308];
     for code in codes.iter() {
@@ -98,7 +98,7 @@ fn test_redirect_307_and_308_tries_to_get_again() {
 
         let url = format!("http://{}/{}", redirect.addr(), code);
         let dst = format!("http://{}/{}", redirect.addr(), "dst");
-        let res = client.get(&url).send().unwrap();
+        let res = client.get(&url).send().await.unwrap();
         assert_eq!(res.url().as_str(), dst);
         assert_eq!(res.status(), reqwest::StatusCode::OK);
         assert_eq!(
@@ -108,19 +108,19 @@ fn test_redirect_307_and_308_tries_to_get_again() {
     }
 }
 
-#[test]
-fn test_redirect_307_and_308_tries_to_post_again() {
+#[tokio::test]
+async fn test_redirect_307_and_308_tries_to_post_again() {
     let client = reqwest::Client::new();
     let codes = [307, 308];
     for code in codes.iter() {
         let redirect = server! {
             request: format!("\
                 POST /{} HTTP/1.1\r\n\
-                content-length: 5\r\n\
                 user-agent: $USERAGENT\r\n\
                 accept: */*\r\n\
                 accept-encoding: gzip\r\n\
                 host: $HOST\r\n\
+                content-length: 5\r\n\
                 \r\n\
                 Hello\
                 ", code),
@@ -136,12 +136,12 @@ fn test_redirect_307_and_308_tries_to_post_again() {
 
             request: format!("\
                 POST /dst HTTP/1.1\r\n\
-                content-length: 5\r\n\
                 user-agent: $USERAGENT\r\n\
                 accept: */*\r\n\
                 accept-encoding: gzip\r\n\
                 referer: http://$HOST/{}\r\n\
                 host: $HOST\r\n\
+                content-length: 5\r\n\
                 \r\n\
                 Hello\
                 ", code),
@@ -155,7 +155,7 @@ fn test_redirect_307_and_308_tries_to_post_again() {
 
         let url = format!("http://{}/{}", redirect.addr(), code);
         let dst = format!("http://{}/{}", redirect.addr(), "dst");
-        let res = client.post(&url).body("Hello").send().unwrap();
+        let res = client.post(&url).body("Hello").send().await.unwrap();
         assert_eq!(res.url().as_str(), dst);
         assert_eq!(res.status(), reqwest::StatusCode::OK);
         assert_eq!(
@@ -167,7 +167,7 @@ fn test_redirect_307_and_308_tries_to_post_again() {
 
 #[test]
 fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
-    let client = reqwest::Client::new();
+    let client = reqwest::blocking::Client::new();
     let codes = [307, 308];
     for &code in codes.iter() {
         let redirect = server! {
@@ -196,7 +196,7 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
         let url = format!("http://{}/{}", redirect.addr(), code);
         let res = client
             .post(&url)
-            .body(reqwest::Body::new(&b"Hello"[..]))
+            .body(reqwest::blocking::Body::new(&b"Hello"[..]))
             .send()
             .unwrap();
         assert_eq!(res.url().as_str(), url);
@@ -204,8 +204,8 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
     }
 }
 
-#[test]
-fn test_redirect_removes_sensitive_headers() {
+#[tokio::test]
+async fn test_redirect_removes_sensitive_headers() {
     let end_server = server! {
         request: b"\
             GET /otherhost HTTP/1.1\r\n\
@@ -252,11 +252,12 @@ fn test_redirect_removes_sensitive_headers() {
             reqwest::header::HeaderValue::from_static("foo=bar"),
         )
         .send()
+        .await
         .unwrap();
 }
 
-#[test]
-fn test_redirect_policy_can_return_errors() {
+#[tokio::test]
+async fn test_redirect_policy_can_return_errors() {
     let server = server! {
         request: b"\
             GET /loop HTTP/1.1\r\n\
@@ -274,13 +275,13 @@ fn test_redirect_policy_can_return_errors() {
             \r\n\
             "
     };
-
-    let err = reqwest::get(&format!("http://{}/loop", server.addr())).unwrap_err();
+    let url = format!("http://{}/loop", server.addr());
+    let err = reqwest::get(&url).await.unwrap_err();
     assert!(err.is_redirect());
 }
 
-#[test]
-fn test_redirect_policy_can_stop_redirects_without_an_error() {
+#[tokio::test]
+async fn test_redirect_policy_can_stop_redirects_without_an_error() {
     let server = server! {
         request: b"\
             GET /no-redirect HTTP/1.1\r\n\
@@ -307,6 +308,7 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() {
         .unwrap()
         .get(&url)
         .send()
+        .await
         .unwrap();
 
     assert_eq!(res.url().as_str(), url);
@@ -317,8 +319,8 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() {
     );
 }
 
-#[test]
-fn test_referer_is_not_set_if_disabled() {
+#[tokio::test]
+async fn test_referer_is_not_set_if_disabled() {
     let server = server! {
         request: b"\
             GET /no-refer HTTP/1.1\r\n\
@@ -357,14 +359,14 @@ fn test_referer_is_not_set_if_disabled() {
         .referer(false)
         .build()
         .unwrap()
-        //client
         .get(&format!("http://{}/no-refer", server.addr()))
         .send()
+        .await
         .unwrap();
 }
 
-#[test]
-fn test_invalid_location_stops_redirect_gh484() {
+#[tokio::test]
+async fn test_invalid_location_stops_redirect_gh484() {
     let server = server! {
         request: b"\
             GET /yikes HTTP/1.1\r\n\
@@ -385,7 +387,7 @@ fn test_invalid_location_stops_redirect_gh484() {
 
     let url = format!("http://{}/yikes", server.addr());
 
-    let res = reqwest::get(&url).unwrap();
+    let res = reqwest::get(&url).await.unwrap();
 
     assert_eq!(res.url().as_str(), url);
     assert_eq!(res.status(), reqwest::StatusCode::FOUND);
@@ -395,8 +397,8 @@ fn test_invalid_location_stops_redirect_gh484() {
     );
 }
 
-#[test]
-fn test_redirect_302_with_set_cookies() {
+#[tokio::test]
+async fn test_redirect_302_with_set_cookies() {
     let code = 302;
     let client = reqwest::ClientBuilder::new()
         .cookie_store(true)
@@ -442,7 +444,7 @@ fn test_redirect_302_with_set_cookies() {
 
     let url = format!("http://{}/{}", server.addr(), code);
     let dst = format!("http://{}/{}", server.addr(), "dst");
-    let res = client.get(&url).send().unwrap();
+    let res = client.get(&url).send().await.unwrap();
 
     assert_eq!(res.url().as_str(), dst);
     assert_eq!(res.status(), reqwest::StatusCode::OK);
diff --git a/tests/timeouts.rs b/tests/timeouts.rs
index 707d08e89..541c18355 100644
--- a/tests/timeouts.rs
+++ b/tests/timeouts.rs
@@ -11,7 +11,7 @@ fn timeout_closes_connection() {
 
     // Make Client drop *after* the Server, so the background doesn't
     // close too early.
-    let client = reqwest::Client::builder()
+    let client = reqwest::blocking::Client::builder()
         .timeout(Duration::from_millis(500))
         .build()
         .unwrap();
@@ -50,7 +50,7 @@ fn write_timeout_large_body() {
 
     // Make Client drop *after* the Server, so the background doesn't
     // close too early.
-    let client = reqwest::Client::builder()
+    let client = reqwest::blocking::Client::builder()
         .timeout(Duration::from_millis(500))
         .build()
         .unwrap();
@@ -80,7 +80,7 @@ fn write_timeout_large_body() {
     let url = format!("http://{}/write-timeout", server.addr());
     let err = client
         .post(&url)
-        .body(reqwest::Body::sized(cursor, len as u64))
+        .body(reqwest::blocking::Body::sized(cursor, len as u64))
         .send()
         .unwrap_err();
 
@@ -108,7 +108,7 @@ fn test_response_timeout() {
     };
 
     let url = format!("http://{}/response-timeout", server.addr());
-    let err = reqwest::Client::builder()
+    let err = reqwest::blocking::Client::builder()
         .timeout(Duration::from_millis(500))
         .build()
         .unwrap()
@@ -142,7 +142,7 @@ fn test_read_timeout() {
     };
 
     let url = format!("http://{}/read-timeout", server.addr());
-    let mut res = reqwest::Client::builder()
+    let mut res = reqwest::blocking::Client::builder()
         .timeout(Duration::from_millis(500))
         .build()
         .unwrap()