fix leon & binstalk-downloader bug relating to features (#1153)

- ci: Check feat powerset of leon & binstalk-downloader in `ci.yml`
 - fix leon feature `cli`: Enable dep `miette` in feature `cli`
 - fix binstalk-downloader when default feature is disabled and no other
   tls related feature is enabled (breaking change due to replace of
   `tls::Version` with newtype `TLSVersion`).

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-06-19 12:22:09 +10:00 committed by GitHub
parent 5c4a542de5
commit 40efe02e34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 65 deletions

View file

@ -60,7 +60,13 @@ pkg-config = ["zstd/pkg-config"]
zlib-ng = ["flate2/zlib-ng"]
# Dummy feature, enabled if rustls or native-tls is enabled.
# Used to avoid compilation error when no feature is enabled.
__tls = []
rustls = [
"__tls",
"reqwest/rustls-tls",
# Enable the following features only if trust-dns-resolver is enabled.
@ -69,7 +75,7 @@ rustls = [
"trust-dns-resolver?/dns-over-https-rustls",
"trust-dns-resolver?/dns-over-quic",
]
native-tls = ["reqwest/native-tls", "trust-dns-resolver?/dns-over-native-tls"]
native-tls = ["__tls", "reqwest/native-tls", "trust-dns-resolver?/dns-over-native-tls"]
# Enable trust-dns-resolver so that features on it will also be enabled.
trust-dns = ["trust-dns-resolver", "reqwest/trust-dns"]

View file

@ -16,7 +16,7 @@ use thiserror::Error as ThisError;
use tower::{limit::rate::RateLimit, Service, ServiceBuilder, ServiceExt};
use tracing::{debug, info};
pub use reqwest::{header, tls, Error as ReqwestError, Method, StatusCode};
pub use reqwest::{header, Error as ReqwestError, Method, StatusCode};
pub use url::Url;
mod delay_request;
@ -28,6 +28,9 @@ pub use certificate::Certificate;
mod request_builder;
pub use request_builder::{Body, RequestBuilder, Response};
mod tls_version;
pub use tls_version::TLSVersion;
#[cfg(feature = "json")]
pub use request_builder::JsonError;
@ -35,7 +38,7 @@ const MAX_RETRY_DURATION: Duration = Duration::from_secs(120);
const MAX_RETRY_COUNT: u8 = 3;
const DEFAULT_RETRY_DURATION_FOR_RATE_LIMIT: Duration = Duration::from_millis(200);
const RETRY_DURATION_FOR_TIMEOUT: Duration = Duration::from_millis(200);
const DEFAULT_MIN_TLS: tls::Version = tls::Version::TLS_1_2;
const DEFAULT_MIN_TLS: TLSVersion = TLSVersion::TLS_1_2;
#[derive(Debug, ThisError)]
#[non_exhaustive]
@ -69,6 +72,7 @@ struct Inner {
#[derive(Clone, Debug)]
pub struct Client(Arc<Inner>);
#[cfg_attr(not(feature = "__tls"), allow(unused_variables, unused_mut))]
impl Client {
/// * `per` - must not be 0.
/// * `num_request` - maximum number of requests to be processed for
@ -77,30 +81,34 @@ impl Client {
/// The Client created would use at least tls 1.2
pub fn new(
user_agent: impl AsRef<str>,
min_tls: Option<tls::Version>,
min_tls: Option<TLSVersion>,
per: Duration,
num_request: NonZeroU64,
certificates: impl IntoIterator<Item = Certificate>,
) -> Result<Self, Error> {
fn inner(
user_agent: &str,
min_tls: Option<tls::Version>,
min_tls: Option<TLSVersion>,
per: Duration,
num_request: NonZeroU64,
certificates: &mut dyn Iterator<Item = Certificate>,
) -> Result<Client, Error> {
let tls_ver = min_tls
.map(|tls| tls.max(DEFAULT_MIN_TLS))
.unwrap_or(DEFAULT_MIN_TLS);
let mut builder = reqwest::ClientBuilder::new()
.user_agent(user_agent)
.https_only(true)
.min_tls_version(tls_ver)
.tcp_nodelay(false);
for certificate in certificates {
builder = builder.add_root_certificate(certificate.0);
#[cfg(feature = "__tls")]
{
let tls_ver = min_tls
.map(|tls| tls.max(DEFAULT_MIN_TLS))
.unwrap_or(DEFAULT_MIN_TLS);
builder = builder.min_tls_version(tls_ver.into());
for certificate in certificates {
builder = builder.add_root_certificate(certificate.0);
}
}
let client = builder.build()?;

View file

@ -1,13 +1,19 @@
#[cfg(feature = "__tls")]
use reqwest::tls;
use super::Error;
#[derive(Clone, Debug)]
pub struct Certificate(pub(super) tls::Certificate);
pub struct Certificate(#[cfg(feature = "__tls")] pub(super) tls::Certificate);
#[cfg_attr(not(feature = "__tls"), allow(unused_variables))]
impl Certificate {
/// Create a Certificate from a binary DER encoded certificate
pub fn from_der(der: impl AsRef<[u8]>) -> Result<Self, Error> {
#[cfg(not(feature = "__tls"))]
return Ok(Self());
#[cfg(feature = "__tls")]
tls::Certificate::from_der(der.as_ref())
.map(Self)
.map_err(Error::from)
@ -15,6 +21,10 @@ impl Certificate {
/// Create a Certificate from a PEM encoded certificate
pub fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self, Error> {
#[cfg(not(feature = "__tls"))]
return Ok(Self());
#[cfg(feature = "__tls")]
tls::Certificate::from_pem(pem.as_ref())
.map(Self)
.map_err(Error::from)

View file

@ -0,0 +1,37 @@
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Inner {
Tls1_2 = 0,
Tls1_3 = 1,
}
/// TLS version for [`crate::remote::Client`].
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TLSVersion(Inner);
impl TLSVersion {
pub const TLS_1_2: TLSVersion = TLSVersion(Inner::Tls1_2);
pub const TLS_1_3: TLSVersion = TLSVersion(Inner::Tls1_3);
}
#[cfg(feature = "__tls")]
impl From<TLSVersion> for reqwest::tls::Version {
fn from(ver: TLSVersion) -> reqwest::tls::Version {
use reqwest::tls::Version;
use Inner::*;
match ver.0 {
Tls1_2 => Version::TLS_1_2,
Tls1_3 => Version::TLS_1_3,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_tls_version_order() {
assert!(TLSVersion::TLS_1_2 < TLSVersion::TLS_1_3);
}
}