diff --git a/impit/src/http3.rs b/impit/src/http3.rs index 5589c176..e911d1c8 100644 --- a/impit/src/http3.rs +++ b/impit/src/http3.rs @@ -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>, + client: Arc>>, /// The background task that processes DNS queries. - bg_join_handle: tokio::task::JoinHandle>, + bg_join_handle: Option>>, /// 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). @@ -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())), + } + } } } @@ -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; + } - dns_h3_support + false } pub async fn set_h3_support(&self, host: &String, supports_h3: bool) { @@ -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(); + } } }