move actix_http::client to awc

This commit is contained in:
fakeshadow 2021-01-20 04:05:11 +08:00
parent 4d688ae921
commit 2cb2a30949
18 changed files with 132 additions and 137 deletions

View File

@ -47,10 +47,10 @@ compress = ["actix-http/compress", "awc/compress"]
secure-cookies = ["actix-http/secure-cookies"] secure-cookies = ["actix-http/secure-cookies"]
# openssl # openssl
openssl = ["actix-tls/accept", "actix-tls/openssl", "awc/openssl", "open-ssl"] openssl = ["actix-http/openssl", "awc/openssl", "actix-tls/accept", "open-ssl"]
# rustls # rustls
rustls = ["actix-tls/accept", "actix-tls/rustls", "awc/rustls", "rust-tls"] rustls = ["actix-http/rustls", "awc/rustls", "actix-tls/accept", "rust-tls"]
[[example]] [[example]]
name = "basic" name = "basic"

View File

@ -44,7 +44,7 @@ actix-service = "2.0.0-beta.3"
actix-codec = "0.4.0-beta.1" actix-codec = "0.4.0-beta.1"
actix-utils = "3.0.0-beta.1" actix-utils = "3.0.0-beta.1"
actix-rt = "2.0.0-beta.2" actix-rt = "2.0.0-beta.2"
actix-tls = "3.0.0-beta.2" actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["accept", "uri"] }
actix = { version = "0.11.0-beta.1", optional = true } actix = { version = "0.11.0-beta.1", optional = true }
base64 = "0.13" base64 = "0.13"
@ -55,9 +55,9 @@ cookie = { version = "0.14.1", features = ["percent-encode"] }
derive_more = "0.99.5" derive_more = "0.99.5"
either = "1.5.3" either = "1.5.3"
encoding_rs = "0.8" encoding_rs = "0.8"
futures-channel = { version = "0.3.7", default-features = false } futures-channel = { version = "0.3.7", default-features = false, features = ["alloc"] }
futures-core = { version = "0.3.7", default-features = false } futures-core = { version = "0.3.7", default-features = false }
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } futures-util = { version = "0.3.7", default-features = false, features = ["alloc", "sink"] }
ahash = "0.6" ahash = "0.6"
h2 = "0.3.0" h2 = "0.3.0"
http = "0.2.2" http = "0.2.2"

View File

@ -18,7 +18,6 @@ mod macros;
pub mod body; pub mod body;
mod builder; mod builder;
pub mod client;
mod config; mod config;
#[cfg(feature = "compress")] #[cfg(feature = "compress")]
pub mod encoding; pub mod encoding;
@ -45,6 +44,7 @@ pub use self::builder::HttpServiceBuilder;
pub use self::config::{KeepAlive, ServiceConfig}; pub use self::config::{KeepAlive, ServiceConfig};
pub use self::error::{Error, ResponseError, Result}; pub use self::error::{Error, ResponseError, Result};
pub use self::extensions::Extensions; pub use self::extensions::Extensions;
pub use self::header::HeaderMap;
pub use self::httpmessage::HttpMessage; pub use self::httpmessage::HttpMessage;
pub use self::message::{Message, RequestHead, RequestHeadType, ResponseHead}; pub use self::message::{Message, RequestHead, RequestHeadType, ResponseHead};
pub use self::payload::{Payload, PayloadStream}; pub use self::payload::{Payload, PayloadStream};

View File

