#[derive(Debug)] pub(crate) struct PeerFormatting { peer: SocketAddr, local: SocketAddr, peer_ip: IpAddr, peer_header: HeaderValue, peer_node: String, by_node: String, port_header: HeaderValue, untrusted_headers: std::sync::Mutex>, } #[derive(Debug)] struct UntrustedHeaders { authority: HeaderValue, tls: bool, base: HeaderMap, } impl PeerFormatting { pub(crate) fn new(peer: SocketAddr, local: SocketAddr) -> Self { let peer_ip = canonical(peer.ip()); let peer_text = peer_ip.to_string(); Self { peer, local, peer_ip, peer_header: HeaderValue::from_str(&peer_text).expect("IP text is a valid header"), peer_node: if peer_ip.is_ipv4() { peer_text } else { node(peer_ip) }, by_node: node(canonical(local.ip())), port_header: HeaderValue::from_str(&local.port().to_string()) .expect("TCP port is a valid header"), untrusted_headers: std::sync::Mutex::new(None), } } /// Text form of the peer address when it needed no canonicalization. pub(crate) fn raw_peer_text(&self) -> Option<&str> { (self.peer.ip() == self.peer_ip) .then(|| self.peer_header.to_str().ok()) .flatten() } fn cached_untrusted(&self, authority: &HeaderValue, tls: bool) -> Option { self.untrusted_headers .lock() .unwrap_or_else(|e| e.into_inner()) .as_ref() .filter(|entry| entry.tls == tls && entry.authority.as_bytes() == authority.as_bytes()) .map(|entry| entry.base.clone()) } fn remember_untrusted(&self, authority: &HeaderValue, tls: bool, base: &HeaderMap) { *self .untrusted_headers .lock() .unwrap_or_else(|e| e.into_inner()) = Some(UntrustedHeaders { authority: authority.clone(), tls, base: base.clone(), }); } }