migrate to minidom 0.6.0

Astro created

Change summary

Cargo.toml            |  2 
src/client/auth.rs    |  9 ++----
src/component/auth.rs |  3 -
src/stream_start.rs   |  3 -
src/xmpp_codec.rs     | 67 ++++++++++++++++++--------------------------
5 files changed, 34 insertions(+), 50 deletions(-)

Detailed changes

Cargo.toml 🔗

@@ -10,7 +10,7 @@ tokio-io = "*"
 bytes = "0.4.4"
 xml5ever = "*"
 tendril = "*"
-minidom = "0.4.4"
+minidom = "0.6.0"
 native-tls = "*"
 tokio-tls = "*"
 sasl = "*"

src/client/auth.rs 🔗

@@ -106,8 +106,7 @@ impl<S: AsyncRead + AsyncWrite> Future for ClientAuth<S> {
             ClientAuthState::WaitRecv(mut stream) =>
                 match stream.poll() {
                     Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
-                        if stanza.name() == "challenge"
-                        && stanza.ns() == Some(NS_XMPP_SASL) =>
+                        if stanza.is("challenge", NS_XMPP_SASL) =>
                     {
                         let content = try!(
                             stanza.text()
@@ -119,16 +118,14 @@ impl<S: AsyncRead + AsyncWrite> Future for ClientAuth<S> {
                         self.poll()
                     },
                     Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
-                        if stanza.name() == "success"
-                        && stanza.ns() == Some(NS_XMPP_SASL) =>
+                        if stanza.is("success", NS_XMPP_SASL) =>
                     {
                         let start = stream.restart();
                         self.state = ClientAuthState::Start(start);
                         self.poll()
                     },
                     Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
-                        if stanza.name() == "failure"
-                        && stanza.ns() == Some(NS_XMPP_SASL) =>
+                        if stanza.is("failure", NS_XMPP_SASL) =>
                     {
                         let e = stanza.children().next()
                             .map(|child| child.name())

src/component/auth.rs 🔗

@@ -71,8 +71,7 @@ impl<S: AsyncRead + AsyncWrite> Future for ComponentAuth<S> {
             ComponentAuthState::WaitRecv(mut stream) =>
                 match stream.poll() {
                     Ok(Async::Ready(Some(Packet::Stanza(ref stanza))))
-                        if stanza.name() == "handshake"
-                        && stanza.ns() == Some(NS_JABBER_COMPONENT_ACCEPT) =>
+                        if stanza.is("handshake", NS_JABBER_COMPONENT_ACCEPT) =>
                     {
                         self.state = ComponentAuthState::Invalid;
                         Ok(Async::Ready(stream))

src/stream_start.rs 🔗

@@ -94,8 +94,7 @@ impl<S: AsyncRead + AsyncWrite> Future for StreamStart<S> {
             StreamStartState::RecvFeatures(mut stream, stream_ns) =>
                 match stream.poll() {
                     Ok(Async::Ready(Some(Packet::Stanza(stanza)))) =>
-                        if stanza.name() == "features"
-                        && stanza.ns() == Some(NS_XMPP_STREAM) {
+                        if stanza.is("features", NS_XMPP_STREAM) {
                             let stream = XMPPStream::new(self.jid.clone(), stream, self.ns.clone(), stanza);
                             (StreamStartState::Invalid, Ok(Async::Ready(stream)))
                         } else {

src/xmpp_codec.rs 🔗

@@ -9,7 +9,7 @@ use std::io::{Error, ErrorKind};
 use std::collections::HashMap;
 use std::collections::vec_deque::VecDeque;
 use tokio_io::codec::{Encoder, Decoder};
-use minidom::{Element, Node};
+use minidom::Element;
 use xml5ever::tokenizer::{XmlTokenizer, TokenSink, Token, Tag, TagKind};
 use xml5ever::interface::Attribute;
 use bytes::{BytesMut, BufMut};
@@ -278,8 +278,7 @@ impl Encoder for XMPPCodec {
                     .map_err(|e| Error::new(ErrorKind::InvalidInput, e))
             },
             Packet::Stanza(stanza) => {
-                let root_ns = self.ns.as_ref().map(|s| s.as_ref());
-                write_element(&stanza, dst, root_ns)
+                stanza.write_to_inner(&mut WriteBytes::new(dst))
                     .and_then(|_| {
                         println!(">> {:?}", dst);
                         Ok(())
@@ -301,42 +300,7 @@ impl Encoder for XMPPCodec {
 }
 
 pub fn write_text<W: Write>(text: &str, writer: &mut W) -> Result<(), std::fmt::Error> {
-    write!(writer, "{}", text)
-}
-
-// TODO: escape everything?
-pub fn write_element<W: Write>(el: &Element, writer: &mut W, parent_ns: Option<&str>) -> Result<(), std::fmt::Error> {
-    write!(writer, "<")?;
-    write!(writer, "{}", el.name())?;
-
-    if let Some(ns) = el.ns() {
-        if parent_ns.map(|s| s.as_ref()) != el.ns() {
-            write!(writer, " xmlns=\"{}\"", ns)?;
-        }
-    }
-
-    for (key, value) in el.attrs() {
-        write!(writer, " {}=\"{}\"", key, value)?;
-    }
-
-    if ! el.nodes().any(|_| true) {
-        write!(writer, " />")?;
-        return Ok(())
-    }
-
-    write!(writer, ">")?;
-
-    for node in el.nodes() {
-        match *node {
-            Node::Element(ref child) =>
-                write_element(child, writer, el.ns())?,
-            Node::Text(ref text) =>
-                write_text(text, writer)?,
-        }
-    }
-
-    write!(writer, "</{}>", el.name())?;
-    Ok(())
+    write!(writer, "{}", escape(text))
 }
 
 /// Copied from `RustyXML` for now
@@ -356,6 +320,31 @@ pub fn escape(input: &str) -> String {
     result
 }
 
+/// BytesMut impl only std::fmt::Write but not std::io::Write. The
+/// latter trait is required for minidom's
+/// `Element::write_to_inner()`.
+struct WriteBytes<'a> {
+    dst: &'a mut BytesMut,
+}
+
+impl<'a> WriteBytes<'a> {
+    fn new(dst: &'a mut BytesMut) -> Self {
+        WriteBytes { dst }
+    }
+}
+
+impl<'a> std::io::Write for WriteBytes<'a> {
+    fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
+        self.dst.put_slice(buf);
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
+        Ok(())
+    }
+}
+
+
 #[cfg(test)]
 mod tests {
     use super::*;