isahc/
info.rs

1//! Runtime support for checking versions and feature availability.
2
3use once_cell::sync::Lazy;
4
5// Query for curl version info just once since it is immutable.
6static CURL_VERSION: Lazy<curl::Version> = Lazy::new(curl::Version::get);
7
8/// Gets a human-readable string with the version number of Isahc and its
9/// dependencies.
10///
11/// This function can be helpful when troubleshooting issues in Isahc or one of
12/// its dependencies.
13pub fn version() -> &'static str {
14    static VERSION_STRING: Lazy<String> = Lazy::new(|| {
15        format!(
16            "isahc/{} (features:{}) {}",
17            env!("CARGO_PKG_VERSION"),
18            env!("ISAHC_FEATURES"),
19            curl::Version::num(),
20        )
21    });
22
23    &VERSION_STRING
24}
25
26/// Check if runtime support is available for the given HTTP version.
27///
28/// This only indicates whether support for communicating with this HTTP version
29/// is available, which is usually determined by which features were enabled
30/// during compilation, but can also be affected by what is available in system
31/// libraries when using dynamic linking.
32///
33/// This does not indicate which versions Isahc will attempt to use by default.
34/// To customize which versions to use within a particular client or request
35/// instance, see [`VersionNegotiation`][crate::config::VersionNegotiation].
36pub fn is_http_version_supported(version: http::Version) -> bool {
37    match version {
38        // HTTP/0.9 was disabled by default as of 7.66.0. See also
39        // https://github.com/sagebind/isahc/issues/310 if we ever decide to
40        // allow enabling it again.
41        http::Version::HTTP_09 => match curl_version() {
42            (7, minor, _) if minor < 66 => true,
43            (major, _, _) if major < 7 => true,
44            _ => false,
45        },
46        http::Version::HTTP_10 => true,
47        http::Version::HTTP_11 => true,
48        http::Version::HTTP_2 => CURL_VERSION.feature_http2(),
49        http::Version::HTTP_3 => CURL_VERSION.feature_http3(),
50        _ => false,
51    }
52}
53
54fn curl_version() -> (u8, u8, u8) {
55    let bits = CURL_VERSION.version_num();
56
57    ((bits >> 16) as u8, (bits >> 8) as u8, bits as u8)
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn version_expected() {
66        let version = version();
67
68        assert!(version.starts_with("isahc/1."));
69        assert!(version.contains("curl/7."));
70    }
71
72    #[test]
73    fn curl_version_expected() {
74        let (major, minor, _patch) = curl_version();
75
76        assert_eq!(major, 7);
77        assert!(minor > 0);
78    }
79
80    #[test]
81    fn http1_always_supported() {
82        assert!(is_http_version_supported(http::Version::HTTP_10));
83        assert!(is_http_version_supported(http::Version::HTTP_11));
84
85        if cfg!(feature = "http2") {
86            assert!(is_http_version_supported(http::Version::HTTP_2));
87        }
88    }
89}