Merge pull request #69 from taiki-e/feature

Fix h1_client feature
This commit is contained in:
Jeremiah Senkpiel 2021-02-15 10:09:23 -08:00 committed by GitHub
commit 40e188e056
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 38 deletions

View File

@ -33,7 +33,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: check
run: cargo check --no-default-features
@ -51,7 +51,7 @@ jobs:
override: true
components: clippy, rustfmt
- name: clippy
- name: clippy
run: cargo clippy --all-targets --workspace --features=docs
- name: fmt
@ -79,3 +79,18 @@ jobs:
with:
command: check
args: --target wasm32-unknown-unknown --no-default-features --features "native_client,wasm_client"
check_features:
name: Check feature combinations
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Install cargo-hack
run: cargo install cargo-hack
- name: Check all feature combinations works properly
# * `--feature-powerset` - run for the feature powerset of the package
# * `--no-dev-deps` - build without dev-dependencies to avoid https://github.com/rust-lang/cargo/issues/4866
# * `--skip docs` - skip `docs` feature
run: cargo hack check --feature-powerset --no-dev-deps --skip docs

View File

@ -37,6 +37,7 @@ async-trait = "0.1.37"
dashmap = "4.0.2"
http-types = "2.3.0"
log = "0.4.7"
cfg-if = "1.0.0"
# h1_client
async-h1 = { version = "2.0.0", optional = true }
@ -91,5 +92,4 @@ tide-rustls = { version = "0.1.4" }
tokio = { version = "0.2.21", features = ["macros"] }
serde = "1.0"
serde_json = "1.0"
cfg-if = "0.1.10"
mockito = "0.23.3"

View File

