forked from lavina/lavina
xmpp: rewrite bind request parser as a coroutine
This commit is contained in:
parent
87d73af811
commit
372efc3701
|
@ -78,89 +78,57 @@ impl Jid {
|
|||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct BindRequest(pub Resource);
|
||||
|
||||
pub struct BindRequestParser(BindRequestParserInner);
|
||||
|
||||
enum BindRequestParserInner {
|
||||
Initial,
|
||||
/// Consumed <bind> start and expects <resource>
|
||||
InBind(Option<String>),
|
||||
/// Consumed <resource> start
|
||||
InBindResourceInitial,
|
||||
/// Consumer <resource> start and inner text
|
||||
InBindResourceEnd(String),
|
||||
}
|
||||
|
||||
impl FromXmlTag for BindRequest {
|
||||
const NS: &'static str = XMLNS;
|
||||
const NAME: &'static str = "bind";
|
||||
}
|
||||
|
||||
impl FromXml for BindRequest {
|
||||
type P = BindRequestParser;
|
||||
type P = impl Parser<Output = Result<Self>>;
|
||||
|
||||
fn parse() -> Self::P {
|
||||
BindRequestParser(BindRequestParserInner::Initial)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rewrite as a generator
|
||||
impl Parser for BindRequestParser {
|
||||
type Output = Result<BindRequest>;
|
||||
|
||||
fn consume<'a>(
|
||||
self: Self,
|
||||
namespace: ResolveResult,
|
||||
event: &Event<'a>,
|
||||
) -> Continuation<Self, Self::Output> {
|
||||
// TODO validate tag names and namespaces
|
||||
use BindRequestParserInner::*;
|
||||
match self.0 {
|
||||
Initial => {
|
||||
let Event::Start(bytes) = event else {
|
||||
return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}")));
|
||||
};
|
||||
if bytes.name().0 != BindRequest::NAME.as_bytes() {
|
||||
return Continuation::Final(Err(ffail!(
|
||||
"Unexpected XML tag: {:?}",
|
||||
bytes.name()
|
||||
)));
|
||||
}
|
||||
let ResolveResult::Bound(Namespace(ns)) = namespace else {
|
||||
return Continuation::Final(Err(ffail!("No namespace provided")));
|
||||
};
|
||||
if ns != XMLNS.as_bytes() {
|
||||
return Continuation::Final(Err(ffail!("Incorrect namespace")));
|
||||
}
|
||||
Continuation::Continue(BindRequestParser(InBind(None)))
|
||||
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||
let mut resource: Option<Box<[u8]>> = None;
|
||||
let Event::Start(bytes) = event else {
|
||||
return Err(ffail!("Unexpected XML event: {event:?}"));
|
||||
};
|
||||
if bytes.name().0 != BindRequest::NAME.as_bytes() {
|
||||
return Err(ffail!("Unexpected XML tag: {:?}", bytes.name()));
|
||||
}
|
||||
InBind(resource) => match event {
|
||||
Event::Start(bytes) => {
|
||||
Continuation::Continue(BindRequestParser(InBindResourceInitial))
|
||||
}
|
||||
Event::End(bytes) => {
|
||||
let Some(resource) = resource else {
|
||||
return Continuation::Final(Err(ffail!("No resource was provided")));
|
||||
};
|
||||
Continuation::Final(Ok(BindRequest(Resource(resource.into()))))
|
||||
}
|
||||
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
|
||||
},
|
||||
InBindResourceInitial => {
|
||||
let Event::Text(text) = event else {
|
||||
return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}")));
|
||||
};
|
||||
let resource = match std::str::from_utf8(text.as_bytes()) {
|
||||
Ok(e) => e.to_string(),
|
||||
Err(err) => return Continuation::Final(Err(err.into())),
|
||||
};
|
||||
Continuation::Continue(BindRequestParser(InBindResourceEnd(resource)))
|
||||
let ResolveResult::Bound(Namespace(ns)) = namespace else {
|
||||
return Err(ffail!("No namespace provided"));
|
||||
};
|
||||
if ns != XMLNS.as_bytes() {
|
||||
return Err(ffail!("Incorrect namespace"));
|
||||
}
|
||||
InBindResourceEnd(resource) => {
|
||||
let Event::End(bytes) = event else {
|
||||
return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}")));
|
||||
};
|
||||
Continuation::Continue(BindRequestParser(InBind(Some(resource))))
|
||||
loop {
|
||||
let (namespace, event) = yield;
|
||||
match event {
|
||||
Event::Start(bytes) if bytes.name().0 == b"resource" => {
|
||||
let (namespace, event) = yield;
|
||||
if let Event::Text(text) = event {
|
||||
resource = Some(text.as_bytes().into());
|
||||
}
|
||||
let (namespace, event) = yield;
|
||||
if let Event::End(_) = event {
|
||||
} else {
|
||||
return Err(ffail!("Unexpected XML event: {event:?}"));
|
||||
}
|
||||
}
|
||||
Event::End(bytes_) => {
|
||||
break;
|
||||
}
|
||||
_ => return Err(ffail!("Unexpected XML event: {event:?}")),
|
||||
}
|
||||
}
|
||||
let Some(resource) = resource else {
|
||||
return Err(ffail!("No resource was provided"));
|
||||
};
|
||||
let resource = match std::str::from_utf8(resource.as_bytes()) {
|
||||
Ok(e) => e.to_string(),
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
Ok(BindRequest(Resource(resource.into())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue