make Client: Send + Sync, RequestBuilder: Send, Response: Send
This commit is contained in:
		| @@ -21,7 +21,7 @@ impl Body { | |||||||
|     /// |     /// | ||||||
|     /// A `Body` constructed from a set of bytes, like `String` or `Vec<u8>`, |     /// A `Body` constructed from a set of bytes, like `String` or `Vec<u8>`, | ||||||
|     /// are stored differently and can be reused. |     /// are stored differently and can be reused. | ||||||
|     pub fn new<R: Read + 'static>(reader: R) -> Body { |     pub fn new<R: Read + Send + 'static>(reader: R) -> Body { | ||||||
|         Body { |         Body { | ||||||
|             reader: Kind::Reader(Box::new(reader), None), |             reader: Kind::Reader(Box::new(reader), None), | ||||||
|         } |         } | ||||||
| @@ -53,7 +53,7 @@ pub fn read_to_string(mut body: Body) -> ::std::io::Result<String> { | |||||||
| } | } | ||||||
|  |  | ||||||
| enum Kind { | enum Kind { | ||||||
|     Reader(Box<Read>, Option<u64>), |     Reader(Box<Read + Send>, Option<u64>), | ||||||
|     Bytes(Vec<u8>), |     Bytes(Vec<u8>), | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
|  | use std::fmt; | ||||||
| use std::io::{self, Read}; | use std::io::{self, Read}; | ||||||
|  | use std::sync::Arc; | ||||||
|  |  | ||||||
| use hyper::client::IntoUrl; | use hyper::client::IntoUrl; | ||||||
| use hyper::header::{Headers, ContentType, Location, Referer, UserAgent}; | use hyper::header::{Headers, ContentType, Location, Referer, UserAgent}; | ||||||
| @@ -22,9 +24,8 @@ static DEFAULT_USER_AGENT: &'static str = concat!(env!("CARGO_PKG_NAME"), "/", e | |||||||
| /// | /// | ||||||
| /// The `Client` holds a connection pool internally, so it is advised that | /// The `Client` holds a connection pool internally, so it is advised that | ||||||
| /// you create one and reuse it. | /// you create one and reuse it. | ||||||
| #[derive(Debug)] |  | ||||||
| pub struct Client { | pub struct Client { | ||||||
|     inner: ::hyper::Client, |     inner: ClientRef,  //::hyper::Client, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Client { | impl Client { | ||||||
| @@ -33,7 +34,9 @@ impl Client { | |||||||
|         let mut client = try!(new_hyper_client()); |         let mut client = try!(new_hyper_client()); | ||||||
|         client.set_redirect_policy(::hyper::client::RedirectPolicy::FollowNone); |         client.set_redirect_policy(::hyper::client::RedirectPolicy::FollowNone); | ||||||
|         Ok(Client { |         Ok(Client { | ||||||
|             inner: client |             inner: ClientRef { | ||||||
|  |                 hyper: Arc::new(client), | ||||||
|  |             } | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -59,7 +62,7 @@ impl Client { | |||||||
|     pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder { |     pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder { | ||||||
|         let url = url.into_url(); |         let url = url.into_url(); | ||||||
|         RequestBuilder { |         RequestBuilder { | ||||||
|             client: self, |             client: self.inner.clone(), | ||||||
|             method: method, |             method: method, | ||||||
|             url: url, |             url: url, | ||||||
|             _version: HttpVersion::Http11, |             _version: HttpVersion::Http11, | ||||||
| @@ -70,6 +73,17 @@ impl Client { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl fmt::Debug for Client { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |         f.pad("Client") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Clone)] | ||||||
|  | struct ClientRef { | ||||||
|  |     hyper: Arc<::hyper::Client>, | ||||||
|  | } | ||||||
|  |  | ||||||
| fn new_hyper_client() -> ::Result<::hyper::Client> { | fn new_hyper_client() -> ::Result<::hyper::Client> { | ||||||
|     use tls::TlsClient; |     use tls::TlsClient; | ||||||
|     Ok(::hyper::Client::with_connector( |     Ok(::hyper::Client::with_connector( | ||||||
| @@ -82,9 +96,8 @@ fn new_hyper_client() -> ::Result<::hyper::Client> { | |||||||
|  |  | ||||||
|  |  | ||||||
| /// A builder to construct the properties of a `Request`. | /// A builder to construct the properties of a `Request`. | ||||||
| #[derive(Debug)] | pub struct RequestBuilder { | ||||||
| pub struct RequestBuilder<'a> { |     client: ClientRef, | ||||||
|     client: &'a Client, |  | ||||||
|  |  | ||||||
|     method: Method, |     method: Method, | ||||||
|     url: Result<Url, ::UrlError>, |     url: Result<Url, ::UrlError>, | ||||||
| @@ -94,7 +107,7 @@ pub struct RequestBuilder<'a> { | |||||||
|     body: Option<::Result<Body>>, |     body: Option<::Result<Body>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> RequestBuilder<'a> { | impl RequestBuilder { | ||||||
|     /// Add a `Header` to this Request. |     /// Add a `Header` to this Request. | ||||||
|     /// |     /// | ||||||
|     /// ```no_run |     /// ```no_run | ||||||
| @@ -105,20 +118,20 @@ impl<'a> RequestBuilder<'a> { | |||||||
|     ///     .header(UserAgent("foo".to_string())) |     ///     .header(UserAgent("foo".to_string())) | ||||||
|     ///     .send(); |     ///     .send(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn header<H: ::header::Header + ::header::HeaderFormat>(mut self, header: H) -> RequestBuilder<'a> { |     pub fn header<H: ::header::Header + ::header::HeaderFormat>(mut self, header: H) -> RequestBuilder { | ||||||
|         self.headers.set(header); |         self.headers.set(header); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|     /// Add a set of Headers to the existing ones on this Request. |     /// Add a set of Headers to the existing ones on this Request. | ||||||
|     /// |     /// | ||||||
|     /// The headers will be merged in to any already set. |     /// The headers will be merged in to any already set. | ||||||
|     pub fn headers(mut self, headers: ::header::Headers) -> RequestBuilder<'a> { |     pub fn headers(mut self, headers: ::header::Headers) -> RequestBuilder { | ||||||
|         self.headers.extend(headers.iter()); |         self.headers.extend(headers.iter()); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Set the request body. |     /// Set the request body. | ||||||
|     pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder<'a> { |     pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder { | ||||||
|         self.body = Some(Ok(body.into())); |         self.body = Some(Ok(body.into())); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| @@ -139,7 +152,7 @@ impl<'a> RequestBuilder<'a> { | |||||||
|     ///     .form(¶ms) |     ///     .form(¶ms) | ||||||
|     ///     .send(); |     ///     .send(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn form<T: Serialize>(mut self, form: &T) -> RequestBuilder<'a> { |     pub fn form<T: Serialize>(mut self, form: &T) -> RequestBuilder { | ||||||
|         let body = serde_urlencoded::to_string(form).map_err(::Error::from); |         let body = serde_urlencoded::to_string(form).map_err(::Error::from); | ||||||
|         self.headers.set(ContentType::form_url_encoded()); |         self.headers.set(ContentType::form_url_encoded()); | ||||||
|         self.body = Some(body.map(|b| b.into())); |         self.body = Some(body.map(|b| b.into())); | ||||||
| @@ -161,7 +174,7 @@ impl<'a> RequestBuilder<'a> { | |||||||
|     ///     .json(&map) |     ///     .json(&map) | ||||||
|     ///     .send(); |     ///     .send(); | ||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn json<T: Serialize>(mut self, json: &T) -> RequestBuilder<'a> { |     pub fn json<T: Serialize>(mut self, json: &T) -> RequestBuilder { | ||||||
|         let body = serde_json::to_vec(json).expect("serde to_vec cannot fail"); |         let body = serde_json::to_vec(json).expect("serde to_vec cannot fail"); | ||||||
|         self.headers.set(ContentType::json()); |         self.headers.set(ContentType::json()); | ||||||
|         self.body = Some(Ok(body.into())); |         self.body = Some(Ok(body.into())); | ||||||
| @@ -188,7 +201,7 @@ impl<'a> RequestBuilder<'a> { | |||||||
|         loop { |         loop { | ||||||
|             let res = { |             let res = { | ||||||
|                 debug!("request {:?} \"{}\"", method, url); |                 debug!("request {:?} \"{}\"", method, url); | ||||||
|                 let mut req = client.inner.request(method.clone(), url.clone()) |                 let mut req = client.hyper.request(method.clone(), url.clone()) | ||||||
|                     .headers(headers.clone()); |                     .headers(headers.clone()); | ||||||
|  |  | ||||||
|                 if let Some(ref mut b) = body { |                 if let Some(ref mut b) = body { | ||||||
| @@ -265,29 +278,42 @@ impl<'a> RequestBuilder<'a> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | 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() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| /// A Response to a submitted `Request`. | /// A Response to a submitted `Request`. | ||||||
| #[derive(Debug)] |  | ||||||
| pub struct Response { | pub struct Response { | ||||||
|     inner: ::hyper::client::Response, |     inner: ::hyper::client::Response, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Response { | impl Response { | ||||||
|     /// Get the `StatusCode`. |     /// Get the `StatusCode`. | ||||||
|  |     #[inline] | ||||||
|     pub fn status(&self) -> &StatusCode { |     pub fn status(&self) -> &StatusCode { | ||||||
|         &self.inner.status |         &self.inner.status | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the `Headers`. |     /// Get the `Headers`. | ||||||
|  |     #[inline] | ||||||
|     pub fn headers(&self) -> &Headers { |     pub fn headers(&self) -> &Headers { | ||||||
|         &self.inner.headers |         &self.inner.headers | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the `HttpVersion`. |     /// Get the `HttpVersion`. | ||||||
|  |     #[inline] | ||||||
|     pub fn version(&self) -> &HttpVersion { |     pub fn version(&self) -> &HttpVersion { | ||||||
|         &self.inner.version |         &self.inner.version | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Try and deserialize the response body as JSON. |     /// Try and deserialize the response body as JSON. | ||||||
|  |     #[inline] | ||||||
|     pub fn json<T: Deserialize>(&mut self) -> ::Result<T> { |     pub fn json<T: Deserialize>(&mut self) -> ::Result<T> { | ||||||
|         serde_json::from_reader(self).map_err(::Error::from) |         serde_json::from_reader(self).map_err(::Error::from) | ||||||
|     } |     } | ||||||
| @@ -295,10 +321,22 @@ impl Response { | |||||||
|  |  | ||||||
| /// Read the body of the Response. | /// Read the body of the Response. | ||||||
| impl Read for Response { | impl Read for Response { | ||||||
|  |     #[inline] | ||||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||||
|         self.inner.read(buf) |         self.inner.read(buf) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl fmt::Debug for Response { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |         f.debug_struct("Response") | ||||||
|  |             .field("status", self.status()) | ||||||
|  |             .field("headers", self.headers()) | ||||||
|  |             .field("version", self.version()) | ||||||
|  |             .finish() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use super::*; |     use super::*; | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -120,3 +120,14 @@ pub fn get<T: IntoUrl>(url: T) -> ::Result<Response> { | |||||||
|     let client = try!(Client::new()); |     let client = try!(Client::new()); | ||||||
|     client.get(url).send() |     client.get(url).send() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn _assert_impls() { | ||||||
|  |     fn assert_send<T: Send>() {} | ||||||
|  |     fn assert_sync<T: Sync>() {} | ||||||
|  |  | ||||||
|  |     assert_send::<Client>(); | ||||||
|  |     assert_sync::<Client>(); | ||||||
|  |  | ||||||
|  |     assert_send::<RequestBuilder>(); | ||||||
|  |     assert_send::<Response>(); | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user