910dcf2036
Signed-off-by: fufesou <linlong1266@gmail.com>
337 lines
12 KiB
Rust
337 lines
12 KiB
Rust
use hbb_common::{
|
|
async_recursion::async_recursion,
|
|
config::{Config, Socks5Server},
|
|
log::{self, info},
|
|
proxy::{Proxy, ProxyScheme},
|
|
tls::{
|
|
get_cached_tls_accept_invalid_cert, get_cached_tls_type, is_plain, upsert_tls_cache,
|
|
TlsType,
|
|
},
|
|
};
|
|
use reqwest::{blocking::Client as SyncClient, Client as AsyncClient};
|
|
|
|
macro_rules! configure_http_client {
|
|
($builder:expr, $tls_type:expr, $danger_accept_invalid_cert:expr, $Client: ty) => {{
|
|
// https://github.com/rustdesk/rustdesk/issues/11569
|
|
// https://docs.rs/reqwest/latest/reqwest/struct.ClientBuilder.html#method.no_proxy
|
|
let mut builder = $builder.no_proxy();
|
|
|
|
match $tls_type {
|
|
TlsType::Plain => {}
|
|
TlsType::NativeTls => {
|
|
builder = builder.use_native_tls();
|
|
if $danger_accept_invalid_cert {
|
|
builder = builder.danger_accept_invalid_certs(true);
|
|
}
|
|
}
|
|
TlsType::Rustls => {
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
match hbb_common::verifier::client_config($danger_accept_invalid_cert) {
|
|
Ok(client_config) => {
|
|
builder = builder.use_preconfigured_tls(client_config);
|
|
}
|
|
Err(e) => {
|
|
hbb_common::log::error!("Failed to get client config: {}", e);
|
|
}
|
|
}
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
{
|
|
builder = builder.use_rustls_tls();
|
|
if $danger_accept_invalid_cert {
|
|
builder = builder.danger_accept_invalid_certs(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let client = if let Some(conf) = Config::get_socks() {
|
|
let proxy_result = Proxy::from_conf(&conf, None);
|
|
|
|
match proxy_result {
|
|
Ok(proxy) => {
|
|
let proxy_setup = match &proxy.intercept {
|
|
ProxyScheme::Http { host, .. } => {
|
|
reqwest::Proxy::all(format!("http://{}", host))
|
|
}
|
|
ProxyScheme::Https { host, .. } => {
|
|
reqwest::Proxy::all(format!("https://{}", host))
|
|
}
|
|
ProxyScheme::Socks5 { addr, .. } => {
|
|
reqwest::Proxy::all(&format!("socks5://{}", addr))
|
|
}
|
|
};
|
|
|
|
match proxy_setup {
|
|
Ok(mut p) => {
|
|
if let Some(auth) = proxy.intercept.maybe_auth() {
|
|
if !auth.username().is_empty() && !auth.password().is_empty() {
|
|
p = p.basic_auth(auth.username(), auth.password());
|
|
}
|
|
}
|
|
builder = builder.proxy(p);
|
|
builder.build().unwrap_or_else(|e| {
|
|
info!("Failed to create a proxied client: {}", e);
|
|
<$Client>::new()
|
|
})
|
|
}
|
|
Err(e) => {
|
|
info!("Failed to set up proxy: {}", e);
|
|
<$Client>::new()
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
info!("Failed to configure proxy: {}", e);
|
|
<$Client>::new()
|
|
}
|
|
}
|
|
} else {
|
|
builder.build().unwrap_or_else(|e| {
|
|
info!("Failed to create a client: {}", e);
|
|
<$Client>::new()
|
|
})
|
|
};
|
|
|
|
client
|
|
}};
|
|
}
|
|
|
|
pub fn create_http_client(tls_type: TlsType, danger_accept_invalid_cert: bool) -> SyncClient {
|
|
let builder = SyncClient::builder();
|
|
configure_http_client!(builder, tls_type, danger_accept_invalid_cert, SyncClient)
|
|
}
|
|
|
|
pub fn create_http_client_async(
|
|
tls_type: TlsType,
|
|
danger_accept_invalid_cert: bool,
|
|
) -> AsyncClient {
|
|
let builder = AsyncClient::builder();
|
|
configure_http_client!(builder, tls_type, danger_accept_invalid_cert, AsyncClient)
|
|
}
|
|
|
|
pub fn get_url_for_tls<'a>(url: &'a str, proxy_conf: &'a Option<Socks5Server>) -> &'a str {
|
|
if is_plain(url) {
|
|
if let Some(conf) = proxy_conf {
|
|
if conf.proxy.starts_with("https://") {
|
|
return &conf.proxy;
|
|
}
|
|
}
|
|
}
|
|
url
|
|
}
|
|
|
|
pub fn create_http_client_with_url(url: &str) -> SyncClient {
|
|
let proxy_conf = Config::get_socks();
|
|
let tls_url = get_url_for_tls(url, &proxy_conf);
|
|
let tls_type = get_cached_tls_type(tls_url);
|
|
let is_tls_type_cached = tls_type.is_some();
|
|
let tls_type = tls_type.unwrap_or(TlsType::Rustls);
|
|
let tls_danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
|
create_http_client_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
tls_danger_accept_invalid_cert,
|
|
tls_danger_accept_invalid_cert,
|
|
)
|
|
}
|
|
|
|
fn create_http_client_with_url_(
|
|
url: &str,
|
|
tls_url: &str,
|
|
tls_type: TlsType,
|
|
is_tls_type_cached: bool,
|
|
danger_accept_invalid_cert: Option<bool>,
|
|
original_danger_accept_invalid_cert: Option<bool>,
|
|
) -> SyncClient {
|
|
let mut client = create_http_client(tls_type, danger_accept_invalid_cert.unwrap_or(false));
|
|
if is_tls_type_cached && original_danger_accept_invalid_cert.is_some() {
|
|
return client;
|
|
}
|
|
if let Err(e) = client.head(url).send() {
|
|
if e.is_request() {
|
|
match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) {
|
|
(TlsType::Rustls, _, None) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with rustls-tls: {:?}, trying accept invalid cert",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
Some(true),
|
|
original_danger_accept_invalid_cert,
|
|
);
|
|
}
|
|
(TlsType::Rustls, false, Some(_)) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with rustls-tls: {:?}, trying native-tls",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_with_url_(
|
|
url,
|
|
tls_url,
|
|
TlsType::NativeTls,
|
|
is_tls_type_cached,
|
|
original_danger_accept_invalid_cert,
|
|
original_danger_accept_invalid_cert,
|
|
);
|
|
}
|
|
(TlsType::NativeTls, _, None) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with native-tls: {:?}, trying accept invalid cert",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
Some(true),
|
|
original_danger_accept_invalid_cert,
|
|
);
|
|
}
|
|
_ => {
|
|
log::error!(
|
|
"Failed to connect to server {} with {:?}, err: {:?}.",
|
|
tls_url,
|
|
tls_type,
|
|
e
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
log::warn!(
|
|
"Failed to connect to server {} with {:?}, err: {}.",
|
|
tls_url,
|
|
tls_type,
|
|
e
|
|
);
|
|
}
|
|
} else {
|
|
log::info!(
|
|
"Successfully connected to server {} with {:?}",
|
|
tls_url,
|
|
tls_type
|
|
);
|
|
upsert_tls_cache(
|
|
tls_url,
|
|
tls_type,
|
|
danger_accept_invalid_cert.unwrap_or(false),
|
|
);
|
|
}
|
|
client
|
|
}
|
|
|
|
pub async fn create_http_client_async_with_url(url: &str) -> AsyncClient {
|
|
let proxy_conf = Config::get_socks();
|
|
let tls_url = get_url_for_tls(url, &proxy_conf);
|
|
let tls_type = get_cached_tls_type(tls_url);
|
|
let is_tls_type_cached = tls_type.is_some();
|
|
let tls_type = tls_type.unwrap_or(TlsType::Rustls);
|
|
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
|
create_http_client_async_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
danger_accept_invalid_cert,
|
|
danger_accept_invalid_cert,
|
|
)
|
|
.await
|
|
}
|
|
|
|
#[async_recursion]
|
|
async fn create_http_client_async_with_url_(
|
|
url: &str,
|
|
tls_url: &str,
|
|
tls_type: TlsType,
|
|
is_tls_type_cached: bool,
|
|
danger_accept_invalid_cert: Option<bool>,
|
|
original_danger_accept_invalid_cert: Option<bool>,
|
|
) -> AsyncClient {
|
|
let mut client =
|
|
create_http_client_async(tls_type, danger_accept_invalid_cert.unwrap_or(false));
|
|
if is_tls_type_cached && original_danger_accept_invalid_cert.is_some() {
|
|
return client;
|
|
}
|
|
if let Err(e) = client.head(url).send().await {
|
|
match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) {
|
|
(TlsType::Rustls, _, None) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with rustls-tls: {:?}, trying accept invalid cert",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_async_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
Some(true),
|
|
original_danger_accept_invalid_cert,
|
|
)
|
|
.await;
|
|
}
|
|
(TlsType::Rustls, false, Some(_)) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with rustls-tls: {:?}, trying native-tls",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_async_with_url_(
|
|
url,
|
|
tls_url,
|
|
TlsType::NativeTls,
|
|
is_tls_type_cached,
|
|
original_danger_accept_invalid_cert,
|
|
original_danger_accept_invalid_cert,
|
|
)
|
|
.await;
|
|
}
|
|
(TlsType::NativeTls, _, None) => {
|
|
log::warn!(
|
|
"Failed to connect to server {} with native-tls: {:?}, trying accept invalid cert",
|
|
tls_url,
|
|
e
|
|
);
|
|
client = create_http_client_async_with_url_(
|
|
url,
|
|
tls_url,
|
|
tls_type,
|
|
is_tls_type_cached,
|
|
Some(true),
|
|
original_danger_accept_invalid_cert,
|
|
)
|
|
.await;
|
|
}
|
|
_ => {
|
|
log::error!(
|
|
"Failed to connect to server {} with {:?}, err: {:?}.",
|
|
tls_url,
|
|
tls_type,
|
|
e
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
log::info!(
|
|
"Successfully connected to server {} with {:?}",
|
|
tls_url,
|
|
tls_type
|
|
);
|
|
upsert_tls_cache(
|
|
tls_url,
|
|
tls_type,
|
|
danger_accept_invalid_cert.unwrap_or(false),
|
|
);
|
|
}
|
|
client
|
|
}
|