mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
use Uri as client connect message
This commit is contained in:
parent
d2c755bb47
commit
b8bfd29d2c
@ -55,7 +55,7 @@ encoding = "0.2"
|
|||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
hashbrown = "0.1.8"
|
hashbrown = "0.1.8"
|
||||||
h2 = "0.1.16"
|
h2 = "0.1.16"
|
||||||
http = "0.1.8"
|
http = "0.1.16"
|
||||||
httparse = "1.3"
|
httparse = "1.3"
|
||||||
indexmap = "1.0"
|
indexmap = "1.0"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
use actix_connect::Address;
|
|
||||||
use http::uri::Uri;
|
|
||||||
use http::HttpTryFrom;
|
|
||||||
|
|
||||||
use super::error::InvalidUrl;
|
|
||||||
use super::pool::Key;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// `Connect` type represents a message that can be sent to
|
|
||||||
/// `Connector` with a connection request.
|
|
||||||
pub struct Connect {
|
|
||||||
pub(crate) uri: Uri,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Connect {
|
|
||||||
/// Create `Connect` message for specified `Uri`
|
|
||||||
pub fn new(uri: Uri) -> Connect {
|
|
||||||
Connect { uri }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct `Uri` instance and create `Connect` message.
|
|
||||||
pub fn try_from<U>(uri: U) -> Result<Connect, InvalidUrl>
|
|
||||||
where
|
|
||||||
Uri: HttpTryFrom<U>,
|
|
||||||
{
|
|
||||||
Ok(Connect {
|
|
||||||
uri: Uri::try_from(uri).map_err(|e| e.into())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_secure(&self) -> bool {
|
|
||||||
if let Some(scheme) = self.uri.scheme_part() {
|
|
||||||
scheme.as_str() == "https"
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn key(&self) -> Key {
|
|
||||||
self.uri.authority_part().unwrap().clone().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn validate(&self) -> Result<(), InvalidUrl> {
|
|
||||||
if self.uri.host().is_none() {
|
|
||||||
Err(InvalidUrl::MissingHost)
|
|
||||||
} else if self.uri.scheme_part().is_none() {
|
|
||||||
Err(InvalidUrl::MissingScheme)
|
|
||||||
} else if let Some(scheme) = self.uri.scheme_part() {
|
|
||||||
match scheme.as_str() {
|
|
||||||
"http" | "ws" | "https" | "wss" => Ok(()),
|
|
||||||
_ => Err(InvalidUrl::UnknownScheme),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Address for Connect {
|
|
||||||
fn host(&self) -> &str {
|
|
||||||
&self.uri.host().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn port(&self) -> Option<u16> {
|
|
||||||
let port = if let Some(port) = self.uri.port() {
|
|
||||||
port
|
|
||||||
} else if let Some(scheme) = self.uri.scheme_part() {
|
|
||||||
match scheme.as_str() {
|
|
||||||
"http" | "ws" => 80,
|
|
||||||
"https" | "wss" => 443,
|
|
||||||
_ => 80,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
80
|
|
||||||
};
|
|
||||||
Some(port)
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,9 +8,9 @@ use actix_connect::{
|
|||||||
};
|
};
|
||||||
use actix_service::{apply_fn, Service, ServiceExt};
|
use actix_service::{apply_fn, Service, ServiceExt};
|
||||||
use actix_utils::timeout::{TimeoutError, TimeoutService};
|
use actix_utils::timeout::{TimeoutError, TimeoutService};
|
||||||
|
use http::Uri;
|
||||||
use tokio_tcp::TcpStream;
|
use tokio_tcp::TcpStream;
|
||||||
|
|
||||||
use super::connect::Connect;
|
|
||||||
use super::connection::Connection;
|
use super::connection::Connection;
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
use super::pool::{ConnectionPool, Protocol};
|
use super::pool::{ConnectionPool, Protocol};
|
||||||
@ -38,8 +38,8 @@ pub struct Connector<T, U> {
|
|||||||
impl Connector<(), ()> {
|
impl Connector<(), ()> {
|
||||||
pub fn new() -> Connector<
|
pub fn new() -> Connector<
|
||||||
impl Service<
|
impl Service<
|
||||||
Request = TcpConnect<Connect>,
|
Request = TcpConnect<Uri>,
|
||||||
Response = TcpConnection<Connect, TcpStream>,
|
Response = TcpConnection<Uri, TcpStream>,
|
||||||
Error = actix_connect::ConnectError,
|
Error = actix_connect::ConnectError,
|
||||||
> + Clone,
|
> + Clone,
|
||||||
TcpStream,
|
TcpStream,
|
||||||
@ -79,8 +79,8 @@ impl<T, U> Connector<T, U> {
|
|||||||
where
|
where
|
||||||
U1: AsyncRead + AsyncWrite + fmt::Debug,
|
U1: AsyncRead + AsyncWrite + fmt::Debug,
|
||||||
T1: Service<
|
T1: Service<
|
||||||
Request = TcpConnect<Connect>,
|
Request = TcpConnect<Uri>,
|
||||||
Response = TcpConnection<Connect, U1>,
|
Response = TcpConnection<Uri, U1>,
|
||||||
Error = actix_connect::ConnectError,
|
Error = actix_connect::ConnectError,
|
||||||
> + Clone,
|
> + Clone,
|
||||||
{
|
{
|
||||||
@ -101,8 +101,8 @@ impl<T, U> Connector<T, U>
|
|||||||
where
|
where
|
||||||
U: AsyncRead + AsyncWrite + fmt::Debug + 'static,
|
U: AsyncRead + AsyncWrite + fmt::Debug + 'static,
|
||||||
T: Service<
|
T: Service<
|
||||||
Request = TcpConnect<Connect>,
|
Request = TcpConnect<Uri>,
|
||||||
Response = TcpConnection<Connect, U>,
|
Response = TcpConnection<Uri, U>,
|
||||||
Error = actix_connect::ConnectError,
|
Error = actix_connect::ConnectError,
|
||||||
> + Clone,
|
> + Clone,
|
||||||
{
|
{
|
||||||
@ -166,16 +166,14 @@ where
|
|||||||
/// Finish configuration process and create connector service.
|
/// Finish configuration process and create connector service.
|
||||||
pub fn service(
|
pub fn service(
|
||||||
self,
|
self,
|
||||||
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
|
||||||
+ Clone {
|
{
|
||||||
#[cfg(not(feature = "ssl"))]
|
#[cfg(not(feature = "ssl"))]
|
||||||
{
|
{
|
||||||
let connector = TimeoutService::new(
|
let connector = TimeoutService::new(
|
||||||
self.timeout,
|
self.timeout,
|
||||||
apply_fn(self.connector, |msg: Connect, srv| {
|
apply_fn(self.connector, |msg: Uri, srv| srv.call(msg.into()))
|
||||||
srv.call(actix_connect::Connect::new(msg))
|
.map(|stream| (stream.into_parts().0, Protocol::Http1)),
|
||||||
})
|
|
||||||
.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,
|
||||||
@ -199,28 +197,26 @@ where
|
|||||||
|
|
||||||
let ssl_service = TimeoutService::new(
|
let ssl_service = TimeoutService::new(
|
||||||
self.timeout,
|
self.timeout,
|
||||||
apply_fn(self.connector.clone(), |msg: Connect, srv| {
|
apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
|
||||||
srv.call(actix_connect::Connect::new(msg))
|
.map_err(ConnectError::from)
|
||||||
})
|
.and_then(
|
||||||
.map_err(ConnectError::from)
|
OpensslConnector::service(self.ssl)
|
||||||
.and_then(
|
.map_err(ConnectError::from)
|
||||||
OpensslConnector::service(self.ssl)
|
.map(|stream| {
|
||||||
.map_err(ConnectError::from)
|
let sock = stream.into_parts().0;
|
||||||
.map(|stream| {
|
let h2 = sock
|
||||||
let sock = stream.into_parts().0;
|
.get_ref()
|
||||||
let h2 = sock
|
.ssl()
|
||||||
.get_ref()
|
.selected_alpn_protocol()
|
||||||
.ssl()
|
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||||
.selected_alpn_protocol()
|
.unwrap_or(false);
|
||||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
if h2 {
|
||||||
.unwrap_or(false);
|
(sock, Protocol::Http2)
|
||||||
if h2 {
|
} else {
|
||||||
(sock, Protocol::Http2)
|
(sock, Protocol::Http1)
|
||||||
} else {
|
}
|
||||||
(sock, Protocol::Http1)
|
}),
|
||||||
}
|
),
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
TimeoutError::Service(e) => e,
|
TimeoutError::Service(e) => e,
|
||||||
@ -229,11 +225,9 @@ where
|
|||||||
|
|
||||||
let tcp_service = TimeoutService::new(
|
let tcp_service = TimeoutService::new(
|
||||||
self.timeout,
|
self.timeout,
|
||||||
apply_fn(self.connector.clone(), |msg: Connect, srv| {
|
apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
|
||||||
srv.call(actix_connect::Connect::new(msg))
|
.map_err(ConnectError::from)
|
||||||
})
|
.map(|stream| (stream.into_parts().0, 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,
|
||||||
@ -271,7 +265,7 @@ mod connect_impl {
|
|||||||
pub(crate) struct InnerConnector<T, Io>
|
pub(crate) struct InnerConnector<T, Io>
|
||||||
where
|
where
|
||||||
Io: AsyncRead + AsyncWrite + 'static,
|
Io: AsyncRead + AsyncWrite + 'static,
|
||||||
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectorError>,
|
T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectorError>,
|
||||||
{
|
{
|
||||||
pub(crate) tcp_pool: ConnectionPool<T, Io>,
|
pub(crate) tcp_pool: ConnectionPool<T, Io>,
|
||||||
}
|
}
|
||||||
@ -279,7 +273,7 @@ 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<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
|
T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>
|
||||||
+ Clone,
|
+ Clone,
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@ -292,9 +286,9 @@ 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<Request = Connect, Response = (Io, Protocol), Error = ConnectorError>,
|
T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectorError>,
|
||||||
{
|
{
|
||||||
type Request = Connect;
|
type Request = Uri;
|
||||||
type Response = IoConnection<Io>;
|
type Response = IoConnection<Io>;
|
||||||
type Error = ConnectorError;
|
type Error = ConnectorError;
|
||||||
type Future = Either<
|
type Future = Either<
|
||||||
@ -306,13 +300,12 @@ mod connect_impl {
|
|||||||
self.tcp_pool.poll_ready()
|
self.tcp_pool.poll_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Connect) -> Self::Future {
|
fn call(&mut self, req: Uri) -> Self::Future {
|
||||||
if req.is_secure() {
|
match req.scheme_str() {
|
||||||
Either::B(err(ConnectError::SslIsNotSupported))
|
Some("https") | Some("wss") => {
|
||||||
} else if let Err(e) = req.validate() {
|
Either::B(err(ConnectError::SslIsNotSupported))
|
||||||
Either::B(err(e))
|
}
|
||||||
} else {
|
_ => Either::A(self.tcp_pool.call(req)),
|
||||||
Either::A(self.tcp_pool.call(req))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,8 +325,8 @@ mod connect_impl {
|
|||||||
where
|
where
|
||||||
Io1: AsyncRead + AsyncWrite + 'static,
|
Io1: AsyncRead + AsyncWrite + 'static,
|
||||||
Io2: AsyncRead + AsyncWrite + 'static,
|
Io2: AsyncRead + AsyncWrite + 'static,
|
||||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
|
||||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
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>,
|
||||||
@ -343,9 +336,9 @@ mod connect_impl {
|
|||||||
where
|
where
|
||||||
Io1: AsyncRead + AsyncWrite + 'static,
|
Io1: AsyncRead + AsyncWrite + 'static,
|
||||||
Io2: AsyncRead + AsyncWrite + 'static,
|
Io2: AsyncRead + AsyncWrite + 'static,
|
||||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
|
T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>
|
||||||
+ Clone,
|
+ Clone,
|
||||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
|
T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>
|
||||||
+ Clone,
|
+ Clone,
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@ -360,10 +353,10 @@ mod connect_impl {
|
|||||||
where
|
where
|
||||||
Io1: AsyncRead + AsyncWrite + 'static,
|
Io1: AsyncRead + AsyncWrite + 'static,
|
||||||
Io2: AsyncRead + AsyncWrite + 'static,
|
Io2: AsyncRead + AsyncWrite + 'static,
|
||||||
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
|
||||||
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
type Request = Connect;
|
type Request = Uri;
|
||||||
type Response = EitherConnection<Io1, Io2>;
|
type Response = EitherConnection<Io1, Io2>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = Either<
|
type Future = Either<
|
||||||
@ -378,17 +371,18 @@ mod connect_impl {
|
|||||||
self.tcp_pool.poll_ready()
|
self.tcp_pool.poll_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Connect) -> Self::Future {
|
fn call(&mut self, req: Uri) -> Self::Future {
|
||||||
if req.is_secure() {
|
match req.scheme_str() {
|
||||||
Either::B(Either::B(InnerConnectorResponseB {
|
Some("https") | Some("wss") => {
|
||||||
fut: self.ssl_pool.call(req),
|
Either::B(Either::B(InnerConnectorResponseB {
|
||||||
_t: PhantomData,
|
fut: self.ssl_pool.call(req),
|
||||||
}))
|
_t: PhantomData,
|
||||||
} else {
|
}))
|
||||||
Either::B(Either::A(InnerConnectorResponseA {
|
}
|
||||||
|
_ => Either::B(Either::A(InnerConnectorResponseA {
|
||||||
fut: self.tcp_pool.call(req),
|
fut: self.tcp_pool.call(req),
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
}))
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +390,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<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
fut: <ConnectionPool<T, Io1> as Service>::Future,
|
fut: <ConnectionPool<T, Io1> as Service>::Future,
|
||||||
_t: PhantomData<Io2>,
|
_t: PhantomData<Io2>,
|
||||||
@ -404,7 +398,7 @@ 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<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
|
||||||
Io1: AsyncRead + AsyncWrite + 'static,
|
Io1: AsyncRead + AsyncWrite + 'static,
|
||||||
Io2: AsyncRead + AsyncWrite + 'static,
|
Io2: AsyncRead + AsyncWrite + 'static,
|
||||||
{
|
{
|
||||||
@ -422,7 +416,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<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
fut: <ConnectionPool<T, Io2> as Service>::Future,
|
fut: <ConnectionPool<T, Io2> as Service>::Future,
|
||||||
_t: PhantomData<Io1>,
|
_t: PhantomData<Io1>,
|
||||||
@ -430,7 +424,7 @@ 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<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
|
||||||
Io1: AsyncRead + AsyncWrite + 'static,
|
Io1: AsyncRead + AsyncWrite + 'static,
|
||||||
Io2: AsyncRead + AsyncWrite + 'static,
|
Io2: AsyncRead + AsyncWrite + 'static,
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
//! Http client api
|
//! Http client api
|
||||||
mod connect;
|
|
||||||
mod connection;
|
mod connection;
|
||||||
mod connector;
|
mod connector;
|
||||||
mod error;
|
mod error;
|
||||||
@ -9,7 +8,6 @@ mod pool;
|
|||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
|
|
||||||
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::{ConnectError, InvalidUrl, SendRequestError};
|
pub use self::error::{ConnectError, InvalidUrl, SendRequestError};
|
||||||
|
@ -7,18 +7,17 @@ use std::time::{Duration, Instant};
|
|||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::future::{ok, Either, FutureResult};
|
use futures::future::{err, ok, Either, FutureResult};
|
||||||
use futures::task::AtomicTask;
|
use futures::task::AtomicTask;
|
||||||
use futures::unsync::oneshot;
|
use futures::unsync::oneshot;
|
||||||
use futures::{Async, Future, Poll};
|
use futures::{Async, Future, Poll};
|
||||||
use h2::client::{handshake, Handshake};
|
use h2::client::{handshake, Handshake};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use http::uri::Authority;
|
use http::uri::{Authority, Uri};
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use tokio_timer::{sleep, Delay};
|
use tokio_timer::{sleep, Delay};
|
||||||
|
|
||||||
use super::connect::Connect;
|
|
||||||
use super::connection::{ConnectionType, IoConnection};
|
use super::connection::{ConnectionType, IoConnection};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
|
|
||||||
@ -48,7 +47,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<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
connector: T,
|
connector: T,
|
||||||
@ -87,9 +86,9 @@ 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<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
|
T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>,
|
||||||
{
|
{
|
||||||
type Request = Connect;
|
type Request = Uri;
|
||||||
type Response = IoConnection<Io>;
|
type Response = IoConnection<Io>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = Either<
|
type Future = Either<
|
||||||
@ -101,8 +100,12 @@ where
|
|||||||
self.0.poll_ready()
|
self.0.poll_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Connect) -> Self::Future {
|
fn call(&mut self, req: Uri) -> Self::Future {
|
||||||
let key = req.key();
|
let key = if let Some(authority) = req.authority_part() {
|
||||||
|
authority.clone().into()
|
||||||
|
} else {
|
||||||
|
return Either::A(err(ConnectError::Unresolverd));
|
||||||
|
};
|
||||||
|
|
||||||
// acquire connection
|
// acquire connection
|
||||||
match self.1.as_ref().borrow_mut().acquire(&key) {
|
match self.1.as_ref().borrow_mut().acquire(&key) {
|
||||||
@ -268,110 +271,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct OpenWaitingConnection<F, Io>
|
|
||||||
// where
|
|
||||||
// Io: AsyncRead + AsyncWrite + 'static,
|
|
||||||
// {
|
|
||||||
// fut: F,
|
|
||||||
// key: Key,
|
|
||||||
// h2: Option<Handshake<Io, Bytes>>,
|
|
||||||
// rx: Option<oneshot::Sender<Result<IoConnection<Io>, ConnectorError>>>,
|
|
||||||
// inner: Option<Rc<RefCell<Inner<Io>>>>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<F, Io> OpenWaitingConnection<F, Io>
|
|
||||||
// where
|
|
||||||
// F: Future<Item = (Io, Protocol), Error = ConnectorError> + 'static,
|
|
||||||
// Io: AsyncRead + AsyncWrite + 'static,
|
|
||||||
// {
|
|
||||||
// fn spawn(
|
|
||||||
// key: Key,
|
|
||||||
// rx: oneshot::Sender<Result<IoConnection<Io>, ConnectorError>>,
|
|
||||||
// inner: Rc<RefCell<Inner<Io>>>,
|
|
||||||
// fut: F,
|
|
||||||
// ) {
|
|
||||||
// tokio_current_thread::spawn(OpenWaitingConnection {
|
|
||||||
// key,
|
|
||||||
// fut,
|
|
||||||
// h2: None,
|
|
||||||
// rx: Some(rx),
|
|
||||||
// inner: Some(inner),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<F, Io> Drop for OpenWaitingConnection<F, Io>
|
|
||||||
// where
|
|
||||||
// Io: AsyncRead + AsyncWrite + 'static,
|
|
||||||
// {
|
|
||||||
// fn drop(&mut self) {
|
|
||||||
// if let Some(inner) = self.inner.take() {
|
|
||||||
// let mut inner = inner.as_ref().borrow_mut();
|
|
||||||
// inner.release();
|
|
||||||
// inner.check_availibility();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<F, Io> Future for OpenWaitingConnection<F, Io>
|
|
||||||
// where
|
|
||||||
// F: Future<Item = (Io, Protocol), Error = ConnectorError>,
|
|
||||||
// Io: AsyncRead + AsyncWrite,
|
|
||||||
// {
|
|
||||||
// type Item = ();
|
|
||||||
// type Error = ();
|
|
||||||
|
|
||||||
// fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
|
||||||
// if let Some(ref mut h2) = self.h2 {
|
|
||||||
// return match h2.poll() {
|
|
||||||
// Ok(Async::Ready((snd, connection))) => {
|
|
||||||
// tokio_current_thread::spawn(connection.map_err(|_| ()));
|
|
||||||
// let _ = self.rx.take().unwrap().send(Ok(IoConnection::new(
|
|
||||||
// ConnectionType::H2(snd),
|
|
||||||
// Instant::now(),
|
|
||||||
// Some(Acquired(self.key.clone(), self.inner.clone())),
|
|
||||||
// )));
|
|
||||||
// Ok(Async::Ready(()))
|
|
||||||
// }
|
|
||||||
// Ok(Async::NotReady) => Ok(Async::NotReady),
|
|
||||||
// Err(e) => {
|
|
||||||
// let _ = self.inner.take();
|
|
||||||
// if let Some(rx) = self.rx.take() {
|
|
||||||
// let _ = rx.send(Err(e.into()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Err(())
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// match self.fut.poll() {
|
|
||||||
// Err(err) => {
|
|
||||||
// let _ = self.inner.take();
|
|
||||||
// if let Some(rx) = self.rx.take() {
|
|
||||||
// let _ = rx.send(Err(err));
|
|
||||||
// }
|
|
||||||
// Err(())
|
|
||||||
// }
|
|
||||||
// Ok(Async::Ready((_, io, proto))) => {
|
|
||||||
// let _ = self.inner.take();
|
|
||||||
// if proto == Protocol::Http1 {
|
|
||||||
// let _ = self.rx.take().unwrap().send(Ok(IoConnection::new(
|
|
||||||
// ConnectionType::H1(io),
|
|
||||||
// Instant::now(),
|
|
||||||
// Some(Acquired(self.key.clone(), self.inner.clone())),
|
|
||||||
// )));
|
|
||||||
// } else {
|
|
||||||
// self.h2 = Some(handshake(io));
|
|
||||||
// return self.poll();
|
|
||||||
// }
|
|
||||||
// Ok(Async::Ready(()))
|
|
||||||
// }
|
|
||||||
// Ok(Async::NotReady) => Ok(Async::NotReady),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
enum Acquire<T> {
|
enum Acquire<T> {
|
||||||
Acquired(ConnectionType<T>, Instant),
|
Acquired(ConnectionType<T>, Instant),
|
||||||
Available,
|
Available,
|
||||||
@ -392,10 +291,7 @@ pub(crate) struct Inner<Io> {
|
|||||||
limit: usize,
|
limit: usize,
|
||||||
acquired: usize,
|
acquired: usize,
|
||||||
available: HashMap<Key, VecDeque<AvailableConnection<Io>>>,
|
available: HashMap<Key, VecDeque<AvailableConnection<Io>>>,
|
||||||
waiters: Slab<(
|
waiters: Slab<(Uri, oneshot::Sender<Result<IoConnection<Io>, ConnectError>>)>,
|
||||||
Connect,
|
|
||||||
oneshot::Sender<Result<IoConnection<Io>, ConnectError>>,
|
|
||||||
)>,
|
|
||||||
waiters_queue: IndexSet<(Key, usize)>,
|
waiters_queue: IndexSet<(Key, usize)>,
|
||||||
task: AtomicTask,
|
task: AtomicTask,
|
||||||
}
|
}
|
||||||
@ -434,14 +330,14 @@ where
|
|||||||
/// connection is not available, wait
|
/// connection is not available, wait
|
||||||
fn wait_for(
|
fn wait_for(
|
||||||
&mut self,
|
&mut self,
|
||||||
connect: Connect,
|
connect: Uri,
|
||||||
) -> (
|
) -> (
|
||||||
oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
|
oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
|
||||||
usize,
|
usize,
|
||||||
) {
|
) {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
let key = connect.key();
|
let key: Key = connect.authority_part().unwrap().clone().into();
|
||||||
let entry = self.waiters.vacant_entry();
|
let entry = self.waiters.vacant_entry();
|
||||||
let token = entry.key();
|
let token = entry.key();
|
||||||
entry.insert((connect, tx));
|
entry.insert((connect, tx));
|
||||||
|
@ -21,8 +21,8 @@ use crate::http::{
|
|||||||
use crate::message::{ConnectionType, Head, RequestHead};
|
use crate::message::{ConnectionType, Head, RequestHead};
|
||||||
|
|
||||||
use super::connection::Connection;
|
use super::connection::Connection;
|
||||||
|
use super::error::{ConnectError, InvalidUrl, SendRequestError};
|
||||||
use super::response::ClientResponse;
|
use super::response::ClientResponse;
|
||||||
use super::{Connect, ConnectError, SendRequestError};
|
|
||||||
|
|
||||||
/// An HTTP Client Request
|
/// An HTTP Client Request
|
||||||
///
|
///
|
||||||
@ -180,23 +180,32 @@ 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 = ConnectError>,
|
T: Service<Request = Uri, 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());
|
let uri = head.uri.clone();
|
||||||
if let Err(e) = connect.validate() {
|
|
||||||
Either::A(err(e.into()))
|
// validate uri
|
||||||
|
if uri.host().is_none() {
|
||||||
|
Either::A(err(InvalidUrl::MissingHost.into()))
|
||||||
|
} else if uri.scheme_part().is_none() {
|
||||||
|
Either::A(err(InvalidUrl::MissingScheme.into()))
|
||||||
|
} else if let Some(scheme) = uri.scheme_part() {
|
||||||
|
match scheme.as_str() {
|
||||||
|
"http" | "ws" | "https" | "wss" => Either::B(
|
||||||
|
connector
|
||||||
|
// connect to the host
|
||||||
|
.call(uri)
|
||||||
|
.from_err()
|
||||||
|
// send request
|
||||||
|
.and_then(move |connection| connection.send_request(head, body)),
|
||||||
|
),
|
||||||
|
_ => Either::A(err(InvalidUrl::UnknownScheme.into())),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Either::B(
|
Either::A(err(InvalidUrl::UnknownScheme.into()))
|
||||||
connector
|
|
||||||
// connect to the host
|
|
||||||
.call(connect)
|
|
||||||
.from_err()
|
|
||||||
// send request
|
|
||||||
.and_then(move |connection| connection.send_request(head, body)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,7 +538,7 @@ impl ClientRequestBuilder {
|
|||||||
if !parts.headers.contains_key(header::HOST) {
|
if !parts.headers.contains_key(header::HOST) {
|
||||||
let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
|
let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
|
||||||
|
|
||||||
let _ = match parts.uri.port() {
|
let _ = match parts.uri.port_u16() {
|
||||||
None | Some(80) | Some(443) => write!(wrt, "{}", host),
|
None | Some(80) | Some(443) => write!(wrt, "{}", host),
|
||||||
Some(port) => write!(wrt, "{}:{}", host, port),
|
Some(port) => write!(wrt, "{}:{}", host, port),
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||||
use actix_connect::{default_connector, Address, Connect as TcpConnect, ConnectError};
|
use actix_connect::{default_connector, Connect as TcpConnect, ConnectError};
|
||||||
use actix_service::{apply_fn, Service};
|
use actix_service::{apply_fn, Service};
|
||||||
use base64;
|
use base64;
|
||||||
use futures::future::{err, Either, FutureResult};
|
use futures::future::{err, Either, FutureResult};
|
||||||
@ -131,7 +131,7 @@ where
|
|||||||
|
|
||||||
// prep connection
|
// prep connection
|
||||||
let connect = TcpConnect::new(request.uri().host().unwrap().to_string())
|
let connect = TcpConnect::new(request.uri().host().unwrap().to_string())
|
||||||
.set_port(request.uri().port().unwrap_or_else(|| proto.port()));
|
.set_port(request.uri().port_u16().unwrap_or_else(|| proto.port()));
|
||||||
|
|
||||||
let fut = Box::new(
|
let fut = Box::new(
|
||||||
self.connector
|
self.connector
|
||||||
|
@ -5,10 +5,10 @@ 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, ConnectError,
|
ClientRequest, ClientRequestBuilder, ClientResponse, ConnectError, Connection,
|
||||||
Connection, Connector, SendRequestError,
|
Connector, SendRequestError,
|
||||||
};
|
};
|
||||||
use actix_http::ws;
|
use actix_http::{http::Uri, 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;
|
||||||
@ -158,8 +158,8 @@ impl TestServerRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_connector(
|
fn new_connector(
|
||||||
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
|
||||||
+ Clone {
|
{
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "ssl")]
|
||||||
{
|
{
|
||||||
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||||
@ -185,8 +185,8 @@ impl TestServerRuntime {
|
|||||||
/// Http connector
|
/// Http connector
|
||||||
pub fn connector(
|
pub fn connector(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
|
) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
|
||||||
+ Clone {
|
{
|
||||||
self.execute(|| TestServerRuntime::new_connector())
|
self.execute(|| TestServerRuntime::new_connector())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user