Add alternate_address to StanzaError

[gone](https://datatracker.ietf.org/doc/html/rfc6120#section-8.3.3.5) and [redirect](https://datatracker.ietf.org/doc/html/rfc6120#section-8.3.3.14) errors may include an alternative address.

> gone
>
> The recipient or server can no longer be contacted at this address,
> typically on a permanent basis (as opposed to the <redirect/> error
> condition, which is used for temporary addressing failures); the
> associated error type SHOULD be "cancel" and the error stanza SHOULD
> include a new address (if available) as the XML character data of the
> <gone/> element (which MUST be a Uniform Resource Identifier [URI] or
> Internationalized Resource Identifier [IRI] at which the entity can
> be contacted, typically an XMPP IRI as specified in [XMPP-URI]).

—

> redirect
>
> The recipient or server is redirecting requests for this information
> to another entity, typically in a temporary fashion (as opposed to
> the <gone/> error condition, which is used for permanent addressing
> failures); the associated error type SHOULD be "modify" and the error
> stanza SHOULD contain the alternate address in the XML character data
> of the <redirect/> element (which MUST be a URI or IRI with which the
> sender can communicate, typically an XMPP IRI as specified in
> [XMPP-URI](https://datatracker.ietf.org/doc/html/rfc6120#ref-XMPP-URI)).
This commit is contained in:
mb 2023-11-24 16:33:40 +01:00 committed by Marc Bauer
parent ac0707e52d
commit 998d2825f8
2 changed files with 93 additions and 6 deletions

View file

@ -232,15 +232,15 @@ mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(IqType, 92);
assert_size!(Iq, 156);
assert_size!(IqType, 104);
assert_size!(Iq, 168);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(IqType, 184);
assert_size!(Iq, 272);
assert_size!(IqType, 208);
assert_size!(Iq, 296);
}
#[test]

View file

@ -10,7 +10,9 @@ use crate::presence::PresencePayload;
use crate::util::error::Error;
use crate::Element;
use jid::Jid;
use minidom::Node;
use std::collections::BTreeMap;
use std::convert::TryFrom;
generate_attribute!(
/// The type of the error.
@ -209,6 +211,11 @@ pub struct StanzaError {
/// A protocol-specific extension for this error.
pub other: Option<Element>,
/// May include an alternate address if `defined_condition` is `Gone` or `Redirect`. It is
/// a Uniform Resource Identifier [URI] or Internationalized Resource Identifier [IRI] at
/// which the entity can be contacted, typically an XMPP IRI as specified in [XMPPURI]
pub alternate_address: Option<String>,
}
impl MessagePayload for StanzaError {}
@ -236,6 +243,7 @@ impl StanzaError {
map
},
other: None,
alternate_address: None,
}
}
}
@ -255,6 +263,7 @@ impl TryFrom<Element> for StanzaError {
defined_condition: DefinedCondition::UndefinedCondition,
texts: BTreeMap::new(),
other: None,
alternate_address: None,
};
let mut defined_condition = None;
@ -277,6 +286,14 @@ impl TryFrom<Element> for StanzaError {
check_no_children!(child, "defined-condition");
check_no_attributes!(child, "defined-condition");
let condition = DefinedCondition::try_from(child.clone())?;
if condition == DefinedCondition::Gone || condition == DefinedCondition::Redirect {
stanza_error.alternate_address = child.nodes().find_map(|node| {
let Node::Text(text) = node else { return None };
return Some(text.to_string());
});
}
defined_condition = Some(condition);
} else {
if stanza_error.other.is_some() {
@ -319,7 +336,7 @@ mod tests {
fn test_size() {
assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1);
assert_size!(StanzaError, 92);
assert_size!(StanzaError, 104);
}
#[cfg(target_pointer_width = "64")]
@ -327,7 +344,7 @@ mod tests {
fn test_size() {
assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1);
assert_size!(StanzaError, 184);
assert_size!(StanzaError, 208);
}
#[test]
@ -415,4 +432,74 @@ mod tests {
let stanza_error = StanzaError::try_from(elem).unwrap();
assert_eq!(stanza_error.type_, ErrorType::Cancel);
}
#[test]
fn test_gone_with_new_address() {
#[cfg(not(feature = "component"))]
let elem: Element = "<error xmlns='jabber:client' type='cancel'><gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>xmpp:room@muc.example.org?join</gone></error>"
.parse()
.unwrap();
#[cfg(feature = "component")]
let elem: Element = "<error xmlns='jabber:component:accept' type='cancel'><gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>xmpp:room@muc.example.org?join</gone></error>"
.parse()
.unwrap();
let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Cancel);
assert_eq!(error.defined_condition, DefinedCondition::Gone);
assert_eq!(
error.alternate_address,
Some("xmpp:room@muc.example.org?join".to_string())
);
}
#[test]
fn test_gone_without_new_address() {
#[cfg(not(feature = "component"))]
let elem: Element = "<error xmlns='jabber:client' type='cancel'><gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /></error>"
.parse()
.unwrap();
#[cfg(feature = "component")]
let elem: Element = "<error xmlns='jabber:component:accept' type='cancel'><gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /></error>"
.parse()
.unwrap();
let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Cancel);
assert_eq!(error.defined_condition, DefinedCondition::Gone);
assert_eq!(error.alternate_address, None);
}
#[test]
fn test_redirect_with_alternate_address() {
#[cfg(not(feature = "component"))]
let elem: Element = "<error xmlns='jabber:client' type='modify'><redirect xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>xmpp:characters@conference.example.org</redirect></error>"
.parse()
.unwrap();
#[cfg(feature = "component")]
let elem: Element = "<error xmlns='jabber:component:accept' type='modify'><redirect xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>xmpp:characters@conference.example.org</redirect></error>"
.parse()
.unwrap();
let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Modify);
assert_eq!(error.defined_condition, DefinedCondition::Redirect);
assert_eq!(
error.alternate_address,
Some("xmpp:characters@conference.example.org".to_string())
);
}
#[test]
fn test_redirect_without_alternate_address() {
#[cfg(not(feature = "component"))]
let elem: Element = "<error xmlns='jabber:client' type='modify'><redirect xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /></error>"
.parse()
.unwrap();
#[cfg(feature = "component")]
let elem: Element = "<error xmlns='jabber:component:accept' type='modify'><redirect xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /></error>"
.parse()
.unwrap();
let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Modify);
assert_eq!(error.defined_condition, DefinedCondition::Redirect);
assert_eq!(error.alternate_address, None);
}
}