diff --git a/Cargo.toml b/Cargo.toml index b5d8eeea..c6cd33b7 100644 --- a/Cargo.toml +++ b/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 = "*" diff --git a/src/client/auth.rs b/src/client/auth.rs index 05006fdd..ef828b37 100644 --- a/src/client/auth.rs +++ b/src/client/auth.rs @@ -106,8 +106,7 @@ impl Future for ClientAuth { 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 Future for ClientAuth { 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()) diff --git a/src/component/auth.rs b/src/component/auth.rs index 773e453d..729fd3c1 100644 --- a/src/component/auth.rs +++ b/src/component/auth.rs @@ -71,8 +71,7 @@ impl Future for ComponentAuth { 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)) diff --git a/src/stream_start.rs b/src/stream_start.rs index 1d1813a3..5dda29ae 100644 --- a/src/stream_start.rs +++ b/src/stream_start.rs @@ -94,8 +94,7 @@ impl Future for StreamStart { 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 { diff --git a/src/xmpp_codec.rs b/src/xmpp_codec.rs index bb725835..5e340a9f 100644 --- a/src/xmpp_codec.rs +++ b/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(text: &str, writer: &mut W) -> Result<(), std::fmt::Error> { - write!(writer, "{}", text) -} - -// TODO: escape everything? -pub fn write_element(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 { + 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::*;