forked from lavina/lavina
1
0
Fork 0

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"))) Continuation::Final(Err(ffail!("Expected start")))
} }
} }
Outer(state) => match event { Outer(mut state) => match event {
Event::Start(ref bytes) => { Event::Start(ref bytes) => {
if bytes.name().0 == b"subject" { if bytes.name().0 == b"subject" {
Continuation::Continue(InSubject(state).into()) Continuation::Continue(InSubject(state).into())
} else if bytes.name().0 == b"body" { } else if bytes.name().0 == b"body" {
Continuation::Continue(InBody(state).into()) Continuation::Continue(InBody(state).into())
} else { } 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(_) => { Event::End(_) => {
@ -129,6 +137,17 @@ impl<T: FromXml> Parser for MessageParser<T> {
Continuation::Final(Err(ffail!("Body not found"))) 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:?}"))), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
}, },
InSubject(mut state) => match event { InSubject(mut state) => match event {
@ -151,7 +170,7 @@ impl<T: FromXml> Parser for MessageParser<T> {
Event::End(_) => Continuation::Continue(Outer(state).into()), Event::End(_) => Continuation::Continue(Outer(state).into()),
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => 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)) => { Continuation::Final(Ok(e)) => {
state.custom.push(e); state.custom.push(e);
Continuation::Continue(Outer(state).into()) Continuation::Continue(Outer(state).into())
@ -594,25 +613,34 @@ mod tests {
use crate::bind::{BindRequest, Name, Resource, Server}; use crate::bind::{BindRequest, Name, Resource, Server};
use super::*; use super::*;
use quick_xml::NsReader;
#[tokio::test] #[tokio::test]
async fn parse_message() { 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 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 result: Message<Ignore> = crate::xml::parse(input).unwrap();
let mut buf = vec![]; assert_eq!(
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap(); result,
let mut parser = Message::parse().consume(ns, &event); Message::<Ignore> {
let result = loop { from: None,
match parser { id: Some("aacea".to_string()),
Continuation::Final(res) => break res, to: Some(Jid {
Continuation::Continue(next) => { name: Some(Name("nikita".into())),
let (ns, event) = reader.read_resolved_event_into_async(&mut buf).await.unwrap(); server: Server("vlnv.dev".into()),
parser = next.consume(ns, &event); 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!( assert_eq!(
result, result,
Message::<Ignore> { Message::<Ignore> {
@ -635,20 +663,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn parse_iq() { 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 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 result: Iq<BindRequest> = crate::xml::parse(input).unwrap();
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();
assert_eq!( assert_eq!(
result, result,
Iq { Iq {

View File

@ -1,10 +1,11 @@
use std::ops::Generator; use std::ops::Generator;
use std::pin::Pin; use std::pin::Pin;
use quick_xml::NsReader;
use quick_xml::events::Event; use quick_xml::events::Event;
use quick_xml::name::ResolveResult; use quick_xml::name::ResolveResult;
use anyhow::{anyhow, Result}; use anyhow::Result;
mod ignore; mod ignore;
pub use ignore::Ignore; pub use ignore::Ignore;
@ -63,6 +64,22 @@ pub enum Continuation<Parser, Res> {
Continue(Parser), 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 { macro_rules! fail_fast {
($errorable: expr) => { ($errorable: expr) => {
match $errorable { match $errorable {