From 862edfde587132736e515d75d633fd53307c0e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Tue, 26 Dec 2017 20:54:56 +0000 Subject: [PATCH 01/15] Break the world --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04aa98f991dee71086269fe39d055903dde1cce3..b721ff666f0ce06d16f9f2310e10815a39629919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,12 @@ license = "LGPL-3.0+" gitlab = { repository = "lumi/xmpp-rs" } [dependencies] -xml-rs = "0.4.1" -xmpp-parsers = "0.7.0" +quick-xml = "0.10.0" +xmpp-parsers = "0.9.0" openssl = "0.9.12" base64 = "0.6.0" -minidom = "0.4.1" -jid = "0.2.1" +minidom = "0.7.0" +jid = { version = "0.4", features = ["minidom"] } sasl = "0.4.0" sha-1 = "0.4" chrono = "0.4.0" From 5508f5b38801bb72cf2e142ecbb25825e60686c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Tue, 26 Dec 2017 21:27:13 +0000 Subject: [PATCH 02/15] plugins/messaging: Receipt doesn't exist anymore --- src/plugins/messaging.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/messaging.rs b/src/plugins/messaging.rs index 9b0d1d439de6d63126babf8213fc44100e0205f8..8ac551734e296c61c393f4d95c67953a9b7170e7 100644 --- a/src/plugins/messaging.rs +++ b/src/plugins/messaging.rs @@ -9,7 +9,7 @@ use jid::Jid; use plugins::stanza::Message; use xmpp_parsers::message::{MessagePayload, MessageType}; use xmpp_parsers::chatstates::ChatState; -use xmpp_parsers::receipts::Receipt; +use xmpp_parsers::receipts::{Request, Received}; use xmpp_parsers::stanza_id::StanzaId; // TODO: use the id (maybe even stanza-id) to identify every message. @@ -98,11 +98,11 @@ impl MessagingPlugin { chat_state: chat_state, }), // XEP-0184 - MessagePayload::Receipt(Receipt::Request) => self.proxy.dispatch(ReceiptRequestEvent { + MessagePayload::ReceiptRequest(Request) => self.proxy.dispatch(ReceiptRequestEvent { from: from.clone(), }), // XEP-0184 - MessagePayload::Receipt(Receipt::Received(id)) => self.proxy.dispatch(ReceiptReceivedEvent { + MessagePayload::ReceiptReceived(Received {id}) => self.proxy.dispatch(ReceiptReceivedEvent { from: from.clone(), id: id.unwrap(), }), From 1a8ea2e38313e94fdfebe3b5a335669bdd8e1131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Tue, 26 Dec 2017 20:55:19 +0000 Subject: [PATCH 03/15] plugins/messaging: Body, Thread, Subject are now structs --- src/plugins/messaging.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/messaging.rs b/src/plugins/messaging.rs index 8ac551734e296c61c393f4d95c67953a9b7170e7..9da0d2a847acec88cb32d8908e3f131253bed452 100644 --- a/src/plugins/messaging.rs +++ b/src/plugins/messaging.rs @@ -7,7 +7,7 @@ use error::Error; use jid::Jid; use plugins::stanza::Message; -use xmpp_parsers::message::{MessagePayload, MessageType}; +use xmpp_parsers::message::{MessagePayload, MessageType, Body}; use xmpp_parsers::chatstates::ChatState; use xmpp_parsers::receipts::{Request, Received}; use xmpp_parsers::stanza_id::StanzaId; @@ -70,7 +70,7 @@ impl MessagingPlugin { id: Some(self.proxy.gen_id()), bodies: { let mut bodies = BTreeMap::new(); - bodies.insert(String::new(), String::from(body)); + bodies.insert(String::new(), Body(body.to_owned())); bodies }, subjects: BTreeMap::new(), @@ -118,9 +118,9 @@ impl MessagingPlugin { if message.bodies.contains_key("") { self.proxy.dispatch(MessageEvent { from: from, - body: message.bodies[""].clone(), - subject: if message.subjects.contains_key("") { Some(message.subjects[""].clone()) } else { None }, - thread: message.thread.clone(), + body: message.bodies[""].clone().0, + subject: if message.subjects.contains_key("") { Some(message.subjects[""].clone().0) } else { None }, + thread: match message.thread.clone() { Some(thread) => Some(thread.0), None => None }, }); } Propagation::Stop From 1a9a100bdc98c91d204775b8208aa7b7eed94555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Tue, 26 Dec 2017 21:10:24 +0000 Subject: [PATCH 04/15] plugins/ibb: IBB enum not available in the parser anymore --- src/plugins/ibb.rs | 155 +++++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 69 deletions(-) diff --git a/src/plugins/ibb.rs b/src/plugins/ibb.rs index a8738a278fe9e6e2d951ffa9d6ced9797a66fcec..428bdd37627e3a41b7d644e0a853f4ba216f0e49 100644 --- a/src/plugins/ibb.rs +++ b/src/plugins/ibb.rs @@ -10,7 +10,7 @@ use jid::Jid; use plugins::stanza::Iq; use plugins::disco::DiscoPlugin; use xmpp_parsers::iq::{IqType, IqSetPayload}; -use xmpp_parsers::ibb::{IBB, Stanza}; +use xmpp_parsers::ibb::{Open, Data, Close, Stanza}; use xmpp_parsers::stanza_error::{StanzaError, ErrorType, DefinedCondition}; use xmpp_parsers::ns; @@ -86,74 +86,79 @@ impl IbbPlugin { } } - fn handle_ibb(&self, from: Jid, ibb: IBB) -> Result<(), StanzaError> { + fn handle_ibb_open(&self, from: Jid, open: Open) -> Result<(), StanzaError> { let mut sessions = self.sessions.lock().unwrap(); - match ibb { - IBB::Open { block_size, sid, stanza } => { - match sessions.entry((from.clone(), sid.clone())) { - Entry::Vacant(_) => Ok(()), - Entry::Occupied(_) => Err(generate_error( - ErrorType::Cancel, - DefinedCondition::NotAcceptable, - "This session is already open." - )), - }?; - let session = Session { - stanza, - block_size, - cur_seq: 65535u16, - }; - sessions.insert((from, sid), session.clone()); - self.proxy.dispatch(IbbOpen { - session: session, - }); - }, - IBB::Data { seq, sid, data } => { - let entry = match sessions.entry((from, sid)) { - Entry::Occupied(entry) => Ok(entry), - Entry::Vacant(_) => Err(generate_error( - ErrorType::Cancel, - DefinedCondition::ItemNotFound, - "This session doesn’t exist." - )), - }?; - let mut session = entry.into_mut(); - if session.stanza != Stanza::Iq { - return Err(generate_error( - ErrorType::Cancel, - DefinedCondition::NotAcceptable, - "Wrong stanza type." - )) - } - let cur_seq = session.cur_seq.wrapping_add(1); - if seq != cur_seq { - return Err(generate_error( - ErrorType::Cancel, - DefinedCondition::NotAcceptable, - "Wrong seq number." - )) - } - session.cur_seq = cur_seq; - self.proxy.dispatch(IbbData { - session: session.clone(), - data, - }); - }, - IBB::Close { sid } => { - let entry = match sessions.entry((from, sid)) { - Entry::Occupied(entry) => Ok(entry), - Entry::Vacant(_) => Err(generate_error( - ErrorType::Cancel, - DefinedCondition::ItemNotFound, - "This session doesn’t exist." - )), - }?; - let session = entry.remove(); - self.proxy.dispatch(IbbClose { - session, - }); - }, + let Open { block_size, sid, stanza } = open; + match sessions.entry((from.clone(), sid.clone())) { + Entry::Vacant(_) => Ok(()), + Entry::Occupied(_) => Err(generate_error( + ErrorType::Cancel, + DefinedCondition::NotAcceptable, + "This session is already open." + )), + }?; + let session = Session { + stanza, + block_size, + cur_seq: 65535u16, + }; + sessions.insert((from, sid), session.clone()); + self.proxy.dispatch(IbbOpen { + session: session, + }); + Ok(()) + } + + fn handle_ibb_data(&self, from: Jid, data: Data) -> Result<(), StanzaError> { + let mut sessions = self.sessions.lock().unwrap(); + let Data { seq, sid, data } = data; + let entry = match sessions.entry((from, sid)) { + Entry::Occupied(entry) => Ok(entry), + Entry::Vacant(_) => Err(generate_error( + ErrorType::Cancel, + DefinedCondition::ItemNotFound, + "This session doesn’t exist." + )), + }?; + let session = entry.into_mut(); + if session.stanza != Stanza::Iq { + return Err(generate_error( + ErrorType::Cancel, + DefinedCondition::NotAcceptable, + "Wrong stanza type." + )) + } + let cur_seq = session.cur_seq.wrapping_add(1); + if seq != cur_seq { + return Err(generate_error( + ErrorType::Cancel, + DefinedCondition::NotAcceptable, + "Wrong seq number." + )) } + session.cur_seq = cur_seq; + self.proxy.dispatch(IbbData { + session: session.clone(), + data, + }); + Ok(()) + } + + fn handle_ibb_close(&self, from: Jid, close: Close) -> Result<(), StanzaError> { + let mut sessions = self.sessions.lock().unwrap(); + let Close { sid } = close; + let entry = match sessions.entry((from, sid)) { + Entry::Occupied(entry) => Ok(entry), + Entry::Vacant(_) => Err(generate_error( + ErrorType::Cancel, + DefinedCondition::ItemNotFound, + "This session doesn’t exist." + )), + }?; + let session = entry.remove(); + self.proxy.dispatch(IbbClose { + session, + }); Ok(()) } @@ -164,8 +169,20 @@ impl IbbPlugin { let id = iq.id.unwrap(); // TODO: use an intermediate plugin to parse this payload. let payload = match IqSetPayload::try_from(payload) { - Ok(IqSetPayload::IBB(ibb)) => { - match self.handle_ibb(from.clone(), ibb) { + Ok(IqSetPayload::IbbOpen(open)) => { + match self.handle_ibb_open(from.clone(), open) { + Ok(_) => IqType::Result(None), + Err(error) => IqType::Error(error), + } + }, + Ok(IqSetPayload::IbbData(data)) => { + match self.handle_ibb_data(from.clone(), data) { + Ok(_) => IqType::Result(None), + Err(error) => IqType::Error(error), + } + }, + Ok(IqSetPayload::IbbClose(close)) => { + match self.handle_ibb_close(from.clone(), close) { Ok(_) => IqType::Result(None), Err(error) => IqType::Error(error), } From 99a4ad5cac0c6986df0bf32ce4343e0a7ac35a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 04:05:19 +0100 Subject: [PATCH 05/15] Use quick_xml crate instead of xml --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c022941d68eca093a87c6807c3d362c33d0bf9e3..c160b7fd04585a07754d676e1471d8f8a01181d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -extern crate xml; +extern crate quick_xml; extern crate xmpp_parsers; extern crate openssl; extern crate minidom; From 5e58956408f6e2b2f0f105d0773e2e42ce9b284d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 04:06:40 +0100 Subject: [PATCH 06/15] Replace xml-rs bits by quickxml in Error --- src/error.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/error.rs b/src/error.rs index f27e94ed70af2556c07bc3e085208a1adb103155..db1a8b6c0950d09e508f57d6892b7d6649e44371 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,8 +9,7 @@ use std::net::TcpStream; use openssl::ssl::HandshakeError; use openssl::error::ErrorStack; -use xml::reader::Error as XmlError; -use xml::writer::Error as EmitterError; +use quick_xml::errors::Error as XmlError; use minidom::Error as MinidomError; @@ -22,7 +21,6 @@ use components::sasl_error::SaslError; #[derive(Debug)] pub enum Error { XmlError(XmlError), - EmitterError(EmitterError), IoError(io::Error), HandshakeError(HandshakeError), OpenSslErrorStack(ErrorStack), @@ -41,12 +39,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: EmitterError) -> Error { - Error::EmitterError(err) - } -} - impl From for Error { fn from(err: io::Error) -> Error { Error::IoError(err) From 5e5086e2efb11c4999626753b972678c3a3bb464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 04:16:53 +0100 Subject: [PATCH 07/15] plugins/roster: Subscription is now an enum --- src/plugins/roster.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/roster.rs b/src/plugins/roster.rs index 487a90ff202cf42908bd86a3a55a4daea60ce7da..f287c46d32a772b1321f011518d660553cb6a2ed 100644 --- a/src/plugins/roster.rs +++ b/src/plugins/roster.rs @@ -77,7 +77,7 @@ impl RosterPlugin { // TODO: use a better error type. pub fn send_roster_set(&self, to: Option, item: Item) -> Result<(), String> { - if item.subscription.is_some() && item.subscription != Some(Subscription::Remove) { + if item.subscription != Subscription::Remove { return Err(String::from("Subscription must be either nothing or Remove.")); } let iq = Iq { @@ -117,10 +117,10 @@ impl RosterPlugin { let mut jids = self.jids.lock().unwrap(); let previous = jids.insert(item.jid.clone(), item.clone()); if previous.is_none() { - assert!(item.subscription != Some(Subscription::Remove)); + assert!(item.subscription != Subscription::Remove); self.proxy.dispatch(RosterPush::Added(item)); } else { - if item.subscription == Some(Subscription::Remove) { + if item.subscription == Subscription::Remove { self.proxy.dispatch(RosterPush::Removed(item)); } else { self.proxy.dispatch(RosterPush::Modified(item)); From 4b322cc62b3655cac4fa0d44b8b8c5968c019a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 04:31:40 +0100 Subject: [PATCH 08/15] connection: Adapt C2S and Component2S impl for quickxml; Thanks eijebong --- src/connection.rs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/connection.rs b/src/connection.rs index 4d639b4e839ec59330a4c44ad519f3768afb4919..fcb33c0ba3351f4a5f5d31aee0323c6c3e016737 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -2,7 +2,7 @@ use transport::Transport; use error::Error; use ns; -use xml::writer::XmlEvent as WriterEvent; +use quick_xml::events::{Event as WriterEvent, BytesStart, BytesEnd}; pub trait Connection { type InitError; @@ -23,17 +23,19 @@ impl Connection for C2S { fn namespace() -> &'static str { ns::CLIENT } fn init(transport: &mut T, domain: &str, id: &str) -> Result<(), Error> { - transport.write_event(WriterEvent::start_element("stream:stream") - .attr("to", domain) - .attr("id", id) - .default_ns(ns::CLIENT) - .ns("stream", ns::STREAM))?; - Ok(()) + let name = "stream:stream"; + let mut elem = BytesStart::borrowed(name.as_bytes(), name.len()); + elem.push_attribute(("to", domain)); + elem.push_attribute(("id", id)); + elem.push_attribute(("xmlns", ns::CLIENT)); + elem.push_attribute(("xmlns:stream", ns::STREAM)); + transport.write_event(WriterEvent::Start(elem)) } fn close(transport: &mut T) -> Result<(), Error> { - transport.write_event(WriterEvent::end_element())?; - Ok(()) + let name = "stream:stream"; + let elem = BytesEnd::borrowed(name.as_bytes()); + transport.write_event(WriterEvent::End(elem)) } } @@ -46,16 +48,18 @@ impl Connection for Component2S { fn namespace() -> &'static str { ns::COMPONENT_ACCEPT } fn init(transport: &mut T, domain: &str, id: &str) -> Result<(), Error> { - transport.write_event(WriterEvent::start_element("stream:stream") - .attr("to", domain) - .attr("id", id) - .default_ns(ns::COMPONENT_ACCEPT) - .ns("stream", ns::STREAM))?; - Ok(()) + let name = "stream:stream"; + let mut elem = BytesStart::borrowed(name.as_bytes(), name.len()); + elem.push_attribute(("to", domain)); + elem.push_attribute(("id", id)); + elem.push_attribute(("xmlns", ns::COMPONENT_ACCEPT)); + elem.push_attribute(("xmlns:stream", ns::STREAM)); + transport.write_event(WriterEvent::Start(elem)) } fn close(transport: &mut T) -> Result<(), Error> { - transport.write_event(WriterEvent::end_element())?; - Ok(()) + let name = "stream:stream"; + let elem = BytesEnd::borrowed(name.as_bytes()); + transport.write_event(WriterEvent::End(elem)) } } From 37148b9097bd645982027243dffe61aa6f788863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 05:31:36 +0100 Subject: [PATCH 09/15] transport: Adapt to quick_xml. Thanks eijebong. --- src/error.rs | 8 +++ src/transport.rs | 123 ++++++++++++++++++++++------------------------- 2 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/error.rs b/src/error.rs index db1a8b6c0950d09e508f57d6892b7d6649e44371..61ce9767072dcf62d045569df428b39402899f65 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,6 +5,7 @@ use std::fmt::Error as FormatError; use std::io; use std::net::TcpStream; +use std::str::Utf8Error; use openssl::ssl::HandshakeError; use openssl::error::ErrorStack; @@ -29,6 +30,7 @@ pub enum Error { SaslError(Option), XmppSaslError(SaslError), FormatError(FormatError), + Utf8Error(Utf8Error), StreamError, EndOfDocument, } @@ -74,3 +76,9 @@ impl From for Error { Error::FormatError(err) } } + +impl From for Error { + fn from(err: Utf8Error) -> Error { + Error::Utf8Error(err) + } +} diff --git a/src/transport.rs b/src/transport.rs index 527134a0ce0dd86106ba4387ce3c4258ef823002..288bfce27ffaa7ca2b3045f76402c8366a3698b7 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -1,11 +1,13 @@ //! Provides transports for the xml streams. +use std::io::BufReader; use std::io::prelude::*; +use std::str; use std::net::{TcpStream, Shutdown}; -use xml::reader::{EventReader, XmlEvent as XmlReaderEvent}; -use xml::writer::{EventWriter, XmlEvent as XmlWriterEvent, EmitterConfig}; +use quick_xml::reader::{Reader as EventReader}; +use quick_xml::events::Event; use std::sync::{Arc, Mutex}; @@ -24,11 +26,11 @@ use sasl::common::ChannelBinding; /// A trait which transports are required to implement. pub trait Transport { - /// Writes an `xml::writer::XmlEvent` to the stream. - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error>; + /// Writes a `quick_xml::events::Event` to the stream. + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result; - /// Reads an `xml::reader::XmlEvent` from the stream. - fn read_event(&mut self) -> Result; + /// Reads a `quick_xml::events::Event` from the stream. + fn read_event(&mut self) -> Result; /// Writes a `minidom::Element` to the stream. fn write_element(&mut self, element: &minidom::Element) -> Result<(), Error>; @@ -48,19 +50,20 @@ pub trait Transport { /// A plain text transport, completely unencrypted. pub struct PlainTransport { inner: Arc>, // TODO: this feels rather ugly - reader: EventReader>, // TODO: especially feels ugly because - // this read would keep the lock - // held very long (potentially) - writer: EventWriter>, + // TODO: especially feels ugly because this read would keep the lock held very long + // (potentially) + reader: EventReader>>, + writer: LockedIO, + buf: Vec, } impl Transport for PlainTransport { - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error> { - Ok(self.writer.write(event)?) + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result { + Ok(self.writer.write(&event.into())?) } - fn read_event(&mut self) -> Result { - Ok(self.reader.next()?) + fn read_event(&mut self) -> Result { + Ok(self.reader.read_event(&mut self.buf)?) } fn write_element(&mut self, element: &minidom::Element) -> Result<(), Error> { @@ -74,13 +77,8 @@ impl Transport for PlainTransport { fn reset_stream(&mut self) { let locked_io = LockedIO::from(self.inner.clone()); - self.reader = EventReader::new(locked_io.clone()); - self.writer = EventWriter::new_with_config(locked_io, EmitterConfig { - line_separator: "".into(), - perform_indent: false, - normalize_empty_elements: false, - .. Default::default() - }); + self.reader = EventReader::from_reader(BufReader::new(locked_io.clone())); + self.writer = locked_io; } fn channel_bind(&self) -> ChannelBinding { @@ -93,21 +91,16 @@ impl PlainTransport { /// Connects to a server without any encryption. pub fn connect(host: &str, port: u16) -> Result { let tcp_stream = TcpStream::connect((host, port))?; - let parser = EventReader::new(tcp_stream); - let parser_stream = parser.into_inner(); - let stream = Arc::new(Mutex::new(parser_stream)); + let stream = Arc::new(Mutex::new(tcp_stream)); let locked_io = LockedIO::from(stream.clone()); - let reader = EventReader::new(locked_io.clone()); - let writer = EventWriter::new_with_config(locked_io, EmitterConfig { - line_separator: "".into(), - perform_indent: false, - normalize_empty_elements: false, - .. Default::default() - }); + let reader = EventReader::from_reader(BufReader::new(locked_io.clone())); + let writer = locked_io; + Ok(PlainTransport { inner: stream, reader: reader, writer: writer, + buf: Vec::new(), }) } @@ -123,19 +116,20 @@ impl PlainTransport { /// A transport which uses STARTTLS. pub struct SslTransport { inner: Arc>>, // TODO: this feels rather ugly - reader: EventReader>>, // TODO: especially feels ugly because - // this read would keep the lock - // held very long (potentially) - writer: EventWriter>>, + // TODO: especially feels ugly because this read would keep the lock held very long + // (potentially) + reader: EventReader>>>, + writer: LockedIO>, + buf: Vec, } impl Transport for SslTransport { - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error> { - Ok(self.writer.write(event)?) + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result { + Ok(self.writer.write(&event.into())?) } - fn read_event(&mut self) -> Result { - Ok(self.reader.next()?) + fn read_event(&mut self) -> Result { + Ok(self.reader.read_event(&mut self.buf)?) } fn write_element(&mut self, element: &minidom::Element) -> Result<(), Error> { @@ -148,13 +142,8 @@ impl Transport for SslTransport { fn reset_stream(&mut self) { let locked_io = LockedIO::from(self.inner.clone()); - self.reader = EventReader::new(locked_io.clone()); - self.writer = EventWriter::new_with_config(locked_io, EmitterConfig { - line_separator: "".into(), - perform_indent: false, - normalize_empty_elements: false, - .. Default::default() - }); + self.reader = EventReader::from_reader(BufReader::new(locked_io.clone())); + self.writer = locked_io; } fn channel_bind(&self) -> ChannelBinding { @@ -172,23 +161,28 @@ impl SslTransport { , ns::CLIENT, ns::STREAM, host)?; write!(stream, "" , ns::TLS)?; - let mut parser = EventReader::new(stream); - loop { // TODO: possibly a timeout? - match parser.next()? { - XmlReaderEvent::StartElement { name, .. } => { - if let Some(ns) = name.namespace { - if ns == ns::TLS && name.local_name == "proceed" { - break; - } - else if ns == ns::STREAM && name.local_name == "error" { - return Err(Error::StreamError); + { + let mut parser = EventReader::from_reader(BufReader::new(&stream)); + let mut buf = Vec::new(); + let ns_buf = Vec::new(); + loop { // TODO: possibly a timeout? + match parser.read_event(&mut buf)? { + Event::Start(ref e) => { + let (namespace, local_name) = parser.resolve_namespace(e.name(), &ns_buf); + let namespace = namespace.map(str::from_utf8); + let local_name = str::from_utf8(local_name)?; + + if let Some(ns) = namespace { + if ns == Ok(ns::TLS) && local_name == "proceed" { + break; + } else if ns == Ok(ns::STREAM) && local_name == "error" { + return Err(Error::StreamError); + } } } - }, - _ => {}, + } } } - let stream = parser.into_inner(); #[cfg(feature = "insecure")] let ssl_stream = { let mut ctx = SslContextBuilder::new(SslMethod::tls())?; @@ -203,17 +197,14 @@ impl SslTransport { }; let ssl_stream = Arc::new(Mutex::new(ssl_stream)); let locked_io = LockedIO::from(ssl_stream.clone()); - let reader = EventReader::new(locked_io.clone()); - let writer = EventWriter::new_with_config(locked_io, EmitterConfig { - line_separator: "".into(), - perform_indent: false, - normalize_empty_elements: false, - .. Default::default() - }); + let reader = EventReader::from_reader(BufReader::new(locked_io.clone())); + let writer = locked_io; + Ok(SslTransport { inner: ssl_stream, reader: reader, writer: writer, + buf: Vec::new(), }) } From 44a03c37d561a06dc13bf602dc5ce4660cfa42fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 06:04:50 +0100 Subject: [PATCH 10/15] component: Remove duplicate call to read_event --- src/component.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/component.rs b/src/component.rs index 00592ed2b06e67ea735f0fb1b39204e3c5281d7e..ff8526e7e2dd26480d6a956ea508c562d9ac4a65 100644 --- a/src/component.rs +++ b/src/component.rs @@ -1,4 +1,3 @@ -use xml; use jid::Jid; use transport::{Transport, PlainTransport}; use error::Error; @@ -10,8 +9,9 @@ use sha_1::{Sha1, Digest}; use minidom::Element; -use xml::reader::XmlEvent as ReaderEvent; +use quick_xml::events::Event as XmlEvent; +use std::str; use std::fmt::Write; use std::sync::{Mutex, Arc}; @@ -131,25 +131,30 @@ impl Component { self.transport.lock().unwrap().write_element(elem) } - fn read_event(&self) -> Result { - self.transport.lock().unwrap().read_event() - } - fn connect(&mut self, secret: String) -> Result<(), Error> { let mut sid = String::new(); loop { - let e = self.read_event()?; + let mut transport = self.transport.lock().unwrap(); + let e = transport.read_event()?; match e { - ReaderEvent::StartElement { attributes, .. } => { - for attribute in attributes { - if attribute.name.namespace == None && attribute.name.local_name == "id" { - sid = attribute.value; + XmlEvent::Start(ref e) => { + let mut attributes = e.attributes() + .map(|o| { + let o = o?; + let key = str::from_utf8(o.key)?; + let value = str::from_utf8(&o.value)?; + Ok((key, value)) + } + ) + .collect::, Error>>()?; + for &(name, value) in &attributes { + if name == "id" { + sid = value.to_owned(); } } - break; - }, - _ => (), + } } + break } let concatenated = format!("{}{}", sid, secret); let mut hasher = Sha1::default(); From 06fd0a354add50fc503960dbfdc2d702d37382db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 06:05:13 +0100 Subject: [PATCH 11/15] client: Adapt to quickxml --- src/client.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/client.rs b/src/client.rs index bfab1746ac7b00cd39e9fd1799c416ba9f7cea44..b2a00537e374c2a0d250c61a0547bd1fa5a333f4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,3 @@ -use xml; use jid::Jid; use transport::{Transport, SslTransport}; use error::Error; @@ -17,7 +16,7 @@ use base64; use minidom::Element; -use xml::reader::XmlEvent as ReaderEvent; +use quick_xml::events::Event as XmlEvent; use std::sync::{Mutex, Arc}; @@ -156,10 +155,6 @@ impl Client { self.transport.lock().unwrap().write_element(elem) } - fn read_event(&self) -> Result { - self.transport.lock().unwrap().read_event() - } - fn connect(&mut self, mut credentials: SaslCredentials) -> Result<(), Error> { let features = self.wait_for_features()?; let ms = &features.sasl_mechanisms.ok_or(Error::SaslError(Some("no SASL mechanisms".to_owned())))?; @@ -269,9 +264,10 @@ impl Client { fn wait_for_features(&mut self) -> Result { // TODO: this is very ugly loop { - let e = self.read_event()?; + let mut transport = self.transport.lock().unwrap(); + let e = transport.read_event(); match e { - ReaderEvent::StartElement { .. } => { + Ok(XmlEvent::Start { .. }) => { break; }, _ => (), From 690e83725c1453d2db27df9cf5e9ae24d503b0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 06:18:31 +0100 Subject: [PATCH 12/15] connection: Unneeded return value --- src/connection.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/connection.rs b/src/connection.rs index fcb33c0ba3351f4a5f5d31aee0323c6c3e016737..c209f37a5735c4417f61c3419c6eb63f47f93d03 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -29,13 +29,15 @@ impl Connection for C2S { elem.push_attribute(("id", id)); elem.push_attribute(("xmlns", ns::CLIENT)); elem.push_attribute(("xmlns:stream", ns::STREAM)); - transport.write_event(WriterEvent::Start(elem)) + transport.write_event(WriterEvent::Start(elem)); + Ok(()) } fn close(transport: &mut T) -> Result<(), Error> { let name = "stream:stream"; let elem = BytesEnd::borrowed(name.as_bytes()); - transport.write_event(WriterEvent::End(elem)) + transport.write_event(WriterEvent::End(elem)); + Ok(()) } } @@ -54,12 +56,14 @@ impl Connection for Component2S { elem.push_attribute(("id", id)); elem.push_attribute(("xmlns", ns::COMPONENT_ACCEPT)); elem.push_attribute(("xmlns:stream", ns::STREAM)); - transport.write_event(WriterEvent::Start(elem)) + transport.write_event(WriterEvent::Start(elem)); + Ok(()) } fn close(transport: &mut T) -> Result<(), Error> { let name = "stream:stream"; let elem = BytesEnd::borrowed(name.as_bytes()); - transport.write_event(WriterEvent::End(elem)) + transport.write_event(WriterEvent::End(elem)); + Ok(()) } } From 5f9d91140d49a66bf6ef68e2caf78e32b10ad3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 06:19:07 +0100 Subject: [PATCH 13/15] transport, component, connection: Do not use unneeded return values --- src/component.rs | 3 ++- src/connection.rs | 8 ++++---- src/transport.rs | 15 +++++++++------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/component.rs b/src/component.rs index ff8526e7e2dd26480d6a956ea508c562d9ac4a65..c8ea7e03814c105cf28ceca84440197716e58e77 100644 --- a/src/component.rs +++ b/src/component.rs @@ -152,7 +152,8 @@ impl Component { sid = value.to_owned(); } } - } + }, + _ => (), } break } diff --git a/src/connection.rs b/src/connection.rs index c209f37a5735c4417f61c3419c6eb63f47f93d03..4b80cdc2149aab78bf027762e267b4508d90c4be 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -29,14 +29,14 @@ impl Connection for C2S { elem.push_attribute(("id", id)); elem.push_attribute(("xmlns", ns::CLIENT)); elem.push_attribute(("xmlns:stream", ns::STREAM)); - transport.write_event(WriterEvent::Start(elem)); + transport.write_event(WriterEvent::Start(elem))?; Ok(()) } fn close(transport: &mut T) -> Result<(), Error> { let name = "stream:stream"; let elem = BytesEnd::borrowed(name.as_bytes()); - transport.write_event(WriterEvent::End(elem)); + transport.write_event(WriterEvent::End(elem))?; Ok(()) } } @@ -56,14 +56,14 @@ impl Connection for Component2S { elem.push_attribute(("id", id)); elem.push_attribute(("xmlns", ns::COMPONENT_ACCEPT)); elem.push_attribute(("xmlns:stream", ns::STREAM)); - transport.write_event(WriterEvent::Start(elem)); + transport.write_event(WriterEvent::Start(elem))?; Ok(()) } fn close(transport: &mut T) -> Result<(), Error> { let name = "stream:stream"; let elem = BytesEnd::borrowed(name.as_bytes()); - transport.write_event(WriterEvent::End(elem)); + transport.write_event(WriterEvent::End(elem))?; Ok(()) } } diff --git a/src/transport.rs b/src/transport.rs index 288bfce27ffaa7ca2b3045f76402c8366a3698b7..2f1474223f31ec872fa0c0c6783272d1a2fbbfb1 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -27,7 +27,7 @@ use sasl::common::ChannelBinding; /// A trait which transports are required to implement. pub trait Transport { /// Writes a `quick_xml::events::Event` to the stream. - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result; + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error>; /// Reads a `quick_xml::events::Event` from the stream. fn read_event(&mut self) -> Result; @@ -58,8 +58,9 @@ pub struct PlainTransport { } impl Transport for PlainTransport { - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result { - Ok(self.writer.write(&event.into())?) + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error> { + self.writer.write(&event.into())?; + Ok(()) } fn read_event(&mut self) -> Result { @@ -124,8 +125,9 @@ pub struct SslTransport { } impl Transport for SslTransport { - fn write_event<'a, E: Into>>(&mut self, event: E) -> Result { - Ok(self.writer.write(&event.into())?) + fn write_event<'a, E: Into>>(&mut self, event: E) -> Result<(), Error> { + self.writer.write(&event.into())?; + Ok(()) } fn read_event(&mut self) -> Result { @@ -179,7 +181,8 @@ impl SslTransport { return Err(Error::StreamError); } } - } + }, + _ => (), } } } From 2fb540f85beadf3c74e7cadb10b7423483c8e37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 16:20:32 +0100 Subject: [PATCH 14/15] component: Fix attributes parsing; thanks Link Mauve --- src/component.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/component.rs b/src/component.rs index c8ea7e03814c105cf28ceca84440197716e58e77..be5982304e629980f41612107bc3ea0105e1ec18 100644 --- a/src/component.rs +++ b/src/component.rs @@ -138,24 +138,22 @@ impl Component { let e = transport.read_event()?; match e { XmlEvent::Start(ref e) => { - let mut attributes = e.attributes() - .map(|o| { - let o = o?; - let key = str::from_utf8(o.key)?; - let value = str::from_utf8(&o.value)?; - Ok((key, value)) - } - ) - .collect::, Error>>()?; - for &(name, value) in &attributes { - if name == "id" { - sid = value.to_owned(); + for attr_result in e.attributes() { + match attr_result { + Ok(attr) => { + let name = str::from_utf8(attr.key)?; + let value = str::from_utf8(&attr.value)?; + if name == "id" { + sid = value.to_owned(); + } + }, + _ => panic!() } } + break; }, _ => (), } - break } let concatenated = format!("{}{}", sid, secret); let mut hasher = Sha1::default(); From 2146244e1c857f6484a5a35a3cb74dc6ba49aaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Thu, 28 Dec 2017 18:08:49 +0100 Subject: [PATCH 15/15] Update docker image --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3038e39f6b519e6eaf51d43be5d20cc6acc61a7f..6d38814dc946b2f865e2e760edfa5525743d2b73 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: "scorpil/rust:nightly" +image: "pitkley/rust:nightly" before_script: - apt-get update -yqq