diff --git a/src/client.rs b/src/client.rs index 112a0be..346a3c0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,21 +3,17 @@ use std::sync::Arc; use std::time::Duration; use hyper::client::IntoUrl; -use hyper::header::{Headers, ContentType, Location, Referer, UserAgent, Accept, Encoding, +use hyper::header::{Location, Referer, UserAgent, Accept, Encoding, AcceptEncoding, Range, qitem}; use hyper::method::Method; use hyper::status::StatusCode; -use hyper::version::HttpVersion; use hyper::Url; use hyper_native_tls::{NativeTlsClient, native_tls}; -use serde::Serialize; -use serde_json; -use serde_urlencoded; - -use body::{self, Body}; +use body; use redirect::{self, RedirectPolicy, check_redirect, remove_sensitive_headers}; +use request::{self, Request, RequestBuilder}; use response::Response; static DEFAULT_USER_AGENT: &'static str = @@ -38,7 +34,7 @@ static DEFAULT_USER_AGENT: &'static str = /// # /// # fn run() -> Result<(), Error> { /// let client = Client::new()?; -/// let resp = client.get("http://httpbin.org/").send()?; +/// let resp = client.get("http://httpbin.org/")?.send()?; /// # drop(resp); /// # Ok(()) /// # } @@ -262,32 +258,32 @@ impl Client { } /// Convenience method to make a `GET` request to a URL. - pub fn get(&self, url: U) -> RequestBuilder { + pub fn get(&self, url: U) -> ::Result { self.request(Method::Get, url) } /// Convenience method to make a `POST` request to a URL. - pub fn post(&self, url: U) -> RequestBuilder { + pub fn post(&self, url: U) -> ::Result { self.request(Method::Post, url) } /// Convenience method to make a `PUT` request to a URL. - pub fn put(&self, url: U) -> RequestBuilder { + pub fn put(&self, url: U) -> ::Result { self.request(Method::Put, url) } /// Convenience method to make a `PATCH` request to a URL. - pub fn patch(&self, url: U) -> RequestBuilder { + pub fn patch(&self, url: U) -> ::Result { self.request(Method::Patch, url) } /// Convenience method to make a `DELETE` request to a URL. - pub fn delete(&self, url: U) -> RequestBuilder { + pub fn delete(&self, url: U) -> ::Result { self.request(Method::Delete, url) } /// Convenience method to make a `HEAD` request to a URL. - pub fn head(&self, url: U) -> RequestBuilder { + pub fn head(&self, url: U) -> ::Result { self.request(Method::Head, url) } @@ -295,17 +291,9 @@ impl Client { /// /// Returns a `RequestBuilder`, which will allow setting headers and /// request body before sending. - pub fn request(&self, method: Method, url: U) -> RequestBuilder { - let url = url.into_url(); - RequestBuilder { - client: self.clone(), - method: method, - url: url, - _version: HttpVersion::Http11, - headers: Headers::new(), - - body: None, - } + pub fn request(&self, method: Method, url: U) -> ::Result { + let url = try_!(url.into_url()); + Ok(request::builder(self.clone(), Request::new(method, url))) } /// Executes a `Request`. @@ -338,8 +326,14 @@ struct ClientRef { } impl ClientRef { - fn execute_request(&self, request: Request) -> ::Result { - let mut headers = request.headers; + fn execute_request(&self, req: Request) -> ::Result { + let ( + mut method, + mut url, + mut headers, + mut body + ) = request::pieces(req); + if !headers.has::() { headers.set(UserAgent(DEFAULT_USER_AGENT.to_owned())); } @@ -352,9 +346,6 @@ impl ClientRef { !headers.has::() { headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)])); } - let mut method = request.method; - let mut url = request.url; - let mut body = request.body; let mut urls = Vec::new(); @@ -446,231 +437,6 @@ impl ClientRef { } } -/// A request which can be executed with `Client::execute()`. -pub struct Request { - method: Method, - url: Url, - headers: Headers, - body: Option, -} - -impl Request { - /// Constructs a new request. - #[inline] - pub fn new(method: Method, url: Url) -> Self { - Request { - method, - url, - headers: Headers::new(), - body: None, - } - } - - /// Get the method. - #[inline] - pub fn method(&self) -> &Method { - &self.method - } - - /// Get a mutable reference to the method. - #[inline] - pub fn method_mut(&mut self) -> &mut Method { - &mut self.method - } - - /// Get the url. - #[inline] - pub fn url(&self) -> &Url { - &self.url - } - - /// Get a mutable reference to the url. - #[inline] - pub fn url_mut(&mut self) -> &mut Url { - &mut self.url - } - - /// Get the headers. - #[inline] - pub fn headers(&self) -> &Headers { - &self.headers - } - - /// Get a mutable reference to the headers. - #[inline] - pub fn headers_mut(&mut self) -> &mut Headers { - &mut self.headers - } - - /// Get the body. - #[inline] - pub fn body(&self) -> Option<&Body> { - self.body.as_ref() - } - - /// Get a mutable reference to the body. - #[inline] - pub fn body_mut(&mut self) -> &mut Option { - &mut self.body - } -} - -/// A builder to construct the properties of a `Request`. -pub struct RequestBuilder { - client: Client, - - method: Method, - url: Result, - _version: HttpVersion, - headers: Headers, - - body: Option<::Result>, -} - -impl RequestBuilder { - /// Add a `Header` to this Request. - /// - /// ```rust - /// # use reqwest::Error; - /// # - /// # fn run() -> Result<(), Error> { - /// use reqwest::header::UserAgent; - /// let client = reqwest::Client::new()?; - /// - /// let res = client.get("https://www.rust-lang.org") - /// .header(UserAgent("foo".to_string())) - /// .send()?; - /// # Ok(()) - /// # } - /// ``` - pub fn header(mut self, header: H) -> RequestBuilder - where - H: ::header::Header + ::header::HeaderFormat, - { - self.headers.set(header); - self - } - /// Add a set of Headers to the existing ones on this Request. - /// - /// The headers will be merged in to any already set. - pub fn headers(mut self, headers: ::header::Headers) -> RequestBuilder { - self.headers.extend(headers.iter()); - self - } - - /// Enable HTTP basic authentication. - pub fn basic_auth(self, username: U, password: Option

) -> RequestBuilder - where - U: Into, - P: Into, - { - self.header(::header::Authorization(::header::Basic{ - username: username.into(), - password: password.map(|p| p.into()), - })) - } - - /// Set the request body. - pub fn body>(mut self, body: T) -> RequestBuilder { - self.body = Some(Ok(body.into())); - self - } - - /// Send a form body. - /// - /// Sets the body to the url encoded serialization of the passed value, - /// and also sets the `Content-Type: application/www-form-url-encoded` - /// header. - /// - /// ```rust - /// # use reqwest::Error; - /// # use std::collections::HashMap; - /// # - /// # fn run() -> Result<(), Error> { - /// let mut params = HashMap::new(); - /// params.insert("lang", "rust"); - /// - /// let client = reqwest::Client::new()?; - /// let res = client.post("http://httpbin.org") - /// .form(¶ms) - /// .send()?; - /// # Ok(()) - /// # } - /// ``` - pub fn form(mut self, form: &T) -> RequestBuilder { - let body = serde_urlencoded::to_string(form).map_err(::error::from); - self.headers.set(ContentType::form_url_encoded()); - self.body = Some(body.map(|b| b.into())); - self - } - - /// Send a JSON body. - /// - /// Sets the body to the JSON serialization of the passed value, and - /// also sets the `Content-Type: application/json` header. - /// - /// ```rust - /// # use reqwest::Error; - /// # use std::collections::HashMap; - /// # - /// # fn run() -> Result<(), Error> { - /// let mut map = HashMap::new(); - /// map.insert("lang", "rust"); - /// - /// let client = reqwest::Client::new()?; - /// let res = client.post("http://httpbin.org") - /// .json(&map)? - /// .send()?; - /// # Ok(()) - /// # } - /// ``` - /// - /// # Errors - /// - /// Serialization can fail if `T`'s implementation of `Serialize` decides to - /// fail, or if `T` contains a map with non-string keys. - pub fn json(mut self, json: &T) -> ::Result { - let body = serde_json::to_vec(json).map_err(::error::from)?; - self.headers.set(ContentType::json()); - self.body = Some(Ok(body.into())); - Ok(self) - } - - /// Build a `Request`, which can be inspected, modified and executed with - /// `Client::execute()`. - pub fn build(self) -> ::Result { - let url = try_!(self.url); - let body = match self.body { - Some(b) => Some(try_!(b)), - None => None, - }; - let req = Request { - method: self.method, - url: url, - headers: self.headers, - body: body, - }; - Ok(req) - } - - /// Constructs the Request and sends it the target URL, returning a Response. - pub fn send(self) -> ::Result { - let client = self.client.clone(); - let request = self.build()?; - client.execute(request) - } -} - -impl fmt::Debug for RequestBuilder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("RequestBuilder") - .field("method", &self.method) - .field("url", &self.url) - .field("headers", &self.headers) - .finish() - } -} - fn make_referer(next: &Url, previous: &Url) -> Option { if next.scheme() == "http" && previous.scheme() == "https" { return None; @@ -682,190 +448,3 @@ fn make_referer(next: &Url, previous: &Url) -> Option { referer.set_fragment(None); Some(Referer(referer.into_string())) } - -#[cfg(test)] -mod tests { - use super::*; - use body; - use hyper::method::Method; - use hyper::Url; - use hyper::header::{Host, Headers, ContentType}; - use std::collections::HashMap; - use serde_urlencoded; - use serde_json; - - #[test] - fn basic_get_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let r = client.get(some_url); - - assert_eq!(r.method, Method::Get); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn basic_head_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let r = client.head(some_url); - - assert_eq!(r.method, Method::Head); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn basic_post_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let r = client.post(some_url); - - assert_eq!(r.method, Method::Post); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn basic_put_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com"; - let r = client.put(some_url); - - assert_eq!(r.method, Method::Put); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn basic_patch_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com"; - let r = client.patch(some_url); - - assert_eq!(r.method, Method::Patch); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn basic_delete_request() { - let client = Client::new().unwrap(); - let some_url = "https://google.com"; - let r = client.delete(some_url); - - assert_eq!(r.method, Method::Delete); - assert_eq!(r.url, Url::parse(some_url)); - } - - #[test] - fn add_header() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let mut r = client.post(some_url); - - let header = Host { - hostname: "google.com".to_string(), - port: None, - }; - - // Add a copy of the header to the request builder - r = r.header(header.clone()); - - // then check it was actually added - assert_eq!(r.headers.get::(), Some(&header)); - } - - #[test] - fn add_headers() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let mut r = client.post(some_url); - - let header = Host { - hostname: "google.com".to_string(), - port: None, - }; - - let mut headers = Headers::new(); - headers.set(header); - - // Add a copy of the headers to the request builder - r = r.headers(headers.clone()); - - // then make sure they were added correctly - assert_eq!(r.headers, headers); - } - - #[test] - fn add_body() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let mut r = client.post(some_url); - - let body = "Some interesting content"; - - r = r.body(body); - - let buf = body::read_to_string(r.body.unwrap().unwrap()).unwrap(); - - assert_eq!(buf, body); - } - - #[test] - fn add_form() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let mut r = client.post(some_url); - - let mut form_data = HashMap::new(); - form_data.insert("foo", "bar"); - - r = r.form(&form_data); - - // Make sure the content type was set - assert_eq!(r.headers.get::(), - Some(&ContentType::form_url_encoded())); - - let buf = body::read_to_string(r.body.unwrap().unwrap()).unwrap(); - - let body_should_be = serde_urlencoded::to_string(&form_data).unwrap(); - assert_eq!(buf, body_should_be); - } - - #[test] - fn add_json() { - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let mut r = client.post(some_url); - - let mut json_data = HashMap::new(); - json_data.insert("foo", "bar"); - - r = r.json(&json_data).unwrap(); - - // Make sure the content type was set - assert_eq!(r.headers.get::(), Some(&ContentType::json())); - - let buf = body::read_to_string(r.body.unwrap().unwrap()).unwrap(); - - let body_should_be = serde_json::to_string(&json_data).unwrap(); - assert_eq!(buf, body_should_be); - } - - #[test] - fn add_json_fail() { - use serde::{Serialize, Serializer}; - use serde::ser::Error; - struct MyStruct; - impl Serialize for MyStruct { - fn serialize(&self, _serializer: S) -> Result - where S: Serializer - { - Err(S::Error::custom("nope")) - } - } - - let client = Client::new().unwrap(); - let some_url = "https://google.com/"; - let r = client.post(some_url); - let json_data = MyStruct{}; - assert!(r.json(&json_data).unwrap_err().is_serialization()); - } -} diff --git a/src/lib.rs b/src/lib.rs index dc29d57..e635264 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ //! # //! # fn run() -> Result<(), Error> { //! let client = reqwest::Client::new()?; -//! let res = client.post("http://httpbin.org/post") +//! let res = client.post("http://httpbin.org/post")? //! .body("the exact body that is sent") //! .send()?; //! # Ok(()) @@ -77,8 +77,8 @@ //! // 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) +//! let res = client.post("http://httpbin.org/post")? +//! .form(¶ms)? //! .send()?; //! # Ok(()) //! # } @@ -101,7 +101,7 @@ //! map.insert("body", "json"); //! //! let client = reqwest::Client::new()?; -//! let res = client.post("http://httpbin.org/post") +//! let res = client.post("http://httpbin.org/post")? //! .json(&map)? //! .send()?; //! # Ok(()) @@ -156,16 +156,18 @@ pub use hyper::version::HttpVersion; pub use hyper::Url; pub use url::ParseError as UrlError; -pub use self::client::{Certificate, Client, ClientBuilder, RequestBuilder}; +pub use self::client::{Certificate, Client, ClientBuilder}; pub use self::error::{Error, Result}; pub use self::body::Body; pub use self::redirect::RedirectPolicy; +pub use self::request::{Request, RequestBuilder}; pub use self::response::Response; mod error; mod body; mod client; mod redirect; +mod request; mod response; @@ -203,8 +205,9 @@ mod response; /// # } /// ``` pub fn get(url: T) -> ::Result { - let client = try!(Client::new()); - client.get(url).send() + Client::new()? + .get(url)? + .send() } fn _assert_impls() { @@ -216,9 +219,10 @@ fn _assert_impls() { assert_sync::(); assert_clone::(); + assert_send::(); assert_send::(); - assert_send::(); + assert_send::(); assert_send::(); assert_sync::(); diff --git a/src/request.rs b/src/request.rs new file mode 100644 index 0000000..5d8b3e6 --- /dev/null +++ b/src/request.rs @@ -0,0 +1,451 @@ +use std::fmt; + +use hyper::header::ContentType; +use serde::Serialize; +use serde_json; +use serde_urlencoded; + +use header::Headers; +use {Body, Client, Method, Url}; + +/// A request which can be executed with `Client::execute()`. +pub struct Request { + method: Method, + url: Url, + headers: Headers, + body: Option, +} + +/// A builder to construct the properties of a `Request`. +pub struct RequestBuilder { + client: Client, + request: Option, +} + +impl Request { + /// Constructs a new request. + #[inline] + pub fn new(method: Method, url: Url) -> Self { + Request { + method, + url, + headers: Headers::new(), + body: None, + } + } + + /// Get the method. + #[inline] + pub fn method(&self) -> &Method { + &self.method + } + + /// Get a mutable reference to the method. + #[inline] + pub fn method_mut(&mut self) -> &mut Method { + &mut self.method + } + + /// Get the url. + #[inline] + pub fn url(&self) -> &Url { + &self.url + } + + /// Get a mutable reference to the url. + #[inline] + pub fn url_mut(&mut self) -> &mut Url { + &mut self.url + } + + /// Get the headers. + #[inline] + pub fn headers(&self) -> &Headers { + &self.headers + } + + /// Get a mutable reference to the headers. + #[inline] + pub fn headers_mut(&mut self) -> &mut Headers { + &mut self.headers + } + + /// Get the body. + #[inline] + pub fn body(&self) -> Option<&Body> { + self.body.as_ref() + } + + /// Get a mutable reference to the body. + #[inline] + pub fn body_mut(&mut self) -> &mut Option { + &mut self.body + } +} + +impl RequestBuilder { + /// Add a `Header` to this Request. + /// + /// ```rust + /// # use reqwest::Error; + /// # + /// # fn run() -> Result<(), Error> { + /// use reqwest::header::UserAgent; + /// let client = reqwest::Client::new()?; + /// + /// let res = client.get("https://www.rust-lang.org")? + /// .header(UserAgent("foo".to_string())) + /// .send()?; + /// # Ok(()) + /// # } + /// ``` + pub fn header(&mut self, header: H) -> &mut RequestBuilder + where + H: ::header::Header + ::header::HeaderFormat, + { + self.request_mut().headers.set(header); + self + } + /// Add a set of Headers to the existing ones on this Request. + /// + /// The headers will be merged in to any already set. + pub fn headers(&mut self, headers: ::header::Headers) -> &mut RequestBuilder { + self.request_mut().headers.extend(headers.iter()); + self + } + + /// Enable HTTP basic authentication. + pub fn basic_auth(&mut self, username: U, password: Option

) -> &mut RequestBuilder + where + U: Into, + P: Into, + { + self.header(::header::Authorization(::header::Basic { + username: username.into(), + password: password.map(|p| p.into()), + })) + } + + /// Set the request body. + pub fn body>(&mut self, body: T) -> &mut RequestBuilder { + self.request_mut().body = Some(body.into()); + self + } + + /// Send a form body. + /// + /// Sets the body to the url encoded serialization of the passed value, + /// and also sets the `Content-Type: application/www-form-url-encoded` + /// header. + /// + /// ```rust + /// # use reqwest::Error; + /// # use std::collections::HashMap; + /// # + /// # fn run() -> Result<(), Error> { + /// let mut params = HashMap::new(); + /// params.insert("lang", "rust"); + /// + /// let client = reqwest::Client::new()?; + /// let res = client.post("http://httpbin.org")? + /// .form(¶ms)? + /// .send()?; + /// # Ok(()) + /// # } + /// ``` + pub fn form(&mut self, form: &T) -> ::Result<&mut RequestBuilder> { + { + // check request_mut() before running serde + let mut req = self.request_mut(); + let body = try_!(serde_urlencoded::to_string(form)); + req.headers.set(ContentType::form_url_encoded()); + req.body = Some(body.into()); + } + Ok(self) + } + + /// Send a JSON body. + /// + /// Sets the body to the JSON serialization of the passed value, and + /// also sets the `Content-Type: application/json` header. + /// + /// ```rust + /// # use reqwest::Error; + /// # use std::collections::HashMap; + /// # + /// # fn run() -> Result<(), Error> { + /// let mut map = HashMap::new(); + /// map.insert("lang", "rust"); + /// + /// let client = reqwest::Client::new()?; + /// let res = client.post("http://httpbin.org")? + /// .json(&map)? + /// .send()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// # Errors + /// + /// Serialization can fail if `T`'s implementation of `Serialize` decides to + /// fail, or if `T` contains a map with non-string keys. + pub fn json(&mut self, json: &T) -> ::Result<&mut RequestBuilder> { + { + // check request_mut() before running serde + let mut req = self.request_mut(); + let body = try_!(serde_json::to_vec(json)); + req.headers.set(ContentType::json()); + req.body = Some(body.into()); + } + Ok(self) + } + + /// Build a `Request`, which can be inspected, modified and executed with + /// `Client::execute()`. + pub fn build(&mut self) -> Request { + self.request + .take() + .expect("RequestBuilder cannot be reused after builder a Request") + } + + /// Constructs the Request and sends it the target URL, returning a Response. + pub fn send(&mut self) -> ::Result<::Response> { + let request = self.build(); + self.client.execute(request) + } + + // private + + fn request_mut(&mut self) -> &mut Request { + self.request + .as_mut() + .expect("RequestBuilder cannot be reused after builder a Request") + } +} + +impl fmt::Debug for Request { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt_request_fields(&mut f.debug_struct("Request"), self) + .finish() + } +} + +impl fmt::Debug for RequestBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref req) = self.request { + fmt_request_fields(&mut f.debug_struct("RequestBuilder"), req) + .finish() + } else { + f.debug_tuple("RequestBuilder") + .field(&"Consumed") + .finish() + } + } +} + +fn fmt_request_fields<'a, 'b>(f: &'a mut fmt::DebugStruct<'a, 'b>, req: &Request) -> &'a mut fmt::DebugStruct<'a, 'b> { + f.field("method", &req.method) + .field("url", &req.url) + .field("headers", &req.headers) +} + +// pub(crate) + +#[inline] +pub fn builder(client: Client, req: Request) -> RequestBuilder { + RequestBuilder { + client: client, + request: Some(req), + } +} + +#[inline] +pub fn pieces(req: Request) -> (Method, Url, Headers, Option) { + (req.method, req.url, req.headers, req.body) +} + +#[cfg(test)] +mod tests { + use body; + use client::Client; + use hyper::method::Method; + use hyper::header::{Host, Headers, ContentType}; + use std::collections::HashMap; + use serde_urlencoded; + use serde_json; + + #[test] + fn basic_get_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.get(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Get); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn basic_head_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.head(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Head); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn basic_post_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.post(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Post); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn basic_put_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.put(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Put); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn basic_patch_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.patch(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Patch); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn basic_delete_request() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let r = client.delete(some_url).unwrap().build(); + + assert_eq!(r.method, Method::Delete); + assert_eq!(r.url.as_str(), some_url); + } + + #[test] + fn add_header() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + + let header = Host { + hostname: "google.com".to_string(), + port: None, + }; + + // Add a copy of the header to the request builder + let r = r.header(header.clone()).build(); + + // then check it was actually added + assert_eq!(r.headers.get::(), Some(&header)); + } + + #[test] + fn add_headers() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + + let header = Host { + hostname: "google.com".to_string(), + port: None, + }; + + let mut headers = Headers::new(); + headers.set(header); + + // Add a copy of the headers to the request builder + let r = r.headers(headers.clone()).build(); + + // then make sure they were added correctly + assert_eq!(r.headers, headers); + } + + #[test] + fn add_body() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + + let body = "Some interesting content"; + + let r = r.body(body).build(); + + let buf = body::read_to_string(r.body.unwrap()).unwrap(); + + assert_eq!(buf, body); + } + + #[test] + fn add_form() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + + let mut form_data = HashMap::new(); + form_data.insert("foo", "bar"); + + let r = r.form(&form_data).unwrap().build(); + + // Make sure the content type was set + assert_eq!(r.headers.get::(), + Some(&ContentType::form_url_encoded())); + + let buf = body::read_to_string(r.body.unwrap()).unwrap(); + + let body_should_be = serde_urlencoded::to_string(&form_data).unwrap(); + assert_eq!(buf, body_should_be); + } + + #[test] + fn add_json() { + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + + let mut json_data = HashMap::new(); + json_data.insert("foo", "bar"); + + let r = r.json(&json_data).unwrap().build(); + + // Make sure the content type was set + assert_eq!(r.headers.get::(), Some(&ContentType::json())); + + let buf = body::read_to_string(r.body.unwrap()).unwrap(); + + let body_should_be = serde_json::to_string(&json_data).unwrap(); + assert_eq!(buf, body_should_be); + } + + #[test] + fn add_json_fail() { + use serde::{Serialize, Serializer}; + use serde::ser::Error; + struct MyStruct; + impl Serialize for MyStruct { + fn serialize(&self, _serializer: S) -> Result + where S: Serializer + { + Err(S::Error::custom("nope")) + } + } + + let client = Client::new().unwrap(); + let some_url = "https://google.com/"; + let mut r = client.post(some_url).unwrap(); + let json_data = MyStruct{}; + assert!(r.json(&json_data).unwrap_err().is_serialization()); + } +} diff --git a/tests/client.rs b/tests/client.rs index 9f26968..bc4ad5e 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -86,7 +86,10 @@ 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) + .unwrap() + .send() + .unwrap(); assert_eq!(res.url().as_str(), dst); assert_eq!(res.status(), &reqwest::StatusCode::Ok); assert_eq!(res.headers().get(), @@ -140,7 +143,11 @@ 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) + .unwrap() + .body("Hello") + .send() + .unwrap(); assert_eq!(res.url().as_str(), dst); assert_eq!(res.status(), &reqwest::StatusCode::Ok); assert_eq!(res.headers().get(), @@ -179,6 +186,7 @@ fn test_redirect_307_does_not_try_if_reader_cannot_reset() { let url = format!("http://{}/{}", redirect.addr(), code); let res = client .post(&url) + .unwrap() .body(reqwest::Body::new(&b"Hello"[..])) .send() .unwrap(); @@ -231,6 +239,7 @@ fn test_redirect_removes_sensitive_headers() { .build() .unwrap() .get(&format!("http://{}/sensitive", mid_server.addr())) + .unwrap() .header(reqwest::header::Cookie(vec![String::from("foo=bar")])) .send() .unwrap(); @@ -288,6 +297,7 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() { .build() .unwrap() .get(&url) + .unwrap() .send() .unwrap(); @@ -337,6 +347,7 @@ fn test_referer_is_not_set_if_disabled() { .build().unwrap() //client .get(&format!("http://{}/no-refer", server.addr())) + .unwrap() .send() .unwrap(); } @@ -363,6 +374,7 @@ fn test_accept_header_is_not_changed_if_set() { let res = client .get(&format!("http://{}/accept", server.addr())) + .unwrap() .header(reqwest::header::Accept::json()) .send() .unwrap(); @@ -391,6 +403,7 @@ fn test_accept_encoding_header_is_not_changed_if_set() { let client = reqwest::Client::new().unwrap(); let res = client.get(&format!("http://{}/accept-encoding", server.addr())) + .unwrap() .header(reqwest::header::AcceptEncoding( vec![reqwest::header::qitem(reqwest::header::Encoding::Identity)] )) @@ -463,6 +476,7 @@ fn test_gzip_empty_body() { let client = reqwest::Client::new().unwrap(); let mut res = client .head(&format!("http://{}/gzip", server.addr())) + .unwrap() .send() .unwrap();