xmpp-rs/minidom/src/parser.rs
Emmanuel Gil Peyrot 714d850e69 Remove the -rs suffix of jid, minidom and xmpp
We know those are Rust libraries, no need to add it to the path.  This
synchronises their directory with the crate name, hopefully reducing
confusion.
2020-06-22 02:17:32 +02:00

184 lines
5.7 KiB
Rust

// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//! Provides a `Parser` type, which takes bytes and returns Elements. It also keeps a hold of
//! ascendant elements to be able to handle namespaces properly.
use crate::element::Element;
use crate::error::{Error, ParserError, Result};
use bytes::BytesMut;
use quick_xml::Reader as EventReader;
use std::cell::RefCell;
use std::str;
/// Parser
#[derive(Debug)]
pub struct Parser {
buffer: RefCell<BytesMut>,
state: ParserState,
}
/// Describes the state of the parser.
///
/// This parser will only accept one-level documents. The root element is kept for convenience, to
/// be able to pass namespaces down to children who are themselves children.
#[derive(Debug)]
pub enum ParserState {
/// Not enough data has been processed to find the first element.
Empty,
/// The normal state. the root element has been identified and children are processed.
Root {
/// Root element. Kept for future reference
root: Element,
/// Child element
child: Option<Element>,
/// XXX: Weird flag to say if we've already sent what we could send or if there's more to
/// send. This Variant needs to be changed.
sent: bool,
},
/// Something was passed in the buffer that made the parser get into an error state.
Error,
/// The root element has been closed. No feed-ing can happen past this point.
Closed,
}
/// Result of polling the parser
#[derive(Debug)]
pub enum ParserResult {
/// Buffer is not empty but needs more data
Partial,
/// An Element has been generated from the buffer.
Single(Element),
}
/*
/// Split <stream:stream> and parse it.
fn split_stream_stream_stream_features(string: String) -> (Element, Element) {
let mut stuff = string.splitn(2, '>');
let stream_opening_str = stuff.next().unwrap().to_string() + "/>";
let rest = stuff.next().unwrap().to_string();
let stream_opening: Element = stream_opening_str.parse().unwrap();
let rest: Element = rest.parse().unwrap();
println!("opening: {}", String::from(&stream_opening));
println!("features: {}", String::from(&rest));
(stream_opening, rest)
}
*/
fn maybe_split_prolog(string: &str) -> &str {
if string.starts_with("<?xml") {
let mut stuff = string.splitn(2, '>');
stuff.next();
stuff.next().unwrap()
} else {
string
}
}
impl Parser {
/// Creates a new Parser
pub fn new() -> Parser {
Parser {
buffer: RefCell::new(BytesMut::new()),
state: ParserState::Empty,
}
}
/// Feed bytes to the parser.
pub fn feed(&mut self, bytes: BytesMut) -> Result<()> {
self.buffer.borrow_mut().unsplit(bytes);
let state = match self.state {
ParserState::Empty => {
// TODO: Try splitting xml prolog and stream header
let foo = self.buffer.borrow();
let header = maybe_split_prolog(str::from_utf8(foo.as_ref())?);
println!("FOO: header: {:?}", header);
let mut reader = EventReader::from_str(header);
let root = Element::from_reader(&mut reader);
match root {
Ok(root) => {
println!("FOO: elem: {:?}", root);
ParserState::Root {
root,
child: None,
sent: false,
}
}
Err(e) => {
println!("FOO: err: {:?}", e);
ParserState::Empty
}
}
}
ParserState::Closed => return Err(Error::ParserError(ParserError::Closed)),
_ => ParserState::Empty,
};
self.state = state;
Ok(())
}
/// Returns Elements to the application.
pub fn poll(&mut self) -> Result<Option<ParserResult>> {
match &self.state {
ParserState::Empty if self.buffer.borrow().len() != 0 => {
Ok(Some(ParserResult::Partial))
}
ParserState::Empty | ParserState::Closed | ParserState::Error => Ok(None),
ParserState::Root {
root, child: None, ..
} => Ok(Some(ParserResult::Single(root.clone()))),
ParserState::Root {
child: Some(child), ..
} => Ok(Some(ParserResult::Single(child.clone()))),
}
}
/// Resets the parser
pub fn reset(&mut self) {
*self = Parser::new();
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::{BufMut, BytesMut};
#[test]
fn test_prolog() {
let mut parser = Parser::new();
let mut buf = BytesMut::new();
buf.put(&b"<?xml version='1.0'?>"[..]);
buf.put(&b"<stream:stream xmlns='jabber:client' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='foo.bar'>"[..]);
match parser.feed(buf) {
Ok(_) => (),
_ => panic!(),
}
let elem = Element::builder("stream:stream", "http://etherx.jabber.org/streams")
.prefix_ns(None, "jabber:client")
.attr("xml:lang", "en")
.attr("version", "1.0")
.attr("to", "foo.bar")
.build();
println!("BAR: elem: {:?}", elem);
match parser.poll() {
Ok(Some(ParserResult::Single(e))) => assert_eq!(e, elem),
_ => panic!(),
}
}
}