Skip to content

Commit

Permalink
feat(h1): allow to set keep alive configuration from response header
Browse files Browse the repository at this point in the history
  • Loading branch information
joelwurtz committed Feb 25, 2025
1 parent 96013ab commit 8b30657
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
13 changes: 13 additions & 0 deletions client/src/pool/exclusive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,19 @@ where
self.destroy_on_drop = true;
}

#[cfg(feature = "http1")]
pub(crate) fn keep_alive_hint(&mut self, timeout: Option<Duration>, max_requests: Option<usize>) {
if let Some(conn) = self.conn.as_mut() {
if let Some(timeout) = timeout {
conn.state.keep_alive_idle = timeout;
}

if let Some(max_requests) = max_requests {
conn.state.max_requests = max_requests;
}
}
}

#[cfg(feature = "http1")]
pub(crate) fn is_destroy_on_drop(&self) -> bool {
self.destroy_on_drop
Expand Down
40 changes: 39 additions & 1 deletion client/src/service/http.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::time::Duration;

use crate::{
connect::Connect,
error::Error,
http::Version,
http::{HeaderName, Version},
pool::{exclusive, shared},
response::Response,
service::ServiceDyn,
Expand Down Expand Up @@ -166,6 +168,9 @@ pub(crate) fn base_service() -> HttpService {
Ok(Ok((res, buf, decoder, is_close))) => {
if is_close {
_conn.destroy_on_drop();
} else {
let (timeout, max) = parse_keep_alive(&res);
_conn.keep_alive_hint(timeout, max);
}
let body = crate::h1::body::ResponseBody::new(_conn, buf, decoder);
let res = res.map(|_| crate::body::ResponseBody::H1(body));
Expand Down Expand Up @@ -201,3 +206,36 @@ pub(crate) fn base_service() -> HttpService {

Box::new(HttpService)
}

const KEEP_ALIVE: HeaderName = HeaderName::from_static("keep-alive");

fn parse_keep_alive<B>(res: &crate::http::Response<B>) -> (Option<Duration>, Option<usize>) {
let header = match res.headers().get(KEEP_ALIVE).map(|h| h.to_str()) {
Some(Ok(header)) => header,
_ => return (None, None),
};

let mut timeout = None;
let mut max = None;

for (key, value) in header.split(',').map(|item| {
let mut kv = item.splitn(2, '=');

(
kv.next().map(|s| s.trim()).unwrap_or_default(),
kv.next().map(|s| s.trim()).unwrap_or_default(),
)
}) {
match key.to_lowercase().as_str() {
"timeout" => {
timeout = value.parse::<u64>().ok().map(Duration::from_secs);
}
"max" => {
max = value.parse().ok();
}
_ => {}
}
}

(timeout, max)
}

0 comments on commit 8b30657

Please sign in to comment.