use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use fluent_uri::Uri as FluentUri;
use qubit_redact::RedactionCompletion;
use qubit_redact::RedactionPolicy;
use qubit_redact::formats::uri::UriRedactionBoundary;
use super::invalid_uri;
use super::uri::Uri;
use super::uri::parse_canonical;
use crate::error::FsResult;
#[derive(Clone, Eq, PartialEq)]
pub struct ConnectionUri {
parsed: FluentUri<String>,
redaction_policy: RedactionPolicy,
}
impl ConnectionUri {
pub fn parse(text: &str) -> FsResult<Self> {
Self::parse_with_policy(text, &RedactionPolicy::standard())
}
pub fn parse_with_policy(text: &str, policy: &RedactionPolicy) -> FsResult<Self> {
let parsed = parse_canonical(text)?;
if parsed.fragment().is_some() {
return Err(invalid_uri("URI fragments are not supported"));
}
Ok(Self {
parsed,
redaction_policy: policy.clone(),
})
}
#[must_use]
#[inline]
pub fn scheme(&self) -> &str {
self.parsed.scheme().as_str()
}
#[inline]
#[must_use]
pub fn has_embedded_secret(&self) -> bool {
UriRedactionBoundary::new(&self.redaction_policy)
.inspect_uri(self.parsed.as_str())
.map_or(true, |inspection| inspection.contains_sensitive())
}
#[inline]
pub fn try_to_uri(&self) -> FsResult<Uri> {
Uri::parse_with_policy(self.parsed.as_str(), &self.redaction_policy)
}
#[inline]
pub fn expose_unredacted<R>(&self, inspect: impl FnOnce(&str) -> R) -> R {
inspect(self.parsed.as_str())
}
#[inline]
#[must_use]
fn redacted_text(&self) -> String {
let redaction = UriRedactionBoundary::new(&self.redaction_policy).redact_uri(self.parsed.as_str());
match redaction.summary().completion() {
RedactionCompletion::Complete => redaction
.into_complete_text()
.expect("complete redaction must retain text")
.into_string(),
RedactionCompletion::Truncated | RedactionCompletion::Exhausted => "<truncated>".to_owned(),
}
}
}
impl Display for ConnectionUri {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
formatter.write_str(&self.redacted_text())
}
}
impl Debug for ConnectionUri {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
let redacted = self.redacted_text();
formatter.debug_tuple("ConnectionUri").field(&redacted).finish()
}
}