tokio-codec-0.1.1/Cargo.toml.orig010064400007650000024000000011601335306562500150250ustar0000000000000000[package] name = "tokio-codec" # When releasing to crates.io: # - Update html_root_url. # - Update doc URL. # - Update CHANGELOG.md. # - Create "v0.1.x" git tag. version = "0.1.1" authors = ["Carl Lerche ", "Bryan Burgers "] license = "MIT" repository = "https://github.com/tokio-rs/tokio" homepage = "https://tokio.rs" documentation = "https://docs.rs/tokio-codec/0.1.1/tokio_codec" description = """ Utilities for encoding and decoding frames. """ categories = ["asynchronous"] [dependencies] tokio-io = { version = "0.1.7", path = "../tokio-io" } bytes = "0.4.7" futures = "0.1.18" tokio-codec-0.1.1/Cargo.toml0000644000000020070000000000000112670ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "tokio-codec" version = "0.1.1" authors = ["Carl Lerche ", "Bryan Burgers "] description = "Utilities for encoding and decoding frames.\n" homepage = "https://tokio.rs" documentation = "https://docs.rs/tokio-codec/0.1.1/tokio_codec" categories = ["asynchronous"] license = "MIT" repository = "https://github.com/tokio-rs/tokio" [dependencies.bytes] version = "0.4.7" [dependencies.futures] version = "0.1.18" [dependencies.tokio-io] version = "0.1.7" tokio-codec-0.1.1/CHANGELOG.md010064400007650000024000000002121335306562500137440ustar0000000000000000# 0.1.1 (September 26, 2018) * Allow setting max line length with `LinesCodec` (#632) # 0.1.0 (June 13, 2018) * Initial release (#353) tokio-codec-0.1.1/LICENSE010064400007650000024000000020461335247035400131450ustar0000000000000000Copyright (c) 2018 Tokio Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tokio-codec-0.1.1/README.md010064400007650000024000000014171335247035400134200ustar0000000000000000# tokio-codec Utilities for encoding and decoding frames. [Documentation](https://docs.rs/tokio-codec) ## Usage First, add this to your `Cargo.toml`: ```toml [dependencies] tokio-codec = "0.1" ``` Next, add this to your crate: ```rust extern crate tokio_codec; ``` You can find extensive documentation and examples about how to use this crate online at [https://tokio.rs](https://tokio.rs). The [API documentation](https://docs.rs/tokio-codec) is also a great place to get started for the nitty-gritty. ## License This project is licensed under the [MIT license](LICENSE). ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tokio by you, shall be licensed as MIT, without any additional terms or conditions. tokio-codec-0.1.1/src/bytes_codec.rs010064400007650000024000000017161335247035400155630ustar0000000000000000use bytes::{Bytes, BufMut, BytesMut}; use tokio_io::_tokio_codec::{Encoder, Decoder}; use std::io; /// A simple `Codec` implementation that just ships bytes around. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct BytesCodec(()); impl BytesCodec { /// Creates a new `BytesCodec` for shipping around raw bytes. pub fn new() -> BytesCodec { BytesCodec(()) } } impl Decoder for BytesCodec { type Item = BytesMut; type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, io::Error> { if buf.len() > 0 { let len = buf.len(); Ok(Some(buf.split_to(len))) } else { Ok(None) } } } impl Encoder for BytesCodec { type Item = Bytes; type Error = io::Error; fn encode(&mut self, data: Bytes, buf: &mut BytesMut) -> Result<(), io::Error> { buf.reserve(data.len()); buf.put(data); Ok(()) } } tokio-codec-0.1.1/src/lib.rs010064400007650000024000000013531335306562500140450ustar0000000000000000#![deny(missing_docs, missing_debug_implementations, warnings)] #![doc(html_root_url = "https://docs.rs/tokio-codec/0.1.1")] //! Utilities for encoding and decoding frames. //! //! Contains adapters to go from streams of bytes, [`AsyncRead`] and //! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`]. //! Framed streams are also known as [transports]. //! //! [`AsyncRead`]: # //! [`AsyncWrite`]: # //! [`Sink`]: # //! [`Stream`]: # //! [transports]: # extern crate bytes; extern crate tokio_io; mod bytes_codec; mod lines_codec; pub use tokio_io::_tokio_codec::{ Decoder, Encoder, Framed, FramedParts, FramedRead, FramedWrite, }; pub use bytes_codec::BytesCodec; pub use lines_codec::LinesCodec; tokio-codec-0.1.1/src/lines_codec.rs010064400007650000024000000160121335247035400155420ustar0000000000000000use bytes::{BufMut, BytesMut}; use tokio_io::_tokio_codec::{Encoder, Decoder}; use std::{cmp, io, str, usize}; /// A simple `Codec` implementation that splits up data into lines. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct LinesCodec { // Stored index of the next index to examine for a `\n` character. // This is used to optimize searching. // For example, if `decode` was called with `abc`, it would hold `3`, // because that is the next index to examine. // The next time `decode` is called with `abcde\n`, the method will // only look at `de\n` before returning. next_index: usize, /// The maximum length for a given line. If `usize::MAX`, lines will be /// read until a `\n` character is reached. max_length: usize, /// Are we currently discarding the remainder of a line which was over /// the length limit? is_discarding: bool, } impl LinesCodec { /// Returns a `LinesCodec` for splitting up data into lines. /// /// # Note /// /// The returned `LinesCodec` will not have an upper bound on the length /// of a buffered line. See the documentation for [`new_with_max_length`] /// for information on why this could be a potential security risk. /// /// [`new_with_max_length`]: #method.new_with_max_length pub fn new() -> LinesCodec { LinesCodec { next_index: 0, max_length: usize::MAX, is_discarding: false, } } /// Returns a `LinesCodec` with a maximum line length limit. /// /// If this is set, calls to `LinesCodec::decode` will return a /// [`LengthError`] when a line exceeds the length limit. Subsequent calls /// will discard up to `limit` bytes from that line until a newline /// character is reached, returning `None` until the line over the limit /// has been fully discarded. After that point, calls to `decode` will /// function as normal. /// /// # Note /// /// Setting a length limit is highly recommended for any `LinesCodec` which /// will be exposed to untrusted input. Otherwise, the size of the buffer /// that holds the line currently being read is unbounded. An attacker could /// exploit this unbounded buffer by sending an unbounded amount of input /// without any `\n` characters, causing unbounded memory consumption. /// /// [`LengthError`]: ../struct.LengthError pub fn new_with_max_length(max_length: usize) -> Self { LinesCodec { max_length, ..LinesCodec::new() } } /// Returns the maximum line length when decoding. /// /// ``` /// use std::usize; /// use tokio_codec::LinesCodec; /// /// let codec = LinesCodec::new(); /// assert_eq!(codec.max_length(), usize::MAX); /// ``` /// ``` /// use tokio_codec::LinesCodec; /// /// let codec = LinesCodec::new_with_max_length(256); /// assert_eq!(codec.max_length(), 256); /// ``` pub fn max_length(&self) -> usize { self.max_length } fn discard(&mut self, newline_offset: Option, read_to: usize, buf: &mut BytesMut) { let discard_to = if let Some(offset) = newline_offset { // If we found a newline, discard up to that offset and // then stop discarding. On the next iteration, we'll try // to read a line normally. self.is_discarding = false; offset + self.next_index + 1 } else { // Otherwise, we didn't find a newline, so we'll discard // everything we read. On the next iteration, we'll continue // discarding up to max_len bytes unless we find a newline. read_to }; buf.advance(discard_to); self.next_index = 0; } } fn utf8(buf: &[u8]) -> Result<&str, io::Error> { str::from_utf8(buf).map_err(|_| io::Error::new( io::ErrorKind::InvalidData, "Unable to decode input as UTF8")) } fn without_carriage_return(s: &[u8]) -> &[u8] { if let Some(&b'\r') = s.last() { &s[..s.len() - 1] } else { s } } impl Decoder for LinesCodec { type Item = String; // TODO: in the next breaking change, this should be changed to a custom // error type that indicates the "max length exceeded" condition better. type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> Result, io::Error> { loop { // Determine how far into the buffer we'll search for a newline. If // there's no max_length set, we'll read to the end of the buffer. let read_to = cmp::min(self.max_length.saturating_add(1), buf.len()); let newline_offset = buf[self.next_index..read_to] .iter() .position(|b| *b == b'\n'); if self.is_discarding { self.discard(newline_offset, read_to, buf); } else { return if let Some(offset) = newline_offset { // Found a line! let newline_index = offset + self.next_index; self.next_index = 0; let line = buf.split_to(newline_index + 1); let line = &line[..line.len() - 1]; let line = without_carriage_return(line); let line = utf8(line)?; Ok(Some(line.to_string())) } else if buf.len() > self.max_length { // Reached the maximum length without finding a // newline, return an error and start discarding on the // next call. self.is_discarding = true; Err(io::Error::new( io::ErrorKind::Other, "line length limit exceeded" )) } else { // We didn't find a line or reach the length limit, so the next // call will resume searching at the current offset. self.next_index = read_to; Ok(None) }; } } } fn decode_eof(&mut self, buf: &mut BytesMut) -> Result, io::Error> { Ok(match self.decode(buf)? { Some(frame) => Some(frame), None => { // No terminating newline - return remaining data, if any if buf.is_empty() || buf == &b"\r"[..] { None } else { let line = buf.take(); let line = without_carriage_return(&line); let line = utf8(line)?; self.next_index = 0; Some(line.to_string()) } } }) } } impl Encoder for LinesCodec { type Item = String; type Error = io::Error; fn encode(&mut self, line: String, buf: &mut BytesMut) -> Result<(), io::Error> { buf.reserve(line.len() + 1); buf.put(line); buf.put_u8(b'\n'); Ok(()) } } tokio-codec-0.1.1/tests/codecs.rs010064400007650000024000000124741335247035400151160ustar0000000000000000extern crate tokio_codec; extern crate bytes; use bytes::{BytesMut, Bytes, BufMut}; use tokio_codec::{BytesCodec, LinesCodec, Decoder, Encoder}; #[test] fn bytes_decoder() { let mut codec = BytesCodec::new(); let buf = &mut BytesMut::new(); buf.put_slice(b"abc"); assert_eq!("abc", codec.decode(buf).unwrap().unwrap()); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!(None, codec.decode(buf).unwrap()); buf.put_slice(b"a"); assert_eq!("a", codec.decode(buf).unwrap().unwrap()); } #[test] fn bytes_encoder() { let mut codec = BytesCodec::new(); // Default capacity of BytesMut #[cfg(target_pointer_width = "64")] const INLINE_CAP: usize = 4 * 8 - 1; #[cfg(target_pointer_width = "32")] const INLINE_CAP: usize = 4 * 4 - 1; let mut buf = BytesMut::new(); codec.encode(Bytes::from_static(&[0; INLINE_CAP + 1]), &mut buf).unwrap(); // Default capacity of Framed Read const INITIAL_CAPACITY: usize = 8 * 1024; let mut buf = BytesMut::with_capacity(INITIAL_CAPACITY); codec.encode(Bytes::from_static(&[0; INITIAL_CAPACITY + 1]), &mut buf).unwrap(); } #[test] fn lines_decoder() { let mut codec = LinesCodec::new(); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("line 1\nline 2\r\nline 3\n\r\n\r"); assert_eq!("line 1", codec.decode(buf).unwrap().unwrap()); assert_eq!("line 2", codec.decode(buf).unwrap().unwrap()); assert_eq!("line 3", codec.decode(buf).unwrap().unwrap()); assert_eq!("", codec.decode(buf).unwrap().unwrap()); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!(None, codec.decode_eof(buf).unwrap()); buf.put("k"); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!("\rk", codec.decode_eof(buf).unwrap().unwrap()); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!(None, codec.decode_eof(buf).unwrap()); } #[test] fn lines_decoder_max_length() { const MAX_LENGTH: usize = 6; let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("line 1 is too long\nline 2\nline 3\r\nline 4\n\r\n\r"); assert!(codec.decode(buf).is_err()); let line = codec.decode(buf).unwrap().unwrap(); assert!(line.len() <= MAX_LENGTH, "{:?}.len() <= {:?}", line, MAX_LENGTH); assert_eq!("line 2", line); assert!(codec.decode(buf).is_err()); let line = codec.decode(buf).unwrap().unwrap(); assert!(line.len() <= MAX_LENGTH, "{:?}.len() <= {:?}", line, MAX_LENGTH); assert_eq!("line 4", line); let line = codec.decode(buf).unwrap().unwrap(); assert!(line.len() <= MAX_LENGTH, "{:?}.len() <= {:?}", line, MAX_LENGTH); assert_eq!("", line); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!(None, codec.decode_eof(buf).unwrap()); buf.put("k"); assert_eq!(None, codec.decode(buf).unwrap()); let line = codec.decode_eof(buf).unwrap().unwrap(); assert!(line.len() <= MAX_LENGTH, "{:?}.len() <= {:?}", line, MAX_LENGTH); assert_eq!("\rk", line); assert_eq!(None, codec.decode(buf).unwrap()); assert_eq!(None, codec.decode_eof(buf).unwrap()); // Line that's one character too long. This could cause an out of bounds // error if we peek at the next characters using slice indexing. // buf.put("aaabbbc"); // assert!(codec.decode(buf).is_err()); } #[test] fn lines_decoder_max_length_underrun() { const MAX_LENGTH: usize = 6; let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("line "); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("too l"); assert!(codec.decode(buf).is_err()); buf.put("ong\n"); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("line 2"); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("\n"); assert_eq!("line 2", codec.decode(buf).unwrap().unwrap()); } #[test] fn lines_decoder_max_length_bursts() { const MAX_LENGTH: usize = 10; let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("line "); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("too l"); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("ong\n"); assert!(codec.decode(buf).is_err()); } #[test] fn lines_decoder_max_length_big_burst() { const MAX_LENGTH: usize = 10; let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("line "); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("too long!\n"); assert!(codec.decode(buf).is_err()); } #[test] fn lines_decoder_max_length_newline_between_decodes() { const MAX_LENGTH: usize = 5; let mut codec = LinesCodec::new_with_max_length(MAX_LENGTH); let buf = &mut BytesMut::new(); buf.reserve(200); buf.put("hello"); assert_eq!(None, codec.decode(buf).unwrap()); buf.put("\nworld"); assert_eq!("hello", codec.decode(buf).unwrap().unwrap()); } #[test] fn lines_encoder() { let mut codec = LinesCodec::new(); let mut buf = BytesMut::new(); codec.encode(String::from("line 1"), &mut buf).unwrap(); assert_eq!("line 1\n", buf); codec.encode(String::from("line 2"), &mut buf).unwrap(); assert_eq!("line 1\nline 2\n", buf); } tokio-codec-0.1.1/tests/framed.rs010064400007650000024000000044311335247035400151060ustar0000000000000000extern crate tokio_codec; extern crate tokio_io; extern crate bytes; extern crate futures; use futures::{Stream, Future}; use std::io::{self, Read}; use tokio_codec::{Framed, FramedParts, Decoder, Encoder}; use tokio_io::AsyncRead; use bytes::{BytesMut, Buf, BufMut, IntoBuf}; const INITIAL_CAPACITY: usize = 8 * 1024; /// Encode and decode u32 values. struct U32Codec; impl Decoder for U32Codec { type Item = u32; type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> io::Result> { if buf.len() < 4 { return Ok(None); } let n = buf.split_to(4).into_buf().get_u32_be(); Ok(Some(n)) } } impl Encoder for U32Codec { type Item = u32; type Error = io::Error; fn encode(&mut self, item: u32, dst: &mut BytesMut) -> io::Result<()> { // Reserve space dst.reserve(4); dst.put_u32_be(item); Ok(()) } } /// This value should never be used struct DontReadIntoThis; impl Read for DontReadIntoThis { fn read(&mut self, _: &mut [u8]) -> io::Result { Err(io::Error::new(io::ErrorKind::Other, "Read into something you weren't supposed to.")) } } impl AsyncRead for DontReadIntoThis {} #[test] fn can_read_from_existing_buf() { let mut parts = FramedParts::new(DontReadIntoThis, U32Codec); parts.read_buf = vec![0, 0, 0, 42].into(); let framed = Framed::from_parts(parts); let num = framed .into_future() .map(|(first_num, _)| { first_num.unwrap() }) .wait() .map_err(|e| e.0) .unwrap(); assert_eq!(num, 42); } #[test] fn external_buf_grows_to_init() { let mut parts = FramedParts::new(DontReadIntoThis, U32Codec); parts.read_buf = vec![0, 0, 0, 42].into(); let framed = Framed::from_parts(parts); let FramedParts { read_buf, .. } = framed.into_parts(); assert_eq!(read_buf.capacity(), INITIAL_CAPACITY); } #[test] fn external_buf_does_not_shrink() { let mut parts = FramedParts::new(DontReadIntoThis, U32Codec); parts.read_buf = vec![0; INITIAL_CAPACITY * 2].into(); let framed = Framed::from_parts(parts); let FramedParts { read_buf, .. } = framed.into_parts(); assert_eq!(read_buf.capacity(), INITIAL_CAPACITY * 2); } tokio-codec-0.1.1/tests/framed_read.rs010064400007650000024000000133461335247035400161060ustar0000000000000000extern crate tokio_codec; extern crate tokio_io; extern crate bytes; extern crate futures; use tokio_io::AsyncRead; use tokio_codec::{FramedRead, Decoder}; use bytes::{BytesMut, Buf, IntoBuf}; use futures::Stream; use futures::Async::{Ready, NotReady}; use std::io::{self, Read}; use std::collections::VecDeque; macro_rules! mock { ($($x:expr,)*) => {{ let mut v = VecDeque::new(); v.extend(vec![$($x),*]); Mock { calls: v } }}; } struct U32Decoder; impl Decoder for U32Decoder { type Item = u32; type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> io::Result> { if buf.len() < 4 { return Ok(None); } let n = buf.split_to(4).into_buf().get_u32_be(); Ok(Some(n)) } } #[test] fn read_multi_frame_in_packet() { let mock = mock! { Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(Some(1)), framed.poll().unwrap()); assert_eq!(Ready(Some(2)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); } #[test] fn read_multi_frame_across_packets() { let mock = mock! { Ok(b"\x00\x00\x00\x00".to_vec()), Ok(b"\x00\x00\x00\x01".to_vec()), Ok(b"\x00\x00\x00\x02".to_vec()), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(Some(1)), framed.poll().unwrap()); assert_eq!(Ready(Some(2)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); } #[test] fn read_not_ready() { let mock = mock! { Err(io::Error::new(io::ErrorKind::WouldBlock, "")), Ok(b"\x00\x00\x00\x00".to_vec()), Ok(b"\x00\x00\x00\x01".to_vec()), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(NotReady, framed.poll().unwrap()); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(Some(1)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); } #[test] fn read_partial_then_not_ready() { let mock = mock! { Ok(b"\x00\x00".to_vec()), Err(io::Error::new(io::ErrorKind::WouldBlock, "")), Ok(b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(NotReady, framed.poll().unwrap()); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(Some(1)), framed.poll().unwrap()); assert_eq!(Ready(Some(2)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); } #[test] fn read_err() { let mock = mock! { Err(io::Error::new(io::ErrorKind::Other, "")), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind()); } #[test] fn read_partial_then_err() { let mock = mock! { Ok(b"\x00\x00".to_vec()), Err(io::Error::new(io::ErrorKind::Other, "")), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind()); } #[test] fn read_partial_would_block_then_err() { let mock = mock! { Ok(b"\x00\x00".to_vec()), Err(io::Error::new(io::ErrorKind::WouldBlock, "")), Err(io::Error::new(io::ErrorKind::Other, "")), }; let mut framed = FramedRead::new(mock, U32Decoder); assert_eq!(NotReady, framed.poll().unwrap()); assert_eq!(io::ErrorKind::Other, framed.poll().unwrap_err().kind()); } #[test] fn huge_size() { let data = [0; 32 * 1024]; let mut framed = FramedRead::new(&data[..], BigDecoder); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); struct BigDecoder; impl Decoder for BigDecoder { type Item = u32; type Error = io::Error; fn decode(&mut self, buf: &mut BytesMut) -> io::Result> { if buf.len() < 32 * 1024 { return Ok(None); } buf.split_to(32 * 1024); Ok(Some(0)) } } } #[test] fn data_remaining_is_error() { let data = [0; 5]; let mut framed = FramedRead::new(&data[..], U32Decoder); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert!(framed.poll().is_err()); } #[test] fn multi_frames_on_eof() { struct MyDecoder(Vec); impl Decoder for MyDecoder { type Item = u32; type Error = io::Error; fn decode(&mut self, _buf: &mut BytesMut) -> io::Result> { unreachable!(); } fn decode_eof(&mut self, _buf: &mut BytesMut) -> io::Result> { if self.0.is_empty() { return Ok(None); } Ok(Some(self.0.remove(0))) } } let mut framed = FramedRead::new(mock!(), MyDecoder(vec![0, 1, 2, 3])); assert_eq!(Ready(Some(0)), framed.poll().unwrap()); assert_eq!(Ready(Some(1)), framed.poll().unwrap()); assert_eq!(Ready(Some(2)), framed.poll().unwrap()); assert_eq!(Ready(Some(3)), framed.poll().unwrap()); assert_eq!(Ready(None), framed.poll().unwrap()); } // ===== Mock ====== struct Mock { calls: VecDeque>>, } impl Read for Mock { fn read(&mut self, dst: &mut [u8]) -> io::Result { match self.calls.pop_front() { Some(Ok(data)) => { debug_assert!(dst.len() >= data.len()); dst[..data.len()].copy_from_slice(&data[..]); Ok(data.len()) } Some(Err(e)) => Err(e), None => Ok(0), } } } impl AsyncRead for Mock { } tokio-codec-0.1.1/tests/framed_write.rs010064400007650000024000000063541335247035400163260ustar0000000000000000extern crate tokio_codec; extern crate tokio_io; extern crate bytes; extern crate futures; use tokio_io::AsyncWrite; use tokio_codec::{Encoder, FramedWrite}; use futures::{Sink, Poll}; use bytes::{BytesMut, BufMut}; use std::io::{self, Write}; use std::collections::VecDeque; macro_rules! mock { ($($x:expr,)*) => {{ let mut v = VecDeque::new(); v.extend(vec![$($x),*]); Mock { calls: v } }}; } struct U32Encoder; impl Encoder for U32Encoder { type Item = u32; type Error = io::Error; fn encode(&mut self, item: u32, dst: &mut BytesMut) -> io::Result<()> { // Reserve space dst.reserve(4); dst.put_u32_be(item); Ok(()) } } #[test] fn write_multi_frame_in_packet() { let mock = mock! { Ok(b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02".to_vec()), }; let mut framed = FramedWrite::new(mock, U32Encoder); assert!(framed.start_send(0).unwrap().is_ready()); assert!(framed.start_send(1).unwrap().is_ready()); assert!(framed.start_send(2).unwrap().is_ready()); // Nothing written yet assert_eq!(1, framed.get_ref().calls.len()); // Flush the writes assert!(framed.poll_complete().unwrap().is_ready()); assert_eq!(0, framed.get_ref().calls.len()); } #[test] fn write_hits_backpressure() { const ITER: usize = 2 * 1024; let mut mock = mock! { // Block the `ITER`th write Err(io::Error::new(io::ErrorKind::WouldBlock, "not ready")), Ok(b"".to_vec()), }; for i in 0..(ITER + 1) { let mut b = BytesMut::with_capacity(4); b.put_u32_be(i as u32); // Append to the end match mock.calls.back_mut().unwrap() { &mut Ok(ref mut data) => { // Write in 2kb chunks if data.len() < ITER { data.extend_from_slice(&b[..]); continue; } } _ => unreachable!(), } // Push a new new chunk mock.calls.push_back(Ok(b[..].to_vec())); } let mut framed = FramedWrite::new(mock, U32Encoder); for i in 0..ITER { assert!(framed.start_send(i as u32).unwrap().is_ready()); } // This should reject assert!(!framed.start_send(ITER as u32).unwrap().is_ready()); // This should succeed and start flushing the buffer. assert!(framed.start_send(ITER as u32).unwrap().is_ready()); // Flush the rest of the buffer assert!(framed.poll_complete().unwrap().is_ready()); // Ensure the mock is empty assert_eq!(0, framed.get_ref().calls.len()); } // ===== Mock ====== struct Mock { calls: VecDeque>>, } impl Write for Mock { fn write(&mut self, src: &[u8]) -> io::Result { match self.calls.pop_front() { Some(Ok(data)) => { assert!(src.len() >= data.len()); assert_eq!(&data[..], &src[..data.len()]); Ok(data.len()) } Some(Err(e)) => Err(e), None => panic!("unexpected write; {:?}", src), } } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl AsyncWrite for Mock { fn shutdown(&mut self) -> Poll<(), io::Error> { Ok(().into()) } }