@ -28,10 +28,10 @@ features = ["openssl", "rustls", "compress"]
default = ["compress"] default = ["compress"]
# openssl # openssl
openssl = ["open-ssl", "actix-http/openssl"] openssl = ["open-ssl", "actix-tls/openssl"]
# rustls # rustls
rustls = ["rust-tls", "actix-http/rustls"] rustls = ["rust-tls", "actix-tls/rustls"]
# content-encoding support # content-encoding support
compress = ["actix-http/compress"] compress = ["actix-http/compress"]
@ -44,15 +44,19 @@ actix-codec = "0.4.0-beta.1"
actix-service = "2.0.0-beta.3" actix-service = "2.0.0-beta.3"
actix-http = "3.0.0-beta.1" actix-http = "3.0.0-beta.1"
actix-rt = "2.0.0-beta.2" actix-rt = "2.0.0-beta.2"
actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["connect", "uri"] }
actix-utils = "3.0.0-beta.1"
# TODO: temporary import actix-tls to bypass some actix-http mods ahash = "0.6"
actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["connect"] }
base64 = "0.13" base64 = "0.13"
bytes = "1" bytes = "1"
cfg-if = "1.0" cfg-if = "1.0"
derive_more = "0.99.5" derive_more = "0.99.5"
futures-core = { version = "0.3.7", default-features = false } futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
futures-util = { version = "0.3.7", default-features = false, features = ["alloc"] }
h2 = "0.3"
http = "0.2.3"
indexmap = "1.6"
log =" 0.4" log =" 0.4"
mime = "0.3" mime = "0.3"
percent-encoding = "2.1" percent-encoding = "2.1"
@ -60,8 +64,11 @@ rand = "0.8"
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_urlencoded = "0.7" serde_urlencoded = "0.7"
slab = "0.4"
open-ssl = { version = "0.10", package = "openssl", optional = true } open-ssl = { version = "0.10", package = "openssl", optional = true }
pin-project = "1"
rust-tls = { version = "0.19.0", package = "rustls", optional = true, features = ["dangerous_configuration"] } rust-tls = { version = "0.19.0", package = "rustls", optional = true, features = ["dangerous_configuration"] }
tokio = { version = "1", features = ["sync"] }
trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true } trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true }
[dev-dependencies] [dev-dependencies]

View File

@ -4,10 +4,10 @@ use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use actix_http::client::{Connect as HttpConnect, ConnectError, Connection, Connector};
use actix_http::http::{self, header, Error as HttpError, HeaderMap, HeaderName}; use actix_http::http::{self, header, Error as HttpError, HeaderMap, HeaderName};
use actix_service::Service; use actix_service::Service;
use crate::client::{Connect as HttpConnect, ConnectError, Connection, Connector};
use crate::connect::{Connect, ConnectorWrapper}; use crate::connect::{Connect, ConnectorWrapper};
use crate::{Client, ClientConfig}; use crate::{Client, ClientConfig};

View File

@ -9,10 +9,10 @@ use futures_util::future::{err, Either, FutureExt, LocalBoxFuture, Ready};
use h2::client::SendRequest; use h2::client::SendRequest;
use pin_project::pin_project; use pin_project::pin_project;
use crate::body::MessageBody; use actix_http::body::MessageBody;
use crate::h1::ClientCodec; use actix_http::h1::ClientCodec;
use crate::message::{RequestHeadType, ResponseHead}; use actix_http::Payload;
use crate::payload::Payload; use actix_http::{RequestHeadType, ResponseHead};
use super::error::SendRequestError; use super::error::SendRequestError;
use super::pool::{Acquired, Protocol}; use super::pool::{Acquired, Protocol};

View File

