Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,16 @@ pub(crate) async fn resolve_host_with_doh_tls(
return Ok(vec![SocketAddr::new(ip, 0)]);
}
let Some(dns_server) = dns_server else {
return tokio::net::lookup_host((host, 0))
.await
.map(|addrs| addrs.collect())
.map_err(|err| FetchError::Runtime(format!("lookup {host}: {err}")));
return resolve_system_host_with(
host,
timeout,
Box::pin(async move {
tokio::net::lookup_host((host, 0))
.await
.map(|addrs| addrs.collect())
}),
)
.await;
};

let addrs = if is_doh_dns_server(dns_server) {
Expand All @@ -144,6 +150,23 @@ pub(crate) async fn resolve_host_with_doh_tls(
.collect())
}

type SystemLookupFuture<'a> =
Pin<Box<dyn Future<Output = std::io::Result<Vec<SocketAddr>>> + Send + 'a>>;

async fn resolve_system_host_with(
host: &str,
timeout: TimeoutBudget,
system_lookup: SystemLookupFuture<'_>,
) -> Result<Vec<SocketAddr>, FetchError> {
timeout
.run(async move {
system_lookup
.await
.map_err(|err| FetchError::Runtime(format!("lookup {host}: {err}")))
})
.await
}

async fn resolve_host_family(
host: &str,
port: u16,
Expand Down Expand Up @@ -1408,6 +1431,20 @@ async fn timeout_fetch<T>(
mod tests {
use super::*;

#[tokio::test]
async fn system_host_resolution_honors_timeout_budget() {
let timeout = Duration::from_millis(10);
let err = resolve_system_host_with(
"example.com",
TimeoutBudget::new(Some(timeout)),
Box::pin(std::future::pending::<std::io::Result<Vec<SocketAddr>>>()),
)
.await
.unwrap_err();

assert_eq!(err.to_string(), "request timed out after 10ms");
}

#[test]
fn host_header_value_brackets_ipv6_literals() {
let url = Url::parse("http://[::1]/").unwrap();
Expand Down
Loading