parser.rs

  1// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
  2// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  3//
  4// This Source Code Form is subject to the terms of the Mozilla Public
  5// License, v. 2.0. If a copy of the MPL was not distributed with this
  6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7
  8//! Provides a `Parser` type, which takes bytes and returns Elements. It also keeps a hold of
  9//! ascendant elements to be able to handle namespaces properly.
 10
 11use crate::element::Element;
 12use crate::error::{Error, ParserError, Result};
 13
 14use bytes::BytesMut;
 15use quick_xml::Reader as EventReader;
 16use std::cell::RefCell;
 17use std::str;
 18
 19/// Parser
 20#[derive(Debug)]
 21pub struct Parser {
 22    buffer: RefCell<BytesMut>,
 23    state: ParserState,
 24}
 25
 26/// Describes the state of the parser.
 27///
 28/// This parser will only accept one-level documents. The root element is kept for convenience, to
 29/// be able to pass namespaces down to children who are themselves children.
 30#[derive(Debug)]
 31pub enum ParserState {
 32    /// Not enough data has been processed to find the first element.
 33    Empty,
 34
 35    /// The normal state. the root element has been identified and children are processed.
 36    Root {
 37        /// Root element. Kept for future reference
 38        root: Element,
 39
 40        /// Child element
 41        child: Option<Element>,
 42
 43        /// XXX: Weird flag to say if we've already sent what we could send or if there's more to
 44        /// send. This Variant needs to be changed.
 45        sent: bool,
 46    },
 47
 48    /// Something was passed in the buffer that made the parser get into an error state.
 49    Error,
 50
 51    /// The root element has been closed. No feed-ing can happen past this point.
 52    Closed,
 53}
 54
 55/// Result of polling the parser
 56#[derive(Debug)]
 57pub enum ParserResult {
 58    /// Buffer is not empty but needs more data
 59    Partial,
 60
 61    /// An Element has been generated from the buffer.
 62    Single(Element),
 63}
 64
 65/*
 66/// Split <stream:stream> and parse it.
 67fn split_stream_stream_stream_features(string: String) -> (Element, Element) {
 68    let mut stuff = string.splitn(2, '>');
 69    let stream_opening_str = stuff.next().unwrap().to_string() + "/>";
 70    let rest = stuff.next().unwrap().to_string();
 71    let stream_opening: Element = stream_opening_str.parse().unwrap();
 72    let rest: Element = rest.parse().unwrap();
 73    println!("opening: {}", String::from(&stream_opening));
 74    println!("features: {}", String::from(&rest));
 75    (stream_opening, rest)
 76}
 77*/
 78
 79fn maybe_split_prolog(string: &str) -> &str {
 80    if string.starts_with("<?xml") {
 81        let mut stuff = string.splitn(2, '>');
 82        stuff.next();
 83        stuff.next().unwrap()
 84    } else {
 85        string
 86    }
 87}
 88
 89impl Parser {
 90    /// Creates a new Parser
 91    pub fn new() -> Parser {
 92        Parser {
 93            buffer: RefCell::new(BytesMut::new()),
 94            state: ParserState::Empty,
 95        }
 96    }
 97
 98    /// Feed bytes to the parser.
 99    pub fn feed(&mut self, bytes: BytesMut) -> Result<()> {
100        self.buffer.borrow_mut().unsplit(bytes);
101        let state = match self.state {
102            ParserState::Empty => {
103                // TODO: Try splitting xml prolog and stream header
104                let foo = self.buffer.borrow();
105                let header = maybe_split_prolog(str::from_utf8(foo.as_ref())?);
106                println!("FOO: header: {:?}", header);
107                let mut reader = EventReader::from_str(header);
108                let root = Element::from_reader(&mut reader);
109                match root {
110                    Ok(root) => {
111                        println!("FOO: elem: {:?}", root);
112                        ParserState::Root {
113                            root,
114                            child: None,
115                            sent: false,
116                        }
117                    }
118                    Err(e) => {
119                        println!("FOO: err: {:?}", e);
120                        ParserState::Empty
121                    }
122                }
123            }
124            ParserState::Closed => return Err(Error::ParserError(ParserError::Closed)),
125            _ => ParserState::Empty,
126        };
127
128        self.state = state;
129        Ok(())
130    }
131
132    /// Returns Elements to the application.
133    pub fn poll(&mut self) -> Result<Option<ParserResult>> {
134        match &self.state {
135            ParserState::Empty if self.buffer.borrow().len() != 0 => {
136                Ok(Some(ParserResult::Partial))
137            }
138            ParserState::Empty | ParserState::Closed | ParserState::Error => Ok(None),
139            ParserState::Root {
140                root, child: None, ..
141            } => Ok(Some(ParserResult::Single(root.clone()))),
142            ParserState::Root {
143                child: Some(child), ..
144            } => Ok(Some(ParserResult::Single(child.clone()))),
145        }
146    }
147
148    /// Resets the parser
149    pub fn reset(&mut self) {
150        *self = Parser::new();
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157    use bytes::{BufMut, BytesMut};
158
159    #[test]
160    fn test_prolog() {
161        let mut parser = Parser::new();
162        let mut buf = BytesMut::new();
163        buf.put(&b"<?xml version='1.0'?>"[..]);
164        buf.put(&b"<stream:stream xmlns='jabber:client' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='foo.bar'>"[..]);
165        match parser.feed(buf) {
166            Ok(_) => (),
167            _ => panic!(),
168        }
169
170        let elem = Element::builder("stream:stream", "http://etherx.jabber.org/streams")
171            .prefix_ns(None, "jabber:client")
172            .attr("xml:lang", "en")
173            .attr("version", "1.0")
174            .attr("to", "foo.bar")
175            .build();
176
177        println!("BAR: elem: {:?}", elem);
178
179        match parser.poll() {
180            Ok(Some(ParserResult::Single(e))) => assert_eq!(e, elem),
181            _ => panic!(),
182        }
183    }
184}