@ -1,13 +1,9 @@
use std::fmt; use std::{fmt, marker::PhantomData, time::Duration};
use std::marker::PhantomData;
use std::time::Duration;
use actix_codec::{AsyncRead, AsyncWrite}; use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::net::TcpStream; use actix_rt::net::TcpStream;
use actix_service::{apply_fn, Service, ServiceExt}; use actix_service::{apply_fn, Service, ServiceExt};
use actix_tls::connect::{ use actix_tls::connect::{Connect as TcpConnect, Connection as TcpConnection};
default_connector, Connect as TcpConnect, Connection as TcpConnection,
};
use actix_utils::timeout::{TimeoutError, TimeoutService}; use actix_utils::timeout::{TimeoutError, TimeoutService};
use http::Uri; use http::Uri;
@ -22,15 +18,13 @@ use actix_tls::connect::ssl::openssl::SslConnector as OpensslConnector;
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
use actix_tls::connect::ssl::rustls::ClientConfig; use actix_tls::connect::ssl::rustls::ClientConfig;
#[cfg(feature = "rustls")]
use std::sync::Arc;
#[cfg(any(feature = "openssl", feature = "rustls"))] #[cfg(any(feature = "openssl", feature = "rustls"))]
enum SslConnector { enum SslConnector {
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
Openssl(OpensslConnector), Openssl(OpensslConnector),
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
Rustls(Arc<ClientConfig>), Rustls(std::sync::Arc<ClientConfig>),
} }
#[cfg(not(any(feature = "openssl", feature = "rustls")))] #[cfg(not(any(feature = "openssl", feature = "rustls")))]
type SslConnector = (); type SslConnector = ();
@ -70,7 +64,7 @@ impl Connector<(), ()> {
> { > {
Connector { Connector {
ssl: Self::build_ssl(vec![b"h2".to_vec(), b"http/1.1".to_vec()]), ssl: Self::build_ssl(vec![b"h2".to_vec(), b"http/1.1".to_vec()]),
connector: default_connector(), connector: connector_impl::default_connector(),
config: ConnectorConfig::default(), config: ConnectorConfig::default(),
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -91,7 +85,7 @@ impl Connector<(), ()> {
let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap(); let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap();
let _ = ssl let _ = ssl
.set_alpn_protos(&alpn) .set_alpn_protos(&alpn)
.map_err(|e| error!("Can not set alpn protocol: {:?}", e)); .map_err(|e| log::error!("Can not set alpn protocol: {:?}", e));
SslConnector::Openssl(ssl.build()) SslConnector::Openssl(ssl.build())
} }
@ -103,7 +97,7 @@ impl Connector<(), ()> {
config config
.root_store .root_store
.add_server_trust_anchors(&actix_tls::accept::rustls::TLS_SERVER_ROOTS); .add_server_trust_anchors(&actix_tls::accept::rustls::TLS_SERVER_ROOTS);
SslConnector::Rustls(Arc::new(config)) SslConnector::Rustls(std::sync::Arc::new(config))
} }
// ssl turned off, provides empty ssl connector // ssl turned off, provides empty ssl connector
@ -156,7 +150,7 @@ where
} }
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
pub fn rustls(mut self, connector: Arc<ClientConfig>) -> Self { pub fn rustls(mut self, connector: std::sync::Arc<ClientConfig>) -> Self {
self.ssl = SslConnector::Rustls(connector); self.ssl = SslConnector::Rustls(connector);
self self
} }
@ -532,3 +526,81 @@ mod connect_impl {
} }
} }
} }
#[cfg(not(feature = "trust-dns"))]
mod connector_impl {
pub use actix_tls::connect::default_connector;
}
// resolver implementation using trust-dns crate.
#[cfg(feature = "trust-dns")]
mod connector_impl {
use std::net::SocketAddr;
use actix_rt::{net::TcpStream, Arbiter};
use actix_service::Service;
use actix_tls::connect::{
Address, Connect, ConnectError, Connection, Resolve, Resolver,
};
use futures_core::future::LocalBoxFuture;
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
system_conf::read_system_conf,
TokioAsyncResolver,
};
pub struct TrustDnsResolver {
resolver: TokioAsyncResolver,
}
impl TrustDnsResolver {
fn new() -> Self {
// dns struct is cached in Arbiter thread local map.
// so new client constructor can reuse the dns resolver on local thread.
if Arbiter::contains_item::<TokioAsyncResolver>() {
Arbiter::get_item(|item: &TokioAsyncResolver| TrustDnsResolver {
resolver: item.clone(),
})
} else {
let (cfg, opts) = match read_system_conf() {
Ok((cfg, opts)) => (cfg, opts),
Err(e) => {
log::error!("TRust-DNS can not load system config: {}", e);
(ResolverConfig::default(), ResolverOpts::default())
}
};
let resolver = TokioAsyncResolver::tokio(cfg, opts).unwrap();
Arbiter::set_item(resolver.clone());
TrustDnsResolver { resolver }
}
}
}
impl Resolve for TrustDnsResolver {
fn lookup<'a>(
&'a self,
host: &'a str,
port: u16,
) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>>
{
Box::pin(async move {
let res = self
.resolver
.lookup_ip(host)
.await?
.iter()
.map(|ip| SocketAddr::new(ip, port))
.collect();
Ok(res)
})
}
}
pub fn default_connector<T: Address + 'static>(
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
+ Clone {
actix_tls::connect::new_connector(Resolver::new_custom(TrustDnsResolver::new()))
}
}

View File

@ -5,8 +5,8 @@ use derive_more::{Display, From};
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
use actix_tls::accept::openssl::SslError; use actix_tls::accept::openssl::SslError;
use crate::error::{Error, ParseError, ResponseError}; use actix_http::error::{Error, ParseError, ResponseError};
use crate::http::{Error as HttpError, StatusCode}; use actix_http::http::{Error as HttpError, StatusCode};
/// 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)]

