Merge pull request #428 from hyperium/client-box

feat(client): remove generic parameter for Connector
This commit is contained in:
Sean McArthur
2015-04-07 18:26:27 -07:00
4 changed files with 64 additions and 37 deletions

View File

@@ -27,7 +27,7 @@ use url::ParseError as UrlError;
use header::{Headers, Header, HeaderFormat}; use header::{Headers, Header, HeaderFormat};
use header::{ContentLength, Location}; use header::{ContentLength, Location};
use method::Method; use method::Method;
use net::{NetworkConnector, HttpConnector, ContextVerifier}; use net::{NetworkConnector, NetworkStream, HttpConnector, ContextVerifier};
use status::StatusClass::Redirection; use status::StatusClass::Redirection;
use {Url, HttpResult}; use {Url, HttpResult};
use HttpError::HttpUriError; use HttpError::HttpUriError;
@@ -41,68 +41,65 @@ pub mod response;
/// A Client to use additional features with Requests. /// A Client to use additional features with Requests.
/// ///
/// Clients can handle things such as: redirect policy. /// Clients can handle things such as: redirect policy.
pub struct Client<C> { pub struct Client {
connector: C, connector: Connector,
redirect_policy: RedirectPolicy, redirect_policy: RedirectPolicy,
} }
impl<'v> Client<HttpConnector<'v>> { impl Client {
/// Create a new Client. /// Create a new Client.
pub fn new() -> Client<HttpConnector<'v>> { pub fn new() -> Client {
Client::with_connector(HttpConnector(None)) Client::with_connector(HttpConnector(None))
} }
/// Set the SSL verifier callback for use with OpenSSL.
pub fn set_ssl_verifier(&mut self, verifier: ContextVerifier<'v>) {
self.connector = HttpConnector(Some(verifier));
}
}
impl<C: NetworkConnector> Client<C> {
/// Create a new client with a specific connector. /// Create a new client with a specific connector.
pub fn with_connector(connector: C) -> Client<C> { pub fn with_connector<C, S>(connector: C) -> Client
where C: NetworkConnector<Stream=S> + Send + 'static, S: NetworkStream + Send {
Client { Client {
connector: connector, connector: with_connector(connector),
redirect_policy: Default::default() redirect_policy: Default::default()
} }
} }
/// Set the SSL verifier callback for use with OpenSSL.
pub fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
self.connector = with_connector(HttpConnector(Some(verifier)));
}
/// Set the RedirectPolicy. /// Set the RedirectPolicy.
pub fn set_redirect_policy(&mut self, policy: RedirectPolicy) { pub fn set_redirect_policy(&mut self, policy: RedirectPolicy) {
self.redirect_policy = policy; self.redirect_policy = policy;
} }
/// Build a Get request. /// Build a Get request.
pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
self.request(Method::Get, url) self.request(Method::Get, url)
} }
/// Build a Head request. /// Build a Head request.
pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
self.request(Method::Head, url) self.request(Method::Head, url)
} }
/// Build a Post request. /// Build a Post request.
pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
self.request(Method::Post, url) self.request(Method::Post, url)
} }
/// Build a Put request. /// Build a Put request.
pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
self.request(Method::Put, url) self.request(Method::Put, url)
} }
/// Build a Delete request. /// Build a Delete request.
pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U, C> { pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> {
self.request(Method::Delete, url) self.request(Method::Delete, url)
} }
/// Build a new request using this Client. /// Build a new request using this Client.
pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U, C> { pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U> {
RequestBuilder { RequestBuilder {
client: self, client: self,
method: method, method: method,
@@ -113,34 +110,60 @@ impl<C: NetworkConnector> Client<C> {
} }
} }
fn with_connector<C: NetworkConnector<Stream=S> + Send + 'static, S: NetworkStream + Send>(c: C) -> Connector {
Connector(Box::new(ConnAdapter(c)))
}
struct ConnAdapter<C: NetworkConnector + Send>(C);
impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> {
type Stream = Box<NetworkStream + Send>;
#[inline]
fn connect(&mut self, host: &str, port: u16, scheme: &str)
-> io::Result<Box<NetworkStream + Send>> {
Ok(try!(self.0.connect(host, port, scheme)).into())
}
}
struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send>);
impl NetworkConnector for Connector {
type Stream = Box<NetworkStream + Send>;
#[inline]
fn connect(&mut self, host: &str, port: u16, scheme: &str)
-> io::Result<Box<NetworkStream + Send>> {
Ok(try!(self.0.connect(host, port, scheme)).into())
}
}
/// Options for an individual Request. /// Options for an individual Request.
/// ///
/// One of these will be built for you if you use one of the convenience /// One of these will be built for you if you use one of the convenience
/// methods, such as `get()`, `post()`, etc. /// methods, such as `get()`, `post()`, etc.
pub struct RequestBuilder<'a, U: IntoUrl, C: NetworkConnector + 'a> { pub struct RequestBuilder<'a, U: IntoUrl> {
client: &'a mut Client<C>, client: &'a mut Client,
url: U, url: U,
headers: Option<Headers>, headers: Option<Headers>,
method: Method, method: Method,
body: Option<Body<'a>>, body: Option<Body<'a>>,
} }
impl<'a, U: IntoUrl, C: NetworkConnector> RequestBuilder<'a, U, C> { impl<'a, U: IntoUrl> RequestBuilder<'a, U> {
/// Set a request body to be sent. /// Set a request body to be sent.
pub fn body<B: IntoBody<'a>>(mut self, body: B) -> RequestBuilder<'a, U, C> { pub fn body<B: IntoBody<'a>>(mut self, body: B) -> RequestBuilder<'a, U> {
self.body = Some(body.into_body()); self.body = Some(body.into_body());
self self
} }
/// Add additional headers to the request. /// Add additional headers to the request.
pub fn headers(mut self, headers: Headers) -> RequestBuilder<'a, U, C> { pub fn headers(mut self, headers: Headers) -> RequestBuilder<'a, U> {
self.headers = Some(headers); self.headers = Some(headers);
self self
} }
/// Add an individual new header to the request. /// Add an individual new header to the request.
pub fn header<H: Header + HeaderFormat>(mut self, header: H) -> RequestBuilder<'a, U, C> { pub fn header<H: Header + HeaderFormat>(mut self, header: H) -> RequestBuilder<'a, U> {
{ {
let mut headers = match self.headers { let mut headers = match self.headers {
Some(ref mut h) => h, Some(ref mut h) => h,

View File

@@ -51,13 +51,11 @@ impl Request<Fresh> {
pub fn with_connector<C, S>(method: method::Method, url: Url, connector: &mut C) pub fn with_connector<C, S>(method: method::Method, url: Url, connector: &mut C)
-> HttpResult<Request<Fresh>> where -> HttpResult<Request<Fresh>> where
C: NetworkConnector<Stream=S>, C: NetworkConnector<Stream=S>,
S: NetworkStream + Send { S: Into<Box<NetworkStream + Send>> {
debug!("{} {}", method, url); debug!("{} {}", method, url);
let (host, port) = try!(get_host_and_port(&url)); let (host, port) = try!(get_host_and_port(&url));
let stream = try!(connector.connect(&*host, port, &*url.scheme)); let stream = try!(connector.connect(&*host, port, &*url.scheme)).into();
// FIXME: Use Type ascription
let stream: Box<NetworkStream + Send> = Box::new(stream);
let stream = ThroughWriter(BufWriter::new(stream)); let stream = ThroughWriter(BufWriter::new(stream));
let mut headers = Headers::new(); let mut headers = Headers::new();

View File

@@ -190,6 +190,7 @@ mod mimewrapper {
#[allow(unconditional_recursion)] #[allow(unconditional_recursion)]
fn _assert_send<T: Send>() { fn _assert_send<T: Send>() {
_assert_send::<Client>();
_assert_send::<client::Request<net::Fresh>>(); _assert_send::<client::Request<net::Fresh>>();
_assert_send::<client::Response>(); _assert_send::<client::Response>();
} }

View File

@@ -75,11 +75,17 @@ impl<T: NetworkStream + Send + Clone> StreamClone for T {
/// A connector creates a NetworkStream. /// A connector creates a NetworkStream.
pub trait NetworkConnector { pub trait NetworkConnector {
/// Type of Stream to create /// Type of Stream to create
type Stream: NetworkStream + Send; type Stream: Into<Box<NetworkStream + Send>>;
/// Connect to a remote address. /// Connect to a remote address.
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>; fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
} }
impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> {
fn from(s: T) -> Box<NetworkStream + Send> {
Box::new(s)
}
}
impl fmt::Debug for Box<NetworkStream + Send> { impl fmt::Debug for Box<NetworkStream + Send> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.pad("Box<NetworkStream>") fmt.pad("Box<NetworkStream>")
@@ -284,13 +290,12 @@ impl NetworkStream for HttpStream {
} }
/// A connector that will produce HttpStreams. /// A connector that will produce HttpStreams.
#[allow(missing_copy_implementations)] pub struct HttpConnector(pub Option<ContextVerifier>);
pub struct HttpConnector<'v>(pub Option<ContextVerifier<'v>>);
/// A method that can set verification methods on an SSL context /// A method that can set verification methods on an SSL context
pub type ContextVerifier<'v> = Box<FnMut(&mut SslContext) -> ()+'v>; pub type ContextVerifier = Box<FnMut(&mut SslContext) -> () + Send>;
impl<'v> NetworkConnector for HttpConnector<'v> { impl NetworkConnector for HttpConnector {
type Stream = HttpStream; type Stream = HttpStream;
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> { fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {