Replace HostAddr with IpAddr in the public interface

This commit is contained in:
Dirkjan Ochtman 2022-02-10 22:15:05 +01:00
parent 95b62891c9
commit 29b7db7530
7 changed files with 108 additions and 55 deletions

View File

@ -1,7 +1,8 @@
//! Common data types included in EPP Requests and Responses
use std::{borrow::Cow, fmt::Display};
use std::{borrow::Cow, fmt::Display, net::IpAddr};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Serialize};
use crate::request::Extension;
@ -148,37 +149,42 @@ pub struct Services<'a> {
/// The &lt;hostAddr&gt; types domain or host transactions
#[derive(Serialize, Deserialize, Debug)]
pub struct HostAddr<'a> {
pub(crate) struct HostAddr<'a> {
#[serde(rename = "ip")]
pub ip_version: Option<Cow<'a, str>>,
#[serde(rename = "$value")]
pub address: Cow<'a, str>,
}
impl<'a> HostAddr<'a> {
/// Creates a 'v4' type HostAddr (mostly useful when you don't want to include an 'ip' attr in the XML)
pub fn new(ip_version: &'a str, address: &'a str) -> Self {
impl From<&IpAddr> for HostAddr<'static> {
fn from(addr: &IpAddr) -> Self {
Self {
ip_version: Some(ip_version.into()),
address: address.into(),
ip_version: Some(match addr {
IpAddr::V4(_) => "v4".into(),
IpAddr::V6(_) => "v6".into(),
}),
address: addr.to_string().into(),
}
}
}
/// Creates a 'v4' type HostAddr
pub fn new_v4(address: &'a str) -> HostAddr {
HostAddr {
ip_version: Some("v4".into()),
address: address.into(),
}
}
pub(crate) fn serialize_host_addrs_option<T: AsRef<[IpAddr]>, S>(
addrs: &Option<T>,
ser: S,
) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let addrs = match addrs {
Some(addrs) => addrs.as_ref(),
None => return ser.serialize_none(),
};
/// Creates a 'v6' type HostAddr
pub fn new_v6(address: &'a str) -> HostAddr {
HostAddr {
ip_version: Some("v6".into()),
address: address.into(),
}
let mut seq = ser.serialize_seq(Some(addrs.len()))?;
for addr in addrs {
seq.serialize_element(&HostAddr::from(addr))?;
}
seq.end()
}
/// The &lt;status&gt; type on contact transactions

View File

@ -1,8 +1,10 @@
use std::borrow::Cow;
use std::net::IpAddr;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::common::{HostAddr, StringValue};
use crate::common::{serialize_host_addrs_option, HostAddr, StringValue};
use crate::Error;
pub mod check;
@ -35,8 +37,34 @@ pub struct HostAttr<'a> {
#[serde(rename = "domain:hostName", alias = "hostName")]
pub name: StringValue<'a>,
/// The &lt;hostAddr&gt; tags
#[serde(rename = "domain:hostAddr", alias = "hostAddr")]
pub addresses: Option<Vec<HostAddr<'a>>>,
#[serde(
rename = "domain:hostAddr",
alias = "hostAddr",
serialize_with = "serialize_host_addrs_option",
deserialize_with = "deserialize_host_addrs_option"
)]
pub addresses: Option<Vec<IpAddr>>,
}
fn deserialize_host_addrs_option<'de, D>(de: D) -> Result<Option<Vec<IpAddr>>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let addrs = Option::<Vec<HostAddr<'static>>>::deserialize(de)?;
let addrs = match addrs {
Some(addrs) => addrs,
None => return Ok(None),
};
let result = addrs
.into_iter()
.map(|addr| IpAddr::from_str(&addr.address))
.collect::<Result<_, _>>();
match result {
Ok(addrs) => Ok(Some(addrs)),
Err(e) => Err(serde::de::Error::custom(format!("{}", e))),
}
}
/// The list of &lt;hostAttr&gt; types for domain transactions. Typically under an &lt;ns&gt; tag

