forked from lavina/lavina
xmpp: fix parsing of unknown elements in messages
This commit is contained in:
parent
4621470bde
commit
887fd95194
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue