diff options
author | cel 🌸 <cel@blos.sm> | 2023-10-20 04:51:56 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-10-20 04:51:56 +0100 |
commit | ba94ee66fafbabd63d6d1ed5edf435d4c46c6796 (patch) | |
tree | fe1bebc35914941b5c4fbd6f0286f4c9f8916154 /src/stanza/mod.rs | |
parent | 2536fa4937f0283b4187142cc6cede8e1dbfafa8 (diff) | |
download | luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.tar.gz luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.tar.bz2 luz-ba94ee66fafbabd63d6d1ed5edf435d4c46c6796.zip |
WIP: refactor to parse incoming stream as state machine
Diffstat (limited to 'src/stanza/mod.rs')
-rw-r--r-- | src/stanza/mod.rs | 656 |
1 files changed, 5 insertions, 651 deletions
diff --git a/src/stanza/mod.rs b/src/stanza/mod.rs index 13fc31e..c5a6da3 100644 --- a/src/stanza/mod.rs +++ b/src/stanza/mod.rs @@ -1,657 +1,11 @@ -// use quick_xml::events::BytesDecl; - pub mod bind; pub mod iq; +pub mod message; +pub mod presence; pub mod sasl; +pub mod starttls; pub mod stream; -use std::collections::BTreeMap; -use std::str; - -// const DECLARATION: BytesDecl<'_> = BytesDecl::new("1.0", None, None); -use async_recursion::async_recursion; -use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; -use quick_xml::name::PrefixDeclaration; -use quick_xml::{Reader, Writer}; -use tokio::io::{AsyncBufRead, AsyncWrite}; - -use crate::{JabberError, Result}; - -#[derive(Clone, Debug)] -/// represents an xml element as a tree of nodes -pub struct Element { - /// element prefix - /// e.g. `foo` in `<foo:bar />`. - prefix: Option<String>, - /// element name - /// e.g. `bar` in `<foo:bar />`. - localname: String, - /// qualifying namespace - /// an element must be qualified by a namespace - /// e.g. for `<stream:features>` in - /// ``` - /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> - /// <stream:features> - /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> - /// <compression xmlns='http://jabber.org/features/compress'> - /// <method>zlib</method> - /// <method>lzw</method> - /// </compression> - /// </stream:features> - /// </stream:stream> - /// ``` - /// would be `"http://etherx.jabber.org/streams"` but for - /// ``` - /// <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> - /// <features> - /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> - /// <compression xmlns='http://jabber.org/features/compress'> - /// <method>zlib</method> - /// <method>lzw</method> - /// </compression> - /// </features> - /// </stream:stream> - /// ``` - /// would be `"jabber:client"` - namespace: String, - /// all namespaces applied to element - /// e.g. for `<bind>` in - /// ``` - /// <stream:features xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'> - /// <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> - /// <compression xmlns='http://jabber.org/features/compress'> - /// <method>zlib</method> - /// <method>lzw</method> - /// </compression> - /// </stream:features> - /// ``` - /// would be `[(None, "urn:ietf:params:xml:ns:xmpp-bind")]` despite - /// `(Some("stream"), "http://etherx.jabber.org/streams")` also being available - // TODO: maybe not even needed, as can calculate when writing which namespaces need to be declared - // but then can't have unused namespace on element, confusing. - namespace_declarations: Box<BTreeMap<Option<String>, String>>, - /// element attributes - attributes: Box<BTreeMap<String, String>>, - // children elements namespaces contain their parents' namespaces - children: Box<Vec<Node>>, -} - -#[derive(Clone, Debug)] -pub enum Node { - Element(Element), - Text(String), - Unknown, -} - -impl From<Element> for Node { - fn from(element: Element) -> Self { - Self::Element(element) - } -} - -impl<S: ToString> From<S> for Node { - fn from(text: S) -> Self { - Self::Text(text.to_string()) - } -} - -impl<'s> From<&Node> for Vec<Event<'s>> { - fn from(node: &Node) -> Self { - match node { - Node::Element(e) => e.into(), - Node::Text(t) => vec![Event::Text(BytesText::new(t))], - Unknown => vec![], - } - } -} - -impl Element { - /// returns the fully qualified name - /// e.g. `foo:bar` in - /// `<foo:bar>`. - pub fn name(&self) -> &str { - if let Some(prefix) = self.prefix { - format!("{}:{}", prefix, self.localname).as_str() - } else { - &self.localname - } - } - - /// returns the localname. - /// e.g. `bar` in `<foo:bar>` - pub fn localname(&self) -> &str { - &self.localname - } - - /// returns the prefix. - /// e.g. `foo` in `<foo:bar>`. returns None if there is - /// no prefix. - pub fn prefix(&self) -> Option<&str> { - self.prefix - } - - /// returns the namespace which applies to the current element, e.g. for - /// `<element xmlns='foo' xmlns:bar='bar'>` - /// it will be `foo` but for - /// `<bar:element xmlns='foo' xmlns:bar='bar'>` - /// it will be `bar`. - pub fn namespace(&self) -> &str { - &self.namespace - } -} - -impl<'s> From<&Element> for Vec<Event<'s>> { - fn from(element: &Element) -> Self { - let name = element.name(); - - let event = BytesStart::new(name); - - // namespace declarations - let namespace_declarations = element.namespace_declarations.iter().map(|declaration| { - let (prefix, namespace) = declaration; - match prefix { - Some(prefix) => return (format!("xmlns:{}", prefix).as_str(), *namespace), - None => return ("xmlns", *namespace), - } - }); - let event = event.with_attributes(namespace_declarations); - - // attributes - let event = event.with_attributes(element.attributes.into_iter()); - - match element.children.is_empty() { - true => return vec![Event::Empty(event)], - false => { - return { - let start: Vec<Event<'s>> = vec![Event::Start(event)]; - let start_and_content: Vec<Event<'s>> = start - .into_iter() - .chain({ - let u = element.children.iter().fold( - Vec::new(), - |acc: Vec<Event<'s>>, child: &Node<'s>| { - acc.into_iter() - .chain(Into::<Vec<Event<'s>>>::into(child).into_iter()) - .collect() - }, - ); - u - }) - .collect(); - let full: Vec<Event<'s>> = start_and_content - .into_iter() - .chain(vec![Event::End(BytesEnd::new(name))]) - .collect(); - full - } - } - } - } -} - -impl Element { - /// if there is only one child in the vec of children, will return that element - pub fn child(&self) -> Result<&Node> { - if self.children.len() == 1 { - Ok(&self.children[0]) - } else if self.children.len() > 1 { - Err(ElementError::MultipleChildren.into()) - } else { - Err(ElementError::NoChildren.into()) - } - } - - /// returns reference to children - pub fn children(&self) -> Result<&Vec<Node>> { - if !self.children.is_empty() { - Ok(&self.children) - } else { - Err(ElementError::NoChildren.into()) - } - } - - /// returns text content, error if there is none - pub fn text_content(&self) -> Result<Vec<&str>> { - let mut text = Vec::new(); - for node in *self.children { - match node { - Node::Text(t) => text.push(t), - _ => {} - } - } - if text.is_empty() { - return Err(ElementError::NotText.into()); - } - Ok(text) - } - - /// returns whether or not the element is qualified by a namespace, either declared - /// by a parent, or itself. - fn namespace_qualified<S: AsRef<str>>( - &self, - namespace_context: &BTreeMap<Option<S>, S>, - ) -> bool { - // create a new local_namespaces combining that in the context and those declared within the element - let mut local_namespaces = *namespace_context.clone(); - self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration)); - - if let Some(namespace) = local_namespaces.get(self.prefix) { - if namespace != self.namespace { - return false; - } - } else { - return false; - }; - - for child in *self.children { - if child.namespace_qualified(&local_namespaces) == false { - return false; - } - } - - true - } - - - /// writes an element to a writer. the element's namespace must be qualified by the - /// context given in `local_namespaces` or the element's internal namespace declarations - pub async fn write<S: AsRef<str>, W: AsyncWrite + Unpin + Send>( - &self, - writer: &mut Writer<W>, - local_namespaces: &BTreeMap<Option<S>, S>, - ) -> Result<()> { - // TODO: instead of having a check if namespace qualified function, have the namespace declarations be added if needed given the context when converting from `Element` to `Event`s - if self.namespace_qualified(local_namespaces) { - let events: Vec<Event> = self.into(); - for event in events { - writer.write_event_async(event).await? - } - Ok(()) - } else { - Err(ElementError::NamespaceNotQualified.into()) - } - } - - pub async fn write_start<S: AsRef<str>, W: AsyncWrite + Unpin + Send>( - &self, - writer: &mut Writer<W>, - local_namespaces: &BTreeMap<Option<S>, S>, - ) -> Result<()> { - if self.namespace_qualified(local_namespaces) { - let mut event = BytesStart::new(self.name()); - - // namespace declarations - self.namespace_declarations.iter().for_each(|declaration| { - let (prefix, namespace) = declaration; - match prefix { - Some(prefix) => { - event.push_attribute((format!("xmlns:{}", prefix).as_str(), *namespace)) - } - None => event.push_attribute(("xmlns", *namespace)), - } - }); - - // attributes - let event = - event.with_attributes(self.attributes.iter().map(|(attr, value)| (*attr, *value))); - - writer.write_event_async(Event::Start(event)).await?; - - Ok(()) - } else { - Err(ElementError::NamespaceNotQualified.into()) - } - } - - pub async fn write_end<W: AsyncWrite + Unpin + Send>( - &self, - writer: &mut Writer<W>, - ) -> Result<()> { - let event = BytesEnd::new(self.name()); - writer.write_event_async(Event::End(event)).await?; - Ok(()) - } - - #[async_recursion] - pub async fn read<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( - reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<S>, S>, - ) -> Result<Self> { - let node = Node::read_recursive(reader, local_namespaces) - .await? - .ok_or(JabberError::UnexpectedEnd)?; - match node { - Node::Element(e) => Ok(e), - Node::Text(_) => Err(JabberError::UnexpectedText), - Node::Unknown => Err(JabberError::UnexpectedElement), - } - } - - pub async fn read_start<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( - reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<S>, S>, - ) -> Result<Element> { - let buf = Vec::new(); - let event = reader.read_event_into_async(&mut buf).await?; - match event { - Event::Start(e) => { - let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); - let converted_prefix; - if let Some(raw_prefix) = prefix { - converted_prefix = Some(str::from_utf8(raw_prefix)?) - } - let prefix = converted_prefix; - - let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - - let mut local_namespaces = local_namespaces.clone(); - let mut namespace_declarations = BTreeMap::new(); - let attributes = BTreeMap::new(); - - for attribute in e.attributes() { - let attribute = attribute?; - if let Some(prefix_declaration) = attribute.key.as_namespace_binding() { - match prefix_declaration { - PrefixDeclaration::Default => { - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(None, value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(None, value); - } - PrefixDeclaration::Named(prefix) => { - let key = str::from_utf8(prefix)?; - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(Some(key), value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(Some(key), value); - } - } - } else { - if let Some(_) = attributes.insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - } - } - - let namespace = *local_namespaces - .get(&prefix) - .ok_or(ElementParseError::NoNamespace)?; - - let mut children = Vec::new(); - - Ok(Self { - prefix, - localname, - namespace, - namespace_declarations: Box::new(namespace_declarations), - attributes: Box::new(attributes), - children: Box::new(children), - }) - } - e => Err(ElementError::NotAStart(e).into()), - } - } -} - -impl Node { - #[async_recursion] - async fn read_recursive<S: AsRef<str>, R: AsyncBufRead + Unpin + Send>( - reader: &mut Reader<R>, - local_namespaces: &BTreeMap<Option<S>, S>, - ) -> Result<Option<Node>> { - let mut buf = Vec::new(); - let event = reader.read_event_into_async(&mut buf).await?; - match event { - Event::Empty(e) => { - let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); - let converted_prefix; - if let Some(raw_prefix) = prefix { - converted_prefix = Some(str::from_utf8(raw_prefix)?) - } - let prefix = converted_prefix; - - let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - - let mut local_namespaces = local_namespaces.clone(); - let mut namespace_declarations = BTreeMap::new(); - let attributes = BTreeMap::new(); - - for attribute in e.attributes() { - let attribute = attribute?; - if let Some(prefix_declaration) = attribute.key.as_namespace_binding() { - match prefix_declaration { - PrefixDeclaration::Default => { - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(None, value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(None, value); - } - PrefixDeclaration::Named(prefix) => { - let key = str::from_utf8(prefix)?; - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(Some(key), value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(Some(key), value); - } - } - } else { - if let Some(_) = attributes.insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - } - } - - let namespace = *local_namespaces - .get(&prefix) - .ok_or(ElementParseError::NoNamespace)?; - - let mut children = Vec::new(); - - Ok(Some(Self::Element(Element { - prefix, - localname, - namespace, - namespace_declarations: Box::new(namespace_declarations), - attributes: Box::new(attributes), - children: Box::new(children), - }))) - } - Event::Start(e) => { - let prefix = e.name().prefix().map(|prefix| prefix.into_inner()); - let converted_prefix; - if let Some(raw_prefix) = prefix { - converted_prefix = Some(str::from_utf8(raw_prefix)?) - } - let prefix = converted_prefix; - - let localname = str::from_utf8(e.local_name().into_inner())?.to_owned(); - - let mut local_namespaces = local_namespaces.clone(); - let mut namespace_declarations = BTreeMap::new(); - let attributes = BTreeMap::new(); - - for attribute in e.attributes() { - let attribute = attribute?; - if let Some(prefix_declaration) = attribute.key.as_namespace_binding() { - match prefix_declaration { - PrefixDeclaration::Default => { - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(None, value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(None, value); - } - PrefixDeclaration::Named(prefix) => { - let key = str::from_utf8(prefix)?; - let value = str::from_utf8(attribute.value.as_ref())?; - if let Some(_) = namespace_declarations.insert(Some(key), value) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - local_namespaces.insert(Some(key), value); - } - } - } else { - if let Some(_) = attributes.insert( - str::from_utf8(attribute.key.into_inner())?, - str::from_utf8(attribute.value.as_ref())?, - ) { - return Err(ElementParseError::DuplicateAttribute.into()); - }; - } - } - - let namespace = *local_namespaces - .get(&prefix) - .ok_or(ElementParseError::NoNamespace)?; - - let mut children = Vec::new(); - while let Some(child_node) = Node::read_recursive(reader, &local_namespaces).await? - { - children.push(child_node) - } - - let mut children = Vec::new(); - - Ok(Some(Self::Element(Element { - prefix, - localname, - namespace, - namespace_declarations: Box::new(namespace_declarations), - attributes: Box::new(attributes), - children: Box::new(children), - }))) - } - Event::End(_) => Ok(None), - Event::Text(e) => Ok(Some(Self::Text(e.unescape()?.as_ref().to_string()))), - e => Ok(Some(Self::Unknown)), - } - } - - fn namespace_qualified<S: AsRef<str>>( - &self, - namespace_context: &BTreeMap<Option<S>, S>, - ) -> bool { - match self { - Self::Element(e) => e.namespace_qualified(namespace_context), - _ => true, - } - } -} - -pub enum NodeBuilder { - Text(String), - Element(ElementBuilder), -} - -pub struct ElementBuilder { - localname: String, - prefix: Option<String>, - namespace: String, - namespace_declarations: BTreeMap<Option<String>, String>, - attributes: BTreeMap<String, String>, - children: Vec<NodeBuilder>, -} - -impl ElementBuilder { - pub fn new<S: ToString>(localname: S, prefix: Option<S>, namespace: S) -> Self { - Self { - prefix, - localname, - namespace, - namespace_declarations: Box::new(BTreeMap::new()), - attributes: Box::new(BTreeMap::new()), - children: Box::new(Vec::new()), - } - } - - pub fn push_namespace_declaration<S: ToString>( - &mut self, - (prefix, namespace): (Option<S>, S), - ) -> Option<S> { - self.namespace_declarations.insert(prefix, namespace) - } - - pub fn push_attribute<S: ToString>(&mut self, (key, value): (S, S)) -> Option<S> { - self.attributes.insert(key, value) - } - - pub fn push_child(&mut self, child: Node) { - self.children.push(child) - } - - /// checks if there is a namespace conflict within the element being built - pub fn namespace_conflict<S: AsRef<str>>( - &self - ) -> bool { - self.namespace_conflict_recursive(&BTreeMap::new()) - } - - fn namespace_conflict_recursive<S: AsRef<str>>( - &self, - parent_namespaces: &BTreeMap<Option<S>, S>, - ) -> bool { - // create a new local_namespaces combining that in the context and those declared within the element - let mut local_namespaces = *parent_namespaces.clone(); - self.namespace_declarations.iter().for_each(|prefix, declaration| local_namespaces.insert(prefix, declaration)); - - if let Some(namespace) = local_namespaces.get(self.prefix) { - if namespace != self.namespace { - return false; - } - } else { - return false; - }; - - for child in *self.children { - if child.namespace_conflict(&local_namespaces) == false { - return false; - } - } - - true - } - - // check for possible conflicts in namespace - pub fn build(self) -> Result<Element> { - for child in self.children { - match child { - Node::Element(e) => { - if !e.namespace_conflict() - } - } - } - Element { - prefix: self.prefix, - localname: self.localname, - namespace: self.namespace, - namespace_declarations: self.namespace_declarations, - attributes: self.attributes, - children: self.children, - } - } -} - -#[derive(Debug)] -pub enum ElementError<'e> { - NotAStart(Event<'e>), - NotText, - NoChildren, - NamespaceNotQualified, - MultipleChildren, -} +use quick_xml::events::{BytesDecl, Event}; -#[derive(Debug)] -pub enum ElementParseError { - DuplicateAttribute, - NoNamespace, -} +pub static DECLARATION: Event = Event::Decl(BytesDecl::new("1.0", None, None)); |