diff --git a/src/service/federation/execute.rs b/src/service/federation/execute.rs index 8f7f347c..7cfe2b90 100644 --- a/src/service/federation/execute.rs +++ b/src/service/federation/execute.rs @@ -163,7 +163,7 @@ async fn into_http_response( request_url = ?url, response_url = ?response.url(), "Received response from {}", - actual.string(), + actual.to_string(), ); let mut http_response_builder = http::Response::builder() @@ -249,7 +249,7 @@ where }; let mut request = request - .try_into_http_request::>(actual.string().as_str(), SATIR, &supported) + .try_into_http_request::>(actual.to_string().as_str(), SATIR, &supported) .map_err(|e| err!(BadServerResponse("Invalid destination: {e:?}")))?; if matches!(T::METADATA.authentication, AuthScheme::ServerSignatures) { diff --git a/src/service/resolver/actual.rs b/src/service/resolver/actual.rs index c3ab9814..213f3aba 100644 --- a/src/service/resolver/actual.rs +++ b/src/service/resolver/actual.rs @@ -10,19 +10,20 @@ use ruma::ServerName; use tuwunel_core::{Err, Result, debug, debug_info, err, error, trace}; use super::{ + DestString, FedDest, cache::{CachedDest, CachedOverride, MAX_IPS}, - fed::{FedDest, PortString, add_port_to_hostname, get_ip_with_port}, + fed::{PortString, add_port_to_hostname, get_ip_with_port}, }; #[derive(Clone, Debug)] pub(crate) struct ActualDest { pub(crate) dest: FedDest, - pub(crate) host: String, + pub(crate) host: DestString, } impl ActualDest { #[inline] - pub(crate) fn string(&self) -> String { self.dest.https_string() } + pub(crate) fn to_string(&self) -> DestString { self.dest.https_string() } } impl super::Service { @@ -65,7 +66,7 @@ impl super::Service { cache: bool, ) -> Result { self.validate_dest(dest)?; - let mut host = dest.as_str().to_owned(); + let mut host: DestString = dest.as_str().into(); let actual_dest = match get_ip_with_port(dest.as_str()) { | Some(host_port) => Self::actual_dest_1(host_port)?, | None => @@ -77,7 +78,7 @@ impl super::Service { self.services.server.check_running()?; match self.request_well_known(dest.as_str()).await? { | Some(delegated) => - self.actual_dest_3(&mut host, cache, delegated) + self.actual_dest_3(&mut host, cache, &delegated) .await?, | _ => match self.query_srv_record(dest.as_str()).await? { | Some(overrider) => @@ -94,16 +95,16 @@ impl super::Service { let host = if let Ok(addr) = host.parse::() { FedDest::Literal(addr) } else if let Ok(addr) = host.parse::() { - FedDest::Named(addr.to_string(), FedDest::default_port()) + FedDest::Named(addr.to_string().into(), FedDest::default_port()) } else if let Some(pos) = host.find(':') { let (host, port) = host.split_at(pos); FedDest::Named( - host.to_owned(), + host.into(), port.try_into() .unwrap_or_else(|_| FedDest::default_port()), ) } else { - FedDest::Named(host, FedDest::default_port()) + FedDest::Named(host.as_str().into(), FedDest::default_port()) }; debug!("Actual destination: {actual_dest:?} hostname: {host:?}"); @@ -126,7 +127,7 @@ impl super::Service { .await?; Ok(FedDest::Named( - host.to_owned(), + host.into(), port.try_into() .unwrap_or_else(|_| FedDest::default_port()), )) @@ -134,20 +135,20 @@ impl super::Service { async fn actual_dest_3( &self, - host: &mut String, + host: &mut DestString, cache: bool, - delegated: String, + delegated: &str, ) -> Result { debug!("3: A .well-known file is available"); - *host = add_port_to_hostname(&delegated).uri_string(); - match get_ip_with_port(&delegated) { + *host = add_port_to_hostname(delegated).uri_string(); + match get_ip_with_port(delegated) { | Some(host_and_port) => Self::actual_dest_3_1(host_and_port), | None => if let Some(pos) = delegated.find(':') { self.actual_dest_3_2(cache, delegated, pos).await } else { trace!("Delegated hostname has no port in this branch"); - match self.query_srv_record(&delegated).await? { + match self.query_srv_record(delegated).await? { | Some(overrider) => self.actual_dest_3_3(cache, delegated, overrider) .await, @@ -162,19 +163,14 @@ impl super::Service { Ok(host_and_port) } - async fn actual_dest_3_2( - &self, - cache: bool, - delegated: String, - pos: usize, - ) -> Result { + async fn actual_dest_3_2(&self, cache: bool, delegated: &str, pos: usize) -> Result { debug!("3.2: Hostname with port in .well-known file"); let (host, port) = delegated.split_at(pos); self.conditional_query_and_cache(host, port.parse::().unwrap_or(8448), cache) .await?; Ok(FedDest::Named( - host.to_owned(), + host.into(), port.try_into() .unwrap_or_else(|_| FedDest::default_port()), )) @@ -183,13 +179,13 @@ impl super::Service { async fn actual_dest_3_3( &self, cache: bool, - delegated: String, + delegated: &str, overrider: FedDest, ) -> Result { debug!("3.3: SRV lookup successful"); let force_port = overrider.port(); self.conditional_query_and_cache_override( - &delegated, + delegated, &overrider.hostname(), force_port.unwrap_or(8448), cache, @@ -198,7 +194,7 @@ impl super::Service { if let Some(port) = force_port { return Ok(FedDest::Named( - delegated, + delegated.into(), format!(":{port}") .as_str() .try_into() @@ -206,14 +202,15 @@ impl super::Service { )); } - Ok(add_port_to_hostname(&delegated)) + Ok(add_port_to_hostname(delegated)) } - async fn actual_dest_3_4(&self, cache: bool, delegated: String) -> Result { + async fn actual_dest_3_4(&self, cache: bool, delegated: &str) -> Result { debug!("3.4: No SRV records, just use the hostname from .well-known"); - self.conditional_query_and_cache(&delegated, 8448, cache) + self.conditional_query_and_cache(delegated, 8448, cache) .await?; - Ok(add_port_to_hostname(&delegated)) + + Ok(add_port_to_hostname(delegated)) } async fn actual_dest_4( @@ -234,9 +231,8 @@ impl super::Service { if let Some(port) = force_port { let port = format!(":{port}"); - return Ok(FedDest::Named( - host.to_owned(), + host.into(), PortString::from(port.as_str()).unwrap_or_else(|_| FedDest::default_port()), )); } @@ -334,7 +330,7 @@ impl super::Service { .target() .to_string() .trim_end_matches('.') - .to_owned(), + .into(), format!(":{}", result.port()) .as_str() .try_into() diff --git a/src/service/resolver/cache.rs b/src/service/resolver/cache.rs index f435058a..db234eeb 100644 --- a/src/service/resolver/cache.rs +++ b/src/service/resolver/cache.rs @@ -11,7 +11,7 @@ use tuwunel_core::{ }; use tuwunel_database::{Cbor, Deserialized, Map}; -use super::fed::FedDest; +use super::{DestString, FedDest}; pub struct Cache { destinations: Arc, @@ -21,7 +21,7 @@ pub struct Cache { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct CachedDest { pub dest: FedDest, - pub host: String, + pub host: DestString, pub expire: SystemTime, } @@ -30,7 +30,7 @@ pub struct CachedOverride { pub ips: IpAddrs, pub port: u16, pub expire: SystemTime, - pub overriding: Option, + pub overriding: Option, } pub type IpAddrs = ArrayVec; diff --git a/src/service/resolver/fed.rs b/src/service/resolver/fed.rs index 3456503f..55fb0d16 100644 --- a/src/service/resolver/fed.rs +++ b/src/service/resolver/fed.rs @@ -1,20 +1,24 @@ use std::{ - borrow::Cow, fmt, net::{IpAddr, SocketAddr}, }; use serde::{Deserialize, Serialize}; -use tuwunel_core::{arrayvec::ArrayString, utils::math::Expected}; +use tuwunel_core::{arrayvec::ArrayString, smallstr::SmallString, utils::math::Expected}; + +use super::DestString; #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] pub enum FedDest { Literal(SocketAddr), - Named(String, PortString), + Named(HostString, PortString), } -/// numeric or service-name -pub type PortString = ArrayString<16>; +/// FedDest::Named host domain +pub(super) type HostString = SmallString<[u8; 32]>; + +/// FedDest::Named numeric or service-name +pub(super) type PortString = ArrayString<16>; const DEFAULT_PORT: &str = ":8448"; @@ -35,31 +39,31 @@ pub(crate) fn add_port_to_hostname(dest: &str) -> FedDest { }; FedDest::Named( - host.to_owned(), + host.into(), PortString::from(port).unwrap_or_else(|_| FedDest::default_port()), ) } impl FedDest { - pub(crate) fn https_string(&self) -> String { + pub(crate) fn https_string(&self) -> DestString { match self { - | Self::Literal(addr) => format!("https://{addr}"), - | Self::Named(host, port) => format!("https://{host}{port}"), + | Self::Literal(addr) => format!("https://{addr}").into(), + | Self::Named(host, port) => format!("https://{host}{port}").into(), } } - pub(crate) fn uri_string(&self) -> String { + pub(crate) fn uri_string(&self) -> DestString { match self { - | Self::Literal(addr) => addr.to_string(), - | Self::Named(host, port) => format!("{host}{port}"), + | Self::Literal(addr) => addr.to_string().into(), + | Self::Named(host, port) => [host.as_str(), port.as_str()].concat().into(), } } #[inline] - pub(crate) fn hostname(&self) -> Cow<'_, str> { + pub(crate) fn hostname(&self) -> HostString { match &self { | Self::Literal(addr) => addr.ip().to_string().into(), - | Self::Named(host, _) => host.into(), + | Self::Named(host, _) => host.clone(), } } diff --git a/src/service/resolver/mod.rs b/src/service/resolver/mod.rs index 56cadc60..14f7f2a2 100644 --- a/src/service/resolver/mod.rs +++ b/src/service/resolver/mod.rs @@ -9,9 +9,9 @@ mod well_known; use std::sync::Arc; use async_trait::async_trait; -use tuwunel_core::{Result, arrayvec::ArrayString, utils::MutexMap}; +use tuwunel_core::{Result, arrayvec::ArrayString, smallstr::SmallString, utils::MutexMap}; -use self::{cache::Cache, dns::Resolver}; +use self::{cache::Cache, dns::Resolver, fed::FedDest}; pub struct Service { pub cache: Arc, @@ -20,6 +20,7 @@ pub struct Service { services: Arc, } +pub(crate) type DestString = SmallString<[u8; 40]>; type Resolving = MutexMap; type NameBuf = ArrayString<256>; diff --git a/src/service/resolver/tests.rs b/src/service/resolver/tests.rs index 068e08bd..709365c7 100644 --- a/src/service/resolver/tests.rs +++ b/src/service/resolver/tests.rs @@ -28,7 +28,7 @@ fn ips_keep_custom_ports() { fn hostnames_get_default_ports() { assert_eq!( add_port_to_hostname("example.com"), - FedDest::Named(String::from("example.com"), ":8448".try_into().unwrap()) + FedDest::Named("example.com".into(), ":8448".try_into().unwrap()) ); } @@ -36,6 +36,6 @@ fn hostnames_get_default_ports() { fn hostnames_keep_custom_ports() { assert_eq!( add_port_to_hostname("example.com:1337"), - FedDest::Named(String::from("example.com"), ":1337".try_into().unwrap()) + FedDest::Named("example.com".into(), ":1337".try_into().unwrap()) ); } diff --git a/src/service/resolver/well_known.rs b/src/service/resolver/well_known.rs index 553bf845..ef013c04 100644 --- a/src/service/resolver/well_known.rs +++ b/src/service/resolver/well_known.rs @@ -1,8 +1,10 @@ use tuwunel_core::{Result, debug, debug_error, debug_info, debug_warn, implement, trace}; +use super::DestString; + #[implement(super::Service)] #[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))] -pub(super) async fn request_well_known(&self, dest: &str) -> Result> { +pub(super) async fn request_well_known(&self, dest: &str) -> Result> { trace!("Requesting well known for {dest}"); let response = self .services @@ -45,5 +47,5 @@ pub(super) async fn request_well_known(&self, dest: &str) -> Result