View File

@ -10,17 +10,17 @@ use futures_core::Stream;
use futures_util::future::poll_fn; use futures_util::future::poll_fn;
use futures_util::{pin_mut, SinkExt, StreamExt}; use futures_util::{pin_mut, SinkExt, StreamExt};
use crate::error::PayloadError; use actix_http::body::{BodySize, MessageBody};
use crate::h1; use actix_http::error::PayloadError;
use crate::header::HeaderMap; use actix_http::h1;
use crate::http::header::{IntoHeaderValue, HOST}; use actix_http::http::header::{IntoHeaderValue, HOST};
use crate::message::{RequestHeadType, ResponseHead}; use actix_http::HeaderMap;
use crate::payload::{Payload, PayloadStream}; use actix_http::{Payload, PayloadStream};
use actix_http::{RequestHeadType, ResponseHead};
use super::connection::{ConnectionLifetime, ConnectionType, IoConnection}; use super::connection::{ConnectionLifetime, ConnectionType, IoConnection};
use super::error::{ConnectError, SendRequestError}; use super::error::{ConnectError, SendRequestError};
use super::pool::Acquired; use super::pool::Acquired;
use crate::body::{BodySize, MessageBody};
pub(crate) async fn send_request<T, B>( pub(crate) async fn send_request<T, B>(
io: T, io: T,

View File

@ -13,10 +13,10 @@ use h2::{
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING}; use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, TRANSFER_ENCODING};
use http::{request::Request, Method, Version}; use http::{request::Request, Method, Version};
use crate::body::{BodySize, MessageBody}; use actix_http::body::{BodySize, MessageBody};
use crate::header::HeaderMap; use actix_http::HeaderMap;
use crate::message::{RequestHeadType, ResponseHead}; use actix_http::Payload;
use crate::payload::Payload; use actix_http::{RequestHeadType, ResponseHead};
use super::config::ConnectorConfig; use super::config::ConnectorConfig;
use super::connection::{ConnectionType, IoConnection}; use super::connection::{ConnectionType, IoConnection};
@ -34,7 +34,7 @@ where
T: AsyncRead + AsyncWrite + Unpin + 'static, T: AsyncRead + AsyncWrite + Unpin + 'static,
B: MessageBody, B: MessageBody,
{ {
trace!("Sending client request: {:?} {:?}", head, body.size()); log::trace!("Sending client request: {:?} {:?}", head, body.size());
let head_req = head.as_ref().method == Method::HEAD; let head_req = head.as_ref().method == Method::HEAD;
let length = body.size(); let length = body.size();
let eof = matches!( let eof = matches!(

View File

@ -12,13 +12,13 @@ use actix_service::Service;
use actix_utils::task::LocalWaker; use actix_utils::task::LocalWaker;
use ahash::AHashMap; use ahash::AHashMap;
use bytes::Bytes; use bytes::Bytes;
use futures_channel::oneshot;
use futures_util::future::{poll_fn, FutureExt, LocalBoxFuture}; use futures_util::future::{poll_fn, FutureExt, LocalBoxFuture};
use h2::client::{Connection, SendRequest}; use h2::client::{Connection, SendRequest};
use http::uri::Authority; use http::uri::Authority;
use indexmap::IndexSet; use indexmap::IndexSet;
use pin_project::pin_project; use pin_project::pin_project;
use slab::Slab; use slab::Slab;
use tokio::sync::oneshot;
use super::config::ConnectorConfig; use super::config::ConnectorConfig;
use super::connection::{ConnectionType, IoConnection}; use super::connection::{ConnectionType, IoConnection};

View File

@ -6,14 +6,14 @@ use std::{fmt, io, net};
use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf}; use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
use actix_http::body::Body; use actix_http::body::Body;
use actix_http::client::{
Connect as ClientConnect, ConnectError, Connection, SendRequestError,
};
use actix_http::h1::ClientCodec; use actix_http::h1::ClientCodec;
use actix_http::http::HeaderMap; use actix_http::http::HeaderMap;
use actix_http::{RequestHead, RequestHeadType, ResponseHead}; use actix_http::{RequestHead, RequestHeadType, ResponseHead};
use actix_service::Service; use actix_service::Service;
use crate::client::{
Connect as ClientConnect, ConnectError, Connection, SendRequestError,
};
use crate::response::ClientResponse; use crate::response::ClientResponse;
pub(crate) struct ConnectorWrapper<T>(pub T); pub(crate) struct ConnectorWrapper<T>(pub T);

View File

@ -1,82 +0,0 @@
// TODO: this mod bypass actix-http and use actix_tls::connect directly.
// Future refactor should change this mod if actix-http still used as upstream dep of awc.
pub use connector_impl::*;
#[cfg(not(feature = "trust-dns"))]
mod connector_impl {
pub use actix_tls::connect::default_connector;
}
#[cfg(feature = "trust-dns")]
mod connector_impl {
// resolver implementation using trust-dns crate.
use std::net::SocketAddr;
use actix_rt::{net::TcpStream, Arbiter};
use actix_service::Service;
use actix_tls::connect::{
Address, Connect, ConnectError, Connection, Resolve, Resolver,
};
use futures_core::future::LocalBoxFuture;
use trust_dns_resolver::{
config::{ResolverConfig, ResolverOpts},
system_conf::read_system_conf,
TokioAsyncResolver,
};
pub struct TrustDnsResolver {
resolver: TokioAsyncResolver,
}
impl TrustDnsResolver {
fn new() -> Self {
// dns struct is cached in Arbiter thread local map.
// so new client constructor can reuse the dns resolver on local thread.
if Arbiter::contains_item::<TokioAsyncResolver>() {
Arbiter::get_item(|item: &TokioAsyncResolver| TrustDnsResolver {
resolver: item.clone(),
})
} else {
let (cfg, opts) = match read_system_conf() {
Ok((cfg, opts)) => (cfg, opts),
Err(e) => {
log::error!("TRust-DNS can not load system config: {}", e);
(ResolverConfig::default(), ResolverOpts::default())
}
};
let resolver = TokioAsyncResolver::tokio(cfg, opts).unwrap();
Arbiter::set_item(resolver.clone());
TrustDnsResolver { resolver }
}
}
}
impl Resolve for TrustDnsResolver {
fn lookup<'a>(
&'a self,
host: &'a str,
port: u16,
) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>>
{
Box::pin(async move {
let res = self
.resolver
.lookup_ip(host)
.await?
.iter()
.map(|ip| SocketAddr::new(ip, port))
.collect();
Ok(res)
})
}
}
pub fn default_connector<T: Address + 'static>(
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
+ Clone {
actix_tls::connect::new_connector(Resolver::new_custom(TrustDnsResolver::new()))
}
}

View File

@ -1,5 +1,5 @@
//! Http client errors //! Http client errors
pub use actix_http::client::{ pub use crate::client::{
ConnectError, FreezeRequestError, InvalidUrl, SendRequestError, ConnectError, FreezeRequestError, InvalidUrl, SendRequestError,
}; };
pub use actix_http::error::PayloadError; pub use actix_http::error::PayloadError;

View File

@ -98,14 +98,15 @@ use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
pub use actix_http::{client::Connector, cookie, http}; pub use crate::client::Connector;
pub use actix_http::{cookie, http};
use actix_http::http::{Error as HttpError, HeaderMap, Method, Uri}; use actix_http::http::{Error as HttpError, HeaderMap, Method, Uri};
use actix_http::RequestHead; use actix_http::RequestHead;
mod builder; mod builder;
mod client;
mod connect; mod connect;
pub mod connector;
pub mod error; pub mod error;
mod frozen; mod frozen;
mod request; mod request;
@ -155,9 +156,7 @@ impl Default for Client {
fn default() -> Self { fn default() -> Self {
Client(Rc::new(ClientConfig { Client(Rc::new(ClientConfig {
connector: RefCell::new(Box::new(ConnectorWrapper( connector: RefCell::new(Box::new(ConnectorWrapper(
Connector::new() Connector::new().finish(),
.connector(connector::default_connector())
.finish(),
))), ))),
headers: HeaderMap::new(), headers: HeaderMap::new(),
timeout: Some(Duration::from_secs(5)), timeout: Some(Duration::from_secs(5)),

View File

@ -120,7 +120,6 @@ async fn test_timeout() {
}); });
let connector = awc::Connector::new() let connector = awc::Connector::new()
.connector(awc::connector::default_connector())
.timeout(Duration::from_secs(15)) .timeout(Duration::from_secs(15))
.finish(); .finish();