@ -9,34 +9,56 @@ use dashmap::DashMap;
use deadpool::managed::Pool;
use http_types::StatusCode;
#[cfg(feature = "native-tls")]
use async_native_tls::TlsStream;
#[cfg(feature = "rustls")]
use async_tls::client::TlsStream;
cfg_if::cfg_if! {
if #[cfg(feature = "rustls")] {
use async_tls::client::TlsStream;
} else if #[cfg(feature = "native-tls")] {
use async_native_tls::TlsStream;
}
}
use super::{async_trait, Error, HttpClient, Request, Response};
mod tcp;
#[cfg(any(feature = "native-tls", feature = "rustls"))]
mod tls;
use tcp::{TcpConnWrapper, TcpConnection};
#[cfg(any(feature = "native-tls", feature = "rustls"))]
use tls::{TlsConnWrapper, TlsConnection};
// This number is based on a few random benchmarks and see whatever gave decent perf vs resource use.
const DEFAULT_MAX_CONCURRENT_CONNECTIONS: usize = 50;
type HttpPool = DashMap<SocketAddr, Pool<TcpStream, std::io::Error>>;
#[cfg(any(feature = "native-tls", feature = "rustls"))]
type HttpsPool = DashMap<SocketAddr, Pool<TlsStream<TcpStream>, Error>>;
/// Async-h1 based HTTP Client, with connecton pooling ("Keep-Alive").
pub struct H1Client {
http_pools: HttpPool,
#[cfg(any(feature = "native-tls", feature = "rustls"))]
https_pools: HttpsPool,
max_concurrent_connections: usize,
}
impl Debug for H1Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let https_pools = if cfg!(any(feature = "native-tls", feature = "rustls")) {
self.http_pools
.iter()
.map(|pool| {
let status = pool.status();
format!(
"Connections: {}, Available: {}, Max: {}",
status.size, status.available, status.max_size
)
})
.collect::<Vec<String>>()
} else {
vec![]
};
f.debug_struct("H1Client")
.field(
"http_pools",
@ -52,20 +74,7 @@ impl Debug for H1Client {
})
.collect::<Vec<String>>(),
)
.field(
"https_pools",
&self
.http_pools
.iter()
.map(|pool| {
let status = pool.status();
format!(
"Connections: {}, Available: {}, Max: {}",
status.size, status.available, status.max_size
)
})
.collect::<Vec<String>>(),
)
.field("https_pools", &https_pools)
.field(
"max_concurrent_connections",
&self.max_concurrent_connections,
@ -85,6 +94,7 @@ impl H1Client {
pub fn new() -> Self {
Self {
http_pools: DashMap::new(),
#[cfg(any(feature = "native-tls", feature = "rustls"))]
https_pools: DashMap::new(),
max_concurrent_connections: DEFAULT_MAX_CONCURRENT_CONNECTIONS,
}
@ -94,6 +104,7 @@ impl H1Client {
pub fn with_max_connections(max: usize) -> Self {
Self {
http_pools: DashMap::new(),
#[cfg(any(feature = "native-tls", feature = "rustls"))]
https_pools: DashMap::new(),
max_concurrent_connections: max,
}
@ -106,6 +117,7 @@ impl HttpClient for H1Client {
req.insert_header("Connection", "keep-alive");
// Insert host
#[cfg(any(feature = "native-tls", feature = "rustls"))]
let host = req
.url()
.host_str()
@ -113,7 +125,9 @@ impl HttpClient for H1Client {
.to_string();
let scheme = req.url().scheme();
if scheme != "http" && scheme != "https" {
if scheme != "http"
&& (scheme != "https" || cfg!(not(any(feature = "native-tls", feature = "rustls"))))
{
return Err(Error::from_str(
StatusCode::BadRequest,
format!("invalid url scheme '{}'", scheme),
@ -124,6 +138,7 @@ impl HttpClient for H1Client {
.url()
.socket_addrs(|| match req.url().scheme() {
"http" => Some(80),
#[cfg(any(feature = "native-tls", feature = "rustls"))]
"https" => Some(443),
_ => None,
})?
@ -156,6 +171,7 @@ impl HttpClient for H1Client {
req.set_local_addr(stream.local_addr().ok());
client::connect(TcpConnWrapper::new(stream), req).await
}
#[cfg(any(feature = "native-tls", feature = "rustls"))]
"https" => {
let pool_ref = if let Some(pool_ref) = self.https_pools.get(&addr) {
pool_ref

View File

@ -8,10 +8,13 @@ use deadpool::managed::{Manager, Object, RecycleResult};
use futures::io::{AsyncRead, AsyncWrite};
use futures::task::{Context, Poll};
#[cfg(feature = "native-tls")]
use async_native_tls::TlsStream;
#[cfg(feature = "rustls")]
use async_tls::client::TlsStream;
cfg_if::cfg_if! {
if #[cfg(feature = "rustls")] {
use async_tls::client::TlsStream;
} else if #[cfg(feature = "native-tls")] {
use async_native_tls::TlsStream;
}
}
use crate::Error;
@ -76,16 +79,18 @@ impl Manager<TlsStream<TcpStream>, Error> for TlsConnection {
}
}
#[cfg(feature = "native-tls")]
async fn add_tls(
host: &str,
stream: TcpStream,
) -> Result<TlsStream<TcpStream>, async_native_tls::Error> {
async_native_tls::connect(host, stream).await
}
#[cfg(feature = "rustls")]
async fn add_tls(host: &str, stream: TcpStream) -> Result<TlsStream<TcpStream>, std::io::Error> {
let connector = async_tls::TlsConnector::default();
connector.connect(host, stream).await
cfg_if::cfg_if! {
if #[cfg(feature = "rustls")] {
async fn add_tls(host: &str, stream: TcpStream) -> Result<TlsStream<TcpStream>, std::io::Error> {
let connector = async_tls::TlsConnector::default();
connector.connect(host, stream).await
}
} else if #[cfg(feature = "native-tls")] {
async fn add_tls(
host: &str,
stream: TcpStream,
) -> Result<TlsStream<TcpStream>, async_native_tls::Error> {
async_native_tls::connect(host, stream).await
}
}
}