use std::{net::SocketAddr, sync::Arc};
use reqwest::{ClientBuilder, Response};
use rustls::{
DigitallySignedStruct, SignatureScheme,
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
pki_types::{CertificateDer, UnixTime},
};
#[derive(Debug)]
struct NoopServerCertVerifier;
impl ServerCertVerifier for NoopServerCertVerifier {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &rustls::pki_types::ServerName<'_>,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
Ok(ServerCertVerified::assertion())
}
fn verify_handshake_signature(
&self,
_msg: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
vec![
SignatureScheme::RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
]
}
}
pub async fn get_with_builder(
url_str: &str,
addr: SocketAddr,
builder: impl FnOnce(ClientBuilder) -> ClientBuilder,
) -> anyhow::Result<Response> {
let url = url::Url::parse(url_str)?;
let host = url
.host_str()
.ok_or_else(|| anyhow::anyhow!("URL does not have a host"))?;
let client_config = rustls::ClientConfig::builder()
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoopServerCertVerifier))
.with_no_client_auth();
let client_builder = builder(reqwest::Client::builder())
.use_rustls_tls()
.rustls_client_config(client_config);
let client = client_builder
.redirect(reqwest::redirect::Policy::none())
.resolve(host, addr)
.no_proxy()
.build()?;
client.get(url_str).send().await.map_err(Into::into)
}
#[allow(dead_code)]
pub async fn get(url_str: &str, addr: SocketAddr) -> anyhow::Result<Response> {
get_with_builder(url_str, addr, |c| c).await
}
#[allow(dead_code)]
pub async fn get_body(url_str: &str, addr: SocketAddr) -> anyhow::Result<String> {
let res = get(url_str, addr).await?;
res.text().await.map_err(Into::into)
}
#[allow(dead_code)]
pub async fn get_body_h2(url_str: &str, addr: SocketAddr) -> anyhow::Result<String> {
let res = get_with_builder(url_str, addr, |c| c.http2_prior_knowledge()).await?;
res.text().await.map_err(Into::into)
}
#[allow(dead_code)]
pub async fn get_response_h2(url_str: &str, addr: SocketAddr) -> anyhow::Result<Response> {
get_with_builder(url_str, addr, |c| c.http2_prior_knowledge()).await
}
#[allow(dead_code)]
pub async fn get_body_h3(url_str: &str, addr: SocketAddr) -> anyhow::Result<String> {
let res = get_with_builder(url_str, addr, |c| c.http3_prior_knowledge()).await?;
res.text().await.map_err(Into::into)
}
#[allow(dead_code)]
pub async fn get_response_h3(url_str: &str, addr: SocketAddr) -> anyhow::Result<Response> {
get_with_builder(url_str, addr, |c| c.http3_prior_knowledge()).await
}