diff --git a/src/proto/codec.rs b/src/proto/codec.rs index 930318c..8bf746c 100644 --- a/src/proto/codec.rs +++ b/src/proto/codec.rs @@ -8,84 +8,12 @@ use bytes::{Buf, BufMut, BytesMut, LittleEndian}; use encoding::{Encoding, EncoderTrap, DecoderTrap}; use encoding::all::WINDOWS_1252; +// Constants +// --------- + /// Length of an encoded 32-bit integer in bytes. const U32_BYTE_LEN: usize = 4; -/*==============* - * DECODE ERROR * - *==============*/ - -/// An error that arose when decoding a protocol message. -#[derive(Debug)] -pub enum DecodeError { - /// Attempted to decode a boolean, but the value was neither 0 nor 1. - /// The invalid value is enclosed. - InvalidBoolError(u8), - /// Attempted to decode an unsigned 16-bit integer, but the value did not - /// fit in 16 bits. The invalid value is enclosed. - InvalidU16Error(u32), - /// Attempted to decode the enclosed bytes as an Windows 1252 encoded - /// string, but one of the bytes was not a valid character encoding. - InvalidStringError(Vec), - /// Attempted to decode a user::Status, but the value was not a valid - /// representation of an enum variant. The invalid value is enclosed. - InvalidUserStatusError(u32), - /// Encountered the enclosed I/O error while decoding. - IOError(io::Error), - /// Attempted to decode a message with the enclosed code, unknown to this - /// library. - UnknownCodeError(u32), -} - -impl fmt::Display for DecodeError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - DecodeError::InvalidBoolError(n) => write!(fmt, "InvalidBoolError: {}", n), - DecodeError::InvalidU16Error(n) => write!(fmt, "InvalidU16Error: {}", n), - DecodeError::InvalidStringError(ref bytes) => { - write!(fmt, "InvalidStringError: {:?}", bytes) - } - DecodeError::InvalidUserStatusError(n) => write!(fmt, "InvalidUserStatusError: {}", n), - DecodeError::IOError(ref err) => write!(fmt, "IOError: {}", err), - DecodeError::UnknownCodeError(code) => write!(fmt, "UnknownCodeError: {}", code), - } - } -} - -impl error::Error for DecodeError { - fn description(&self) -> &str { - match *self { - DecodeError::InvalidBoolError(_) => "InvalidBoolError", - DecodeError::InvalidU16Error(_) => "InvalidU16Error", - DecodeError::InvalidStringError(_) => "InvalidStringError", - DecodeError::InvalidUserStatusError(_) => "InvalidUserStatusError", - DecodeError::IOError(_) => "IOError", - DecodeError::UnknownCodeError(code) => "UnknownCodeError", - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - DecodeError::InvalidBoolError(_) => None, - DecodeError::InvalidU16Error(_) => None, - DecodeError::InvalidStringError(_) => None, - DecodeError::InvalidUserStatusError(_) => None, - DecodeError::IOError(ref err) => Some(err), - DecodeError::UnknownCodeError(_) => None, - } - } -} - -impl From for DecodeError { - fn from(err: io::Error) -> Self { - DecodeError::IOError(err) - } -} - -fn unexpected_eof_error(value_type: &str) -> DecodeError { - DecodeError::from(io::Error::new(io::ErrorKind::UnexpectedEof, value_type)) -} - /*===================================* * BASIC TYPES ENCODING AND DECODING * *===================================*/ @@ -108,7 +36,7 @@ fn unexpected_eof_error(value_type: &str) -> DecodeError { /// Only here to enable `ProtoDecoder::decode_vec`. pub trait ProtoDecode: Sized { /// Attempts to decode an instance of `Self` using the given decoder. - fn decode(decoder: &mut ProtoDecoder) -> Result; + fn decode(decoder: &mut ProtoDecoder) -> io::Result; } /// This trait is implemented by types that can be encoded into messages with @@ -132,59 +60,93 @@ impl<'a> ProtoDecoder<'a> { ProtoDecoder { inner: inner } } - pub fn has_remaining(&self) -> bool { - self.inner.has_remaining() + // Private helper methods + // ---------------------- + + // Builds an EOF error encountered when reading a value of the given type. + fn unexpected_eof_error(type_name: &str) -> io::Error { + io::Error::new( + io::ErrorKind::UnexpectedEof, + format!("reading {}", type_name), + ) } - pub fn decode_u32(&mut self) -> Result { - if self.inner.remaining() < U32_BYTE_LEN { - return Err(unexpected_eof_error("u32")); + // Builds an InvalidData error for the given value of the given type. + fn invalid_data_error(type_name: &str, value: T) -> io::Error { + io::Error::new( + io::ErrorKind::InvalidData, + format!("invalid {}: {:?}", type_name, value), + ) + } + + // Asserts that the underlying buffer contains at least `n` more bytes from + // which to read a value of the given type. + // Returns Ok(()) if there are that many bytes, an error otherwise. + fn expect_remaining(&mut self, type_name: &str, n: usize) -> io::Result<()> { + if self.inner.remaining() < n { + Err(Self::unexpected_eof_error(type_name)) + } else { + Ok(()) } + } + + // Decodes a u32 value as the first step in decoding a value of the given type. + fn decode_u32_generic(&mut self, type_name: &str) -> io::Result { + self.expect_remaining(type_name, U32_BYTE_LEN)?; Ok(self.inner.get_u32::()) } - pub fn decode_u16(&mut self) -> Result { - let n = self.decode_u32()?; + // Public methods + // -------------- + + pub fn has_remaining(&self) -> bool { + self.inner.has_remaining() + } + + pub fn decode_u32(&mut self) -> io::Result { + self.decode_u32_generic("u32") + } + + pub fn decode_u16(&mut self) -> io::Result { + let n = self.decode_u32_generic("u16")?; if n > u16::MAX as u32 { - return Err(DecodeError::InvalidU16Error(n)); + return Err(Self::invalid_data_error("u16", n)); } Ok(n as u16) } - pub fn decode_bool(&mut self) -> Result { - if self.inner.remaining() < 1 { - return Err(unexpected_eof_error("bool")); - } + pub fn decode_bool(&mut self) -> io::Result { + self.expect_remaining("bool", 1)?; match self.inner.get_u8() { 0 => Ok(false), 1 => Ok(true), - n => Err(DecodeError::InvalidBoolError(n)), + n => Err(Self::invalid_data_error("bool", n)), } } - pub fn decode_ipv4_addr(&mut self) -> Result { - let ip = self.decode_u32()?; + pub fn decode_ipv4_addr(&mut self) -> io::Result { + let ip = self.decode_u32_generic("ipv4 address")?; Ok(net::Ipv4Addr::from(ip)) } - pub fn decode_string(&mut self) -> Result { - let len = self.decode_u32()? as usize; - if self.inner.remaining() < len { - return Err(unexpected_eof_error("string")); - } + pub fn decode_string(&mut self) -> io::Result { + let len = self.decode_u32_generic("string length")? as usize; + self.expect_remaining("string", len)?; + let result = { let bytes = &self.inner.bytes()[..len]; WINDOWS_1252.decode(bytes, DecoderTrap::Strict).map_err( - |_| { - DecodeError::InvalidStringError(bytes.to_vec()) + |err| { + Self::invalid_data_error("string", (err, bytes)) }, ) }; + self.inner.advance(len); result } - pub fn decode_pair(&mut self) -> Result<(T, U), DecodeError> + pub fn decode_pair(&mut self) -> io::Result<(T, U)> where T: ProtoDecode, U: ProtoDecode, @@ -194,8 +156,8 @@ impl<'a> ProtoDecoder<'a> { Ok((first, second)) } - pub fn decode_vec(&mut self) -> Result, DecodeError> { - let len = self.decode_u32()? as usize; + pub fn decode_vec(&mut self) -> io::Result> { + let len = self.decode_u32_generic("vector length")? as usize; let mut vec = Vec::with_capacity(len); for _ in 0..len { let val = T::decode(self)?; @@ -279,7 +241,7 @@ impl<'a> ProtoEncoder<'a> { } impl ProtoDecode for u32 { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_u32() } } @@ -291,7 +253,7 @@ impl ProtoEncode for u32 { } impl ProtoDecode for bool { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_bool() } } @@ -303,7 +265,7 @@ impl ProtoEncode for bool { } impl ProtoDecode for u16 { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_u16() } } @@ -315,7 +277,7 @@ impl ProtoEncode for u16 { } impl ProtoDecode for net::Ipv4Addr { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_ipv4_addr() } } @@ -327,7 +289,7 @@ impl ProtoEncode for net::Ipv4Addr { } impl ProtoDecode for String { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_string() } } @@ -365,7 +327,7 @@ impl<'a> ProtoEncode for &'a String { } impl ProtoDecode for (T, U) { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_pair::() } } @@ -377,7 +339,7 @@ impl ProtoEncode for (T, U) { } impl ProtoDecode for Vec { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { decoder.decode_vec::() } } @@ -414,6 +376,28 @@ pub mod tests { assert_eq!(output, input); } + pub fn expect_io_error(result: io::Result, kind: io::ErrorKind, message: &str) + where + T: fmt::Debug + Send + 'static, + { + match result { + Err(e) => { + assert_eq!(e.kind(), kind); + let ok = match e.get_ref() { + Some(e) => { + assert_eq!(e.description(), message); + true + } + None => false, + }; + if !ok { + panic!(e) + } + } + Ok(message) => panic!(message), + } + } + // Helper for succinctness in tests below. fn new_cursor(vec: Vec) -> io::Cursor { io::Cursor::new(BytesMut::from(vec)) @@ -431,6 +415,36 @@ pub mod tests { (u32::MAX, [255, 255, 255, 255]), ]; + #[test] + fn expect_io_error_success() { + let kind = io::ErrorKind::InvalidInput; + let message = "some message"; + let result: io::Result<()> = Err(io::Error::new(kind, message)); + expect_io_error(result, kind, message); + } + + #[test] + #[should_panic] + fn expect_io_error_not_err() { + expect_io_error(Ok(()), io::ErrorKind::InvalidInput, "some message"); + } + + #[test] + #[should_panic] + fn expect_io_error_wrong_kind() { + let result: io::Result<()> = + Err(io::Error::new(io::ErrorKind::UnexpectedEof, "some message")); + expect_io_error(result, io::ErrorKind::InvalidInput, "some message"); + } + + #[test] + #[should_panic] + fn expect_io_error_wrong_message() { + let result: io::Result<()> = + Err(io::Error::new(io::ErrorKind::InvalidInput, "some message")); + expect_io_error(result, io::ErrorKind::InvalidInput, "other message"); + } + #[test] fn encode_u32() { for &(val, ref encoded_bytes) in &U32_ENCODINGS { @@ -460,6 +474,13 @@ pub mod tests { } } + #[test] + fn decode_u32_unexpected_eof() { + let mut cursor = new_cursor(vec![13]); + let result = ProtoDecoder::new(&mut cursor).decode_u32(); + expect_io_error(result, io::ErrorKind::UnexpectedEof, "reading u32"); + } + #[test] fn encode_bool() { let mut bytes = BytesMut::from(vec![13]); @@ -485,10 +506,17 @@ pub mod tests { } #[test] - #[should_panic] fn decode_bool_invalid() { let mut cursor = new_cursor(vec![42]); - ProtoDecoder::new(&mut cursor).decode_bool().unwrap(); + let result = ProtoDecoder::new(&mut cursor).decode_bool(); + expect_io_error(result, io::ErrorKind::InvalidData, "invalid bool: 42"); + } + + #[test] + fn decode_bool_unexpected_eof() { + let mut cursor = new_cursor(vec![]); + let result = ProtoDecoder::new(&mut cursor).decode_bool(); + expect_io_error(result, io::ErrorKind::UnexpectedEof, "reading bool"); } #[test] @@ -530,10 +558,17 @@ pub mod tests { } #[test] - #[should_panic] fn decode_u16_invalid() { let mut cursor = new_cursor(vec![0, 0, 1, 0]); - ProtoDecoder::new(&mut cursor).decode_u16().unwrap(); + let result = ProtoDecoder::new(&mut cursor).decode_u16(); + expect_io_error(result, io::ErrorKind::InvalidData, "invalid u16: 65536"); + } + + #[test] + fn decode_u16_unexpected_eof() { + let mut cursor = new_cursor(vec![]); + let result = ProtoDecoder::new(&mut cursor).decode_u16(); + expect_io_error(result, io::ErrorKind::UnexpectedEof, "reading u16"); } #[test] diff --git a/src/proto/mod.rs b/src/proto/mod.rs index 1b42ccc..5061c68 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -8,7 +8,7 @@ mod stream; mod transport; mod user; -pub use self::codec::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; +pub use self::codec::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; pub use self::handler::*; pub use self::packet::*; pub use self::stream::*; diff --git a/src/proto/peer/message.rs b/src/proto/peer/message.rs index c64818b..c7cbea1 100644 --- a/src/proto/peer/message.rs +++ b/src/proto/peer/message.rs @@ -1,7 +1,7 @@ use std::io; -use proto::{DecodeError, MutPacket, Packet, PacketReadError, ProtoDecode, ProtoDecoder, - ProtoEncode, ProtoEncoder, ReadFromPacket, WriteToPacket}; +use proto::{MutPacket, Packet, PacketReadError, ProtoDecode, ProtoDecoder, ProtoEncode, + ProtoEncoder, ReadFromPacket, WriteToPacket}; use proto::peer::constants::*; /*=========* @@ -41,7 +41,7 @@ impl ReadFromPacket for Message { } impl ProtoDecode for Message { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let code = decoder.decode_u32()?; let message = match code { CODE_PIERCE_FIREWALL => { @@ -53,7 +53,10 @@ impl ProtoDecode for Message { Message::PeerInit(peer_init) } _ => { - return Err(DecodeError::UnknownCodeError(code)); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("unknown peer message code: {}", code), + )) } }; Ok(message) @@ -135,7 +138,7 @@ impl ProtoEncode for PeerInit { } impl ProtoDecode for PeerInit { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; let connection_type = decoder.decode_string()?; let token = decoder.decode_u32()?; @@ -154,8 +157,8 @@ mod tests { use bytes::BytesMut; - use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; - use proto::codec::tests::roundtrip; + use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; + use proto::codec::tests::{expect_io_error, roundtrip}; use super::*; @@ -165,10 +168,12 @@ mod tests { ProtoEncoder::new(&mut bytes).encode_u32(1337).unwrap(); let mut cursor = io::Cursor::new(bytes); - match Message::decode(&mut ProtoDecoder::new(&mut cursor)) { - Err(DecodeError::UnknownCodeError(1337)) => {} - result => panic!(result), - } + let result = Message::decode(&mut ProtoDecoder::new(&mut cursor)); + expect_io_error( + result, + io::ErrorKind::InvalidData, + "unknown peer message code: 1337", + ); } #[test] diff --git a/src/proto/server/request.rs b/src/proto/server/request.rs index 76a7400..6d5e249 100644 --- a/src/proto/server/request.rs +++ b/src/proto/server/request.rs @@ -3,7 +3,7 @@ use std::io; use crypto::md5::Md5; use crypto::digest::Digest; -use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; +use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; use proto::packet::{MutPacket, WriteToPacket}; use proto::server::constants::*; @@ -149,7 +149,7 @@ impl ProtoEncode for ServerRequest { } impl ProtoDecode for ServerRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let code = decoder.decode_u32()?; let request = match code { CODE_CANNOT_CONNECT => { @@ -194,7 +194,10 @@ impl ProtoDecode for ServerRequest { ServerRequest::UserStatusRequest(request) } _ => { - return Err(DecodeError::UnknownCodeError(code)); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("unknown server request code: {}", code), + )) } }; Ok(request) @@ -227,7 +230,7 @@ impl ProtoEncode for CannotConnectRequest { } impl ProtoDecode for CannotConnectRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let token = decoder.decode_u32()?; let user_name = decoder.decode_string()?; Ok(Self { token, user_name }) @@ -263,7 +266,7 @@ impl ProtoEncode for ConnectToPeerRequest { } impl ProtoDecode for ConnectToPeerRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let token = decoder.decode_u32()?; let user_name = decoder.decode_string()?; let connection_type = decoder.decode_string()?; @@ -301,7 +304,7 @@ impl ProtoEncode for FileSearchRequest { } impl ProtoDecode for FileSearchRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let ticket = decoder.decode_u32()?; let query = decoder.decode_string()?; Ok(Self { ticket, query }) @@ -373,7 +376,7 @@ impl ProtoEncode for LoginRequest { } impl ProtoDecode for LoginRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let username = decoder.decode_string()?; let password = decoder.decode_string()?; let major = decoder.decode_u32()?; @@ -412,7 +415,7 @@ impl ProtoEncode for PeerAddressRequest { } impl ProtoDecode for PeerAddressRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let username = decoder.decode_string()?; Ok(Self { username: username }) } @@ -441,7 +444,7 @@ impl ProtoEncode for RoomJoinRequest { } impl ProtoDecode for RoomJoinRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; Ok(Self { room_name: room_name }) } @@ -470,7 +473,7 @@ impl ProtoEncode for RoomLeaveRequest { } impl ProtoDecode for RoomLeaveRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; Ok(Self { room_name: room_name }) } @@ -502,7 +505,7 @@ impl ProtoEncode for RoomMessageRequest { } impl ProtoDecode for RoomMessageRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let message = decoder.decode_string()?; Ok(Self { room_name, message }) @@ -532,7 +535,7 @@ impl ProtoEncode for SetListenPortRequest { } impl ProtoDecode for SetListenPortRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let port = decoder.decode_u16()?; Ok(Self { port: port }) } @@ -561,7 +564,7 @@ impl ProtoEncode for UserStatusRequest { } impl ProtoDecode for UserStatusRequest { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; Ok(Self { user_name: user_name }) } @@ -578,8 +581,8 @@ mod tests { use bytes::BytesMut; - use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; - use proto::codec::tests::roundtrip; + use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; + use proto::codec::tests::{expect_io_error, roundtrip}; use super::*; @@ -589,10 +592,12 @@ mod tests { ProtoEncoder::new(&mut bytes).encode_u32(1337).unwrap(); let mut cursor = io::Cursor::new(bytes); - match ServerRequest::decode(&mut ProtoDecoder::new(&mut cursor)) { - Err(DecodeError::UnknownCodeError(1337)) => {} - result => panic!(result), - } + let result = ServerRequest::decode(&mut ProtoDecoder::new(&mut cursor)); + expect_io_error( + result, + io::ErrorKind::InvalidData, + "unknown server request code: 1337", + ); } #[test] diff --git a/src/proto/server/response.rs b/src/proto/server/response.rs index 69d8712..075a51f 100644 --- a/src/proto/server/response.rs +++ b/src/proto/server/response.rs @@ -2,7 +2,7 @@ use std::io; use std::net; use proto::server::constants::*; -use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder, User, UserStatus}; +use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder, User, UserStatus}; use proto::packet::{Packet, PacketReadError, ReadFromPacket}; /*=================* @@ -178,7 +178,7 @@ impl ProtoEncode for ServerResponse { } impl ProtoDecode for ServerResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let code = decoder.decode_u32()?; let response = match code { CODE_CONNECT_TO_PEER => { @@ -250,7 +250,10 @@ impl ProtoDecode for ServerResponse { ServerResponse::WishlistIntervalResponse(response) } _ => { - return Err(DecodeError::UnknownCodeError(code)); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("unknown server response code: {}", code), + )); } }; Ok(response) @@ -303,7 +306,7 @@ impl ProtoEncode for ConnectToPeerResponse { } impl ProtoDecode for ConnectToPeerResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; let connection_type = decoder.decode_string()?; let ip = decoder.decode_ipv4_addr()?; @@ -356,7 +359,7 @@ impl ProtoEncode for FileSearchResponse { } impl ProtoDecode for FileSearchResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; let ticket = decoder.decode_u32()?; let query = decoder.decode_string()?; @@ -430,7 +433,7 @@ impl ProtoEncode for LoginResponse { } impl ProtoDecode for LoginResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let ok = decoder.decode_bool()?; if !ok { let reason = decoder.decode_string()?; @@ -476,7 +479,7 @@ impl ProtoEncode for ParentMinSpeedResponse { } impl ProtoDecode for ParentMinSpeedResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let value = decoder.decode_u32()?; Ok(Self { value }) } @@ -505,7 +508,7 @@ impl ProtoEncode for ParentSpeedRatioResponse { } impl ProtoDecode for ParentSpeedRatioResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let value = decoder.decode_u32()?; Ok(Self { value }) } @@ -541,7 +544,7 @@ impl ProtoEncode for PeerAddressResponse { } impl ProtoDecode for PeerAddressResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let username = decoder.decode_string()?; let ip = decoder.decode_ipv4_addr()?; let port = decoder.decode_u16()?; @@ -572,7 +575,7 @@ impl ProtoEncode for PrivilegedUsersResponse { } impl ProtoDecode for PrivilegedUsersResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let users = decoder.decode_vec::()?; Ok(Self { users }) } @@ -738,7 +741,7 @@ impl ProtoEncode for UserInfo { } impl ProtoDecode for UserInfo { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let average_speed = decoder.decode_u32()?; let num_downloads = decoder.decode_u32()?; let unknown = decoder.decode_u32()?; @@ -814,7 +817,7 @@ fn build_users( } impl ProtoDecode for RoomJoinResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let user_names = decoder.decode_vec::()?; let user_statuses = decoder.decode_vec::()?; @@ -868,7 +871,7 @@ impl ProtoEncode for RoomLeaveResponse { } impl ProtoDecode for RoomLeaveResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; Ok(Self { room_name }) } @@ -958,7 +961,7 @@ impl RoomListResponse { rooms } - fn decode_rooms(decoder: &mut ProtoDecoder) -> Result, DecodeError> { + fn decode_rooms(decoder: &mut ProtoDecoder) -> io::Result> { let room_names = decoder.decode_vec::()?; let user_counts = decoder.decode_vec::()?; Ok(Self::build_rooms(room_names, user_counts)) @@ -988,7 +991,7 @@ impl ProtoEncode for RoomListResponse { } impl ProtoDecode for RoomListResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let rooms = Self::decode_rooms(decoder)?; let owned_private_rooms = Self::decode_rooms(decoder)?; let other_private_rooms = Self::decode_rooms(decoder)?; @@ -1035,7 +1038,7 @@ impl ProtoEncode for RoomMessageResponse { } impl ProtoDecode for RoomMessageResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let user_name = decoder.decode_string()?; let message = decoder.decode_string()?; @@ -1081,7 +1084,7 @@ impl ProtoEncode for RoomTickersResponse { } impl ProtoDecode for RoomTickersResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let tickers = decoder.decode_vec::<(String, String)>()?; Ok(Self { room_name, tickers }) @@ -1143,7 +1146,7 @@ impl ProtoEncode for RoomUserJoinedResponse { } impl ProtoDecode for RoomUserJoinedResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let user_name = decoder.decode_string()?; let status = UserStatus::decode(decoder)?; @@ -1186,7 +1189,7 @@ impl ProtoEncode for RoomUserLeftResponse { } impl ProtoDecode for RoomUserLeftResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let room_name = decoder.decode_string()?; let user_name = decoder.decode_string()?; Ok(Self { @@ -1237,7 +1240,7 @@ impl ProtoEncode for UserInfoResponse { } impl ProtoDecode for UserInfoResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; let average_speed = decoder.decode_u32()?; let num_downloads = decoder.decode_u32()?; @@ -1286,7 +1289,7 @@ impl ProtoEncode for UserStatusResponse { } impl ProtoDecode for UserStatusResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let user_name = decoder.decode_string()?; let status = UserStatus::decode(decoder)?; let is_privileged = decoder.decode_bool()?; @@ -1321,7 +1324,7 @@ impl ProtoEncode for WishlistIntervalResponse { } impl ProtoDecode for WishlistIntervalResponse { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let seconds = decoder.decode_u32()?; Ok(Self { seconds }) } @@ -1338,11 +1341,25 @@ mod tests { use bytes::BytesMut; - use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; - use proto::codec::tests::roundtrip; + use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder}; + use proto::codec::tests::{expect_io_error, roundtrip}; use super::*; + #[test] + fn invalid_code() { + let mut bytes = BytesMut::new(); + ProtoEncoder::new(&mut bytes).encode_u32(1337).unwrap(); + + let mut cursor = io::Cursor::new(bytes); + let result = ServerResponse::decode(&mut ProtoDecoder::new(&mut cursor)); + expect_io_error( + result, + io::ErrorKind::InvalidData, + "unknown server response code: 1337", + ); + } + #[test] fn roundtrip_connect_to_peer() { roundtrip(ServerResponse::ConnectToPeerResponse( diff --git a/src/proto/transport.rs b/src/proto/transport.rs index b4e5935..c4f67fb 100644 --- a/src/proto/transport.rs +++ b/src/proto/transport.rs @@ -6,8 +6,7 @@ use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::codec::length_delimited; use proto::peer; -use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder, ServerResponse, - ServerRequest}; +use proto::{ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder, ServerResponse, ServerRequest}; /* ------- * * Helpers * @@ -20,7 +19,7 @@ fn new_framed(io: T) -> length_delimited::Framed Result { +fn decode_server_response(bytes: &mut BytesMut) -> io::Result { unimplemented!(); } @@ -28,7 +27,7 @@ fn encode_server_request(request: &ServerRequest) -> Result unimplemented!(); } -fn decode_peer_message(bytes: BytesMut) -> Result { +fn decode_peer_message(bytes: BytesMut) -> io::Result { let mut cursor = io::Cursor::new(bytes); let message = peer::Message::decode(&mut ProtoDecoder::new(&mut cursor))?; if cursor.has_remaining() { @@ -56,14 +55,14 @@ pub struct ServerTransport { } impl ServerTransport { - fn new(io: T) -> ServerTransport { + pub fn new(io: T) -> ServerTransport { ServerTransport { framed: new_framed(io) } } } impl Stream for ServerTransport { type Item = ServerResponse; - type Error = DecodeError; + type Error = io::Error; fn poll(&mut self) -> Poll, Self::Error> { match self.framed.poll() { @@ -73,7 +72,7 @@ impl Stream for ServerTransport { } Ok(Async::Ready(None)) => Ok(Async::Ready(None)), Ok(Async::NotReady) => Ok(Async::NotReady), - Err(err) => Err(DecodeError::from(err)), + Err(err) => Err(err), } } } @@ -112,7 +111,7 @@ impl PeerTransport { impl Stream for PeerTransport { type Item = peer::Message; - type Error = DecodeError; + type Error = io::Error; fn poll(&mut self) -> Poll, Self::Error> { match self.framed.poll() { @@ -122,7 +121,7 @@ impl Stream for PeerTransport { } Ok(Async::Ready(None)) => Ok(Async::Ready(None)), Ok(Async::NotReady) => Ok(Async::NotReady), - Err(err) => Err(DecodeError::from(err)), + Err(err) => Err(err), } } } diff --git a/src/proto/user.rs b/src/proto/user.rs index 5b4cce5..762d529 100644 --- a/src/proto/user.rs +++ b/src/proto/user.rs @@ -1,7 +1,7 @@ use std::io; -use proto::{DecodeError, MutPacket, Packet, PacketReadError, ProtoDecode, ProtoDecoder, - ProtoEncode, ProtoEncoder, ReadFromPacket, WriteToPacket}; +use proto::{MutPacket, Packet, PacketReadError, ProtoDecode, ProtoDecoder, ProtoEncode, + ProtoEncoder, ReadFromPacket, WriteToPacket}; const STATUS_OFFLINE: u32 = 1; const STATUS_AWAY: u32 = 2; @@ -54,13 +54,16 @@ impl ProtoEncode for UserStatus { } impl ProtoDecode for UserStatus { - fn decode(decoder: &mut ProtoDecoder) -> Result { + fn decode(decoder: &mut ProtoDecoder) -> io::Result { let value = decoder.decode_u32()?; match value { STATUS_OFFLINE => Ok(UserStatus::Offline), STATUS_AWAY => Ok(UserStatus::Away), STATUS_ONLINE => Ok(UserStatus::Online), - _ => Err(DecodeError::InvalidUserStatusError(value)), + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("invalid user status: {}", value), + )), } } }