From 245aa0b64ae9fa3ae6a0b64630fb9c618d8fc1f7 Mon Sep 17 00:00:00 2001 From: Rudi Floren Date: Mon, 1 Jun 2026 17:20:58 +0200 Subject: [PATCH 1/4] feat: flatten hello::ServiceMenu The types from are not 100% compatible with . This is the first part of fixing this. --- src/hello.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/hello.rs b/src/hello.rs index 59c364b..64375f2 100644 --- a/src/hello.rs +++ b/src/hello.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use chrono::{DateTime, Utc}; use instant_xml::{Deserializer, FromXml, ToXml}; -use crate::common::{Options, ServiceExtension, Services, EPP_XMLNS}; +use crate::common::{ServiceExtension, Services, EPP_XMLNS}; // Request @@ -16,7 +16,8 @@ pub(crate) struct Hello; /// Type for data within the `` section of an EPP greeting #[derive(Debug, Eq, PartialEq)] pub struct ServiceMenu { - pub options: Options<'static>, + pub version: String, + pub lang: String, pub services: Services<'static>, } @@ -51,10 +52,8 @@ impl<'xml> FromXml<'xml> for ServiceMenu { }; *into = Some(Self { - options: Options { - version: flattened.version.into(), - lang: flattened.lang.into(), - }, + version: flattened.version, + lang: flattened.lang, services: Services { obj_uris: flattened.obj_uris.into_iter().map(|s| s.into()).collect(), svc_ext: flattened.svc_ext, @@ -338,8 +337,8 @@ mod tests { object.service_date, Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap() ); - assert_eq!(object.svc_menu.options.version, "1.0"); - assert_eq!(object.svc_menu.options.lang, "en"); + assert_eq!(object.svc_menu.version, "1.0"); + assert_eq!(object.svc_menu.lang, "en"); assert_eq!(object.svc_menu.services.obj_uris.len(), 4); assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5); assert_eq!(object.dcp.statement.len(), 2); @@ -359,8 +358,8 @@ mod tests { object.service_date, Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap() ); - assert_eq!(object.svc_menu.options.version, "1.0"); - assert_eq!(object.svc_menu.options.lang, "en"); + assert_eq!(object.svc_menu.version, "1.0"); + assert_eq!(object.svc_menu.lang, "en"); assert_eq!(object.svc_menu.services.obj_uris.len(), 4); assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5); assert_eq!(object.dcp.statement.len(), 2); From 165fc98e165d89ef9fd7a957008ae438d36a9d0e Mon Sep 17 00:00:00 2001 From: Rudi Floren Date: Tue, 2 Jun 2026 16:09:08 +0200 Subject: [PATCH 2/4] feat: use own type for ServiceMenu::services The fields in can not be passed to directly. Reusing the type made this too easy. Instead ServiceMenu now uses it's own Services higher level abstraction type. --- src/hello.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hello.rs b/src/hello.rs index 64375f2..118a844 100644 --- a/src/hello.rs +++ b/src/hello.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use chrono::{DateTime, Utc}; use instant_xml::{Deserializer, FromXml, ToXml}; -use crate::common::{ServiceExtension, Services, EPP_XMLNS}; +use crate::common::{ServiceExtension, EPP_XMLNS}; // Request @@ -18,7 +18,16 @@ pub(crate) struct Hello; pub struct ServiceMenu { pub version: String, pub lang: String, - pub services: Services<'static>, + pub services: Services, +} + +/// Offered services by the remote EPP server, represented by the `` tag in EPP greeting XML +#[derive(Debug, Eq, PartialEq)] +pub struct Services { + /// The service URIs being offered by the EPP server represented by `` in EPP XML + pub obj_uris: Vec, + /// The service extensions being offered by the EPP server represented by `` in EPP XML + pub svc_ext: Option>, } /// Simplified service menu type for deserialization to `ServiceMenu` type from EPP greeting XML @@ -55,7 +64,7 @@ impl<'xml> FromXml<'xml> for ServiceMenu { version: flattened.version, lang: flattened.lang, services: Services { - obj_uris: flattened.obj_uris.into_iter().map(|s| s.into()).collect(), + obj_uris: flattened.obj_uris, svc_ext: flattened.svc_ext, }, }); From 4e3583216b1279c426b58126959eb4d0873d3131 Mon Sep 17 00:00:00 2001 From: Rudi Floren Date: Thu, 28 May 2026 19:57:24 +0200 Subject: [PATCH 3/4] fix: support multiple langs in can contain multiple objects. The previous version tried to reuse types used in but they are incompatible --- src/hello.rs | 35 ++++++++++-- .../response/greeting_multi_lang.xml | 55 +++++++++++++++++++ 2 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 tests/resources/response/greeting_multi_lang.xml diff --git a/src/hello.rs b/src/hello.rs index 118a844..c3f9f9d 100644 --- a/src/hello.rs +++ b/src/hello.rs @@ -17,7 +17,7 @@ pub(crate) struct Hello; #[derive(Debug, Eq, PartialEq)] pub struct ServiceMenu { pub version: String, - pub lang: String, + pub langs: Vec, pub services: Services, } @@ -31,11 +31,14 @@ pub struct Services { } /// Simplified service menu type for deserialization to `ServiceMenu` type from EPP greeting XML +/// +/// Implements the `epp:svcMenuType` type defined in RFC 5730. #[derive(Debug, FromXml, PartialEq)] #[xml(ns(EPP_XMLNS), rename = "svcMenu")] struct FlattenedServiceMenu { version: String, - lang: String, + #[xml(rename = "lang")] + langs: Vec, #[xml(rename = "objURI")] obj_uris: Vec, #[xml(rename = "svcExtension")] @@ -62,7 +65,7 @@ impl<'xml> FromXml<'xml> for ServiceMenu { *into = Some(Self { version: flattened.version, - lang: flattened.lang, + langs: flattened.langs, services: Services { obj_uris: flattened.obj_uris, svc_ext: flattened.svc_ext, @@ -347,7 +350,29 @@ mod tests { Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap() ); assert_eq!(object.svc_menu.version, "1.0"); - assert_eq!(object.svc_menu.lang, "en"); + assert_eq!(object.svc_menu.langs.first().unwrap(), "en"); + assert_eq!(object.svc_menu.services.obj_uris.len(), 4); + assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5); + assert_eq!(object.dcp.statement.len(), 2); + assert_eq!( + object.dcp.expiry.unwrap().inner, + ExpiryType::Relative(Relative("P1M".into())) + ); + } + + #[test] + fn greeting_multi_lang() { + let xml = get_xml("response/greeting_multi_lang.xml").unwrap(); + let object = xml::deserialize::(xml.as_str()).unwrap(); + + assert_eq!(object.service_id, "ISPAPI EPP Server"); + assert_eq!( + object.service_date, + Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap() + ); + assert_eq!(object.svc_menu.version, "1.0"); + assert_eq!(object.svc_menu.langs.first().unwrap(), "en"); + assert_eq!(object.svc_menu.langs.get(1).unwrap(), "fr"); assert_eq!(object.svc_menu.services.obj_uris.len(), 4); assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5); assert_eq!(object.dcp.statement.len(), 2); @@ -368,7 +393,7 @@ mod tests { Utc.with_ymd_and_hms(2021, 7, 25, 14, 51, 17).unwrap() ); assert_eq!(object.svc_menu.version, "1.0"); - assert_eq!(object.svc_menu.lang, "en"); + assert_eq!(object.svc_menu.langs.first().unwrap(), "en"); assert_eq!(object.svc_menu.services.obj_uris.len(), 4); assert_eq!(object.svc_menu.services.svc_ext.unwrap().ext_uris.len(), 5); assert_eq!(object.dcp.statement.len(), 2); diff --git a/tests/resources/response/greeting_multi_lang.xml b/tests/resources/response/greeting_multi_lang.xml new file mode 100644 index 0000000..673c8ce --- /dev/null +++ b/tests/resources/response/greeting_multi_lang.xml @@ -0,0 +1,55 @@ + + + + ISPAPI EPP Server + 2021-07-25T14:51:17.0Z + + 1.0 + en + fr + urn:ietf:params:xml:ns:host-1.0 + urn:ietf:params:xml:ns:domain-1.0 + urn:ietf:params:xml:ns:contact-1.0 + http://schema.ispapi.net/epp/xml/keyvalue-1.0 + + urn:ietf:params:xml:ns:secDNS-1.1 + urn:ietf:params:xml:ns:secDNS-1.0 + urn:ietf:params:xml:ns:rgp-1.0 + urn:ietf:params:xml:ns:fee-0.7 + http://schema.ispapi.net/epp/xml/keyvalue-1.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P1M + + + + \ No newline at end of file From 6c1ad92fa9c58bfa1fffff4d132490f8ec1776ea Mon Sep 17 00:00:00 2001 From: Rudi Floren Date: Mon, 1 Jun 2026 17:12:46 +0200 Subject: [PATCH 4/4] chore: move login-used types to login module --- src/common.rs | 32 -------------------------------- src/login.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/common.rs b/src/common.rs index ed95339..b704108 100644 --- a/src/common.rs +++ b/src/common.rs @@ -32,26 +32,6 @@ impl Extension for NoExtension { type Response = Self; } -/// The `