///|
pub suberror InputError {
InvalidInput(String)
} derive(Debug)
///|
/// DNS labels as immutable octets. Never split an instance label on dots.
pub struct DnsName {
priv labels : Array[Bytes]
priv key : Bytes
} derive(Debug)
///|
pub fn DnsName::from_labels(labels : Array[Bytes]) -> DnsName raise InputError {
let mut size = 1
for label in labels {
guard label.length() > 0 && label.length() <= 63 else {
raise InvalidInput("DNS label must contain 1..63 octets")
}
size += label.length() + 1
guard size <= 256 else {
raise InvalidInput("mDNS name exceeds 255 octets plus terminator")
}
}
let folded : Array[Byte] = []
for label in labels {
folded.push(label.length().to_byte())
for byte in label {
let value = byte.to_int()
folded.push(
(if value >= 65 && value <= 90 { value + 32 } else { value }).to_byte(),
)
}
}
folded.push(0)
{ labels: labels.copy(), key: Bytes::makei(folded.length(), i => folded[i]), }
}
///|
pub fn DnsName::from_utf8_labels(
labels : Array[String],
) -> DnsName raise InputError {
DnsName::from_labels(labels.map(s => @utf8.encode(s)))
}
///|
pub fn DnsName::labels(self : DnsName) -> Array[Bytes] {
self.labels.copy()
}
///|
pub fn DnsName::to_wire(self : DnsName) -> Bytes {
let out : Array[Byte] = []
for label in self.labels {
out.push(label.length().to_byte())
for b in label {
out.push(b)
}
}
out.push(0)
Bytes::makei(out.length(), i => out[i])
}
///|
/// A collision-free wire key with ASCII case folding only.
pub fn DnsName::canonical_key(self : DnsName) -> Bytes {
self.key
}
///|
pub fn DnsName::same_name(self : DnsName, other : DnsName) -> Bool {
self.canonical_key() == other.canonical_key()
}
///|
/// Absolute, reversible ASCII presentation. UTF-8 remains intact in labels().
pub fn DnsName::to_presentation(self : DnsName) -> String {
let out = StringBuilder()
for label in self.labels {
for b in label {
let n = b.to_int()
if n >= 33 && n <= 126 && n != 46 && n != 92 {
out.write_char(n.unsafe_to_char())
} else {
out.write_string("\\")
out.write_char((48 + n / 100).unsafe_to_char())
out.write_char((48 + n / 10 % 10).unsafe_to_char())
out.write_char((48 + n % 10).unsafe_to_char())
}
}
out.write_char('.')
}
if self.labels.is_empty() {
"."
} else {
out.to_string()
}
}