Merge pull request #428 from hyperium/client-box
feat(client): remove generic parameter for Connector
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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>();
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/net.rs
15
src/net.rs
@@ -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> {
|
||||||
|
|||||||
Reference in New Issue
Block a user