hyperium / hyper

An HTTP library for Rust
https://hyper.rs
MIT License
14.08k stars 1.55k forks source link

[0.14.x] Expose `hyper::client::connect::http::ConnectError` #3592

Closed hasezoey closed 3 months ago

hasezoey commented 3 months ago

Is your feature request related to a problem? Please describe. Currently from what i can tell ConnectError is not exposed to the public, preventing downcasting hyper::Error::source to it, and so making matching against the OsError "ConnectionRefused" impossible.

Describe the solution you'd like Expose the type like HttpConnector, HttpInfo are already.

Describe alternatives you've considered A alternative that would work for my use-case is to add helper function to hyper::Error like is_connect to detect ConnectionRefused. Another alternative (likely very fragile and will stop working without notice):

if let Some(inner_err) = hyper_err.source() {
    if format!("{:#?}", inner_err).contains("ConnectionRefused") {
        debug!("Connection refused found!");
    }
}

Additional context I dont know if 0.x is still being developed or even supported, but currently we are using tonic, which still relies on hyper 0.14, and i would like to detect if a service creation failed because the connection failed with a ConnectionRefused error.

seanmonstar commented 3 months ago

If the error was an io::Error, it will be part of the source chain. Even without the ConnectError type exposed. You can use a function like this to find it:

pub(crate) fn find_source<E: StdError + 'static>(mut err: &dyn (StdError + 'static)) -> Option<&E> {
    while let Some(cause) = err {
        if let Some(ref typed) = cause.downcast_ref() {
            return Some(typed);
        }
        err = cause.source();
    }

    // else
    None
}
hasezoey commented 3 months ago

thanks, i didnt know yet that this could be chained (without much problems), though the code that worked for me was

/// Find a specific error in the [`Error::source`] chain
fn find_source<E: Error + 'static>(err: &dyn Error) -> Option<&E> {
    let mut err = err.source();
    while let Some(cause) = err {
        if let Some(typed) = cause.downcast_ref() {
            return Some(typed);
        }
        err = cause.source();
    }

    None
}

rustc 1.76 / 1.70, edition 2021