xmpp: fix parsing of unknown elements in messages

This commit is contained in:
Nikita Vilunov 2023-10-03 00:17:48 +02:00
parent 4621470bde
commit 887fd95194
2 changed files with 64 additions and 32 deletions

View File

@ -103,14 +103,22 @@ impl<T: FromXml> Parser for MessageParser<T> {
Continuation::Final(Err(ffail!("Expected start")))
}
}
Outer(state) => match event {
Outer(mut state) => match event {
Event::Start(ref bytes) => {
if bytes.name().0 == b"subject" {
Continuation::Continue(InSubject(state).into())
} else if bytes.name().0 == b"body" {
Continuation::Continue(InBody(state).into())
} else {
Continuation::Continue(InCustom(state, T::parse()).into())
let parser = T::parse();
match parser.consume(namespace, event) {
Continuation::Final(Ok(e)) => {
state.custom.push(e);
Continuation::Continue(Outer(state).into())
}
Continuation::Final(Err(e)) => Continuation::Final(Err(e)),
Continuation::Continue(p) => Continuation::Continue(InCustom(state, p).into()),
}
}
}
Event::End(_) => {
@ -129,6 +137,17 @@ impl<T: FromXml> Parser for MessageParser<T> {
Continuation::Final(Err(ffail!("Body not found")))
}
}
Event::Empty(_) => {
let parser = T::parse();
match parser.consume(namespace, event) {
Continuation::Final(Ok(e)) => {
state.custom.push(e);
Continuation::Continue(Outer(state).into())
}
Continuation::Final(Err(e)) => Continuation::Final(Err(e)),
Continuation::Continue(p) => Continuation::Continue(InCustom(state, p).into()),
}
}
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
InSubject(mut state) => match event {
@ -151,7 +170,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
Event::End(_) => Continuation::Continue(Outer(state).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
},
InCustom(mut state, mut custom) => match custom.consume(namespace, event) {
InCustom(mut state, custom) => match custom.consume(namespace, event) {
Continuation::Final(Ok(e)) => {
state.custom.push(e);
Continuation::Continue(Outer(state).into())
@ -594,25 +613,34 @@ mod tests {
use crate::bind::{BindRequest, Name, Resource, Server};
use super::*;
use quick_xml::NsReader;
#[tokio::test]
async fn parse_message() {
let input = r#"<message id="aacea" type="chat" to="nikita@vlnv.dev"><subject>daa</subject><body>bbb</body><unknown-stuff></unknown-stuff></message>"#;
let mut reader = NsReader::from_reader(input.as_bytes());
let mut buf = vec![];
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
let mut parser = Message::parse().consume(ns, &event);
let result = loop {
match parser {
Continuation::Final(res) => break res,
Continuation::Continue(next) => {
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
parser = next.consume(ns, &event);
}
let result: Message<Ignore> = crate::xml::parse(input).unwrap();
assert_eq!(
result,
Message::<Ignore> {
from: None,
id: Some("aacea".to_string()),
to: Some(Jid {
name: Some(Name("nikita".into())),
server: Server("vlnv.dev".into()),
resource: None
}),
r#type: MessageType::Chat,
lang: None,
subject: Some("daa".into()),
body: "bbb".into(),
custom: vec![Ignore],
}
}
.unwrap();
)
}
#[tokio::test]
async fn parse_message_empty_custom() {
let input = r#"<message id="aacea" type="chat" to="nikita@vlnv.dev"><subject>daa</subject><body>bbb</body><unknown-stuff/></message>"#;
let result: Message<Ignore> = crate::xml::parse(input).unwrap();
assert_eq!(
result,
Message::<Ignore> {
@ -635,20 +663,7 @@ mod tests {
#[tokio::test]
async fn parse_iq() {
let input = r#"<iq id="bind_1" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>mobile</resource></bind></iq>"#;
let mut reader = NsReader::from_reader(input.as_bytes());
let mut buf = vec![];
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
let mut parser = Iq::<BindRequest>::parse().consume(ns, &event);
let result = loop {
match parser {
Continuation::Final(res) => break res,
Continuation::Continue(next) => {
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap();
parser = next.consume(ns, &event);
}
}
}
.unwrap();
let result: Iq<BindRequest> = crate::xml::parse(input).unwrap();
assert_eq!(
result,
Iq {

View File

@ -1,10 +1,11 @@
use std::ops::Generator;
use std::pin::Pin;
use quick_xml::NsReader;
use quick_xml::events::Event;
use quick_xml::name::ResolveResult;
use anyhow::{anyhow, Result};
use anyhow::Result;
mod ignore;
pub use ignore::Ignore;
@ -63,6 +64,22 @@ pub enum Continuation<Parser, Res> {
Continue(Parser),
}
pub fn parse<T: FromXml>(input: &str) -> Result<T> {
let mut reader = NsReader::from_reader(input.as_bytes());
let mut buf = vec![];
let (ns, event) = reader.read_resolved_event_into(&mut buf)?;
let mut parser: Continuation<_, std::result::Result<T, anyhow::Error>> = T::parse().consume(ns, &event);
loop {
match parser {
Continuation::Final(res) => break res,
Continuation::Continue(next) => {
let (ns, event) = reader.read_resolved_event_into(&mut buf)?;
parser = next.consume(ns, &event);
}
}
}
}
macro_rules! fail_fast {
($errorable: expr) => {
match $errorable {