Add custom DNS resolver for *.localhost (#280)

This commit is contained in:
Gregory Schier
2025-10-24 08:01:12 -07:00
committed by GitHub
parent 9439cfa2ba
commit 43437abae7
5 changed files with 65 additions and 4 deletions

10
src-tauri/Cargo.lock generated
View File

@@ -1259,7 +1259,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -2352,9 +2352,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.14"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -2368,7 +2368,7 @@ dependencies = [
"libc",
"percent-encoding",
"pin-project-lite",
"socket2 0.5.10",
"socket2 0.6.1",
"system-configuration",
"tokio",
"tower-service",
@@ -7816,6 +7816,7 @@ dependencies = [
"cookie",
"eventsource-client",
"http",
"hyper-util",
"log",
"md5 0.8.0",
"mime_guess",
@@ -7841,6 +7842,7 @@ dependencies = [
"thiserror 2.0.17",
"tokio",
"tokio-stream",
"tower-service",
"ts-rs",
"uuid",
"yaak-common",

View File

@@ -68,6 +68,8 @@ tauri-plugin-shell = { workspace = true }
tauri-plugin-single-instance = { version = "2.3.4", features = ["deep-link"] }
tauri-plugin-updater = "2.9.0"
tauri-plugin-window-state = "2.4.0"
hyper-util = { version = "0.1.17", default-features = false, features = ["client-legacy"] }
tower-service = "0.3.3"
thiserror = { workspace = true }
tokio = { workspace = true, features = ["sync"] }
tokio-stream = "0.1.17"

54
src-tauri/src/dns.rs Normal file
View File

@@ -0,0 +1,54 @@
use hyper_util::client::legacy::connect::dns::{
GaiResolver as HyperGaiResolver, Name as HyperName,
};
use reqwest::dns::{Addrs, Name, Resolve, Resolving};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
use std::sync::Arc;
use tower_service::Service;
#[derive(Clone)]
pub(crate) struct LocalhostResolver {
fallback: HyperGaiResolver,
}
impl LocalhostResolver {
pub fn new() -> Arc<Self> {
let resolver = HyperGaiResolver::new();
Arc::new(Self { fallback: resolver })
}
}
impl Resolve for LocalhostResolver {
fn resolve(&self, name: Name) -> Resolving {
let host = name.as_str().to_lowercase();
let is_localhost = host.ends_with(".localhost");
if is_localhost {
// Port 0 is fine; reqwest replaces it with the URL's explicit
// port or the schemes default (80/443, etc.).
// (See docs note below.)
let addrs: Vec<SocketAddr> = vec![
SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0),
SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 0),
];
return Box::pin(async move {
Ok::<Addrs, Box<dyn std::error::Error + Send + Sync>>(Box::new(addrs.into_iter()))
});
}
let mut fallback = self.fallback.clone();
let name_str = name.as_str().to_string();
Box::pin(async move {
match HyperName::from_str(&name_str) {
Ok(n) => fallback
.call(n)
.await
.map(|addrs| Box::new(addrs) as Addrs)
.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
Err(e) => Err(Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
}
})
}
}

View File

@@ -33,6 +33,7 @@ use yaak_plugins::events::{
use yaak_plugins::manager::PluginManager;
use yaak_plugins::template_callback::PluginTemplateCallback;
use yaak_templates::{RenderErrorBehavior, RenderOptions};
use crate::dns::LocalhostResolver;
pub async fn send_http_request<R: Runtime>(
window: &WebviewWindow<R>,
@@ -110,6 +111,7 @@ pub async fn send_http_request<R: Runtime>(
.gzip(true)
.brotli(true)
.deflate(true)
.dns_resolver(LocalhostResolver::new())
.referer(false)
.tls_info(true);

View File

@@ -60,6 +60,7 @@ mod updates;
mod uri_scheme;
mod window;
mod window_menu;
mod dns;
#[derive(serde::Serialize)]
#[serde(default, rename_all = "camelCase")]