View File

@ -104,11 +104,12 @@ pub struct DomainCreateResponse {
#[cfg(test)]
mod tests {
use super::{DomainContact, DomainCreate, HostList, Period};
use crate::common::{HostAddr, NoExtension};
use crate::common::NoExtension;
use crate::domain::{HostAttr, HostAttrList, HostObjList};
use crate::request::Transaction;
use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
use std::net::IpAddr;
#[test]
fn command() {
@ -208,8 +209,8 @@ mod tests {
HostAttr {
name: "ns2.eppdev-1.com".into(),
addresses: Some(vec![
HostAddr::new_v4("177.232.12.58"),
HostAddr::new_v6("2404:6800:4001:801::200e"),
IpAddr::from([177, 232, 12, 58]),
IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e]),
]),
},
];

View File

@ -1,7 +1,9 @@
//! Types for EPP host create request
use std::net::IpAddr;
use super::XMLNS;
use crate::common::{HostAddr, NoExtension, StringValue};
use crate::common::{serialize_host_addrs_option, NoExtension, StringValue};
use crate::request::{Command, Transaction};
use serde::{Deserialize, Serialize};
@ -13,7 +15,7 @@ impl<'a> Command for HostCreate<'a> {
}
impl<'a> HostCreate<'a> {
pub fn new(host: &'a str, addresses: Option<&'a [HostAddr]>) -> Self {
pub fn new(host: &'a str, addresses: Option<&'a [IpAddr]>) -> Self {
Self {
host: HostCreateRequestData {
xmlns: XMLNS,
@ -36,8 +38,8 @@ pub struct HostCreateRequestData<'a> {
#[serde(rename = "host:name")]
pub name: StringValue<'a>,
/// The list of IP addresses for the host
#[serde(rename = "host:addr")]
pub addresses: Option<&'a [HostAddr<'a>]>,
#[serde(rename = "host:addr", serialize_with = "serialize_host_addrs_option")]
pub addresses: Option<&'a [IpAddr]>,
}
#[derive(Serialize, Debug)]
@ -70,8 +72,8 @@ pub struct HostCreateResponse {
#[cfg(test)]
mod tests {
use super::HostCreate;
use crate::common::{HostAddr, NoExtension};
use super::{HostCreate, IpAddr};
use crate::common::NoExtension;
use crate::request::Transaction;
use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
@ -81,8 +83,8 @@ mod tests {
let xml = get_xml("request/host/create.xml").unwrap();
let addresses = &[
HostAddr::new("v4", "29.245.122.14"),
HostAddr::new("v6", "2404:6800:4001:801::200e"),
IpAddr::from([29, 245, 122, 14]),
IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e]),
];
let object = HostCreate::new("host1.eppdev-1.com", Some(addresses));

View File

@ -1,5 +1,8 @@
//! Types for EPP host info request
use std::net::IpAddr;
use std::str::FromStr;
use super::XMLNS;
use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue};
use crate::request::{Command, Transaction};
@ -57,8 +60,8 @@ pub struct HostInfoResponseData {
#[serde(rename = "status")]
pub statuses: Vec<ObjectStatus<'static>>,
/// The list of host IP addresses
#[serde(rename = "addr")]
pub addresses: Vec<HostAddr<'static>>,
#[serde(rename = "addr", deserialize_with = "deserialize_host_addrs")]
pub addresses: Vec<IpAddr>,
/// The epp user to whom the host belongs
#[serde(rename = "clID")]
pub client_id: StringValue<'static>,
@ -79,6 +82,18 @@ pub struct HostInfoResponseData {
pub transferred_at: Option<StringValue<'static>>,
}
fn deserialize_host_addrs<'de, D>(de: D) -> Result<Vec<IpAddr>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let addrs = Vec::<HostAddr<'static>>::deserialize(de)?;
addrs
.into_iter()
.map(|addr| IpAddr::from_str(&addr.address))
.collect::<Result<_, _>>()
.map_err(|e| serde::de::Error::custom(format!("{}", e)))
}
/// Type that represents the &lt;resData&gt; tag for host info response
#[derive(Deserialize, Debug)]
pub struct HostInfoResponse {
@ -89,7 +104,7 @@ pub struct HostInfoResponse {
#[cfg(test)]
mod tests {
use super::HostInfo;
use super::{HostInfo, IpAddr};
use crate::common::NoExtension;
use crate::request::Transaction;
use crate::response::ResultCode;
@ -122,20 +137,12 @@ mod tests {
assert_eq!(result.info_data.roid, "UNDEF-ROID".into());
assert_eq!(result.info_data.statuses[0].status, "ok".to_string());
assert_eq!(
*(result.info_data.addresses[0].ip_version.as_ref().unwrap()),
"v4".to_string()
result.info_data.addresses[0],
IpAddr::from([29, 245, 122, 14])
);
assert_eq!(
result.info_data.addresses[0].address,
"29.245.122.14".to_string()
);
assert_eq!(
*(result.info_data.addresses[1].ip_version.as_ref().unwrap()),
"v6".to_string()
);
assert_eq!(
result.info_data.addresses[1].address,
"2404:6800:4001:0801:0000:0000:0000:200e".to_string()
result.info_data.addresses[1],
IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e])
);
assert_eq!(result.info_data.client_id, "eppdev".into());
assert_eq!(result.info_data.creator_id, "creator".into());

View File

@ -1,7 +1,9 @@
//! Types for EPP host update request
use std::net::IpAddr;
use super::XMLNS;
use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue};
use crate::common::{serialize_host_addrs_option, NoExtension, ObjectStatus, StringValue};
use crate::request::{Command, Transaction};
use serde::Serialize;
@ -53,8 +55,8 @@ pub struct HostChangeInfo<'a> {
#[derive(Serialize, Debug)]
pub struct HostAddRemove<'a> {
/// The IP addresses to be added to or removed from the host
#[serde(rename = "host:addr")]
pub addresses: Option<&'a [HostAddr<'a>]>,
#[serde(rename = "host:addr", serialize_with = "serialize_host_addrs_option")]
pub addresses: Option<&'a [IpAddr]>,
/// The statuses to be added to or removed from the host
#[serde(rename = "host:status")]
pub statuses: Option<&'a [ObjectStatus<'a>]>,
@ -90,8 +92,9 @@ pub struct HostUpdate<'a> {
#[cfg(test)]
mod tests {
use super::IpAddr;
use super::{HostAddRemove, HostChangeInfo, HostUpdate};
use crate::common::{HostAddr, NoExtension, ObjectStatus};
use crate::common::{NoExtension, ObjectStatus};
use crate::request::Transaction;
use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
@ -100,7 +103,9 @@ mod tests {
fn command() {
let xml = get_xml("request/host/update.xml").unwrap();
let addr = &[HostAddr::new("v6", "2404:6800:4001:801::200e")];
let addr = &[IpAddr::from([
0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e,
])];
let add = HostAddRemove {
addresses: Some(addr),

View File

@ -55,6 +55,7 @@ mod tests {
use crate::request::Transaction;
use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SVTRID};
use std::net::IpAddr;
#[test]
fn command() {
@ -142,7 +143,10 @@ mod tests {
assert_eq!(host.roid, "1234".into());
assert!(host.statuses.iter().any(|s| s.status == "ok"));
assert!(host.addresses.iter().any(|a| a.address == *"1.1.1.1"));
assert!(host
.addresses
.iter()
.any(|a| a == &IpAddr::from([1, 1, 1, 1])));
assert_eq!(host.client_id, "1234".into());
assert_eq!(host.creator_id, "user".into());
assert_eq!(host.created_at, "2021-12-01T22:40:48Z".into());