1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

use actix-connect crate

This commit is contained in:
Nikolay Kim 2019-03-13 14:41:40 -07:00
parent f627d01055
commit 1941aa0217
16 changed files with 280 additions and 300 deletions

View File

@ -31,7 +31,7 @@ path = "src/lib.rs"
default = ["fail"] default = ["fail"]
# openssl # openssl
ssl = ["openssl", "actix-connector/ssl"] ssl = ["openssl", "actix-connect/ssl"]
# failure integration. it is on by default, it will be off in future versions # failure integration. it is on by default, it will be off in future versions
# actix itself does not use failure anymore # actix itself does not use failure anymore
@ -40,7 +40,8 @@ fail = ["failure"]
[dependencies] [dependencies]
actix-service = "0.3.4" actix-service = "0.3.4"
actix-codec = "0.1.1" actix-codec = "0.1.1"
actix-connector = "0.3.0" #actix-connector = "0.3.0"
actix-connect = { path="../actix-net/actix-connect" }
actix-utils = "0.3.4" actix-utils = "0.3.4"
actix-server-config = "0.1.0" actix-server-config = "0.1.0"
@ -71,6 +72,7 @@ sha1 = "0.6"
slab = "0.4" slab = "0.4"
serde_urlencoded = "0.5.3" serde_urlencoded = "0.5.3"
time = "0.1" time = "0.1"
tokio-tcp = "0.1.3"
tokio-timer = "0.2" tokio-timer = "0.2"
tokio-current-thread = "0.1" tokio-current-thread = "0.1"
trust-dns-resolver = { version="0.11.0-alpha.2", default-features = false } trust-dns-resolver = { version="0.11.0-alpha.2", default-features = false }

View File

