Skip to content

Commit 06249b8

Browse files
committed
feat: add http_keep_alive to Config
Also renamed `no_delay` to `tcp_no_delay`. the options for configuring this in Isahc and Hyper are unfortunately not super clear.
1 parent 6508f13 commit 06249b8

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

src/config.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ use std::time::Duration;
66
#[non_exhaustive]
77
#[derive(Clone, Debug)]
88
pub struct Config {
9+
/// HTTP/1.1 `keep-alive` (connection pooling).
10+
///
11+
/// Default: `true`.
12+
pub http_keep_alive: bool,
913
/// TCP `NO_DELAY`.
1014
///
1115
/// Default: `false`.
12-
pub no_delay: bool,
16+
pub tcp_no_delay: bool,
1317
/// Connection timeout duration.
1418
///
1519
/// Default: `Some(Duration::from_secs(60))`.
@@ -20,7 +24,8 @@ impl Config {
2024
/// Construct new empty config.
2125
pub fn new() -> Self {
2226
Self {
23-
no_delay: false,
27+
http_keep_alive: true,
28+
tcp_no_delay: false,
2429
timeout: Some(Duration::from_secs(60)),
2530
}
2631
}
@@ -33,9 +38,15 @@ impl Default for Config {
3338
}
3439

3540
impl Config {
41+
/// Set HTTP/1.1 `keep-alive` (connection pooling).
42+
pub fn set_http_keep_alive(mut self, keep_alive: bool) -> Self {
43+
self.http_keep_alive = keep_alive;
44+
self
45+
}
46+
3647
/// Set TCP `NO_DELAY`.
37-
pub fn set_no_delay(mut self, no_delay: bool) -> Self {
38-
self.no_delay = no_delay;
48+
pub fn set_tcp_no_delay(mut self, no_delay: bool) -> Self {
49+
self.tcp_no_delay = no_delay;
3950
self
4051
}
4152

src/h1/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,37 @@ impl HttpClient for H1Client {
156156
for (idx, addr) in addrs.into_iter().enumerate() {
157157
let has_another_addr = idx != max_addrs_idx;
158158

159+
#[cfg(feature = "unstable-config")]
160+
if !self.config.http_keep_alive {
161+
match scheme {
162+
"http" => {
163+
let stream = async_std::net::TcpStream::connect(addr).await?;
164+
req.set_peer_addr(stream.peer_addr().ok());
165+
req.set_local_addr(stream.local_addr().ok());
166+
let tcp_conn = client::connect(stream, req);
167+
return if let Some(timeout) = self.config.timeout {
168+
async_std::future::timeout(timeout, tcp_conn).await?
169+
} else {
170+
tcp_conn.await
171+
};
172+
}
173+
#[cfg(any(feature = "native-tls", feature = "rustls"))]
174+
"https" => {
175+
let raw_stream = async_std::net::TcpStream::connect(addr).await?;
176+
req.set_peer_addr(raw_stream.peer_addr().ok());
177+
req.set_local_addr(raw_stream.local_addr().ok());
178+
let tls_stream = tls::add_tls(&host, raw_stream).await?;
179+
let tsl_conn = client::connect(tls_stream, req);
180+
return if let Some(timeout) = self.config.timeout {
181+
async_std::future::timeout(timeout, tsl_conn).await?
182+
} else {
183+
tsl_conn.await
184+
};
185+
}
186+
_ => unreachable!(),
187+
}
188+
}
189+
159190
match scheme {
160191
"http" => {
161192
let pool_ref = if let Some(pool_ref) = self.http_pools.get(&addr) {

src/h1/tcp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl Manager<TcpStream, std::io::Error> for TcpConnection {
6565
let tcp_stream = TcpStream::connect(self.addr).await?;
6666

6767
#[cfg(feature = "unstable-config")]
68-
tcp_stream.set_nodelay(self.config.no_delay)?;
68+
tcp_stream.set_nodelay(self.config.tcp_no_delay)?;
6969

7070
Ok(tcp_stream)
7171
}
@@ -75,7 +75,7 @@ impl Manager<TcpStream, std::io::Error> for TcpConnection {
7575
let mut cx = Context::from_waker(futures::task::noop_waker_ref());
7676

7777
#[cfg(feature = "unstable-config")]
78-
conn.set_nodelay(self.config.no_delay)?;
78+
conn.set_nodelay(self.config.tcp_no_delay)?;
7979

8080
match Pin::new(conn).poll_read(&mut cx, &mut buf) {
8181
Poll::Ready(Err(error)) => Err(error),

src/h1/tls.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl Manager<TlsStream<TcpStream>, Error> for TlsConnection {
7474
let raw_stream = async_std::net::TcpStream::connect(self.addr).await?;
7575

7676
#[cfg(feature = "unstable-config")]
77-
raw_stream.set_nodelay(self.config.no_delay)?;
77+
raw_stream.set_nodelay(self.config.tcp_no_delay)?;
7878

7979
let tls_stream = add_tls(&self.host, raw_stream).await?;
8080
Ok(tls_stream)
@@ -86,7 +86,7 @@ impl Manager<TlsStream<TcpStream>, Error> for TlsConnection {
8686

8787
#[cfg(feature = "unstable-config")]
8888
conn.get_ref()
89-
.set_nodelay(self.config.no_delay)
89+
.set_nodelay(self.config.tcp_no_delay)
9090
.map_err(Error::from)?;
9191

9292
match Pin::new(conn).poll_read(&mut cx, &mut buf) {
@@ -105,12 +105,12 @@ impl Manager<TlsStream<TcpStream>, Error> for TlsConnection {
105105

106106
cfg_if::cfg_if! {
107107
if #[cfg(feature = "rustls")] {
108-
async fn add_tls(host: &str, stream: TcpStream) -> Result<TlsStream<TcpStream>, std::io::Error> {
108+
pub(crate) async fn add_tls(host: &str, stream: TcpStream) -> Result<TlsStream<TcpStream>, std::io::Error> {
109109
let connector = async_tls::TlsConnector::default();
110110
connector.connect(host, stream).await
111111
}
112112
} else if #[cfg(feature = "native-tls")] {
113-
async fn add_tls(
113+
pub(crate) async fn add_tls(
114114
host: &str,
115115
stream: TcpStream,
116116
) -> Result<TlsStream<TcpStream>, async_native_tls::Error> {

src/hyper.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ impl HttpClient for HyperClient {
9797
///
9898
/// Config options may not impact existing connections.
9999
fn set_config(&mut self, config: Config) -> http_types::Result<()> {
100+
let connector = HttpsConnector::new();
101+
let mut builder = hyper::Client::builder();
102+
103+
if !config.http_keep_alive {
104+
builder.pool_max_idle_per_host(1);
105+
}
106+
107+
self.client = Box::new(builder.build(connector));
100108
self.config = config;
101109

102110
Ok(())
@@ -115,7 +123,11 @@ impl TryFrom<Config> for HyperClient {
115123

116124
fn try_from(config: Config) -> Result<Self, Self::Error> {
117125
let connector = HttpsConnector::new();
118-
let builder = hyper::Client::builder();
126+
let mut builder = hyper::Client::builder();
127+
128+
if !config.http_keep_alive {
129+
builder.pool_max_idle_per_host(1);
130+
}
119131

120132
Ok(Self {
121133
client: Box::new(builder.build(connector)),

src/isahc.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ impl HttpClient for IsahcClient {
8282
fn set_config(&mut self, config: Config) -> http_types::Result<()> {
8383
let mut builder = isahc::HttpClient::builder();
8484

85-
if config.no_delay {
85+
if !config.http_keep_alive {
86+
builder = builder.connection_cache_size(0);
87+
}
88+
if config.tcp_no_delay {
8689
builder = builder.tcp_nodelay();
8790
}
8891
if let Some(timeout) = config.timeout {
@@ -109,7 +112,10 @@ impl TryFrom<Config> for IsahcClient {
109112
fn try_from(config: Config) -> Result<Self, Self::Error> {
110113
let mut builder = isahc::HttpClient::builder();
111114

112-
if config.no_delay {
115+
if !config.http_keep_alive {
116+
builder = builder.connection_cache_size(0);
117+
}
118+
if config.tcp_no_delay {
113119
builder = builder.tcp_nodelay();
114120
}
115121
if let Some(timeout) = config.timeout {

0 commit comments

Comments
 (0)