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>`,
|
||||
/// 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 {
|
||||
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 {
|
||||
Reader(Box<Read>, Option<u64>),
|
||||
Reader(Box<Read + Send>, Option<u64>),
|
||||
Bytes(Vec<u8>),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::io::{self, Read};
|
||||
use std::sync::Arc;
|
||||
|
||||
use hyper::client::IntoUrl;
|
||||
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
|
||||
/// you create one and reuse it.
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
inner: ::hyper::Client,
|
||||
inner: ClientRef, //::hyper::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
@@ -33,7 +34,9 @@ impl Client {
|
||||
let mut client = try!(new_hyper_client());
|
||||
client.set_redirect_policy(::hyper::client::RedirectPolicy::FollowNone);
|
||||
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 {
|
||||
let url = url.into_url();
|
||||
RequestBuilder {
|
||||
client: self,
|
||||
client: self.inner.clone(),
|
||||
method: method,
|
||||
url: url,
|
||||
_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> {
|
||||
use tls::TlsClient;
|
||||
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`.
|
||||
#[derive(Debug)]
|
||||
pub struct RequestBuilder<'a> {
|
||||
client: &'a Client,
|
||||
pub struct RequestBuilder {
|
||||
client: ClientRef,
|
||||
|
||||
method: Method,
|
||||
url: Result<Url, ::UrlError>,
|
||||
@@ -94,7 +107,7 @@ pub struct RequestBuilder<'a> {
|
||||
body: Option<::Result<Body>>,
|
||||
}
|
||||
|
||||
impl<'a> RequestBuilder<'a> {
|
||||
impl RequestBuilder {
|
||||
/// Add a `Header` to this Request.
|
||||
///
|
||||
/// ```no_run
|
||||
@@ -105,20 +118,20 @@ impl<'a> RequestBuilder<'a> {
|
||||
/// .header(UserAgent("foo".to_string()))
|
||||
/// .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
|
||||
}
|
||||
/// 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<'a> {
|
||||
pub fn headers(mut self, headers: ::header::Headers) -> RequestBuilder {
|
||||
self.headers.extend(headers.iter());
|
||||
self
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
@@ -139,7 +152,7 @@ impl<'a> RequestBuilder<'a> {
|
||||
/// .form(¶ms)
|
||||
/// .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);
|
||||
self.headers.set(ContentType::form_url_encoded());
|
||||
self.body = Some(body.map(|b| b.into()));
|
||||
@@ -161,7 +174,7 @@ impl<'a> RequestBuilder<'a> {
|
||||
/// .json(&map)
|
||||
/// .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");
|
||||
self.headers.set(ContentType::json());
|
||||
self.body = Some(Ok(body.into()));
|
||||
@@ -188,7 +201,7 @@ impl<'a> RequestBuilder<'a> {
|
||||
loop {
|
||||
let res = {
|
||||
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());
|
||||
|
||||
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`.
|
||||
#[derive(Debug)]
|
||||
pub struct Response {
|
||||
inner: ::hyper::client::Response,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Get the `StatusCode`.
|
||||
#[inline]
|
||||
pub fn status(&self) -> &StatusCode {
|
||||
&self.inner.status
|
||||
}
|
||||
|
||||
/// Get the `Headers`.
|
||||
#[inline]
|
||||
pub fn headers(&self) -> &Headers {
|
||||
&self.inner.headers
|
||||
}
|
||||
|
||||
/// Get the `HttpVersion`.
|
||||
#[inline]
|
||||
pub fn version(&self) -> &HttpVersion {
|
||||
&self.inner.version
|
||||
}
|
||||
|
||||
/// Try and deserialize the response body as JSON.
|
||||
#[inline]
|
||||
pub fn json<T: Deserialize>(&mut self) -> ::Result<T> {
|
||||
serde_json::from_reader(self).map_err(::Error::from)
|
||||
}
|
||||
@@ -295,10 +321,22 @@ impl Response {
|
||||
|
||||
/// Read the body of the Response.
|
||||
impl Read for Response {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
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)]
|
||||
mod tests {
|
||||
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());
|
||||
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