@ -8,7 +8,7 @@ fn main() -> Result<(), Error> {
env_logger::init(); env_logger::init();
System::new("test").block_on(lazy(|| { System::new("test").block_on(lazy(|| {
let mut connector = client::Connector::default().service(); let mut connector = client::Connector::new().service();
client::ClientRequest::get("https://www.rust-lang.org/") // <- Create request builder client::ClientRequest::get("https://www.rust-lang.org/") // <- Create request builder
.header("User-Agent", "Actix-web") .header("User-Agent", "Actix-web")

View File

@ -1,8 +1,7 @@
use actix_connector::{RequestHost, RequestPort};
use http::uri::Uri; use http::uri::Uri;
use http::{Error as HttpError, HttpTryFrom}; use http::HttpTryFrom;
use super::error::{ConnectorError, InvalidUrlKind}; use super::error::InvalidUrl;
use super::pool::Key; use super::pool::Key;
#[derive(Debug)] #[derive(Debug)]
@ -19,7 +18,7 @@ impl Connect {
} }
/// Construct `Uri` instance and create `Connect` message. /// Construct `Uri` instance and create `Connect` message.
pub fn try_from<U>(uri: U) -> Result<Connect, HttpError> pub fn try_from<U>(uri: U) -> Result<Connect, InvalidUrl>
where where
Uri: HttpTryFrom<U>, Uri: HttpTryFrom<U>,
{ {
@ -40,30 +39,26 @@ impl Connect {
self.uri.authority_part().unwrap().clone().into() self.uri.authority_part().unwrap().clone().into()
} }
pub(crate) fn validate(&self) -> Result<(), ConnectorError> { pub(crate) fn validate(&self) -> Result<(), InvalidUrl> {
if self.uri.host().is_none() { if self.uri.host().is_none() {
Err(ConnectorError::InvalidUrl(InvalidUrlKind::MissingHost)) Err(InvalidUrl::MissingHost)
} else if self.uri.scheme_part().is_none() { } else if self.uri.scheme_part().is_none() {
Err(ConnectorError::InvalidUrl(InvalidUrlKind::MissingScheme)) Err(InvalidUrl::MissingScheme)
} else if let Some(scheme) = self.uri.scheme_part() { } else if let Some(scheme) = self.uri.scheme_part() {
match scheme.as_str() { match scheme.as_str() {
"http" | "ws" | "https" | "wss" => Ok(()), "http" | "ws" | "https" | "wss" => Ok(()),
_ => Err(ConnectorError::InvalidUrl(InvalidUrlKind::UnknownScheme)), _ => Err(InvalidUrl::UnknownScheme),
} }
} else { } else {
Ok(()) Ok(())
} }
} }
}
impl RequestHost for Connect { pub(crate) fn host(&self) -> &str {
fn host(&self) -> &str {
&self.uri.host().unwrap() &self.uri.host().unwrap()
} }
}
impl RequestPort for Connect { pub(crate) fn port(&self) -> u16 {
fn port(&self) -> u16 {
if let Some(port) = self.uri.port() { if let Some(port) = self.uri.port() {
port port
} else if let Some(scheme) = self.uri.scheme_part() { } else if let Some(scheme) = self.uri.scheme_part() {

View File

@ -1,14 +1,16 @@
use std::fmt;
use std::marker::PhantomData;
use std::time::Duration; use std::time::Duration;
use actix_codec::{AsyncRead, AsyncWrite}; use actix_codec::{AsyncRead, AsyncWrite};
use actix_connector::{Resolver, TcpConnector}; use actix_connect::{default_connector, Stream};
use actix_service::{Service, ServiceExt}; use actix_service::{apply_fn, Service, ServiceExt};
use actix_utils::timeout::{TimeoutError, TimeoutService}; use actix_utils::timeout::{TimeoutError, TimeoutService};
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; use tokio_tcp::TcpStream;
use super::connect::Connect; use super::connect::Connect;
use super::connection::Connection; use super::connection::Connection;
use super::error::ConnectorError; use super::error::ConnectError;
use super::pool::{ConnectionPool, Protocol}; use super::pool::{ConnectionPool, Protocol};
#[cfg(feature = "ssl")] #[cfg(feature = "ssl")]
@ -19,20 +21,28 @@ type SslConnector = ();
/// Http client connector builde instance. /// Http client connector builde instance.
/// `Connector` type uses builder-like pattern for connector service construction. /// `Connector` type uses builder-like pattern for connector service construction.
pub struct Connector { pub struct Connector<T, U> {
resolver: Resolver<Connect>, connector: T,
timeout: Duration, timeout: Duration,
conn_lifetime: Duration, conn_lifetime: Duration,
conn_keep_alive: Duration, conn_keep_alive: Duration,
disconnect_timeout: Duration, disconnect_timeout: Duration,
limit: usize, limit: usize,
#[allow(dead_code)] #[allow(dead_code)]
connector: SslConnector, ssl: SslConnector,
_t: PhantomData<U>,
} }
impl Default for Connector { impl Connector<(), ()> {
fn default() -> Connector { pub fn new() -> Connector<
let connector = { impl Service<
Request = actix_connect::Connect,
Response = Stream<TcpStream>,
Error = actix_connect::ConnectError,
> + Clone,
TcpStream,
> {
let ssl = {
#[cfg(feature = "ssl")] #[cfg(feature = "ssl")]
{ {
use log::error; use log::error;
@ -49,30 +59,51 @@ impl Default for Connector {
}; };
Connector { Connector {
connector, ssl,
resolver: Resolver::default(), connector: default_connector(),
timeout: Duration::from_secs(1), timeout: Duration::from_secs(1),
conn_lifetime: Duration::from_secs(75), conn_lifetime: Duration::from_secs(75),
conn_keep_alive: Duration::from_secs(15), conn_keep_alive: Duration::from_secs(15),
disconnect_timeout: Duration::from_millis(3000), disconnect_timeout: Duration::from_millis(3000),
limit: 100, limit: 100,
_t: PhantomData,
} }
} }
} }
impl Connector { impl<T, U> Connector<T, U> {
/// Use custom resolver. /// Use custom connector.
pub fn resolver(mut self, resolver: Resolver<Connect>) -> Self { pub fn connector<T1, U1>(self, connector: T1) -> Connector<T1, U1>
self.resolver = resolver;; where
self U1: AsyncRead + AsyncWrite + fmt::Debug,
} T1: Service<
Request = actix_connect::Connect,
/// Use custom resolver configuration. Response = Stream<U1>,
pub fn resolver_config(mut self, cfg: ResolverConfig, opts: ResolverOpts) -> Self { Error = actix_connect::ConnectError,
self.resolver = Resolver::new(cfg, opts); > + Clone,
self {
Connector {
connector,
timeout: self.timeout,
conn_lifetime: self.conn_lifetime,
conn_keep_alive: self.conn_keep_alive,
disconnect_timeout: self.disconnect_timeout,
limit: self.limit,
ssl: self.ssl,
_t: PhantomData,
}
}
} }
impl<T, U> Connector<T, U>
where
U: AsyncRead + AsyncWrite + fmt::Debug + 'static,
T: Service<
Request = actix_connect::Connect,
Response = Stream<U>,
Error = actix_connect::ConnectError,
> + Clone,
{
/// Connection timeout, i.e. max time to connect to remote host including dns name resolution. /// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
/// Set to 1 second by default. /// Set to 1 second by default.
pub fn timeout(mut self, timeout: Duration) -> Self { pub fn timeout(mut self, timeout: Duration) -> Self {
@ -83,7 +114,7 @@ impl Connector {
#[cfg(feature = "ssl")] #[cfg(feature = "ssl")]
/// Use custom `SslConnector` instance. /// Use custom `SslConnector` instance.
pub fn ssl(mut self, connector: SslConnector) -> Self { pub fn ssl(mut self, connector: SslConnector) -> Self {
self.connector = connector; self.ssl = connector;
self self
} }
@ -133,24 +164,18 @@ impl Connector {
/// Finish configuration process and create connector service. /// Finish configuration process and create connector service.
pub fn service( pub fn service(
self, self,
) -> impl Service< ) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
Request = Connect, + Clone {
Response = impl Connection,
Error = ConnectorError,
> + Clone {
#[cfg(not(feature = "ssl"))] #[cfg(not(feature = "ssl"))]
{ {
let connector = TimeoutService::new( let connector = TimeoutService::new(
self.timeout, self.timeout,
self.resolver.map_err(ConnectorError::from).and_then( self.connector
TcpConnector::default() .map(|stream| (stream.into_parts().0, Protocol::Http1)),
.from_err()
.map(|(msg, io)| (msg, io, Protocol::Http1)),
),
) )
.map_err(|e| match e { .map_err(|e| match e {
TimeoutError::Service(e) => e, TimeoutError::Service(e) => e,
TimeoutError::Timeout => ConnectorError::Timeout, TimeoutError::Timeout => ConnectError::Timeout,
}); });
connect_impl::InnerConnector { connect_impl::InnerConnector {
@ -166,48 +191,49 @@ impl Connector {
#[cfg(feature = "ssl")] #[cfg(feature = "ssl")]
{ {
const H2: &[u8] = b"h2"; const H2: &[u8] = b"h2";
use actix_connector::ssl::OpensslConnector; use actix_connect::ssl::OpensslConnector;
let ssl_service = TimeoutService::new( let ssl_service = TimeoutService::new(
self.timeout, self.timeout,
self.resolver apply_fn(self.connector.clone(), |msg: Connect, srv| {
.clone() srv.call(actix_connect::Connect::new(msg.host(), msg.port()))
.map_err(ConnectorError::from) })
.and_then(TcpConnector::default().from_err()) .map_err(ConnectError::from)
.and_then( .and_then(
OpensslConnector::service(self.connector) OpensslConnector::service(self.ssl)
.map_err(ConnectorError::from) .map_err(ConnectError::from)
.map(|(msg, io)| { .map(|stream| {
let h2 = io let sock = stream.into_parts().0;
let h2 = sock
.get_ref() .get_ref()
.ssl() .ssl()
.selected_alpn_protocol() .selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2)) .map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false); .unwrap_or(false);
if h2 { if h2 {
(msg, io, Protocol::Http2) (sock, Protocol::Http2)
} else { } else {
(msg, io, Protocol::Http1) (sock, Protocol::Http1)
} }
}), }),
), ),
) )
.map_err(|e| match e { .map_err(|e| match e {
TimeoutError::Service(e) => e, TimeoutError::Service(e) => e,
TimeoutError::Timeout => ConnectorError::Timeout, TimeoutError::Timeout => ConnectError::Timeout,
}); });
let tcp_service = TimeoutService::new( let tcp_service = TimeoutService::new(
self.timeout, self.timeout,
self.resolver.map_err(ConnectorError::from).and_then( apply_fn(self.connector.clone(), |msg: Connect, srv| {
TcpConnector::default() srv.call(actix_connect::Connect::new(msg.host(), msg.port()))
.from_err() })
.map(|(msg, io)| (msg, io, Protocol::Http1)), .map_err(ConnectError::from)
), .map(|stream| (stream.into_parts().0, Protocol::Http1)),
) )
.map_err(|e| match e { .map_err(|e| match e {
TimeoutError::Service(e) => e, TimeoutError::Service(e) => e,
TimeoutError::Timeout => ConnectorError::Timeout, TimeoutError::Timeout => ConnectError::Timeout,
}); });
connect_impl::InnerConnector { connect_impl::InnerConnector {
@ -253,11 +279,8 @@ mod connect_impl {
impl<T, Io> Clone for InnerConnector<T, Io> impl<T, Io> Clone for InnerConnector<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
Request = Connect, + Clone,
Response = (Connect, Io, Protocol),
Error = ConnectorError,
> + Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
InnerConnector { InnerConnector {
@ -269,11 +292,7 @@ mod connect_impl {
impl<T, Io> Service for InnerConnector<T, Io> impl<T, Io> Service for InnerConnector<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectorError>,
Request = Connect,
Response = (Connect, Io, Protocol),
Error = ConnectorError,
>,
{ {
type Request = Connect; type Request = Connect;
type Response = IoConnection<Io>; type Response = IoConnection<Io>;
@ -289,7 +308,7 @@ mod connect_impl {
fn call(&mut self, req: Connect) -> Self::Future { fn call(&mut self, req: Connect) -> Self::Future {
if req.is_secure() { if req.is_secure() {
Either::B(err(ConnectorError::SslIsNotSupported)) Either::B(err(ConnectError::SslIsNotSupported))
} else if let Err(e) = req.validate() { } else if let Err(e) = req.validate() {
Either::B(err(e)) Either::B(err(e))
} else { } else {
@ -303,7 +322,7 @@ mod connect_impl {
mod connect_impl { mod connect_impl {
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::{err, Either, FutureResult}; use futures::future::{Either, FutureResult};
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use super::*; use super::*;
@ -313,16 +332,8 @@ mod connect_impl {
where where
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
T1: Service< T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
Request = Connect, T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
Response = (Connect, Io1, Protocol),
Error = ConnectorError,
>,
T2: Service<
Request = Connect,
Response = (Connect, Io2, Protocol),
Error = ConnectorError,
>,
{ {
pub(crate) tcp_pool: ConnectionPool<T1, Io1>, pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
pub(crate) ssl_pool: ConnectionPool<T2, Io2>, pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
@ -332,16 +343,10 @@ mod connect_impl {
where where
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
T1: Service< T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
Request = Connect, + Clone,
Response = (Connect, Io1, Protocol), T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
Error = ConnectorError, + Clone,
> + Clone,
T2: Service<
Request = Connect,
Response = (Connect, Io2, Protocol),
Error = ConnectorError,
> + Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
InnerConnector { InnerConnector {
@ -355,20 +360,12 @@ mod connect_impl {
where where
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
T1: Service< T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
Request = Connect, T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
Response = (Connect, Io1, Protocol),
Error = ConnectorError,
>,
T2: Service<
Request = Connect,
Response = (Connect, Io2, Protocol),
Error = ConnectorError,
>,
{ {
type Request = Connect; type Request = Connect;
type Response = EitherConnection<Io1, Io2>; type Response = EitherConnection<Io1, Io2>;
type Error = ConnectorError; type Error = ConnectError;
type Future = Either< type Future = Either<
FutureResult<Self::Response, Self::Error>, FutureResult<Self::Response, Self::Error>,
Either< Either<
@ -382,9 +379,7 @@ mod connect_impl {
} }
fn call(&mut self, req: Connect) -> Self::Future { fn call(&mut self, req: Connect) -> Self::Future {
if let Err(e) = req.validate() { if req.is_secure() {
Either::A(err(e))
} else if req.is_secure() {
Either::B(Either::B(InnerConnectorResponseB { Either::B(Either::B(InnerConnectorResponseB {
fut: self.ssl_pool.call(req), fut: self.ssl_pool.call(req),
_t: PhantomData, _t: PhantomData,
@ -401,11 +396,7 @@ mod connect_impl {
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2> pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
where where
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io1, Protocol),
Error = ConnectorError,
>,
{ {
fut: <ConnectionPool<T, Io1> as Service>::Future, fut: <ConnectionPool<T, Io1> as Service>::Future,
_t: PhantomData<Io2>, _t: PhantomData<Io2>,
@ -413,16 +404,12 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2> impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
where where
T: Service< T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io1, Protocol),
Error = ConnectorError,
>,
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
{ {
type Item = EitherConnection<Io1, Io2>; type Item = EitherConnection<Io1, Io2>;
type Error = ConnectorError; type Error = ConnectError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.fut.poll()? { match self.fut.poll()? {
@ -435,11 +422,7 @@ mod connect_impl {
pub(crate) struct InnerConnectorResponseB<T, Io1, Io2> pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
where where
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io2, Protocol),
Error = ConnectorError,
>,
{ {
fut: <ConnectionPool<T, Io2> as Service>::Future, fut: <ConnectionPool<T, Io2> as Service>::Future,
_t: PhantomData<Io1>, _t: PhantomData<Io1>,
@ -447,16 +430,12 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2> impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
where where
T: Service< T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io2, Protocol),
Error = ConnectorError,
>,
Io1: AsyncRead + AsyncWrite + 'static, Io1: AsyncRead + AsyncWrite + 'static,
Io2: AsyncRead + AsyncWrite + 'static, Io2: AsyncRead + AsyncWrite + 'static,
{ {
type Item = EitherConnection<Io1, Io2>; type Item = EitherConnection<Io1, Io2>;
type Error = ConnectorError; type Error = ConnectError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.fut.poll()? { match self.fut.poll()? {

View File

@ -11,11 +11,7 @@ use crate::response::Response;
/// A set of errors that can occur while connecting to an HTTP host /// A set of errors that can occur while connecting to an HTTP host
#[derive(Debug, Display, From)] #[derive(Debug, Display, From)]
pub enum ConnectorError { pub enum ConnectError {
/// Invalid URL
#[display(fmt = "Invalid URL")]
InvalidUrl(InvalidUrlKind),
/// SSL feature is not enabled /// SSL feature is not enabled
#[display(fmt = "SSL is not supported")] #[display(fmt = "SSL is not supported")]
SslIsNotSupported, SslIsNotSupported,
@ -45,24 +41,30 @@ pub enum ConnectorError {
#[display(fmt = "Internal error: connector has been disconnected")] #[display(fmt = "Internal error: connector has been disconnected")]
Disconnected, Disconnected,
/// Unresolved host name
#[display(fmt = "Connector received `Connect` method with unresolved host")]
Unresolverd,
/// Connection io error /// Connection io error
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
Io(io::Error), Io(io::Error),
} }
#[derive(Debug, Display)] impl From<actix_connect::ConnectError> for ConnectError {
pub enum InvalidUrlKind { fn from(err: actix_connect::ConnectError) -> ConnectError {
#[display(fmt = "Missing url scheme")] match err {
MissingScheme, actix_connect::ConnectError::Resolver(e) => ConnectError::Resolver(e),
#[display(fmt = "Unknown url scheme")] actix_connect::ConnectError::NoRecords => ConnectError::NoRecords,
UnknownScheme, actix_connect::ConnectError::InvalidInput => panic!(),
#[display(fmt = "Missing host name")] actix_connect::ConnectError::Unresolverd => ConnectError::Unresolverd,
MissingHost, actix_connect::ConnectError::Io(e) => ConnectError::Io(e),
}
}
} }
#[cfg(feature = "ssl")] #[cfg(feature = "ssl")]
impl<T> From<HandshakeError<T>> for ConnectorError { impl<T> From<HandshakeError<T>> for ConnectError {
fn from(err: HandshakeError<T>) -> ConnectorError { fn from(err: HandshakeError<T>) -> ConnectError {
match err { match err {
HandshakeError::SetupFailure(stack) => SslError::from(stack).into(), HandshakeError::SetupFailure(stack) => SslError::from(stack).into(),
HandshakeError::Failure(stream) => stream.into_error().into(), HandshakeError::Failure(stream) => stream.into_error().into(),
@ -71,12 +73,27 @@ impl<T> From<HandshakeError<T>> for ConnectorError {
} }
} }
#[derive(Debug, Display, From)]
pub enum InvalidUrl {
#[display(fmt = "Missing url scheme")]
MissingScheme,
#[display(fmt = "Unknown url scheme")]
UnknownScheme,
#[display(fmt = "Missing host name")]
MissingHost,
#[display(fmt = "Url parse error: {}", _0)]
HttpError(http::Error),
}
/// A set of errors that can occur during request sending and response reading /// A set of errors that can occur during request sending and response reading
#[derive(Debug, Display, From)] #[derive(Debug, Display, From)]
pub enum SendRequestError { pub enum SendRequestError {
/// Invalid URL
#[display(fmt = "Invalid URL: {}", _0)]
Url(InvalidUrl),
/// Failed to connect to host /// Failed to connect to host
#[display(fmt = "Failed to connect to host: {}", _0)] #[display(fmt = "Failed to connect to host: {}", _0)]
Connector(ConnectorError), Connect(ConnectError),
/// Error sending request /// Error sending request
Send(io::Error), Send(io::Error),
/// Error parsing response /// Error parsing response
@ -92,10 +109,10 @@ pub enum SendRequestError {
impl ResponseError for SendRequestError { impl ResponseError for SendRequestError {
fn error_response(&self) -> Response { fn error_response(&self) -> Response {
match *self { match *self {
SendRequestError::Connector(ConnectorError::Timeout) => { SendRequestError::Connect(ConnectError::Timeout) => {
Response::GatewayTimeout() Response::GatewayTimeout()
} }
SendRequestError::Connector(_) => Response::BadGateway(), SendRequestError::Connect(_) => Response::BadGateway(),
_ => Response::InternalServerError(), _ => Response::InternalServerError(),
} }
.into() .into()

View File

@ -6,7 +6,7 @@ use futures::future::{err, ok, Either};
use futures::{Async, Future, Poll, Sink, Stream}; use futures::{Async, Future, Poll, Sink, Stream};
use super::connection::{ConnectionLifetime, ConnectionType, IoConnection}; use super::connection::{ConnectionLifetime, ConnectionType, IoConnection};
use super::error::{ConnectorError, SendRequestError}; use super::error::{ConnectError, SendRequestError};
use super::pool::Acquired; use super::pool::Acquired;
use super::response::ClientResponse; use super::response::ClientResponse;
use crate::body::{BodyLength, MessageBody}; use crate::body::{BodyLength, MessageBody};
@ -62,7 +62,7 @@ where
} }
ok(res) ok(res)
} else { } else {
err(ConnectorError::Disconnected.into()) err(ConnectError::Disconnected.into())
} }
}) })
}) })

View File

@ -12,6 +12,6 @@ mod response;
pub use self::connect::Connect; pub use self::connect::Connect;
pub use self::connection::Connection; pub use self::connection::Connection;
pub use self::connector::Connector; pub use self::connector::Connector;
pub use self::error::{ConnectorError, InvalidUrlKind, SendRequestError}; pub use self::error::{ConnectError, InvalidUrl, SendRequestError};
pub use self::request::{ClientRequest, ClientRequestBuilder}; pub use self::request::{ClientRequest, ClientRequestBuilder};
pub use self::response::ClientResponse; pub use self::response::ClientResponse;

View File

@ -20,7 +20,7 @@ use tokio_timer::{sleep, Delay};
use super::connect::Connect; use super::connect::Connect;
use super::connection::{ConnectionType, IoConnection}; use super::connection::{ConnectionType, IoConnection};
use super::error::ConnectorError; use super::error::ConnectError;
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum Protocol { pub enum Protocol {
@ -48,11 +48,7 @@ pub(crate) struct ConnectionPool<T, Io: AsyncRead + AsyncWrite + 'static>(
impl<T, Io> ConnectionPool<T, Io> impl<T, Io> ConnectionPool<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io, Protocol),
Error = ConnectorError,
>,
{ {
pub(crate) fn new( pub(crate) fn new(
connector: T, connector: T,
@ -91,17 +87,13 @@ where
impl<T, Io> Service for ConnectionPool<T, Io> impl<T, Io> Service for ConnectionPool<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + 'static,
T: Service< T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
Request = Connect,
Response = (Connect, Io, Protocol),
Error = ConnectorError,
>,
{ {
type Request = Connect; type Request = Connect;
type Response = IoConnection<Io>; type Response = IoConnection<Io>;
type Error = ConnectorError; type Error = ConnectError;
type Future = Either< type Future = Either<
FutureResult<IoConnection<Io>, ConnectorError>, FutureResult<Self::Response, Self::Error>,
Either<WaitForConnection<Io>, OpenConnection<T::Future, Io>>, Either<WaitForConnection<Io>, OpenConnection<T::Future, Io>>,
>; >;
@ -151,7 +143,7 @@ where
{ {
key: Key, key: Key,
token: usize, token: usize,
rx: oneshot::Receiver<Result<IoConnection<Io>, ConnectorError>>, rx: oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
inner: Option<Rc<RefCell<Inner<Io>>>>, inner: Option<Rc<RefCell<Inner<Io>>>>,
} }
@ -173,7 +165,7 @@ where
Io: AsyncRead + AsyncWrite, Io: AsyncRead + AsyncWrite,
{ {
type Item = IoConnection<Io>; type Item = IoConnection<Io>;
type Error = ConnectorError; type Error = ConnectError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.rx.poll() { match self.rx.poll() {
@ -187,7 +179,7 @@ where
Ok(Async::NotReady) => Ok(Async::NotReady), Ok(Async::NotReady) => Ok(Async::NotReady),
Err(_) => { Err(_) => {
let _ = self.inner.take(); let _ = self.inner.take();
Err(ConnectorError::Disconnected) Err(ConnectError::Disconnected)
} }
} }
} }
@ -206,7 +198,7 @@ where
impl<F, Io> OpenConnection<F, Io> impl<F, Io> OpenConnection<F, Io>
where where
F: Future<Item = (Connect, Io, Protocol), Error = ConnectorError>, F: Future<Item = (Io, Protocol), Error = ConnectError>,
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + 'static,
{ {
fn new(key: Key, inner: Rc<RefCell<Inner<Io>>>, fut: F) -> Self { fn new(key: Key, inner: Rc<RefCell<Inner<Io>>>, fut: F) -> Self {
@ -234,11 +226,11 @@ where
impl<F, Io> Future for OpenConnection<F, Io> impl<F, Io> Future for OpenConnection<F, Io>
where where
F: Future<Item = (Connect, Io, Protocol), Error = ConnectorError>, F: Future<Item = (Io, Protocol), Error = ConnectError>,
Io: AsyncRead + AsyncWrite, Io: AsyncRead + AsyncWrite,
{ {
type Item = IoConnection<Io>; type Item = IoConnection<Io>;
type Error = ConnectorError; type Error = ConnectError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(ref mut h2) = self.h2 { if let Some(ref mut h2) = self.h2 {
@ -258,7 +250,7 @@ where
match self.fut.poll() { match self.fut.poll() {
Err(err) => Err(err), Err(err) => Err(err),
Ok(Async::Ready((_, io, proto))) => { Ok(Async::Ready((io, proto))) => {
let _ = self.inner.take(); let _ = self.inner.take();
if proto == Protocol::Http1 { if proto == Protocol::Http1 {
Ok(Async::Ready(IoConnection::new( Ok(Async::Ready(IoConnection::new(
@ -289,7 +281,7 @@ where
// impl<F, Io> OpenWaitingConnection<F, Io> // impl<F, Io> OpenWaitingConnection<F, Io>
// where // where
// F: Future<Item = (Connect, Io, Protocol), Error = ConnectorError> + 'static, // F: Future<Item = (Io, Protocol), Error = ConnectorError> + 'static,
// Io: AsyncRead + AsyncWrite + 'static, // Io: AsyncRead + AsyncWrite + 'static,
// { // {
// fn spawn( // fn spawn(
@ -323,7 +315,7 @@ where
// impl<F, Io> Future for OpenWaitingConnection<F, Io> // impl<F, Io> Future for OpenWaitingConnection<F, Io>
// where // where
// F: Future<Item = (Connect, Io, Protocol), Error = ConnectorError>, // F: Future<Item = (Io, Protocol), Error = ConnectorError>,
// Io: AsyncRead + AsyncWrite, // Io: AsyncRead + AsyncWrite,
// { // {
// type Item = (); // type Item = ();
@ -402,7 +394,7 @@ pub(crate) struct Inner<Io> {
available: HashMap<Key, VecDeque<AvailableConnection<Io>>>, available: HashMap<Key, VecDeque<AvailableConnection<Io>>>,
waiters: Slab<( waiters: Slab<(
Connect, Connect,
oneshot::Sender<Result<IoConnection<Io>, ConnectorError>>, oneshot::Sender<Result<IoConnection<Io>, ConnectError>>,
)>, )>,
waiters_queue: IndexSet<(Key, usize)>, waiters_queue: IndexSet<(Key, usize)>,
task: AtomicTask, task: AtomicTask,
@ -444,7 +436,7 @@ where
&mut self, &mut self,
connect: Connect, connect: Connect,
) -> ( ) -> (
oneshot::Receiver<Result<IoConnection<Io>, ConnectorError>>, oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
usize, usize,
) { ) {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
@ -534,7 +526,7 @@ where
// impl<T, Io> Future for ConnectorPoolSupport<T, Io> // impl<T, Io> Future for ConnectorPoolSupport<T, Io>
// where // where
// Io: AsyncRead + AsyncWrite + 'static, // Io: AsyncRead + AsyncWrite + 'static,
// T: Service<Connect, Response = (Connect, Io, Protocol), Error = ConnectorError>, // T: Service<Connect, Response = (Io, Protocol), Error = ConnectorError>,
// T::Future: 'static, // T::Future: 'static,
// { // {
// type Item = (); // type Item = ();

View File

@ -5,6 +5,7 @@ use std::io::Write;
use actix_service::Service; use actix_service::Service;
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{BufMut, Bytes, BytesMut};
use cookie::{Cookie, CookieJar}; use cookie::{Cookie, CookieJar};
use futures::future::{err, Either};
use futures::{Future, Stream}; use futures::{Future, Stream};
use percent_encoding::{percent_encode, USERINFO_ENCODE_SET}; use percent_encoding::{percent_encode, USERINFO_ENCODE_SET};
use serde::Serialize; use serde::Serialize;
@ -21,7 +22,7 @@ use crate::message::{ConnectionType, Head, RequestHead};
use super::connection::Connection; use super::connection::Connection;
use super::response::ClientResponse; use super::response::ClientResponse;
use super::{Connect, ConnectorError, SendRequestError}; use super::{Connect, ConnectError, SendRequestError};
/// An HTTP Client Request /// An HTTP Client Request
/// ///
@ -32,7 +33,8 @@ use super::{Connect, ConnectorError, SendRequestError};
/// ///
/// fn main() { /// fn main() {
/// System::new("test").block_on(lazy(|| { /// System::new("test").block_on(lazy(|| {
/// let mut connector = client::Connector::default().service(); /// let mut connector = client::Connector::new().service();
///
/// client::ClientRequest::get("http://www.rust-lang.org") // <- Create request builder /// client::ClientRequest::get("http://www.rust-lang.org") // <- Create request builder
/// .header("User-Agent", "Actix-web") /// .header("User-Agent", "Actix-web")
/// .finish().unwrap() /// .finish().unwrap()
@ -178,17 +180,24 @@ where
) -> impl Future<Item = ClientResponse, Error = SendRequestError> ) -> impl Future<Item = ClientResponse, Error = SendRequestError>
where where
B: 'static, B: 'static,
T: Service<Request = Connect, Response = I, Error = ConnectorError>, T: Service<Request = Connect, Response = I, Error = ConnectError>,
I: Connection, I: Connection,
{ {
let Self { head, body } = self; let Self { head, body } = self;
let connect = Connect::new(head.uri.clone());
if let Err(e) = connect.validate() {
Either::A(err(e.into()))
} else {
Either::B(
connector connector
// connect to the host // connect to the host
.call(Connect::new(head.uri.clone())) .call(connect)
.from_err() .from_err()
// send request // send request
.and_then(move |connection| connection.send_request(head, body)) .and_then(move |connection| connection.send_request(head, body)),
)
}
} }
} }

View File

@ -1,7 +1,7 @@
//! Http client request //! Http client request
use std::io; use std::io;
use actix_connector::ConnectorError; use actix_connect::ConnectError;
use derive_more::{Display, From}; use derive_more::{Display, From};
use http::{header::HeaderValue, Error as HttpError, StatusCode}; use http::{header::HeaderValue, Error as HttpError, StatusCode};
@ -43,7 +43,7 @@ pub enum ClientError {
Protocol(ProtocolError), Protocol(ProtocolError),
/// Connect error /// Connect error
#[display(fmt = "Connector error: {:?}", _0)] #[display(fmt = "Connector error: {:?}", _0)]
Connect(ConnectorError), Connect(ConnectError),
/// IO Error /// IO Error
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
Io(io::Error), Io(io::Error),

View File

@ -4,7 +4,7 @@ mod service;
pub use self::connect::Connect; pub use self::connect::Connect;
pub use self::error::ClientError; pub use self::error::ClientError;
pub use self::service::{Client, DefaultClient}; pub use self::service::Client;
#[derive(PartialEq, Hash, Debug, Clone, Copy)] #[derive(PartialEq, Hash, Debug, Clone, Copy)]
pub(crate) enum Protocol { pub(crate) enum Protocol {

View File

@ -2,8 +2,8 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_connector::{Connect as TcpConnect, ConnectorError, DefaultConnector}; use actix_connect::{default_connector, Connect as TcpConnect, ConnectError};
use actix_service::Service; use actix_service::{apply_fn, Service};
use base64; use base64;
use futures::future::{err, Either, FutureResult}; use futures::future::{err, Either, FutureResult};
use futures::{try_ready, Async, Future, Poll, Sink, Stream}; use futures::{try_ready, Async, Future, Poll, Sink, Stream};
@ -20,21 +20,29 @@ use crate::ws::Codec;
use super::{ClientError, Connect, Protocol}; use super::{ClientError, Connect, Protocol};
/// Default client, uses default connector.
pub type DefaultClient = Client<DefaultConnector>;
/// WebSocket's client /// WebSocket's client
pub struct Client<T> pub struct Client<T> {
where
T: Service<Request = TcpConnect, Error = ConnectorError>,
T::Response: AsyncRead + AsyncWrite,
{
connector: T, connector: T,
} }
impl Client<()> {
/// Create client with default connector.
pub fn default() -> Client<
impl Service<
Request = TcpConnect,
Response = impl AsyncRead + AsyncWrite,
Error = ConnectError,
> + Clone,
> {
Client::new(apply_fn(default_connector(), |msg: TcpConnect, srv| {
srv.call(msg).map(|stream| stream.into_parts().0)
}))
}
}
impl<T> Client<T> impl<T> Client<T>
where where
T: Service<Request = TcpConnect, Error = ConnectorError>, T: Service<Request = TcpConnect, Error = ConnectError>,
T::Response: AsyncRead + AsyncWrite, T::Response: AsyncRead + AsyncWrite,
{ {
/// Create new websocket's client factory /// Create new websocket's client factory
@ -43,15 +51,9 @@ where
} }
} }
impl Default for Client<DefaultConnector> {
fn default() -> Self {
Client::new(DefaultConnector::default())
}
}
impl<T> Clone for Client<T> impl<T> Clone for Client<T>
where where
T: Service<Request = TcpConnect, Error = ConnectorError> + Clone, T: Service<Request = TcpConnect, Error = ConnectError> + Clone,
T::Response: AsyncRead + AsyncWrite, T::Response: AsyncRead + AsyncWrite,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -63,7 +65,7 @@ where
impl<T> Service for Client<T> impl<T> Service for Client<T>
where where
T: Service<Request = TcpConnect, Error = ConnectorError>, T: Service<Request = TcpConnect, Error = ConnectError>,
T::Response: AsyncRead + AsyncWrite + 'static, T::Response: AsyncRead + AsyncWrite + 'static,
T::Future: 'static, T::Future: 'static,
{ {

View File

@ -21,7 +21,7 @@ mod proto;
mod service; mod service;
mod transport; mod transport;
pub use self::client::{Client, ClientError, Connect, DefaultClient}; pub use self::client::{Client, ClientError, Connect};
pub use self::codec::{Codec, Frame, Message}; pub use self::codec::{Codec, Frame, Message};
pub use self::frame::Parser; pub use self::frame::Parser;
pub use self::proto::{CloseCode, CloseReason, OpCode}; pub use self::proto::{CloseCode, CloseReason, OpCode};

View File

@ -1,18 +1,17 @@
//! Various helpers for Actix applications to use during testing. //! Various helpers for Actix applications to use during testing.
use std::sync::mpsc; use std::sync::mpsc;
use std::{net, thread}; use std::{net, thread, time};
use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_http::body::MessageBody; use actix_http::body::MessageBody;
use actix_http::client::{ use actix_http::client::{
ClientRequest, ClientRequestBuilder, ClientResponse, Connect, Connection, Connector, ClientRequest, ClientRequestBuilder, ClientResponse, Connect, ConnectError,
ConnectorError, SendRequestError, Connection, Connector, SendRequestError,
}; };
use actix_http::ws; use actix_http::ws;
use actix_rt::{Runtime, System}; use actix_rt::{Runtime, System};
use actix_server::{Server, StreamServiceFactory}; use actix_server::{Server, StreamServiceFactory};
use actix_service::Service; use actix_service::Service;
use futures::future::{lazy, Future}; use futures::future::{lazy, Future};
use http::Method; use http::Method;
use net2::TcpBuilder; use net2::TcpBuilder;
@ -44,21 +43,15 @@ use net2::TcpBuilder;
/// ``` /// ```
pub struct TestServer; pub struct TestServer;
/// /// Test server controller
pub struct TestServerRuntime<T> { pub struct TestServerRuntime {
addr: net::SocketAddr, addr: net::SocketAddr,
conn: T,
rt: Runtime, rt: Runtime,
} }
impl TestServer { impl TestServer {
/// Start new test server with application factory /// Start new test server with application factory
pub fn new<F: StreamServiceFactory>( pub fn new<F: StreamServiceFactory>(factory: F) -> TestServerRuntime {
factory: F,
) -> TestServerRuntime<
impl Service<Request = Connect, Response = impl Connection, Error = ConnectorError>
+ Clone,
> {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
// run server in separate thread // run server in separate thread
@ -79,35 +72,9 @@ impl TestServer {
let (system, addr) = rx.recv().unwrap(); let (system, addr) = rx.recv().unwrap();
System::set_current(system); System::set_current(system);
TestServerRuntime {
let mut rt = Runtime::new().unwrap(); addr,
let conn = rt rt: Runtime::new().unwrap(),
.block_on(lazy(|| Ok::<_, ()>(TestServer::new_connector())))
.unwrap();
TestServerRuntime { addr, conn, rt }
}
fn new_connector(
) -> impl Service<
Request = Connect,
Response = impl Connection,
Error = ConnectorError,
> + Clone {
#[cfg(feature = "ssl")]
{
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
let _ = builder
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
Connector::default().ssl(builder.build()).service()
}
#[cfg(not(feature = "ssl"))]
{
Connector::default().service()
} }
} }
@ -122,7 +89,7 @@ impl TestServer {
} }
} }
impl<T> TestServerRuntime<T> { impl TestServerRuntime {
/// Execute future on current core /// Execute future on current core
pub fn block_on<F, I, E>(&mut self, fut: F) -> Result<I, E> pub fn block_on<F, I, E>(&mut self, fut: F) -> Result<I, E>
where where
@ -131,12 +98,12 @@ impl<T> TestServerRuntime<T> {
self.rt.block_on(fut) self.rt.block_on(fut)
} }
/// Execute future on current core /// Execute function on current core
pub fn execute<F, I, E>(&mut self, fut: F) -> Result<I, E> pub fn execute<F, R>(&mut self, fut: F) -> R
where where
F: Future<Item = I, Error = E>, F: FnOnce() -> R,
{ {
self.rt.block_on(fut) self.rt.block_on(lazy(|| Ok::<_, ()>(fut()))).unwrap()
} }
/// Construct test server url /// Construct test server url
@ -190,17 +157,37 @@ impl<T> TestServerRuntime<T> {
.take() .take()
} }
/// Http connector fn new_connector(
pub fn connector(&mut self) -> &mut T { ) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
&mut self.conn + Clone {
#[cfg(feature = "ssl")]
{
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE);
let _ = builder
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
Connector::new()
.timeout(time::Duration::from_millis(500))
.ssl(builder.build())
.service()
}
#[cfg(not(feature = "ssl"))]
{
Connector::new()
.timeout(time::Duration::from_millis(500))
.service()
}
} }
/// Http connector /// Http connector
pub fn new_connector(&mut self) -> T pub fn connector(
where &mut self,
T: Clone, ) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
{ + Clone {
self.conn.clone() self.execute(|| TestServerRuntime::new_connector())
} }
/// Stop http server /// Stop http server
@ -209,11 +196,7 @@ impl<T> TestServerRuntime<T> {
} }
} }
impl<T> TestServerRuntime<T> impl TestServerRuntime {
where
T: Service<Request = Connect, Error = ConnectorError> + Clone,
T::Response: Connection,
{
/// Connect to websocket server at a given path /// Connect to websocket server at a given path
pub fn ws_at( pub fn ws_at(
&mut self, &mut self,
@ -236,11 +219,12 @@ where
&mut self, &mut self,
req: ClientRequest<B>, req: ClientRequest<B>,
) -> Result<ClientResponse, SendRequestError> { ) -> Result<ClientResponse, SendRequestError> {
self.rt.block_on(req.send(&mut self.conn)) let mut conn = self.connector();
self.rt.block_on(req.send(&mut conn))
} }
} }
impl<T> Drop for TestServerRuntime<T> { impl Drop for TestServerRuntime {
fn drop(&mut self) { fn drop(&mut self) {
self.stop() self.stop()
} }

View File

@ -36,7 +36,7 @@ fn test_h1_v2() {
.finish(|_| future::ok::<_, ()>(Response::Ok().body(STR))) .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.map(|_| ()) .map(|_| ())
}); });
let mut connector = srv.new_connector(); let mut connector = srv.connector();
let request = srv.get().finish().unwrap(); let request = srv.get().finish().unwrap();
let response = srv.block_on(request.send(&mut connector)).unwrap(); let response = srv.block_on(request.send(&mut connector)).unwrap();
@ -70,7 +70,7 @@ fn test_connection_close() {
.finish(|_| ok::<_, ()>(Response::Ok().body(STR))) .finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map(|_| ()) .map(|_| ())
}); });
let mut connector = srv.new_connector(); let mut connector = srv.connector();
let request = srv.get().close().finish().unwrap(); let request = srv.get().close().finish().unwrap();
let response = srv.block_on(request.send(&mut connector)).unwrap(); let response = srv.block_on(request.send(&mut connector)).unwrap();
@ -90,7 +90,7 @@ fn test_with_query_parameter() {
}) })
.map(|_| ()) .map(|_| ())
}); });
let mut connector = srv.new_connector(); let mut connector = srv.connector();
let request = client::ClientRequest::get(srv.url("/?qp=5")) let request = client::ClientRequest::get(srv.url("/?qp=5"))
.finish() .finish()

View File

@ -432,7 +432,7 @@ fn test_h1_headers() {
future::ok::<_, ()>(builder.body(data.clone())) future::ok::<_, ()>(builder.body(data.clone()))
}) })
}); });
let mut connector = srv.new_connector(); let mut connector = srv.connector();
let req = srv.get().finish().unwrap(); let req = srv.get().finish().unwrap();
@ -479,7 +479,7 @@ fn test_h2_headers() {
future::ok::<_, ()>(builder.body(data.clone())) future::ok::<_, ()>(builder.body(data.clone()))
}).map_err(|_| ())) }).map_err(|_| ()))
}); });
let mut connector = srv.new_connector(); let mut connector = srv.connector();
let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap(); let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap();
let mut response = srv.block_on(req.send(&mut connector)).unwrap(); let mut response = srv.block_on(req.send(&mut connector)).unwrap();