perf(http): introduce MemBuf, a shared read buffer
This commit is contained in:
		@@ -1,5 +1,8 @@
 | 
			
		||||
use std::{cmp, usize};
 | 
			
		||||
use std::io::{self, Read};
 | 
			
		||||
use std::usize;
 | 
			
		||||
use std::io;
 | 
			
		||||
 | 
			
		||||
use http::buf::MemSlice;
 | 
			
		||||
use http::io::MemRead;
 | 
			
		||||
 | 
			
		||||
use self::Kind::{Length, Chunked, Eof};
 | 
			
		||||
 | 
			
		||||
@@ -76,15 +79,16 @@ impl Decoder {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Decoder {
 | 
			
		||||
    pub fn decode<R: Read>(&mut self, body: &mut R, buf: &mut [u8]) -> io::Result<usize> {
 | 
			
		||||
    pub fn decode<R: MemRead>(&mut self, body: &mut R) -> io::Result<MemSlice> {
 | 
			
		||||
        match self.kind {
 | 
			
		||||
            Length(ref mut remaining) => {
 | 
			
		||||
                trace!("Sized read, remaining={:?}", remaining);
 | 
			
		||||
                if *remaining == 0 {
 | 
			
		||||
                    Ok(0)
 | 
			
		||||
                    Ok(MemSlice::empty())
 | 
			
		||||
                } else {
 | 
			
		||||
                    let to_read = cmp::min(*remaining as usize, buf.len());
 | 
			
		||||
                    let num = try!(body.read(&mut buf[..to_read])) as u64;
 | 
			
		||||
                    let to_read = *remaining as usize;
 | 
			
		||||
                    let buf = try!(body.read_mem(to_read));
 | 
			
		||||
                    let num = buf.len() as u64;
 | 
			
		||||
                    trace!("Length read: {}", num);
 | 
			
		||||
                    if num > *remaining {
 | 
			
		||||
                        *remaining = 0;
 | 
			
		||||
@@ -93,30 +97,37 @@ impl Decoder {
 | 
			
		||||
                    } else {
 | 
			
		||||
                        *remaining -= num;
 | 
			
		||||
                    }
 | 
			
		||||
                    Ok(num as usize)
 | 
			
		||||
                    Ok(buf)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Chunked(ref mut state, ref mut size) => {
 | 
			
		||||
                loop {
 | 
			
		||||
                    let mut read = 0;
 | 
			
		||||
                    let mut buf = None;
 | 
			
		||||
                    // advances the chunked state
 | 
			
		||||
                    *state = try!(state.step(body, size, buf, &mut read));
 | 
			
		||||
                    *state = try!(state.step(body, size, &mut buf));
 | 
			
		||||
                    if *state == ChunkedState::End {
 | 
			
		||||
                        trace!("end of chunked");
 | 
			
		||||
                        return Ok(0);
 | 
			
		||||
                        return Ok(MemSlice::empty());
 | 
			
		||||
                    }
 | 
			
		||||
                    if read > 0 {
 | 
			
		||||
                        return Ok(read);
 | 
			
		||||
                    if let Some(buf) = buf {
 | 
			
		||||
                        return Ok(buf);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Eof(ref mut is_eof) => {
 | 
			
		||||
                match body.read(buf) {
 | 
			
		||||
                    Ok(0) => {
 | 
			
		||||
                        *is_eof = true;
 | 
			
		||||
                        Ok(0)
 | 
			
		||||
                if *is_eof {
 | 
			
		||||
                    Ok(MemSlice::empty())
 | 
			
		||||
                } else {
 | 
			
		||||
                    // 8192 chosen because its about 2 packets, there probably
 | 
			
		||||
                    // won't be that much available, so don't have MemReaders
 | 
			
		||||
                    // allocate buffers to big
 | 
			
		||||
                    match body.read_mem(8192) {
 | 
			
		||||
                        Ok(slice) => {
 | 
			
		||||
                            *is_eof = slice.is_empty();
 | 
			
		||||
                            Ok(slice)
 | 
			
		||||
                        }
 | 
			
		||||
                        other => other,
 | 
			
		||||
                    }
 | 
			
		||||
                    other => other,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -125,29 +136,29 @@ impl Decoder {
 | 
			
		||||
 | 
			
		||||
macro_rules! byte (
 | 
			
		||||
    ($rdr:ident) => ({
 | 
			
		||||
        let mut buf = [0];
 | 
			
		||||
        match try!($rdr.read(&mut buf)) {
 | 
			
		||||
            1 => buf[0],
 | 
			
		||||
            _ => return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
 | 
			
		||||
                                           "Unexpected eof during chunk size line")),
 | 
			
		||||
        let buf = try!($rdr.read_mem(1));
 | 
			
		||||
        if !buf.is_empty() {
 | 
			
		||||
            buf[0]
 | 
			
		||||
        } else {
 | 
			
		||||
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
 | 
			
		||||
                                      "Unexpected eof during chunk size line"));
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
impl ChunkedState {
 | 
			
		||||
    fn step<R: Read>(&self,
 | 
			
		||||
                     body: &mut R,
 | 
			
		||||
                     size: &mut u64,
 | 
			
		||||
                     buf: &mut [u8],
 | 
			
		||||
                     read: &mut usize)
 | 
			
		||||
                     -> io::Result<ChunkedState> {
 | 
			
		||||
    fn step<R: MemRead>(&self,
 | 
			
		||||
                        body: &mut R,
 | 
			
		||||
                        size: &mut u64,
 | 
			
		||||
                        buf: &mut Option<MemSlice>)
 | 
			
		||||
                        -> io::Result<ChunkedState> {
 | 
			
		||||
        use self::ChunkedState::*;
 | 
			
		||||
        Ok(match *self {
 | 
			
		||||
            Size => try!(ChunkedState::read_size(body, size)),
 | 
			
		||||
            SizeLws => try!(ChunkedState::read_size_lws(body)),
 | 
			
		||||
            Extension => try!(ChunkedState::read_extension(body)),
 | 
			
		||||
            SizeLf => try!(ChunkedState::read_size_lf(body, size)),
 | 
			
		||||
            Body => try!(ChunkedState::read_body(body, size, buf, read)),
 | 
			
		||||
            Body => try!(ChunkedState::read_body(body, size, buf)),
 | 
			
		||||
            BodyCr => try!(ChunkedState::read_body_cr(body)),
 | 
			
		||||
            BodyLf => try!(ChunkedState::read_body_lf(body)),
 | 
			
		||||
            EndCr => try!(ChunkedState::read_end_cr(body)),
 | 
			
		||||
@@ -155,8 +166,8 @@ impl ChunkedState {
 | 
			
		||||
            End => ChunkedState::End,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn read_size<R: Read>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("Read size");
 | 
			
		||||
    fn read_size<R: MemRead>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("Read chunk hex size");
 | 
			
		||||
        let radix = 16;
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b @ b'0'...b'9' => {
 | 
			
		||||
@@ -181,7 +192,7 @@ impl ChunkedState {
 | 
			
		||||
        }
 | 
			
		||||
        Ok(ChunkedState::Size)
 | 
			
		||||
    }
 | 
			
		||||
    fn read_size_lws<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_size_lws<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("read_size_lws");
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            // LWS can follow the chunk size, but no more digits can come
 | 
			
		||||
@@ -194,14 +205,14 @@ impl ChunkedState {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn read_extension<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_extension<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("read_extension");
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\r' => return Ok(ChunkedState::SizeLf),
 | 
			
		||||
            _ => return Ok(ChunkedState::Extension), // no supported extensions
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn read_size_lf<R: Read>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_size_lf<R: MemRead>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("Chunk size is {:?}", size);
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\n' if *size > 0 => Ok(ChunkedState::Body),
 | 
			
		||||
@@ -210,10 +221,9 @@ impl ChunkedState {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_body<R: Read>(rdr: &mut R,
 | 
			
		||||
    fn read_body<R: MemRead>(rdr: &mut R,
 | 
			
		||||
                          rem: &mut u64,
 | 
			
		||||
                          buf: &mut [u8],
 | 
			
		||||
                          read: &mut usize)
 | 
			
		||||
                          buf: &mut Option<MemSlice>)
 | 
			
		||||
                          -> io::Result<ChunkedState> {
 | 
			
		||||
        trace!("Chunked read, remaining={:?}", rem);
 | 
			
		||||
 | 
			
		||||
@@ -223,19 +233,16 @@ impl ChunkedState {
 | 
			
		||||
            r => r as usize,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let to_read = cmp::min(rem_cap, buf.len());
 | 
			
		||||
        let count = try!(rdr.read(&mut buf[..to_read]));
 | 
			
		||||
 | 
			
		||||
        trace!("to_read = {}", to_read);
 | 
			
		||||
        trace!("count = {}", count);
 | 
			
		||||
        let to_read = rem_cap;
 | 
			
		||||
        let slice = try!(rdr.read_mem(to_read));
 | 
			
		||||
        let count = slice.len();
 | 
			
		||||
 | 
			
		||||
        if count == 0 {
 | 
			
		||||
            *rem = 0;
 | 
			
		||||
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "early eof"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *buf = Some(slice);
 | 
			
		||||
        *rem -= count as u64;
 | 
			
		||||
        *read = count;
 | 
			
		||||
 | 
			
		||||
        if *rem > 0 {
 | 
			
		||||
            Ok(ChunkedState::Body)
 | 
			
		||||
@@ -243,26 +250,26 @@ impl ChunkedState {
 | 
			
		||||
            Ok(ChunkedState::BodyCr)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn read_body_cr<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_body_cr<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\r' => Ok(ChunkedState::BodyLf),
 | 
			
		||||
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR")),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn read_body_lf<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_body_lf<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\n' => Ok(ChunkedState::Size),
 | 
			
		||||
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF")),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_end_cr<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_end_cr<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\r' => Ok(ChunkedState::EndLf),
 | 
			
		||||
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR")),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn read_end_lf<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
    fn read_end_lf<R: MemRead>(rdr: &mut R) -> io::Result<ChunkedState> {
 | 
			
		||||
        match byte!(rdr) {
 | 
			
		||||
            b'\n' => Ok(ChunkedState::End),
 | 
			
		||||
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF")),
 | 
			
		||||
@@ -277,8 +284,23 @@ mod tests {
 | 
			
		||||
    use std::io::Write;
 | 
			
		||||
    use super::Decoder;
 | 
			
		||||
    use super::ChunkedState;
 | 
			
		||||
    use http::io::MemRead;
 | 
			
		||||
    use http::buf::{MemBuf, MemSlice};
 | 
			
		||||
    use mock::AsyncIo;
 | 
			
		||||
 | 
			
		||||
    impl<'a> MemRead for &'a [u8] {
 | 
			
		||||
        fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> {
 | 
			
		||||
            let n = ::std::cmp::min(len, self.len());
 | 
			
		||||
            if n > 0 {
 | 
			
		||||
                let mut buf = MemBuf::with_capacity(n);
 | 
			
		||||
                buf.read_from(self).unwrap();
 | 
			
		||||
                Ok(buf.slice(n))
 | 
			
		||||
            } else {
 | 
			
		||||
                Ok(MemSlice::empty())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_read_chunk_size() {
 | 
			
		||||
        use std::io::ErrorKind::{UnexpectedEof, InvalidInput};
 | 
			
		||||
@@ -287,13 +309,10 @@ mod tests {
 | 
			
		||||
            let mut state = ChunkedState::Size;
 | 
			
		||||
            let mut rdr = &mut s.as_bytes();
 | 
			
		||||
            let mut size = 0;
 | 
			
		||||
            let mut count = 0;
 | 
			
		||||
            loop {
 | 
			
		||||
                let mut buf = [0u8; 10];
 | 
			
		||||
                let result = state.step(&mut rdr, &mut size, &mut buf, &mut count);
 | 
			
		||||
                let result = state.step(rdr, &mut size, &mut None);
 | 
			
		||||
                let desc = format!("read_size failed for {:?}", s);
 | 
			
		||||
                state = result.expect(desc.as_str());
 | 
			
		||||
                trace!("State {:?}", state);
 | 
			
		||||
                if state == ChunkedState::Body || state == ChunkedState::EndCr {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -305,10 +324,8 @@ mod tests {
 | 
			
		||||
            let mut state = ChunkedState::Size;
 | 
			
		||||
            let mut rdr = &mut s.as_bytes();
 | 
			
		||||
            let mut size = 0;
 | 
			
		||||
            let mut count = 0;
 | 
			
		||||
            loop {
 | 
			
		||||
                let mut buf = [0u8; 10];
 | 
			
		||||
                let result = state.step(&mut rdr, &mut size, &mut buf, &mut count);
 | 
			
		||||
                let result = state.step(rdr, &mut size, &mut None);
 | 
			
		||||
                state = match result {
 | 
			
		||||
                    Ok(s) => s,
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
@@ -317,7 +334,6 @@ mod tests {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                trace!("State {:?}", state);
 | 
			
		||||
                if state == ChunkedState::Body || state == ChunkedState::End {
 | 
			
		||||
                    panic!(format!("Was Ok. Expected Err for {:?}", s));
 | 
			
		||||
                }
 | 
			
		||||
@@ -359,9 +375,8 @@ mod tests {
 | 
			
		||||
    fn test_read_sized_early_eof() {
 | 
			
		||||
        let mut bytes = &b"foo bar"[..];
 | 
			
		||||
        let mut decoder = Decoder::length(10);
 | 
			
		||||
        let mut buf = [0u8; 10];
 | 
			
		||||
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
 | 
			
		||||
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
 | 
			
		||||
        assert_eq!(decoder.decode(&mut bytes).unwrap().len(), 7);
 | 
			
		||||
        let e = decoder.decode(&mut bytes).unwrap_err();
 | 
			
		||||
        assert_eq!(e.kind(), io::ErrorKind::Other);
 | 
			
		||||
        assert_eq!(e.description(), "early eof");
 | 
			
		||||
    }
 | 
			
		||||
@@ -373,68 +388,63 @@ mod tests {
 | 
			
		||||
            foo bar\
 | 
			
		||||
        "[..];
 | 
			
		||||
        let mut decoder = Decoder::chunked();
 | 
			
		||||
        let mut buf = [0u8; 10];
 | 
			
		||||
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
 | 
			
		||||
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
 | 
			
		||||
        assert_eq!(decoder.decode(&mut bytes).unwrap().len(), 7);
 | 
			
		||||
        let e = decoder.decode(&mut bytes).unwrap_err();
 | 
			
		||||
        assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
 | 
			
		||||
        assert_eq!(e.description(), "early eof");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_read_chunked_single_read() {
 | 
			
		||||
        let content = b"10\r\n1234567890abcdef\r\n0\r\n";
 | 
			
		||||
        let mut mock_buf = io::Cursor::new(content);
 | 
			
		||||
        let mut buf = [0u8; 16];
 | 
			
		||||
        let count = Decoder::chunked().decode(&mut mock_buf, &mut buf).expect("decode");
 | 
			
		||||
        assert_eq!(16, count);
 | 
			
		||||
        let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n"[..];
 | 
			
		||||
        let buf = Decoder::chunked().decode(&mut mock_buf).expect("decode");
 | 
			
		||||
        assert_eq!(16, buf.len());
 | 
			
		||||
        let result = String::from_utf8(buf.to_vec()).expect("decode String");
 | 
			
		||||
        assert_eq!("1234567890abcdef", &result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_read_chunked_after_eof() {
 | 
			
		||||
        let content = b"10\r\n1234567890abcdef\r\n0\r\n\r\n";
 | 
			
		||||
        let mut mock_buf = io::Cursor::new(content);
 | 
			
		||||
        let mut buf = [0u8; 50];
 | 
			
		||||
        let mut mock_buf = &b"10\r\n1234567890abcdef\r\n0\r\n\r\n"[..];
 | 
			
		||||
        let mut decoder = Decoder::chunked();
 | 
			
		||||
 | 
			
		||||
        // normal read
 | 
			
		||||
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
 | 
			
		||||
        assert_eq!(16, count);
 | 
			
		||||
        let result = String::from_utf8(buf[0..count].to_vec()).expect("decode String");
 | 
			
		||||
        let buf = decoder.decode(&mut mock_buf).expect("decode");
 | 
			
		||||
        assert_eq!(16, buf.len());
 | 
			
		||||
        let result = String::from_utf8(buf.to_vec()).expect("decode String");
 | 
			
		||||
        assert_eq!("1234567890abcdef", &result);
 | 
			
		||||
 | 
			
		||||
        // eof read
 | 
			
		||||
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
 | 
			
		||||
        assert_eq!(0, count);
 | 
			
		||||
        let buf = decoder.decode(&mut mock_buf).expect("decode");
 | 
			
		||||
        assert_eq!(0, buf.len());
 | 
			
		||||
 | 
			
		||||
        // ensure read after eof also returns eof
 | 
			
		||||
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
 | 
			
		||||
        assert_eq!(0, count);
 | 
			
		||||
        let buf = decoder.decode(&mut mock_buf).expect("decode");
 | 
			
		||||
        assert_eq!(0, buf.len());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // perform an async read using a custom buffer size and causing a blocking
 | 
			
		||||
    // read at the specified byte
 | 
			
		||||
    fn read_async(mut decoder: Decoder,
 | 
			
		||||
                  content: &[u8],
 | 
			
		||||
                  block_at: usize,
 | 
			
		||||
                  read_buffer_size: usize)
 | 
			
		||||
                  block_at: usize)
 | 
			
		||||
                  -> String {
 | 
			
		||||
        let content_len = content.len();
 | 
			
		||||
        let mock_buf = io::Cursor::new(content.clone());
 | 
			
		||||
        let mut ins = AsyncIo::new(mock_buf, block_at);
 | 
			
		||||
        let mut outs = vec![];
 | 
			
		||||
        let mut ins = AsyncIo::new(content, block_at);
 | 
			
		||||
        let mut outs = Vec::new();
 | 
			
		||||
        loop {
 | 
			
		||||
            let mut buf = vec![0; read_buffer_size];
 | 
			
		||||
            match decoder.decode(&mut ins, buf.as_mut_slice()) {
 | 
			
		||||
                Ok(0) => break,
 | 
			
		||||
                Ok(i) => outs.write(&buf[0..i]).expect("write buffer"),
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    if e.kind() != io::ErrorKind::WouldBlock {
 | 
			
		||||
                        break;
 | 
			
		||||
            match decoder.decode(&mut ins) {
 | 
			
		||||
                Ok(buf) => {
 | 
			
		||||
                    if buf.is_empty() {
 | 
			
		||||
                        break; // eof
 | 
			
		||||
                    }
 | 
			
		||||
                    ins.block_in(content_len); // we only block once
 | 
			
		||||
                    0 as usize
 | 
			
		||||
                    outs.write(&buf).expect("write buffer");
 | 
			
		||||
                }
 | 
			
		||||
                Err(e) => match e.kind() {
 | 
			
		||||
                    io::ErrorKind::WouldBlock => {
 | 
			
		||||
                        ins.block_in(content_len); // we only block once
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => panic!("unexpected decode error: {}", e),
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
@@ -442,22 +452,12 @@ mod tests {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // iterate over the different ways that this async read could go.
 | 
			
		||||
    // tests every combination of buffer size that is passed in, with a blocking
 | 
			
		||||
    // read at each byte along the content - The shotgun approach
 | 
			
		||||
    // tests blocking a read at each byte along the content - The shotgun approach
 | 
			
		||||
    fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {
 | 
			
		||||
        let content_len = content.len();
 | 
			
		||||
        for block_at in 0..content_len {
 | 
			
		||||
            for read_buffer_size in 1..content_len {
 | 
			
		||||
                let actual = read_async(decoder.clone(),
 | 
			
		||||
                                        content.as_bytes(),
 | 
			
		||||
                                        block_at,
 | 
			
		||||
                                        read_buffer_size);
 | 
			
		||||
                assert_eq!(expected,
 | 
			
		||||
                    &actual,
 | 
			
		||||
                    "Failed async. Blocking at {} with read buffer size {}",
 | 
			
		||||
                    block_at,
 | 
			
		||||
                    read_buffer_size);
 | 
			
		||||
            }
 | 
			
		||||
            let actual = read_async(decoder.clone(), content.as_bytes(), block_at);
 | 
			
		||||
            assert_eq!(expected, &actual, "Failed async. Blocking at {}", block_at);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -469,7 +469,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_read_chunked_async() {
 | 
			
		||||
        let content = "3\r\nfoo\r\n3\r\nbar\r\n0\r\n";
 | 
			
		||||
        let content = "3\r\nfoo\r\n3\r\nbar\r\n0\r\n\r\n";
 | 
			
		||||
        let expected = "foobar";
 | 
			
		||||
        all_async_cases(content, expected, Decoder::chunked());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user