diff --git a/README.md b/README.md index 6d4c333..d20bcb1 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,29 @@ preparing breaking changes, for most recently released code, look to the ## Example -```rust,no_run -extern crate reqwest; +Async: +```rust,no_run +use std::collections::HashMap; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let resp: HashMap = reqwest::get("https://httpbin.org/ip") + .await? + .json() + .await?; + println!("{:#?}", resp); + Ok(()) +} +``` + +Blocking: + +```rust,no_run use std::collections::HashMap; fn main() -> Result<(), Box> { - let resp: HashMap = reqwest::get("https://httpbin.org/ip")? + let resp: HashMap = 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 c4dad41..0000000 --- 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 d52a60f..0000000 --- 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) -> Result -where - F: Future>, -{ - let mut resp = f.await?; - resp.json::().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 0000000..32ecabe --- /dev/null +++ b/examples/blocking.rs @@ -0,0 +1,19 @@ +//! `cargo run --example blocking` +#![deny(warnings)] + +fn main() -> Result<(), Box> { + 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 7c8d059..cfdb6e4 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 1a31f61..5673420 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 1cbd218..16a329f 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 73753da..c42f83e 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,19 +1,17 @@ -//! `cargo run --example simple` #![deny(warnings)] -fn main() -> Result<(), Box> { - 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 dd4ac00..9afbc25 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> = vec![ diff --git a/src/async_impl/multipart.rs b/src/async_impl/multipart.rs index 48ec7d1..96c9c94 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 a3e1d30..18f9f48 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 4413457..4f7e39c 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> { - /// 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 5712af4..8519814 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> { /// 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> { /// 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> { /// 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 e34e54e..59dc3b5 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 0000000..6d54f37 --- /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`, 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(url: T) -> crate::Result { + 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 1b7bc46..0f1cecf 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> { //! 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 e994b8e..87f3a0d 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> { - /// 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> { /// 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(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> { - /// 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> { - /// 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> { - /// 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> { - /// 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> { /// // from bytes! /// let bytes: Vec = 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(¶ms) /// .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> { - /// 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 { + pub fn send(self) -> crate::Result { self.client.execute(self.request?) } @@ -510,7 +486,7 @@ impl RequestBuilder { /// /// ```rust /// # fn run() -> Result<(), Box> { - /// 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> { - /// 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> { - /// 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 cd68dcf..798a622 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> { - /// 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> { /// 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> { @@ -136,7 +137,7 @@ impl Response { /// /// ```rust /// # fn run() -> Result<(), Box> { - /// 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> { - /// 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> { - /// 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> { - /// 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> { - /// 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 = 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> { - /// 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 { let Response { body, @@ -335,7 +336,7 @@ impl Response { /// ```rust,no_run /// # extern crate reqwest; /// # fn run() -> Result<(), Box> { - /// 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 69d1d49..e18dc1a 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 { -/// reqwest::get("http://httpbin.org/ip")?.json() +/// async fn make_request() -> Result { +/// 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::()) { /// 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 { match self.inner.kind { Kind::Status(code) => Some(code), @@ -466,15 +459,15 @@ impl From for Kind { } } -impl From> for Kind +impl From> for Kind where T: Into, { - fn from(err: crate::wait::Waited) -> Kind { + fn from(err: crate::blocking::Waited) -> 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 cd144ff..524ec34 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`, 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(¶ms) -//! .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(url: T) -> crate::Result { - Client::builder().build()?.get(url).send() +pub async fn get(url: T) -> crate::Result { + Client::builder().build()?.get(url).send().await } fn _assert_impls() { diff --git a/tests/async.rs b/tests/async.rs deleted file mode 100644 index d8a6ea7..0000000 --- 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::().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::>(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![ - 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 eb843f5..d3c2850 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("mozilla-modern.badssl.com")); } #[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("mozilla-modern.badssl.com")); } #[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("self-signed.badssl.com")); } #[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("wrong.host.badssl.com")); @@ -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 0000000..d41c0f4 --- /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::().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 85ba691..598e812 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -1,8 +1,30 @@ #[macro_use] mod support; -#[test] -fn test_response_text() { +use std::io::Write; +use std::time::Duration; + +use futures::TryStreamExt; + +use reqwest::multipart::{Form, Part}; +use reqwest::{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\ @@ -14,65 +36,27 @@ fn test_response_text() { ", 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::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 client = Client::new(); - let body = res.text().unwrap(); - assert_eq!(b"Hello", body.as_bytes()); + 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_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\ - " - }; +#[tokio::test] +async fn response_json() { + let _ = env_logger::try_init(); - 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 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\ @@ -84,32 +68,100 @@ 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::().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::().await.expect("Failed to get json"); + assert_eq!("Hello", text); } -#[test] -fn test_response_copy_to() { +#[tokio::test] +async fn multipart() { + let _ = env_logger::try_init(); + + let stream = futures::stream::once(futures::future::ready::>(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 /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\ @@ -118,31 +170,35 @@ fn test_response_copy_to() { ", response: b"\ HTTP/1.1 200 OK\r\n\ - Server: test\r\n\ Content-Length: 5\r\n\ \r\n\ Hello\ - " + ", + read_timeout: Duration::from_secs(2) }; - 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" - ); + let client = Client::builder() + .timeout(Duration::from_millis(500)) + .build() + .unwrap(); - assert_eq!("Hello".to_owned(), res.text().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())); } -#[test] -fn test_get() { +#[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\ @@ -151,362 +207,119 @@ fn test_get() { ", 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::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\ + 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![ + 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: 0\r\n\ + Content-Length: 7\r\n\ \r\n\ " }; - let url = format!("http://{}/2", server.addr()); - let mut res = reqwest::Client::new() + let url = format!("http://{}/post", server.addr()); + + let client = Client::new(); + + let res = client .post(&url) - .body("Hello") + .body(Body::wrap_stream(source)) .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::Client::new() - .post(&url) - .form(form) - .send() - .expect("request send"); + .await + .expect("Failed to post"); 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::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::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) - .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::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::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::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/gzip.rs b/tests/gzip.rs index f6d7578..c1bf596 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 0d68bd9..631ad81 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 08f3b99..2c62c32 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 2da9d32..eef1653 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 707d08e..541c183 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()