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
96 changes: 59 additions & 37 deletions impit/src/http3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ use hickory_proto::ProtoError;
use hickory_client::client::{Client, ClientHandle};
use hickory_client::proto::runtime::iocompat::AsyncIoTokioAsStd;
use hickory_client::proto::tcp::TcpClientStream;
use log::debug;
use tokio::net::TcpStream as TokioTcpStream;

/// A struct encapsulating the components required to make HTTP/3 requests.
pub struct H3Engine {
/// The DNS client used to resolve DNS queries.
client: Arc<Mutex<Client>>,
client: Arc<Option<Mutex<Client>>>,
/// The background task that processes DNS queries.
bg_join_handle: tokio::task::JoinHandle<Result<(), ProtoError>>,
bg_join_handle: Option<tokio::task::JoinHandle<Result<(), ProtoError>>>,
/// A map of hosts that support HTTP/3.
///
/// This is populated by the DNS queries and manual calls to `set_h3_support` (based on the `Alt-Svc` header).
Expand All @@ -34,14 +35,26 @@ impl H3Engine {
None,
TokioRuntimeProvider::new(),
);
let (client, bg) = Client::new(stream, sender, None).await.unwrap();
let client_result = Client::new(stream, sender, None).await;

let bg_join_handle = tokio::spawn(bg);
match client_result {
Ok((client, bg)) => {
let bg_join_handle = tokio::spawn(bg);

H3Engine {
client: Arc::new(Mutex::new(client)),
bg_join_handle,
h3_alt_svc: Arc::new(RwLock::new(HashMap::new())),
H3Engine {
client: Arc::new(Some(Mutex::new(client))),
bg_join_handle: Some(bg_join_handle),
h3_alt_svc: Arc::new(RwLock::new(HashMap::new())),
}
}
Err(err) => {
debug!("Failed to create DNS client for HTTP3 resolution: {}", err);
H3Engine {
client: Arc::new(None),
bg_join_handle: None,
h3_alt_svc: Arc::new(RwLock::new(HashMap::new())),
}
}
}
}

Expand All @@ -53,37 +66,44 @@ impl H3Engine {
}
}

let domain_name = Name::from_utf8(host).unwrap();

let response = {
let mut client = self.client.lock().await;
client
.query(
domain_name,
hickory_proto::rr::DNSClass::IN,
hickory_proto::rr::RecordType::HTTPS,
)
.await
let domain_name = match Name::from_utf8(host) {
Ok(name) => name,
Err(_) => return false,
};

let dns_h3_support = response.is_ok_and(|response| {
response.answers().iter().any(|answer| {
if let RData::HTTPS(data) = answer.data() {
return data.svc_params().iter().any(|param| {
if let SvcParamValue::Alpn(alpn_protocols) = param.1.clone() {
return alpn_protocols.0.iter().any(|alpn| alpn == "h3");
}

false
});
}
false
})
});

self.set_h3_support(host, dns_h3_support).await;
if let Some(client) = self.client.as_ref() {
let response = {
let mut client = client.lock().await;
client
.query(
domain_name,
hickory_proto::rr::DNSClass::IN,
hickory_proto::rr::RecordType::HTTPS,
)
.await
};

let dns_h3_support = response.is_ok_and(|response| {
response.answers().iter().any(|answer| {
if let RData::HTTPS(data) = answer.data() {
return data.svc_params().iter().any(|param| {
if let SvcParamValue::Alpn(alpn_protocols) = param.1.clone() {
return alpn_protocols.0.iter().any(|alpn| alpn == "h3");
}

false
});
}
false
})
});

self.set_h3_support(host, dns_h3_support).await;

return dns_h3_support;
Comment thread
barjin marked this conversation as resolved.
}

dns_h3_support
false
}

pub async fn set_h3_support(&self, host: &String, supports_h3: bool) {
Expand All @@ -98,6 +118,8 @@ impl H3Engine {

impl Drop for H3Engine {
fn drop(&mut self) {
self.bg_join_handle.abort();
if let Some(join_handle) = self.bg_join_handle.as_ref() {
join_handle.abort();
}
}
}
Loading