#[derive(Debug, Default, Clone)]
pub(crate) struct Fields {
pub registrar: Option<String>,
pub created: Option<String>,
pub expires: Option<String>,
pub nameservers: Vec<String>,
}
pub(crate) fn extract(body: &str) -> Fields {
let mut f = Fields::default();
for line in body.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('%') || line.starts_with('#') {
continue;
}
let Some((key, value)) = line.split_once(':') else {
continue;
};
let key = key.trim().to_ascii_lowercase();
let value = value.trim();
if value.is_empty() {
continue;
}
match key.as_str() {
"registrar" | "sponsoring registrar" | "registrar name" => {
if f.registrar.is_none() {
f.registrar = Some(value.to_string());
}
}
"creation date"
| "created"
| "created on"
| "created date"
| "registered"
| "registered on"
| "registration time"
| "domain registration date" => {
if f.created.is_none() {
f.created = Some(value.to_string());
}
}
"registry expiry date"
| "registrar registration expiration date"
| "expiry date"
| "expiration date"
| "expiration time"
| "expires"
| "expires on"
| "paid-till" => {
if f.expires.is_none() {
f.expires = Some(value.to_string());
}
}
"name server" | "nameserver" | "nserver" | "name servers" => {
let ns = value
.split_whitespace()
.next()
.unwrap_or(value)
.trim_end_matches('.')
.to_ascii_lowercase();
if !ns.is_empty() && !f.nameservers.contains(&ns) {
f.nameservers.push(ns);
}
}
_ => {}
}
}
f
}
#[cfg(test)]
mod tests {
use super::extract;
const SAMPLE: &str = "\
% sample response
Domain Name: RUST-LANG.ORG
Registry Domain ID: D402200000000000000-LROR
Registrar: MarkMonitor Inc.
Creation Date: 2010-04-08T15:24:12Z
Registry Expiry Date: 2028-04-08T15:24:12Z
Name Server: NS-1000.AWSDNS-00.CO.UK.
Name Server: NS-2000.AWSDNS-00.NET.
";
#[test]
fn extracts_common_fields() {
let f = extract(SAMPLE);
assert_eq!(f.registrar.as_deref(), Some("MarkMonitor Inc."));
assert_eq!(f.created.as_deref(), Some("2010-04-08T15:24:12Z"));
assert_eq!(f.expires.as_deref(), Some("2028-04-08T15:24:12Z"));
assert_eq!(
f.nameservers,
vec![
"ns-1000.awsdns-00.co.uk".to_string(),
"ns-2000.awsdns-00.net".to_string()
]
);
}
#[test]
fn ignores_comments_and_blank_lines() {
let body = "% comment\n\n# another\nRegistrar: Test\n";
assert_eq!(extract(body).registrar.as_deref(), Some("Test"));
}
}