Merge branch 'master' into refactor/awc_client_builder

This commit is contained in:
fakeshadow 2021-02-18 03:56:51 -08:00 committed by GitHub
commit 51353c4dd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 118 deletions

View File

@ -16,7 +16,7 @@ use crate::message::{RequestHeadType, ResponseHead};
use crate::payload::Payload;
use super::error::SendRequestError;
use super::pool::{Acquired, Protocol};
use super::pool::Acquired;
use super::{h1proto, h2proto};
pub(crate) enum ConnectionType<Io> {
@ -49,7 +49,7 @@ impl H2Connection {
}
}
// wake up waker when drop
// cancel spawned connection task on drop.
impl Drop for H2Connection {
fn drop(&mut self) {
self.handle.abort();
@ -74,8 +74,6 @@ impl DerefMut for H2Connection {
pub trait Connection {
type Io: AsyncRead + AsyncWrite + Unpin;
fn protocol(&self) -> Protocol;
/// Send request and body
fn send_request<B: MessageBody + 'static, H: Into<RequestHeadType>>(
self,
@ -154,14 +152,6 @@ where
{
type Io = T;
fn protocol(&self) -> Protocol {
match self.io {
Some(ConnectionType::H1(_)) => Protocol::Http1,
Some(ConnectionType::H2(_)) => Protocol::Http2,
None => Protocol::Http1,
}
}
fn send_request<B: MessageBody + 'static, H: Into<RequestHeadType>>(
mut self,
head: H,
@ -210,7 +200,7 @@ where
}
#[allow(dead_code)]
pub(crate) enum EitherConnection<A, B>
pub(crate) enum EitherIoConnection<A, B>
where
A: AsyncRead + AsyncWrite + Unpin + 'static,
B: AsyncRead + AsyncWrite + Unpin + 'static,
@ -219,28 +209,21 @@ where
B(IoConnection<B>),
}
impl<A, B> Connection for EitherConnection<A, B>
impl<A, B> Connection for EitherIoConnection<A, B>
where
A: AsyncRead + AsyncWrite + Unpin + 'static,
B: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Io = EitherIo<A, B>;
fn protocol(&self) -> Protocol {
match self {
EitherConnection::A(con) => con.protocol(),
EitherConnection::B(con) => con.protocol(),
}
}
fn send_request<RB: MessageBody + 'static, H: Into<RequestHeadType>>(
self,
head: H,
body: RB,
) -> LocalBoxFuture<'static, Result<(ResponseHead, Payload), SendRequestError>> {
match self {
EitherConnection::A(con) => con.send_request(head, body),
EitherConnection::B(con) => con.send_request(head, body),
EitherIoConnection::A(con) => con.send_request(head, body),
EitherIoConnection::B(con) => con.send_request(head, body),
}
}
@ -253,11 +236,11 @@ where
Result<(ResponseHead, Framed<Self::Io, ClientCodec>), SendRequestError>,
> {
match self {
EitherConnection::A(con) => Box::pin(async {
EitherIoConnection::A(con) => Box::pin(async {
let (head, framed) = con.open_tunnel(head).await?;
Ok((head, framed.into_map_io(EitherIo::A)))
}),
EitherConnection::B(con) => Box::pin(async {
EitherIoConnection::B(con) => Box::pin(async {
let (head, framed) = con.open_tunnel(head).await?;
Ok((head, framed.into_map_io(EitherIo::B)))
}),

View File

@ -356,7 +356,7 @@ where
mod connect_impl {
use std::task::{Context, Poll};
use futures_util::future::{err, Either, Ready};
use futures_core::future::LocalBoxFuture;
use super::*;
use crate::client::connection::IoConnection;
@ -388,10 +388,7 @@ mod connect_impl {
{
type Response = IoConnection<Io>;
type Error = ConnectError;
type Future = Either<
<ConnectionPool<T, Io> as Service<Connect>>::Future,
Ready<Result<IoConnection<Io>, ConnectError>>,
>;
type Future = LocalBoxFuture<'static, Result<IoConnection<Io>, ConnectError>>;
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
@ -400,9 +397,9 @@ mod connect_impl {
fn call(&self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
Some("https") | Some("wss") => {
Either::Right(err(ConnectError::SslIsNotSupported))
Box::pin(async { Err(ConnectError::SslIsNotSupported) })
}
_ => Either::Left(self.tcp_pool.call(req)),
_ => self.tcp_pool.call(req),
}
}
}
@ -411,33 +408,29 @@ mod connect_impl {
#[cfg(any(feature = "openssl", feature = "rustls"))]
mod connect_impl {
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::ready;
use futures_util::future::Either;
use super::*;
use crate::client::connection::EitherConnection;
use crate::client::connection::EitherIoConnection;
pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
pub(crate) struct InnerConnector<S1, S2, Io1, Io2>
where
S1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError>,
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError>,
{
pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
pub(crate) tcp_pool: ConnectionPool<S1, Io1>,
pub(crate) ssl_pool: ConnectionPool<S2, Io2>,
}
impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
impl<S1, S2, Io1, Io2> Clone for InnerConnector<S1, S2, Io1, Io2>
where
S1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
{
fn clone(&self) -> Self {
InnerConnector {
@ -447,19 +440,16 @@ mod connect_impl {
}
}
impl<T1, T2, Io1, Io2> Service<Connect> for InnerConnector<T1, T2, Io1, Io2>
impl<S1, S2, Io1, Io2> Service<Connect> for InnerConnector<S1, S2, Io1, Io2>
where
S1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
T2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
{
type Response = EitherConnection<Io1, Io2>;
type Response = EitherIoConnection<Io1, Io2>;
type Error = ConnectError;
type Future = Either<
InnerConnectorResponseA<T1, Io1, Io2>,
InnerConnectorResponseB<T2, Io1, Io2>,
>;
type Future = InnerConnectorResponse<S1, S2, Io1, Io2>;
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
@ -467,69 +457,44 @@ mod connect_impl {
fn call(&self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
Some("https") | Some("wss") => Either::Right(InnerConnectorResponseB {
fut: self.ssl_pool.call(req),
_phantom: PhantomData,
}),
_ => Either::Left(InnerConnectorResponseA {
fut: self.tcp_pool.call(req),
_phantom: PhantomData,
}),
Some("https") | Some("wss") => {
InnerConnectorResponse::Io2(self.ssl_pool.call(req))
}
_ => InnerConnectorResponse::Io1(self.tcp_pool.call(req)),
}
}
}
#[pin_project::pin_project]
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
#[pin_project::pin_project(project = InnerConnectorProj)]
pub(crate) enum InnerConnectorResponse<S1, S2, Io1, Io2>
where
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
{
#[pin]
fut: <ConnectionPool<T, Io1> as Service<Connect>>::Future,
_phantom: PhantomData<Io2>,
}
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
where
T: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
Io1(#[pin] <ConnectionPool<S1, Io1> as Service<Connect>>::Future),
Io2(#[pin] <ConnectionPool<S2, Io2> as Service<Connect>>::Future),
}
impl<S1, S2, Io1, Io2> Future for InnerConnectorResponse<S1, S2, Io1, Io2>
where
S1: Service<Connect, Response = (Io1, Protocol), Error = ConnectError> + 'static,
S2: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Output = Result<EitherIoConnection<Io1, Io2>, ConnectError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(EitherConnection::A),
)
}
}
#[pin_project::pin_project]
pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
where
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
{
#[pin]
fut: <ConnectionPool<T, Io2> as Service<Connect>>::Future,
_phantom: PhantomData<Io1>,
}
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
where
T: Service<Connect, Response = (Io2, Protocol), Error = ConnectError> + 'static,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(EitherConnection::B),
)
match self.project() {
InnerConnectorProj::Io1(fut) => {
fut.poll(cx).map_ok(EitherIoConnection::A)
}
InnerConnectorProj::Io2(fut) => {
fut.poll(cx).map_ok(EitherIoConnection::B)
}
}
}
}
}

View File

@ -510,25 +510,43 @@ where
match msg {
Message::Item(mut req) => {
let pl = this.codec.message_type();
req.head_mut().peer_addr = *this.peer_addr;
// merge on_connect_ext data into request extensions
this.on_connect_data.merge_into(&mut req);
if pl == MessageType::Stream && this.flow.upgrade.is_some() {
this.messages.push_back(DispatcherMessage::Upgrade(req));
break;
}
if pl == MessageType::Payload || pl == MessageType::Stream {
let (ps, pl) = Payload::create(false);
let (req1, _) =
req.replace_payload(crate::Payload::H1(pl));
req = req1;
*this.payload = Some(ps);
match this.codec.message_type() {
// Request is upgradable. add upgrade message and break.
// everything remain in read buffer would be handed to
// upgraded Request.
MessageType::Stream if this.flow.upgrade.is_some() => {
this.messages
.push_back(DispatcherMessage::Upgrade(req));
break;
}
// Request is not upgradable.
MessageType::Payload | MessageType::Stream => {
/*
PayloadSender and Payload are smart pointers share the
same state.
PayloadSender is attached to dispatcher and used to sink
new chunked request data to state.
Payload is attached to Request and passed to Service::call
where the state can be collected and consumed.
*/
let (ps, pl) = Payload::create(false);
let (req1, _) =
req.replace_payload(crate::Payload::H1(pl));
req = req1;
*this.payload = Some(ps);
}
// Request has no payload.
MessageType::None => {}
}
// handle request early
// handle request early when no future in InnerDispatcher state.
if this.state.is_empty() {
self.as_mut().handle_request(req, cx)?;
this = self.as_mut().project();