aioduct 0.2.5

Async-native HTTP client built directly on hyper 1.x — no hyper-util, no legacy
Documentation
use http::Uri;
use http::uri::Scheme;

use crate::error::Error;

pub(crate) fn canonical_http_scheme(scheme: &Scheme) -> Result<Scheme, Error> {
    if scheme.as_str().eq_ignore_ascii_case("http") {
        Ok(Scheme::HTTP)
    } else if scheme.as_str().eq_ignore_ascii_case("https") {
        Ok(Scheme::HTTPS)
    } else {
        Err(Error::Unsupported(format!(
            "forwarding URI scheme `{scheme}` is not supported"
        )))
    }
}

pub(crate) fn canonicalize_http_uri(uri: Uri) -> Result<(Uri, Scheme), Error> {
    let parsed_scheme = uri
        .scheme()
        .ok_or_else(|| Error::InvalidUrl("forward: final URI has no scheme".into()))?;
    let scheme = canonical_http_scheme(parsed_scheme)?;
    if parsed_scheme == &scheme {
        return Ok((uri, scheme));
    }

    let mut parts = uri.into_parts();
    parts.scheme = Some(scheme.clone());
    let uri =
        Uri::from_parts(parts).map_err(|error| Error::InvalidUrl(format!("forward: {error}")))?;
    Ok((uri, scheme))
}

pub(crate) fn default_port(scheme: Option<&Scheme>) -> Option<u16> {
    let scheme = scheme?;
    if scheme.as_str().eq_ignore_ascii_case("http") {
        Some(80)
    } else if scheme.as_str().eq_ignore_ascii_case("https") {
        Some(443)
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn canonicalizes_case_preserving_standard_schemes() {
        for (raw, expected) in [("HTTP", Scheme::HTTP), ("HtTpS", Scheme::HTTPS)] {
            let scheme = raw.parse::<Scheme>().unwrap();
            assert_ne!(scheme, expected, "proof premise changed for {raw}");
            assert_eq!(canonical_http_scheme(&scheme).unwrap(), expected);
        }
    }
}