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:
parent
ac0707e52d
commit
998d2825f8
2 changed files with 93 additions and 6 deletions
|
|
@ -232,15 +232,15 @@ mod tests {
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_size() {
|
fn test_size() {
|
||||||
assert_size!(IqType, 92);
|
assert_size!(IqType, 104);
|
||||||
assert_size!(Iq, 156);
|
assert_size!(Iq, 168);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_size() {
|
fn test_size() {
|
||||||
assert_size!(IqType, 184);
|
assert_size!(IqType, 208);
|
||||||
assert_size!(Iq, 272);
|
assert_size!(Iq, 296);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ use crate::presence::PresencePayload;
|
||||||
use crate::util::error::Error;
|
use crate::util::error::Error;
|
||||||
use crate::Element;
|
use crate::Element;
|
||||||
use jid::Jid;
|
use jid::Jid;
|
||||||
|
use minidom::Node;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
generate_attribute!(
|
generate_attribute!(
|
||||||
/// The type of the error.
|
/// The type of the error.
|
||||||
|
|
@ -209,6 +211,11 @@ pub struct StanzaError {
|
||||||
|
|
||||||
/// A protocol-specific extension for this error.
|
/// A protocol-specific extension for this error.
|
||||||
pub other: Option<Element>,
|
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 [XMPP‑URI]
|
||||||
|
pub alternate_address: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessagePayload for StanzaError {}
|
impl MessagePayload for StanzaError {}
|
||||||
|
|
@ -236,6 +243,7 @@ impl StanzaError {
|
||||||
map
|
map
|
||||||
},
|
},
|
||||||
other: None,
|
other: None,
|
||||||
|
alternate_address: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,6 +263,7 @@ impl TryFrom<Element> for StanzaError {
|
||||||
defined_condition: DefinedCondition::UndefinedCondition,
|
defined_condition: DefinedCondition::UndefinedCondition,
|
||||||
texts: BTreeMap::new(),
|
texts: BTreeMap::new(),
|
||||||
other: None,
|
other: None,
|
||||||
|
alternate_address: None,
|
||||||
};
|
};
|
||||||
let mut defined_condition = None;
|
let mut defined_condition = None;
|
||||||
|
|
||||||
|
|
@ -277,6 +286,14 @@ impl TryFrom<Element> for StanzaError {
|
||||||
check_no_children!(child, "defined-condition");
|
check_no_children!(child, "defined-condition");
|
||||||
check_no_attributes!(child, "defined-condition");
|
check_no_attributes!(child, "defined-condition");
|
||||||
let condition = DefinedCondition::try_from(child.clone())?;
|
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);
|
defined_condition = Some(condition);
|
||||||
} else {
|
} else {
|
||||||
if stanza_error.other.is_some() {
|
if stanza_error.other.is_some() {
|
||||||
|
|
@ -319,7 +336,7 @@ mod tests {
|
||||||
fn test_size() {
|
fn test_size() {
|
||||||
assert_size!(ErrorType, 1);
|
assert_size!(ErrorType, 1);
|
||||||
assert_size!(DefinedCondition, 1);
|
assert_size!(DefinedCondition, 1);
|
||||||
assert_size!(StanzaError, 92);
|
assert_size!(StanzaError, 104);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
|
@ -327,7 +344,7 @@ mod tests {
|
||||||
fn test_size() {
|
fn test_size() {
|
||||||
assert_size!(ErrorType, 1);
|
assert_size!(ErrorType, 1);
|
||||||
assert_size!(DefinedCondition, 1);
|
assert_size!(DefinedCondition, 1);
|
||||||
assert_size!(StanzaError, 184);
|
assert_size!(StanzaError, 208);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -415,4 +432,74 @@ mod tests {
|
||||||
let stanza_error = StanzaError::try_from(elem).unwrap();
|
let stanza_error = StanzaError::try_from(elem).unwrap();
|
||||||
assert_eq!(stanza_error.type_, ErrorType::Cancel);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue