forked from lavina/lavina
xmpp: rewrite bind request parser as a coroutine (#12)
Reviewed-on: lavina/lavina#12
This commit is contained in:
parent
444b608e96
commit
1b3551f108
|
@ -78,89 +78,56 @@ impl Jid {
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct BindRequest(pub Resource);
|
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 {
|
impl FromXmlTag for BindRequest {
|
||||||
const NS: &'static str = XMLNS;
|
const NS: &'static str = XMLNS;
|
||||||
const NAME: &'static str = "bind";
|
const NAME: &'static str = "bind";
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromXml for BindRequest {
|
impl FromXml for BindRequest {
|
||||||
type P = BindRequestParser;
|
type P = impl Parser<Output = Result<Self>>;
|
||||||
|
|
||||||
fn parse() -> Self::P {
|
fn parse() -> Self::P {
|
||||||
BindRequestParser(BindRequestParserInner::Initial)
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||||
}
|
let mut resource: Option<Str> = None;
|
||||||
}
|
let Event::Start(bytes) = event else {
|
||||||
|
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||||
// TODO rewrite as a generator
|
};
|
||||||
impl Parser for BindRequestParser {
|
if bytes.name().0 != BindRequest::NAME.as_bytes() {
|
||||||
type Output = Result<BindRequest>;
|
return Err(anyhow!("Unexpected XML tag: {:?}", bytes.name()));
|
||||||
|
|
||||||
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(anyhow!("Unexpected XML event: {event:?}")));
|
|
||||||
};
|
|
||||||
if bytes.name().0 != BindRequest::NAME.as_bytes() {
|
|
||||||
return Continuation::Final(Err(anyhow!(
|
|
||||||
"Unexpected XML tag: {:?}",
|
|
||||||
bytes.name()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
let ResolveResult::Bound(Namespace(ns)) = namespace else {
|
|
||||||
return Continuation::Final(Err(anyhow!("No namespace provided")));
|
|
||||||
};
|
|
||||||
if ns != XMLNS.as_bytes() {
|
|
||||||
return Continuation::Final(Err(anyhow!("Incorrect namespace")));
|
|
||||||
}
|
|
||||||
Continuation::Continue(BindRequestParser(InBind(None)))
|
|
||||||
}
|
}
|
||||||
InBind(resource) => match event {
|
let ResolveResult::Bound(Namespace(ns)) = namespace else {
|
||||||
Event::Start(bytes) => {
|
return Err(anyhow!("No namespace provided"));
|
||||||
Continuation::Continue(BindRequestParser(InBindResourceInitial))
|
};
|
||||||
}
|
if ns != XMLNS.as_bytes() {
|
||||||
Event::End(bytes) => {
|
return Err(anyhow!("Incorrect namespace"));
|
||||||
let Some(resource) = resource else {
|
}
|
||||||
return Continuation::Final(Err(anyhow!("No resource was provided")));
|
loop {
|
||||||
|
let (namespace, event) = yield;
|
||||||
|
match event {
|
||||||
|
Event::Start(bytes) if bytes.name().0 == b"resource" => {
|
||||||
|
let (namespace, event) = yield;
|
||||||
|
let Event::Text(text) = event else {
|
||||||
|
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||||
};
|
};
|
||||||
Continuation::Final(Ok(BindRequest(Resource(resource.into()))))
|
resource = Some(std::str::from_utf8(&*text)?.into());
|
||||||
|
let (namespace, event) = yield;
|
||||||
|
let Event::End(bytes) = event else {
|
||||||
|
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||||
|
};
|
||||||
|
if bytes.name().0 != b"resource" {
|
||||||
|
return Err(anyhow!("Unexpected XML tag: {:?}", bytes.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::End(bytes) if bytes.name().0 == BindRequest::NAME.as_bytes() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||||
}
|
}
|
||||||
_ => Continuation::Final(Err(anyhow!("Unexpected XML event: {event:?}"))),
|
|
||||||
},
|
|
||||||
InBindResourceInitial => {
|
|
||||||
let Event::Text(text) = event else {
|
|
||||||
return Continuation::Final(Err(anyhow!("Unexpected XML event: {event:?}")));
|
|
||||||
};
|
|
||||||
let resource = match std::str::from_utf8(&*text) {
|
|
||||||
Ok(e) => e.to_string(),
|
|
||||||
Err(err) => return Continuation::Final(Err(err.into())),
|
|
||||||
};
|
|
||||||
Continuation::Continue(BindRequestParser(InBindResourceEnd(resource)))
|
|
||||||
}
|
|
||||||
InBindResourceEnd(resource) => {
|
|
||||||
let Event::End(bytes) = event else {
|
|
||||||
return Continuation::Final(Err(anyhow!("Unexpected XML event: {event:?}")));
|
|
||||||
};
|
|
||||||
Continuation::Continue(BindRequestParser(InBind(Some(resource))))
|
|
||||||
}
|
}
|
||||||
|
let Some(resource) = resource else {
|
||||||
|
return Err(anyhow!("No resource was provided"));
|
||||||
|
};
|
||||||
|
Ok(BindRequest(Resource(resource)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue