Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(client): impl Sync for Client #563

Merged
merged 1 commit into from
Jun 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn main() {
}
};

let mut client = Client::new();
let client = Client::new();

let mut res = client.get(&*url)
.header(Connection::close())
Expand Down
2 changes: 1 addition & 1 deletion examples/client_http2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {
}
};

let mut client = Client::with_protocol(h2::new_protocol());
let client = Client::with_protocol(h2::new_protocol());

// `Connection: Close` is not a valid header for HTTP/2, but the client handles it gracefully.
let mut res = client.get(&*url)
Expand Down
46 changes: 35 additions & 11 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//!
//! ```no_run
//! # use hyper::Client;
//! let mut client = Client::new();
//! let client = Client::new();
//!
//! let res = client.get("http://example.domain").send().unwrap();
//! assert_eq!(res.status, hyper::Ok);
Expand All @@ -23,14 +23,38 @@
//!
//! ```no_run
//! # use hyper::Client;
//! let mut client = Client::new();
//! let client = Client::new();
//!
//! let res = client.post("http://example.domain")
//! .body("foo=bar")
//! .send()
//! .unwrap();
//! assert_eq!(res.status, hyper::Ok);
//! ```
//!
//! # Sync
//!
//! The `Client` implements `Sync`, so you can share it among multiple threads
//! and make multiple requests simultaneously.
//!
//! ```no_run
//! # use hyper::Client;
//! use std::sync::Arc;
//! use std::thread;
//!
//! // Note: an Arc is used here because `thread::spawn` creates threads that
//! // can outlive the main thread, so we must use reference counting to keep
//! // the Client alive long enough. Scoped threads could skip the Arc.
//! let client = Arc::new(Client::new());
//! let clone1 = client.clone();
//! let clone2 = client.clone();
//! thread::spawn(move || {
//! clone1.get("http://example.domain").send().unwrap();
//! });
//! thread::spawn(move || {
//! clone2.post("http://example.domain/post").body("foo=bar").send().unwrap();
//! });
//! ```
use std::default::Default;
use std::io::{self, copy, Read};
use std::iter::Extend;
Expand Down Expand Up @@ -61,7 +85,7 @@ use http::h1::Http11Protocol;
///
/// Clients can handle things such as: redirect policy, connection pooling.
pub struct Client {
protocol: Box<Protocol + Send>,
protocol: Box<Protocol + Send + Sync>,
redirect_policy: RedirectPolicy,
}

Expand All @@ -79,12 +103,12 @@ impl Client {

/// Create a new client with a specific connector.
pub fn with_connector<C, S>(connector: C) -> Client
where C: NetworkConnector<Stream=S> + Send + 'static, S: NetworkStream + Send {
where C: NetworkConnector<Stream=S> + Send + Sync + 'static, S: NetworkStream + Send {
Client::with_protocol(Http11Protocol::with_connector(connector))
}

/// Create a new client with a specific `Protocol`.
pub fn with_protocol<P: Protocol + Send + 'static>(protocol: P) -> Client {
pub fn with_protocol<P: Protocol + Send + Sync + 'static>(protocol: P) -> Client {
Client {
protocol: Box::new(protocol),
redirect_policy: Default::default()
Expand All @@ -102,33 +126,33 @@ impl Client {
}

/// Build a Get request.
pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Get, url)
}

/// Build a Head request.
pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Head, url)
}

/// Build a Post request.
pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Post, url)
}

/// Build a Put request.
pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Put, url)
}

/// Build a Delete request.
pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> {
self.request(Method::Delete, url)
}


/// Build a new request using this Client.
pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U> {
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder<U> {
RequestBuilder {
client: self,
method: method,
Expand Down
8 changes: 4 additions & 4 deletions src/http/h1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,17 +275,17 @@ impl Http11Protocol {
/// Creates a new `Http11Protocol` instance that will use the given `NetworkConnector` for
/// establishing HTTP connections.
pub fn with_connector<C, S>(c: C) -> Http11Protocol
where C: NetworkConnector<Stream=S> + Send + 'static,
where C: NetworkConnector<Stream=S> + Send + Sync + 'static,
S: NetworkStream + Send {
Http11Protocol {
connector: Connector(Box::new(ConnAdapter(c))),
}
}
}

struct ConnAdapter<C: NetworkConnector + Send>(C);
struct ConnAdapter<C: NetworkConnector + Send + Sync>(C);

impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> {
impl<C: NetworkConnector<Stream=S> + Send + Sync, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> {
type Stream = Box<NetworkStream + Send>;
#[inline]
fn connect(&self, host: &str, port: u16, scheme: &str)
Expand All @@ -298,7 +298,7 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne
}
}

struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send>);
struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send + Sync>);

impl NetworkConnector for Connector {
type Stream = Box<NetworkStream + Send>;
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,8 @@ fn _assert_send<T: Send>() {
_assert_send::<client::Request<net::Fresh>>();
_assert_send::<client::Response>();
}

#[allow(unconditional_recursion)]
fn _assert_sync<T: Sync>() {
_assert_sync::<Client>();
}
8 changes: 4 additions & 4 deletions src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ impl NetworkConnector for MockConnector {
///
/// Otherwise, it behaves the same as `MockConnector`.
pub struct ChannelMockConnector {
calls: Sender<String>,
calls: Mutex<Sender<String>>,
}

impl ChannelMockConnector {
pub fn new(calls: Sender<String>) -> ChannelMockConnector {
ChannelMockConnector { calls: calls }
ChannelMockConnector { calls: Mutex::new(calls) }
}
}

Expand All @@ -158,13 +158,13 @@ impl NetworkConnector for ChannelMockConnector {
#[inline]
fn connect(&self, _host: &str, _port: u16, _scheme: &str)
-> ::Result<MockStream> {
self.calls.send("connect".into()).unwrap();
self.calls.lock().unwrap().send("connect".into()).unwrap();
Ok(MockStream::new())
}

#[inline]
fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
self.calls.send("set_ssl_verifier".into()).unwrap();
self.calls.lock().unwrap().send("set_ssl_verifier".into()).unwrap();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ impl NetworkStream for HttpStream {
pub struct HttpConnector(pub Option<ContextVerifier>);

/// A method that can set verification methods on an SSL context
pub type ContextVerifier = Box<Fn(&mut SslContext) -> () + Send>;
pub type ContextVerifier = Box<Fn(&mut SslContext) -> () + Send + Sync>;

impl NetworkConnector for HttpConnector {
type Stream = HttpStream;
Expand Down