Skip to content

Commit

Permalink
feat!(client): expose whether a connection is reused from the pool
Browse files Browse the repository at this point in the history
This introduces a new type `ErrorConnectInfo` that contains information
about connection pool as well as transport-related data. This new type
can now be obtained from the `Error::connect_info()` method, which means
that this is a breaking change as the return type from the method has
changed. That said, all information that was available on the previous
return type is available on the new type through various getter methods.
  • Loading branch information
magurotuna committed Aug 18, 2024
1 parent df55aba commit 20dd247
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 10 deletions.
52 changes: 42 additions & 10 deletions src/client/legacy/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub struct Error {
kind: ErrorKind,
source: Option<Box<dyn StdError + Send + Sync>>,
#[cfg(any(feature = "http1", feature = "http2"))]
connect_info: Option<Connected>,
connect_info: Option<ErroredConnectInfo>,
}

#[derive(Debug)]
Expand All @@ -71,6 +71,34 @@ enum ErrorKind {
SendRequest,
}

/// Extra information about a failed connection.
pub struct ErroredConnectInfo {
conn_info: Connected,
is_reused: bool,
}

impl ErroredConnectInfo {
/// Determines if the connected transport is to an HTTP proxy.
pub fn is_proxied(&self) -> bool {
self.conn_info.is_proxied()
}

/// Copies the extra connection information into an `Extensions` map.
pub fn get_extras(&self, extensions: &mut http::Extensions) {
self.conn_info.get_extras(extensions);
}

/// Determines if the connected transport negotiated HTTP/2 as its next protocol.
pub fn is_negotiated_h2(&self) -> bool {
self.conn_info.is_negotiated_h2()
}

/// Determines if the connection is a reused one from the connection pool.
pub fn is_reused(&self) -> bool {
self.is_reused
}
}

macro_rules! e {
($kind:ident) => {
Error {
Expand Down Expand Up @@ -282,7 +310,7 @@ where
if req.version() == Version::HTTP_2 {
warn!("Connection is HTTP/1, but request requires HTTP/2");
return Err(TrySendError::Nope(
e!(UserUnsupportedVersion).with_connect_info(pooled.conn_info.clone()),
e!(UserUnsupportedVersion).with_connect_info(&pooled),
));
}

Expand Down Expand Up @@ -317,14 +345,12 @@ where
Err(mut err) => {
return if let Some(req) = err.take_message() {
Err(TrySendError::Retryable {
error: e!(Canceled, err.into_error())
.with_connect_info(pooled.conn_info.clone()),
error: e!(Canceled, err.into_error()).with_connect_info(&pooled),
req,
})
} else {
Err(TrySendError::Nope(
e!(SendRequest, err.into_error())
.with_connect_info(pooled.conn_info.clone()),
e!(SendRequest, err.into_error()).with_connect_info(&pooled),
))
}
}
Expand Down Expand Up @@ -464,7 +490,7 @@ where
Ok(checked_out)
}
// Connect won, checkout can just be dropped.
Either::Right((Ok(connected), _checkout)) => Ok(connected),
Either::Right((Ok(connected), _checkout)) => Ok(connected)
// Either checkout or connect could get canceled:
//
// 1. Connect is canceled if this is HTTP/2 and there is
Expand Down Expand Up @@ -1619,14 +1645,20 @@ impl Error {

/// Returns the info of the client connection on which this error occurred.
#[cfg(any(feature = "http1", feature = "http2"))]
pub fn connect_info(&self) -> Option<&Connected> {
pub fn connect_info(&self) -> Option<&ErroredConnectInfo> {
self.connect_info.as_ref()
}

#[cfg(any(feature = "http1", feature = "http2"))]
fn with_connect_info(self, connect_info: Connected) -> Self {
fn with_connect_info<B>(self, pooled: &pool::Pooled<PoolClient<B>, PoolKey>) -> Self
where
B: Send + 'static,
{
Self {
connect_info: Some(connect_info),
connect_info: Some(ErroredConnectInfo {
conn_info: pooled.conn_info.clone(),
is_reused: pooled.is_reused(),
}),
..self
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/client/legacy/connect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub trait Connection {
pub struct Connected {
pub(super) alpn: Alpn,
pub(super) is_proxied: bool,
pub(super) is_reused: bool,
pub(super) extra: Option<Extra>,
pub(super) poisoned: PoisonPill,
}
Expand Down Expand Up @@ -149,6 +150,7 @@ impl Connected {
Connected {
alpn: Alpn::None,
is_proxied: false,
is_reused: false,
extra: None,
poisoned: PoisonPill::healthy(),
}
Expand Down Expand Up @@ -226,6 +228,7 @@ impl Connected {
Connected {
alpn: self.alpn,
is_proxied: self.is_proxied,
is_reused: self.is_reused,
extra: self.extra.clone(),
poisoned: self.poisoned.clone(),
}
Expand Down

0 comments on commit 20dd247

Please sign in to comment.